memorix 1.2.6 → 1.2.8
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 +20 -0
- package/README.md +6 -3
- package/README.zh-CN.md +5 -2
- package/dist/cli/index.js +1272 -105
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/app.js +7 -2
- package/dist/index.js +809 -52
- package/dist/index.js.map +1 -1
- package/dist/maintenance-runner.d.ts +6 -0
- package/dist/maintenance-runner.js +204 -25
- package/dist/maintenance-runner.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +20 -0
- package/dist/sdk.d.ts +1 -1
- package/dist/sdk.js +809 -52
- package/dist/sdk.js.map +1 -1
- package/dist/types.d.ts +38 -1
- package/dist/types.js.map +1 -1
- package/docs/1.2.7-CONTEXT-CONTINUITY.md +68 -0
- package/docs/API_REFERENCE.md +6 -2
- package/docs/dev-log/progress.txt +48 -0
- package/docs/hooks-architecture.md +2 -1
- package/package.json +3 -3
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/omp/memorix/extensions/memorix.js +17 -0
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/extensions/memorix.js +17 -0
- package/plugins/pi/memorix/package.json +1 -1
- package/src/cli/capability-map.ts +1 -0
- package/src/cli/command-guide.ts +10 -0
- package/src/cli/commands/agent-integrations.ts +102 -5
- package/src/cli/commands/checkpoint.ts +144 -0
- package/src/cli/commands/serve-http.ts +14 -3
- package/src/cli/commands/setup.ts +44 -0
- package/src/cli/index.ts +3 -1
- package/src/codegraph/auto-context.ts +51 -5
- package/src/dashboard/server.ts +11 -0
- package/src/hooks/handler.ts +103 -11
- package/src/hooks/normalizer.ts +85 -1
- package/src/hooks/types.ts +16 -0
- package/src/knowledge/workset.ts +43 -2
- package/src/memory/compaction.ts +165 -0
- package/src/memory/observations.ts +67 -20
- package/src/runtime/maintenance-jobs.ts +84 -4
- package/src/runtime/project-maintenance.ts +63 -6
- package/src/server/tool-profile.ts +1 -0
- package/src/server.ts +94 -0
- package/src/store/compaction-checkpoint-store.ts +397 -0
- package/src/store/sqlite-db.ts +41 -0
- package/src/types.ts +46 -0
package/dist/cli/index.js
CHANGED
|
@@ -3212,7 +3212,7 @@ ${import_picocolors.default.gray(m3)} ${s2}
|
|
|
3212
3212
|
|
|
3213
3213
|
// src/cli/version.ts
|
|
3214
3214
|
function getCliVersion() {
|
|
3215
|
-
return true ? "1.2.
|
|
3215
|
+
return true ? "1.2.8" : pkg.version;
|
|
3216
3216
|
}
|
|
3217
3217
|
var init_version = __esm({
|
|
3218
3218
|
"src/cli/version.ts"() {
|
|
@@ -9304,6 +9304,7 @@ function getDatabase(dataDir) {
|
|
|
9304
9304
|
db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
|
|
9305
9305
|
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
9306
9306
|
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
9307
|
+
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
9307
9308
|
try {
|
|
9308
9309
|
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
9309
9310
|
} catch {
|
|
@@ -9344,7 +9345,7 @@ function getDatabase(dataDir) {
|
|
|
9344
9345
|
_dbCache.set(normalized, db2);
|
|
9345
9346
|
return db2;
|
|
9346
9347
|
}
|
|
9347
|
-
var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
|
|
9348
|
+
var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
|
|
9348
9349
|
var init_sqlite_db = __esm({
|
|
9349
9350
|
"src/store/sqlite-db.ts"() {
|
|
9350
9351
|
"use strict";
|
|
@@ -9796,6 +9797,31 @@ CREATE TABLE IF NOT EXISTS maintenance_targets (
|
|
|
9796
9797
|
data_dir TEXT NOT NULL,
|
|
9797
9798
|
updated_at INTEGER NOT NULL
|
|
9798
9799
|
);
|
|
9800
|
+
`;
|
|
9801
|
+
CREATE_COMPACTION_CHECKPOINTS_TABLE = `
|
|
9802
|
+
CREATE TABLE IF NOT EXISTS compaction_checkpoints (
|
|
9803
|
+
id TEXT PRIMARY KEY,
|
|
9804
|
+
project_id TEXT NOT NULL,
|
|
9805
|
+
session_id TEXT NOT NULL,
|
|
9806
|
+
agent TEXT NOT NULL,
|
|
9807
|
+
phase TEXT NOT NULL,
|
|
9808
|
+
capture_kind TEXT NOT NULL,
|
|
9809
|
+
reason TEXT NOT NULL DEFAULT 'unknown',
|
|
9810
|
+
source_event TEXT NOT NULL,
|
|
9811
|
+
source_key TEXT NOT NULL,
|
|
9812
|
+
summary TEXT,
|
|
9813
|
+
tokens_before INTEGER,
|
|
9814
|
+
first_kept_entry_id TEXT,
|
|
9815
|
+
details_json TEXT NOT NULL DEFAULT '{}',
|
|
9816
|
+
transcript_available INTEGER NOT NULL DEFAULT 0,
|
|
9817
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
9818
|
+
pre_captured_at TEXT NOT NULL,
|
|
9819
|
+
completed_at TEXT,
|
|
9820
|
+
delivered_at TEXT,
|
|
9821
|
+
delivery_count INTEGER NOT NULL DEFAULT 0,
|
|
9822
|
+
created_at TEXT NOT NULL,
|
|
9823
|
+
updated_at TEXT NOT NULL
|
|
9824
|
+
);
|
|
9799
9825
|
`;
|
|
9800
9826
|
CREATE_INDEXES = `
|
|
9801
9827
|
CREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);
|
|
@@ -9843,6 +9869,9 @@ CREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowl
|
|
|
9843
9869
|
CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_ready ON maintenance_jobs(status, run_after);
|
|
9844
9870
|
CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_project ON maintenance_jobs(project_id, status, run_after);
|
|
9845
9871
|
CREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_targets(updated_at);
|
|
9872
|
+
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_project_recent ON compaction_checkpoints(project_id, status, completed_at DESC, pre_captured_at DESC);
|
|
9873
|
+
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC);
|
|
9874
|
+
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key);
|
|
9846
9875
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
9847
9876
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
9848
9877
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -9916,6 +9945,15 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
9916
9945
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_knowledge_workflows_workspace_status ON knowledge_workflows(workspaceId, status, updatedAt DESC)");
|
|
9917
9946
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowledge_workflow_runs(projectId, workflowId, startedAt DESC)");
|
|
9918
9947
|
}
|
|
9948
|
+
},
|
|
9949
|
+
{
|
|
9950
|
+
id: "1.2.7-compaction-checkpoints",
|
|
9951
|
+
apply: (db2) => {
|
|
9952
|
+
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
9953
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_project_recent ON compaction_checkpoints(project_id, status, completed_at DESC, pre_captured_at DESC)");
|
|
9954
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC)");
|
|
9955
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key)");
|
|
9956
|
+
}
|
|
9919
9957
|
}
|
|
9920
9958
|
];
|
|
9921
9959
|
_dbCache = /* @__PURE__ */ new Map();
|
|
@@ -17146,6 +17184,10 @@ var init_maintenance_jobs = __esm({
|
|
|
17146
17184
|
LIMIT 1
|
|
17147
17185
|
`).get(input.projectId, input.kind, dedupeKey);
|
|
17148
17186
|
if (existing) {
|
|
17187
|
+
if (input.kind === "vector-backfill" && existing.status === "retry") {
|
|
17188
|
+
this.commit();
|
|
17189
|
+
return rowToJob(existing);
|
|
17190
|
+
}
|
|
17149
17191
|
const nextRunAfter = Math.min(Number(existing.run_after), runAfter);
|
|
17150
17192
|
this.db.prepare(`
|
|
17151
17193
|
UPDATE maintenance_jobs
|
|
@@ -17156,6 +17198,26 @@ var init_maintenance_jobs = __esm({
|
|
|
17156
17198
|
this.commit();
|
|
17157
17199
|
return rowToJob(updated);
|
|
17158
17200
|
}
|
|
17201
|
+
if (input.kind === "vector-backfill") {
|
|
17202
|
+
const failed = this.db.prepare(`
|
|
17203
|
+
SELECT * FROM maintenance_jobs
|
|
17204
|
+
WHERE project_id = ? AND kind = ? AND dedupe_key = ? AND status = 'failed'
|
|
17205
|
+
ORDER BY updated_at DESC
|
|
17206
|
+
LIMIT 1
|
|
17207
|
+
`).get(input.projectId, input.kind, dedupeKey);
|
|
17208
|
+
if (failed) {
|
|
17209
|
+
this.db.prepare(`
|
|
17210
|
+
UPDATE maintenance_jobs
|
|
17211
|
+
SET status = 'pending', attempts = 0, max_attempts = ?, run_after = ?,
|
|
17212
|
+
payload_json = ?, lease_owner = NULL, lease_expires_at = NULL,
|
|
17213
|
+
last_error = NULL, completed_at = NULL, updated_at = ?
|
|
17214
|
+
WHERE id = ?
|
|
17215
|
+
`).run(maxAttempts, runAfter, payloadJson, now3, failed.id);
|
|
17216
|
+
const revived = this.getRow(failed.id);
|
|
17217
|
+
this.commit();
|
|
17218
|
+
return rowToJob(revived);
|
|
17219
|
+
}
|
|
17220
|
+
}
|
|
17159
17221
|
const id = randomUUID2();
|
|
17160
17222
|
this.db.prepare(`
|
|
17161
17223
|
INSERT INTO maintenance_jobs (
|
|
@@ -17327,15 +17389,42 @@ var init_maintenance_jobs = __esm({
|
|
|
17327
17389
|
const now3 = options2.now ?? Date.now();
|
|
17328
17390
|
const delayMs = Number.isFinite(options2.delayMs) ? Math.max(0, Math.floor(options2.delayMs)) : 0;
|
|
17329
17391
|
const payloadJson = options2.payload === void 0 ? null : JSON.stringify(options2.payload);
|
|
17392
|
+
const status = options2.status === "retry" ? "retry" : "pending";
|
|
17393
|
+
const hasLastError = options2.lastError !== void 0;
|
|
17394
|
+
const lastError = hasLastError ? errorText(options2.lastError) : null;
|
|
17330
17395
|
this.db.prepare(`
|
|
17331
17396
|
UPDATE maintenance_jobs
|
|
17332
|
-
SET status =
|
|
17397
|
+
SET status = ?, run_after = ?, attempts = CASE WHEN ? THEN 0 ELSE attempts END,
|
|
17333
17398
|
payload_json = COALESCE(?, payload_json),
|
|
17399
|
+
last_error = CASE
|
|
17400
|
+
WHEN ? THEN NULL
|
|
17401
|
+
WHEN ? THEN ?
|
|
17402
|
+
ELSE last_error
|
|
17403
|
+
END,
|
|
17334
17404
|
lease_owner = NULL, lease_expires_at = NULL, updated_at = ?
|
|
17335
17405
|
WHERE id = ? AND status = 'running' AND lease_owner = ?
|
|
17336
|
-
`).run(
|
|
17406
|
+
`).run(
|
|
17407
|
+
status,
|
|
17408
|
+
now3 + delayMs,
|
|
17409
|
+
options2.resetAttempts ? 1 : 0,
|
|
17410
|
+
payloadJson,
|
|
17411
|
+
options2.clearLastError ? 1 : 0,
|
|
17412
|
+
hasLastError ? 1 : 0,
|
|
17413
|
+
lastError,
|
|
17414
|
+
now3,
|
|
17415
|
+
id,
|
|
17416
|
+
workerId
|
|
17417
|
+
);
|
|
17337
17418
|
return this.get(id);
|
|
17338
17419
|
}
|
|
17420
|
+
resolveFailedVectorBackfills(projectId, dedupeKey = "vector-backfill", now3 = Date.now()) {
|
|
17421
|
+
const result = this.db.prepare(`
|
|
17422
|
+
UPDATE maintenance_jobs
|
|
17423
|
+
SET status = 'completed', completed_at = ?, updated_at = ?
|
|
17424
|
+
WHERE project_id = ? AND kind = 'vector-backfill' AND dedupe_key = ? AND status = 'failed'
|
|
17425
|
+
`).run(now3, now3, projectId, dedupeKey);
|
|
17426
|
+
return Number(result.changes ?? 0);
|
|
17427
|
+
}
|
|
17339
17428
|
fail(id, workerId, error2, now3 = Date.now()) {
|
|
17340
17429
|
this.begin();
|
|
17341
17430
|
try {
|
|
@@ -17431,6 +17520,9 @@ var init_maintenance_jobs = __esm({
|
|
|
17431
17520
|
delayMs: result.delayMs,
|
|
17432
17521
|
resetAttempts: result.resetAttempts,
|
|
17433
17522
|
payload: result.payload,
|
|
17523
|
+
status: result.status,
|
|
17524
|
+
lastError: result.lastError,
|
|
17525
|
+
clearLastError: result.clearLastError,
|
|
17434
17526
|
now: now3
|
|
17435
17527
|
});
|
|
17436
17528
|
return { state: "rescheduled", job: updated2 };
|
|
@@ -18126,10 +18218,10 @@ var init_store = __esm({
|
|
|
18126
18218
|
return row ? rowToSnapshot(row) : void 0;
|
|
18127
18219
|
}
|
|
18128
18220
|
listSnapshots(projectId, limit = 20) {
|
|
18129
|
-
const
|
|
18221
|
+
const safeLimit2 = Number.isFinite(limit) ? Math.max(1, Math.min(200, Math.floor(limit))) : 20;
|
|
18130
18222
|
return this.db.prepare(
|
|
18131
18223
|
"SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT ?"
|
|
18132
|
-
).all(projectId,
|
|
18224
|
+
).all(projectId, safeLimit2).map(rowToSnapshot);
|
|
18133
18225
|
}
|
|
18134
18226
|
/**
|
|
18135
18227
|
* Record a completed scan and mark all current structural facts with its
|
|
@@ -18409,6 +18501,9 @@ function normalizeEmbeddingFailure(error2) {
|
|
|
18409
18501
|
message: raw
|
|
18410
18502
|
};
|
|
18411
18503
|
}
|
|
18504
|
+
function vectorBackfillError(error2) {
|
|
18505
|
+
return sanitizeCredentials(normalizeEmbeddingFailure(error2).message).slice(0, 1e3);
|
|
18506
|
+
}
|
|
18412
18507
|
function queueVectorBackfill(projectId) {
|
|
18413
18508
|
const dataDir = projectDir;
|
|
18414
18509
|
if (!dataDir) return;
|
|
@@ -19164,17 +19259,53 @@ async function backfillVectorEmbeddings(options2 = {}) {
|
|
|
19164
19259
|
let succeeded = 0;
|
|
19165
19260
|
let failed = 0;
|
|
19166
19261
|
let lastFailure;
|
|
19262
|
+
const recordFailure = (message) => {
|
|
19263
|
+
if (!lastFailure) lastFailure = message;
|
|
19264
|
+
};
|
|
19265
|
+
const candidates = [];
|
|
19266
|
+
for (const id of ids) {
|
|
19267
|
+
const observation = observationById.get(id);
|
|
19268
|
+
if (!observation) {
|
|
19269
|
+
vectorMissingIds.delete(id);
|
|
19270
|
+
continue;
|
|
19271
|
+
}
|
|
19272
|
+
candidates.push({
|
|
19273
|
+
id,
|
|
19274
|
+
observation,
|
|
19275
|
+
text: [observation.title, observation.narrative, ...observation.facts].join(" ")
|
|
19276
|
+
});
|
|
19277
|
+
}
|
|
19167
19278
|
try {
|
|
19168
|
-
|
|
19169
|
-
|
|
19170
|
-
|
|
19171
|
-
|
|
19172
|
-
|
|
19279
|
+
if (candidates.length === 0) {
|
|
19280
|
+
return { attempted: ids.length, succeeded, failed };
|
|
19281
|
+
}
|
|
19282
|
+
let embeddings = null;
|
|
19283
|
+
try {
|
|
19284
|
+
const provider2 = await getEmbeddingProvider();
|
|
19285
|
+
if (!provider2) {
|
|
19286
|
+
if (isEmbeddingExplicitlyDisabled()) {
|
|
19287
|
+
for (const candidate2 of candidates) vectorMissingIds.delete(candidate2.id);
|
|
19288
|
+
} else {
|
|
19289
|
+
recordFailure("embedding provider unavailable");
|
|
19290
|
+
failed += candidates.length;
|
|
19291
|
+
}
|
|
19292
|
+
} else {
|
|
19293
|
+
embeddings = await provider2.embedBatch(candidates.map((candidate2) => candidate2.text));
|
|
19173
19294
|
}
|
|
19174
|
-
|
|
19175
|
-
|
|
19176
|
-
|
|
19177
|
-
|
|
19295
|
+
} catch (error2) {
|
|
19296
|
+
recordFailure(vectorBackfillError(error2));
|
|
19297
|
+
failed += candidates.length;
|
|
19298
|
+
}
|
|
19299
|
+
if (embeddings) {
|
|
19300
|
+
for (let index = 0; index < candidates.length; index++) {
|
|
19301
|
+
const { id, observation: obs } = candidates[index];
|
|
19302
|
+
const embedding = embeddings[index];
|
|
19303
|
+
if (!embedding || embedding.length === 0) {
|
|
19304
|
+
recordFailure("embedding provider returned no vector");
|
|
19305
|
+
failed++;
|
|
19306
|
+
continue;
|
|
19307
|
+
}
|
|
19308
|
+
try {
|
|
19178
19309
|
if (!isVectorCompatibleWithCurrentIndex(embedding)) {
|
|
19179
19310
|
await upgradeVectorSchemaAfterFirstEmbedding(embedding);
|
|
19180
19311
|
}
|
|
@@ -19183,7 +19314,7 @@ async function backfillVectorEmbeddings(options2 = {}) {
|
|
|
19183
19314
|
console.error(
|
|
19184
19315
|
`[memorix] Backfill embedding mismatch for obs-${id}: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? "unknown"}d (kept in queue)`
|
|
19185
19316
|
);
|
|
19186
|
-
|
|
19317
|
+
recordFailure(`dimension mismatch: provider returned ${embedding.length}d, index expects ${vectorDimensions ?? "unknown"}d`);
|
|
19187
19318
|
failed++;
|
|
19188
19319
|
continue;
|
|
19189
19320
|
}
|
|
@@ -19222,15 +19353,10 @@ async function backfillVectorEmbeddings(options2 = {}) {
|
|
|
19222
19353
|
await insertObservation(doc);
|
|
19223
19354
|
vectorMissingIds.delete(id);
|
|
19224
19355
|
succeeded++;
|
|
19225
|
-
}
|
|
19226
|
-
|
|
19227
|
-
} else {
|
|
19228
|
-
lastFailure = "embedding provider unavailable";
|
|
19356
|
+
} catch (error2) {
|
|
19357
|
+
recordFailure(vectorBackfillError(error2));
|
|
19229
19358
|
failed++;
|
|
19230
19359
|
}
|
|
19231
|
-
} catch (err) {
|
|
19232
|
-
lastFailure = err instanceof Error ? err.message : String(err);
|
|
19233
|
-
failed++;
|
|
19234
19360
|
}
|
|
19235
19361
|
}
|
|
19236
19362
|
} finally {
|
|
@@ -19243,7 +19369,12 @@ async function backfillVectorEmbeddings(options2 = {}) {
|
|
|
19243
19369
|
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
19244
19370
|
};
|
|
19245
19371
|
}
|
|
19246
|
-
return {
|
|
19372
|
+
return {
|
|
19373
|
+
attempted: ids.length,
|
|
19374
|
+
succeeded,
|
|
19375
|
+
failed,
|
|
19376
|
+
...lastFailure ? { lastError: lastFailure } : {}
|
|
19377
|
+
};
|
|
19247
19378
|
}
|
|
19248
19379
|
var observations, nextId, projectDir, searchIndexPrepared, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
19249
19380
|
var init_observations = __esm({
|
|
@@ -27531,6 +27662,7 @@ __export(setup_exports, {
|
|
|
27531
27662
|
installOpenClawBundlePackage: () => installOpenClawBundlePackage,
|
|
27532
27663
|
installPiPackage: () => installPiPackage,
|
|
27533
27664
|
installPluginPackage: () => installPluginPackage,
|
|
27665
|
+
removeLegacyCodexMemorixMcpConfig: () => removeLegacyCodexMemorixMcpConfig,
|
|
27534
27666
|
tryInstallCodexPlugin: () => tryInstallCodexPlugin
|
|
27535
27667
|
});
|
|
27536
27668
|
import { spawnSync } from "child_process";
|
|
@@ -27778,6 +27910,31 @@ function mergeTomlMcpConfig(existingContent, generatedContent) {
|
|
|
27778
27910
|
return `${parts.join("\n\n")}
|
|
27779
27911
|
`;
|
|
27780
27912
|
}
|
|
27913
|
+
function isLegacyCodexMemorixNodeServer(server) {
|
|
27914
|
+
if (server.name !== "memorix" || server.command.trim().toLowerCase() !== "node") return false;
|
|
27915
|
+
const startsMemorixStdio = server.args.some((arg) => arg.trim().toLowerCase() === "serve");
|
|
27916
|
+
const sourceEntry = server.args.some((arg) => {
|
|
27917
|
+
const normalized = arg.replace(/\\/g, "/").toLowerCase();
|
|
27918
|
+
return /\/memorix\/dist\/cli\/index\.(?:[cm]?js)$/.test(normalized);
|
|
27919
|
+
});
|
|
27920
|
+
return startsMemorixStdio && sourceEntry;
|
|
27921
|
+
}
|
|
27922
|
+
async function removeLegacyCodexMemorixMcpConfig(configPath = path17.join(homedir24(), ".codex", "config.toml")) {
|
|
27923
|
+
let existingContent;
|
|
27924
|
+
try {
|
|
27925
|
+
existingContent = await readFile5(configPath, "utf-8");
|
|
27926
|
+
} catch {
|
|
27927
|
+
return { configPath, removed: false };
|
|
27928
|
+
}
|
|
27929
|
+
const adapter = new CodexMCPAdapter();
|
|
27930
|
+
const legacyServer = adapter.parse(existingContent).find(isLegacyCodexMemorixNodeServer);
|
|
27931
|
+
if (!legacyServer) return { configPath, removed: false };
|
|
27932
|
+
let nextContent = removeTomlSection(existingContent, "mcp_servers.memorix.env");
|
|
27933
|
+
nextContent = removeTomlSection(nextContent, "mcp_servers.memorix");
|
|
27934
|
+
await writeFile5(configPath, nextContent ? `${nextContent}
|
|
27935
|
+
` : "", "utf-8");
|
|
27936
|
+
return { configPath, removed: true };
|
|
27937
|
+
}
|
|
27781
27938
|
function mergeYamlMcpConfig(existingContent, generatedContent) {
|
|
27782
27939
|
let existing = {};
|
|
27783
27940
|
try {
|
|
@@ -28259,6 +28416,16 @@ async function installAgentSetup(agent, plan, global2) {
|
|
|
28259
28416
|
const install = tryInstallCodexPlugin();
|
|
28260
28417
|
if (install.ok) v3.success(install.message);
|
|
28261
28418
|
else v3.warn(install.message);
|
|
28419
|
+
if (install.ok) {
|
|
28420
|
+
try {
|
|
28421
|
+
const migration = await removeLegacyCodexMemorixMcpConfig();
|
|
28422
|
+
if (migration.removed) {
|
|
28423
|
+
v3.info(`codex: removed legacy source-path MCP config from ${migration.configPath}`);
|
|
28424
|
+
}
|
|
28425
|
+
} catch {
|
|
28426
|
+
v3.warn("codex: plugin installed, but the legacy MCP config could not be checked");
|
|
28427
|
+
}
|
|
28428
|
+
}
|
|
28262
28429
|
} else if (agent === "claude" && result.marketplaceRoot) {
|
|
28263
28430
|
const install = tryInstallClaudePlugin(result.marketplaceRoot);
|
|
28264
28431
|
if (install.ok) v3.success(install.message);
|
|
@@ -34934,7 +35101,7 @@ function renderTaskWorksetPrompt(input) {
|
|
|
34934
35101
|
});
|
|
34935
35102
|
appendLine(lines, "Task lens: " + input.lens, maxTokens, omitted, "lens");
|
|
34936
35103
|
const hasContinuation = Boolean(
|
|
34937
|
-
input.continuation?.previousSession || (input.continuation?.memories.length ?? 0) > 0
|
|
35104
|
+
input.continuation?.previousSession || (input.continuation?.memories.length ?? 0) > 0 || input.continuation?.compactCheckpoint
|
|
34938
35105
|
);
|
|
34939
35106
|
if (hasContinuation && input.continuation) {
|
|
34940
35107
|
appendLine(lines, "", maxTokens, omitted, "continuation-heading");
|
|
@@ -34974,6 +35141,24 @@ function renderTaskWorksetPrompt(input) {
|
|
|
34974
35141
|
}
|
|
34975
35142
|
);
|
|
34976
35143
|
}
|
|
35144
|
+
if (input.continuation.compactCheckpoint) {
|
|
35145
|
+
const checkpoint = input.continuation.compactCheckpoint;
|
|
35146
|
+
const source = `${checkpoint.agent}, ${checkpoint.captureKind}, ${checkpoint.reason}`;
|
|
35147
|
+
appendLine(
|
|
35148
|
+
lines,
|
|
35149
|
+
"- Recent host compact checkpoint (" + source + "): " + short(checkpoint.summary, 36),
|
|
35150
|
+
maxTokens,
|
|
35151
|
+
omitted,
|
|
35152
|
+
"continuation-compact-checkpoint",
|
|
35153
|
+
selected,
|
|
35154
|
+
{
|
|
35155
|
+
kind: "continuation",
|
|
35156
|
+
id: "compact:" + checkpoint.id,
|
|
35157
|
+
reason: "recent host-native compact lifecycle evidence",
|
|
35158
|
+
trust: "historical"
|
|
35159
|
+
}
|
|
35160
|
+
);
|
|
35161
|
+
}
|
|
34977
35162
|
}
|
|
34978
35163
|
if (input.cautions.length > 0 || input.cautionMemory.length > 0) {
|
|
34979
35164
|
appendLine(lines, "", maxTokens, omitted, "caution-heading");
|
|
@@ -35243,7 +35428,7 @@ async function buildTaskWorkset(input) {
|
|
|
35243
35428
|
...input.verificationHints
|
|
35244
35429
|
]).slice(0, 4);
|
|
35245
35430
|
const normalizedCautions = unique(cautions.map((caution) => caution.kind)).map((kind) => cautions.find((caution) => caution.kind === kind)).slice(0, 6);
|
|
35246
|
-
const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0) ? {
|
|
35431
|
+
const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0 || input.continuation.compactCheckpoint) ? {
|
|
35247
35432
|
...input.continuation.previousSession ? {
|
|
35248
35433
|
previousSession: {
|
|
35249
35434
|
...input.continuation.previousSession,
|
|
@@ -35254,7 +35439,13 @@ async function buildTaskWorkset(input) {
|
|
|
35254
35439
|
...memory,
|
|
35255
35440
|
title: short(memory.title, 20),
|
|
35256
35441
|
...memory.detail ? { detail: short(memory.detail, CONTINUATION_DETAIL_TOKEN_BUDGET) } : {}
|
|
35257
|
-
}))
|
|
35442
|
+
})),
|
|
35443
|
+
...input.continuation.compactCheckpoint ? {
|
|
35444
|
+
compactCheckpoint: {
|
|
35445
|
+
...input.continuation.compactCheckpoint,
|
|
35446
|
+
summary: short(input.continuation.compactCheckpoint.summary, 44)
|
|
35447
|
+
}
|
|
35448
|
+
} : {}
|
|
35258
35449
|
} : void 0;
|
|
35259
35450
|
const base = {
|
|
35260
35451
|
version: "1.2",
|
|
@@ -37477,6 +37668,311 @@ var init_session = __esm({
|
|
|
37477
37668
|
}
|
|
37478
37669
|
});
|
|
37479
37670
|
|
|
37671
|
+
// src/store/compaction-checkpoint-store.ts
|
|
37672
|
+
var compaction_checkpoint_store_exports = {};
|
|
37673
|
+
__export(compaction_checkpoint_store_exports, {
|
|
37674
|
+
CompactionCheckpointStore: () => CompactionCheckpointStore
|
|
37675
|
+
});
|
|
37676
|
+
import { createHash as createHash10, randomUUID as randomUUID9 } from "crypto";
|
|
37677
|
+
function optionalText5(value) {
|
|
37678
|
+
return typeof value === "string" && value ? value : void 0;
|
|
37679
|
+
}
|
|
37680
|
+
function optionalNumber2(value) {
|
|
37681
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
37682
|
+
}
|
|
37683
|
+
function parseDetails(value) {
|
|
37684
|
+
if (typeof value !== "string" || !value) return void 0;
|
|
37685
|
+
try {
|
|
37686
|
+
const parsed = JSON.parse(value);
|
|
37687
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
37688
|
+
} catch {
|
|
37689
|
+
return void 0;
|
|
37690
|
+
}
|
|
37691
|
+
}
|
|
37692
|
+
function sanitizeSummary(value) {
|
|
37693
|
+
if (!value?.trim()) return void 0;
|
|
37694
|
+
return sanitizeCredentials(value).slice(0, MAX_SUMMARY_CHARS).trim() || void 0;
|
|
37695
|
+
}
|
|
37696
|
+
function sanitizeDetails(value) {
|
|
37697
|
+
if (!value) return void 0;
|
|
37698
|
+
try {
|
|
37699
|
+
const sanitized = sanitizeCredentials(JSON.stringify(value));
|
|
37700
|
+
if (sanitized.length > MAX_DETAILS_CHARS) return { truncated: true };
|
|
37701
|
+
const parsed = JSON.parse(sanitized);
|
|
37702
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
37703
|
+
} catch {
|
|
37704
|
+
return { unavailable: true };
|
|
37705
|
+
}
|
|
37706
|
+
}
|
|
37707
|
+
function sourceKeyFor(input, summary) {
|
|
37708
|
+
if (input.sourceKey?.trim()) return input.sourceKey.trim().slice(0, 300);
|
|
37709
|
+
const material = [
|
|
37710
|
+
input.projectId,
|
|
37711
|
+
input.sessionId,
|
|
37712
|
+
input.agent,
|
|
37713
|
+
input.sourceEvent,
|
|
37714
|
+
summary ?? "",
|
|
37715
|
+
input.tokensBefore ?? "",
|
|
37716
|
+
input.firstKeptEntryId ?? ""
|
|
37717
|
+
].join("\0");
|
|
37718
|
+
return `derived:${createHash10("sha256").update(material).digest("hex").slice(0, 32)}`;
|
|
37719
|
+
}
|
|
37720
|
+
function rowToCheckpoint(row) {
|
|
37721
|
+
return {
|
|
37722
|
+
id: row.id,
|
|
37723
|
+
projectId: row.project_id,
|
|
37724
|
+
sessionId: row.session_id,
|
|
37725
|
+
agent: row.agent,
|
|
37726
|
+
phase: row.phase,
|
|
37727
|
+
captureKind: row.capture_kind,
|
|
37728
|
+
reason: row.reason,
|
|
37729
|
+
sourceEvent: row.source_event,
|
|
37730
|
+
sourceKey: row.source_key,
|
|
37731
|
+
...optionalText5(row.summary) ? { summary: row.summary } : {},
|
|
37732
|
+
...optionalNumber2(row.tokens_before) !== void 0 ? { tokensBefore: Number(row.tokens_before) } : {},
|
|
37733
|
+
...optionalText5(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
|
|
37734
|
+
...parseDetails(row.details_json) ? { details: parseDetails(row.details_json) } : {},
|
|
37735
|
+
transcriptAvailable: Boolean(row.transcript_available),
|
|
37736
|
+
status: row.status,
|
|
37737
|
+
preCapturedAt: row.pre_captured_at,
|
|
37738
|
+
...optionalText5(row.completed_at) ? { completedAt: row.completed_at } : {},
|
|
37739
|
+
...optionalText5(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
|
|
37740
|
+
deliveryCount: Number(row.delivery_count ?? 0),
|
|
37741
|
+
createdAt: row.created_at,
|
|
37742
|
+
updatedAt: row.updated_at
|
|
37743
|
+
};
|
|
37744
|
+
}
|
|
37745
|
+
function safeReason(value) {
|
|
37746
|
+
return value === "manual" || value === "auto" ? value : "unknown";
|
|
37747
|
+
}
|
|
37748
|
+
function safeLimit(value, fallback) {
|
|
37749
|
+
if (!Number.isFinite(value) || value == null) return fallback;
|
|
37750
|
+
return Math.max(1, Math.min(500, Math.floor(value)));
|
|
37751
|
+
}
|
|
37752
|
+
var MAX_SUMMARY_CHARS, MAX_DETAILS_CHARS, CompactionCheckpointStore;
|
|
37753
|
+
var init_compaction_checkpoint_store = __esm({
|
|
37754
|
+
"src/store/compaction-checkpoint-store.ts"() {
|
|
37755
|
+
"use strict";
|
|
37756
|
+
init_esm_shims();
|
|
37757
|
+
init_secret_filter();
|
|
37758
|
+
init_sqlite_db();
|
|
37759
|
+
MAX_SUMMARY_CHARS = 24e3;
|
|
37760
|
+
MAX_DETAILS_CHARS = 4e3;
|
|
37761
|
+
CompactionCheckpointStore = class {
|
|
37762
|
+
db;
|
|
37763
|
+
constructor(dataDir) {
|
|
37764
|
+
this.db = getDatabase(dataDir);
|
|
37765
|
+
}
|
|
37766
|
+
recordPreflight(input) {
|
|
37767
|
+
const pending = this.db.prepare(`
|
|
37768
|
+
SELECT * FROM compaction_checkpoints
|
|
37769
|
+
WHERE project_id = ? AND session_id = ? AND agent = ?
|
|
37770
|
+
AND phase = 'pre' AND status = 'active'
|
|
37771
|
+
ORDER BY pre_captured_at DESC, created_at DESC
|
|
37772
|
+
LIMIT 1
|
|
37773
|
+
`).get(input.projectId, input.sessionId, input.agent);
|
|
37774
|
+
if (pending) return rowToCheckpoint(pending);
|
|
37775
|
+
const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
37776
|
+
const checkpoint = {
|
|
37777
|
+
id: randomUUID9(),
|
|
37778
|
+
projectId: input.projectId,
|
|
37779
|
+
sessionId: input.sessionId,
|
|
37780
|
+
agent: input.agent,
|
|
37781
|
+
phase: "pre",
|
|
37782
|
+
captureKind: "preflight",
|
|
37783
|
+
reason: safeReason(input.reason),
|
|
37784
|
+
sourceEvent: input.sourceEvent,
|
|
37785
|
+
sourceKey: `pre:${randomUUID9()}`,
|
|
37786
|
+
transcriptAvailable: Boolean(input.transcriptAvailable),
|
|
37787
|
+
status: "active",
|
|
37788
|
+
preCapturedAt: now3,
|
|
37789
|
+
deliveryCount: 0,
|
|
37790
|
+
createdAt: now3,
|
|
37791
|
+
updatedAt: now3
|
|
37792
|
+
};
|
|
37793
|
+
this.insert(checkpoint);
|
|
37794
|
+
return checkpoint;
|
|
37795
|
+
}
|
|
37796
|
+
complete(input) {
|
|
37797
|
+
const completedAt = input.completedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
37798
|
+
const summary = sanitizeSummary(input.summary);
|
|
37799
|
+
const pending = this.db.prepare(`
|
|
37800
|
+
SELECT * FROM compaction_checkpoints
|
|
37801
|
+
WHERE project_id = ? AND session_id = ? AND agent = ?
|
|
37802
|
+
AND phase = 'pre' AND status = 'active'
|
|
37803
|
+
ORDER BY pre_captured_at DESC, created_at DESC
|
|
37804
|
+
LIMIT 1
|
|
37805
|
+
`).get(input.projectId, input.sessionId, input.agent);
|
|
37806
|
+
if (!input.sourceKey?.trim() && !summary && input.tokensBefore === void 0 && !input.firstKeptEntryId && !pending) {
|
|
37807
|
+
const priorLifecycle = this.db.prepare(`
|
|
37808
|
+
SELECT * FROM compaction_checkpoints
|
|
37809
|
+
WHERE project_id = ? AND session_id = ? AND agent = ?
|
|
37810
|
+
AND phase = 'complete' AND capture_kind = 'lifecycle'
|
|
37811
|
+
AND source_event = ? AND status = 'active'
|
|
37812
|
+
ORDER BY completed_at DESC, created_at DESC
|
|
37813
|
+
LIMIT 1
|
|
37814
|
+
`).get(input.projectId, input.sessionId, input.agent, input.sourceEvent);
|
|
37815
|
+
if (priorLifecycle) return rowToCheckpoint(priorLifecycle);
|
|
37816
|
+
}
|
|
37817
|
+
const sourceKey = input.sourceKey?.trim() ? input.sourceKey.trim().slice(0, 300) : pending ? `lifecycle:${pending.id}` : sourceKeyFor(input, summary);
|
|
37818
|
+
const existing = this.db.prepare(`
|
|
37819
|
+
SELECT * FROM compaction_checkpoints
|
|
37820
|
+
WHERE project_id = ? AND source_key = ?
|
|
37821
|
+
LIMIT 1
|
|
37822
|
+
`).get(input.projectId, sourceKey);
|
|
37823
|
+
if (existing) return rowToCheckpoint(existing);
|
|
37824
|
+
const captureKind = summary ? "native-summary" : "lifecycle";
|
|
37825
|
+
const details = sanitizeDetails(input.details);
|
|
37826
|
+
if (pending) {
|
|
37827
|
+
const checkpoint2 = rowToCheckpoint(pending);
|
|
37828
|
+
const nextReason = safeReason(input.reason) === "unknown" ? checkpoint2.reason : safeReason(input.reason);
|
|
37829
|
+
this.db.prepare(`
|
|
37830
|
+
UPDATE compaction_checkpoints
|
|
37831
|
+
SET phase = 'complete', capture_kind = ?, reason = ?, source_event = ?, source_key = ?,
|
|
37832
|
+
summary = ?, tokens_before = ?, first_kept_entry_id = ?, details_json = ?,
|
|
37833
|
+
completed_at = ?, updated_at = ?
|
|
37834
|
+
WHERE id = ?
|
|
37835
|
+
`).run(
|
|
37836
|
+
captureKind,
|
|
37837
|
+
nextReason,
|
|
37838
|
+
input.sourceEvent,
|
|
37839
|
+
sourceKey,
|
|
37840
|
+
summary ?? null,
|
|
37841
|
+
input.tokensBefore ?? null,
|
|
37842
|
+
input.firstKeptEntryId ?? null,
|
|
37843
|
+
JSON.stringify(details ?? {}),
|
|
37844
|
+
completedAt,
|
|
37845
|
+
completedAt,
|
|
37846
|
+
checkpoint2.id
|
|
37847
|
+
);
|
|
37848
|
+
return this.get(checkpoint2.id);
|
|
37849
|
+
}
|
|
37850
|
+
const checkpoint = {
|
|
37851
|
+
id: randomUUID9(),
|
|
37852
|
+
projectId: input.projectId,
|
|
37853
|
+
sessionId: input.sessionId,
|
|
37854
|
+
agent: input.agent,
|
|
37855
|
+
phase: "complete",
|
|
37856
|
+
captureKind,
|
|
37857
|
+
reason: safeReason(input.reason),
|
|
37858
|
+
sourceEvent: input.sourceEvent,
|
|
37859
|
+
sourceKey,
|
|
37860
|
+
...summary ? { summary } : {},
|
|
37861
|
+
...input.tokensBefore !== void 0 ? { tokensBefore: input.tokensBefore } : {},
|
|
37862
|
+
...input.firstKeptEntryId ? { firstKeptEntryId: input.firstKeptEntryId } : {},
|
|
37863
|
+
...details ? { details } : {},
|
|
37864
|
+
transcriptAvailable: false,
|
|
37865
|
+
status: "active",
|
|
37866
|
+
preCapturedAt: completedAt,
|
|
37867
|
+
completedAt,
|
|
37868
|
+
deliveryCount: 0,
|
|
37869
|
+
createdAt: completedAt,
|
|
37870
|
+
updatedAt: completedAt
|
|
37871
|
+
};
|
|
37872
|
+
this.insert(checkpoint);
|
|
37873
|
+
return checkpoint;
|
|
37874
|
+
}
|
|
37875
|
+
get(id) {
|
|
37876
|
+
const row = this.db.prepare("SELECT * FROM compaction_checkpoints WHERE id = ?").get(id);
|
|
37877
|
+
return row ? rowToCheckpoint(row) : void 0;
|
|
37878
|
+
}
|
|
37879
|
+
list(options2) {
|
|
37880
|
+
const conditions = ["project_id = ?"];
|
|
37881
|
+
const values = [options2.projectId];
|
|
37882
|
+
if (options2.sessionId) {
|
|
37883
|
+
conditions.push("session_id = ?");
|
|
37884
|
+
values.push(options2.sessionId);
|
|
37885
|
+
}
|
|
37886
|
+
if (options2.agent) {
|
|
37887
|
+
conditions.push("agent = ?");
|
|
37888
|
+
values.push(options2.agent);
|
|
37889
|
+
}
|
|
37890
|
+
if (!options2.includeArchived) {
|
|
37891
|
+
conditions.push("status = 'active'");
|
|
37892
|
+
}
|
|
37893
|
+
const rows = this.db.prepare(`
|
|
37894
|
+
SELECT * FROM compaction_checkpoints
|
|
37895
|
+
WHERE ${conditions.join(" AND ")}
|
|
37896
|
+
ORDER BY COALESCE(completed_at, pre_captured_at) DESC, created_at DESC
|
|
37897
|
+
LIMIT ?
|
|
37898
|
+
`).all(...values, safeLimit(options2.limit, 20));
|
|
37899
|
+
return rows.map(rowToCheckpoint);
|
|
37900
|
+
}
|
|
37901
|
+
findUndelivered(projectId, sessionId, agent) {
|
|
37902
|
+
const row = this.db.prepare(`
|
|
37903
|
+
SELECT * FROM compaction_checkpoints
|
|
37904
|
+
WHERE project_id = ? AND session_id = ? AND agent = ?
|
|
37905
|
+
AND phase = 'complete' AND status = 'active' AND delivered_at IS NULL
|
|
37906
|
+
ORDER BY completed_at DESC, created_at DESC
|
|
37907
|
+
LIMIT 1
|
|
37908
|
+
`).get(projectId, sessionId, agent);
|
|
37909
|
+
return row ? rowToCheckpoint(row) : void 0;
|
|
37910
|
+
}
|
|
37911
|
+
findLatestCompleted(projectId, options2 = {}) {
|
|
37912
|
+
const excludeSession = options2.excludeSession;
|
|
37913
|
+
const exclusion = excludeSession ? " AND NOT (session_id = ? AND agent = ? )" : "";
|
|
37914
|
+
const values = excludeSession ? [projectId, excludeSession.sessionId, excludeSession.agent] : [projectId];
|
|
37915
|
+
const row = this.db.prepare(`
|
|
37916
|
+
SELECT * FROM compaction_checkpoints
|
|
37917
|
+
WHERE project_id = ? AND phase = 'complete' AND status = 'active'
|
|
37918
|
+
${exclusion}
|
|
37919
|
+
ORDER BY completed_at DESC, created_at DESC
|
|
37920
|
+
LIMIT 1
|
|
37921
|
+
`).get(...values);
|
|
37922
|
+
return row ? rowToCheckpoint(row) : void 0;
|
|
37923
|
+
}
|
|
37924
|
+
archive(id, archivedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
37925
|
+
const result = this.db.prepare(`
|
|
37926
|
+
UPDATE compaction_checkpoints
|
|
37927
|
+
SET status = 'archived', updated_at = ?
|
|
37928
|
+
WHERE id = ? AND status = 'active'
|
|
37929
|
+
`).run(archivedAt, id);
|
|
37930
|
+
return Number(result.changes ?? 0) > 0 ? this.get(id) : void 0;
|
|
37931
|
+
}
|
|
37932
|
+
markDelivered(id, deliveredAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
37933
|
+
const result = this.db.prepare(`
|
|
37934
|
+
UPDATE compaction_checkpoints
|
|
37935
|
+
SET delivered_at = ?, delivery_count = delivery_count + 1, updated_at = ?
|
|
37936
|
+
WHERE id = ? AND phase = 'complete' AND status = 'active' AND delivered_at IS NULL
|
|
37937
|
+
`).run(deliveredAt, deliveredAt, id);
|
|
37938
|
+
return Number(result.changes ?? 0) > 0 ? this.get(id) : void 0;
|
|
37939
|
+
}
|
|
37940
|
+
insert(checkpoint) {
|
|
37941
|
+
this.db.prepare(`
|
|
37942
|
+
INSERT INTO compaction_checkpoints (
|
|
37943
|
+
id, project_id, session_id, agent, phase, capture_kind, reason,
|
|
37944
|
+
source_event, source_key, summary, tokens_before, first_kept_entry_id,
|
|
37945
|
+
details_json, transcript_available, status, pre_captured_at, completed_at,
|
|
37946
|
+
delivered_at, delivery_count, created_at, updated_at
|
|
37947
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
37948
|
+
`).run(
|
|
37949
|
+
checkpoint.id,
|
|
37950
|
+
checkpoint.projectId,
|
|
37951
|
+
checkpoint.sessionId,
|
|
37952
|
+
checkpoint.agent,
|
|
37953
|
+
checkpoint.phase,
|
|
37954
|
+
checkpoint.captureKind,
|
|
37955
|
+
checkpoint.reason,
|
|
37956
|
+
checkpoint.sourceEvent,
|
|
37957
|
+
checkpoint.sourceKey,
|
|
37958
|
+
checkpoint.summary ?? null,
|
|
37959
|
+
checkpoint.tokensBefore ?? null,
|
|
37960
|
+
checkpoint.firstKeptEntryId ?? null,
|
|
37961
|
+
JSON.stringify(checkpoint.details ?? {}),
|
|
37962
|
+
checkpoint.transcriptAvailable ? 1 : 0,
|
|
37963
|
+
checkpoint.status,
|
|
37964
|
+
checkpoint.preCapturedAt,
|
|
37965
|
+
checkpoint.completedAt ?? null,
|
|
37966
|
+
checkpoint.deliveredAt ?? null,
|
|
37967
|
+
checkpoint.deliveryCount,
|
|
37968
|
+
checkpoint.createdAt,
|
|
37969
|
+
checkpoint.updatedAt
|
|
37970
|
+
);
|
|
37971
|
+
}
|
|
37972
|
+
};
|
|
37973
|
+
}
|
|
37974
|
+
});
|
|
37975
|
+
|
|
37480
37976
|
// src/codegraph/auto-context.ts
|
|
37481
37977
|
var auto_context_exports = {};
|
|
37482
37978
|
__export(auto_context_exports, {
|
|
@@ -37662,6 +38158,22 @@ async function buildAutoProjectContext(input) {
|
|
|
37662
38158
|
if (continuationRequested) {
|
|
37663
38159
|
await initSessionStore(input.dataDir);
|
|
37664
38160
|
continuation = await getSessionResumeBrief(input.project.id, task, input.reader);
|
|
38161
|
+
const { CompactionCheckpointStore: CompactionCheckpointStore2 } = await Promise.resolve().then(() => (init_compaction_checkpoint_store(), compaction_checkpoint_store_exports));
|
|
38162
|
+
const checkpoint = new CompactionCheckpointStore2(input.dataDir).findLatestCompleted(
|
|
38163
|
+
input.project.id,
|
|
38164
|
+
input.excludeCompactionCheckpointFor ? { excludeSession: input.excludeCompactionCheckpointFor } : void 0
|
|
38165
|
+
);
|
|
38166
|
+
const completedAtMs = checkpoint ? Date.parse(checkpoint.completedAt ?? checkpoint.preCapturedAt) : Number.NaN;
|
|
38167
|
+
if (checkpoint && Number.isFinite(completedAtMs) && completedAtMs <= now3.getTime() && now3.getTime() - completedAtMs <= COMPACT_CHECKPOINT_MAX_AGE_MS) {
|
|
38168
|
+
continuation.compactCheckpoint = {
|
|
38169
|
+
id: checkpoint.id,
|
|
38170
|
+
agent: checkpoint.agent,
|
|
38171
|
+
captureKind: checkpoint.captureKind === "native-summary" ? "native-summary" : "lifecycle",
|
|
38172
|
+
reason: checkpoint.reason,
|
|
38173
|
+
...checkpoint.completedAt ? { completedAt: checkpoint.completedAt } : {},
|
|
38174
|
+
summary: checkpoint.summary ?? "The host completed context compaction without exposing a native summary. Reconstruct only what the current task needs from current code and durable evidence."
|
|
38175
|
+
};
|
|
38176
|
+
}
|
|
37665
38177
|
}
|
|
37666
38178
|
const workset = await buildTaskWorkset({
|
|
37667
38179
|
projectId: input.project.id,
|
|
@@ -37870,7 +38382,7 @@ function formatAutoProjectContextSummary(context) {
|
|
|
37870
38382
|
reliableSources.length > 0 ? `- ${reliableSources.length} current code-bound memory link(s)` : "- none yet"
|
|
37871
38383
|
);
|
|
37872
38384
|
const continuation = context.workset.continuation;
|
|
37873
|
-
if (continuation?.previousSession || continuation?.memories.length) {
|
|
38385
|
+
if (continuation?.previousSession || continuation?.memories.length || continuation?.compactCheckpoint) {
|
|
37874
38386
|
lines.push("", "Resume from prior work");
|
|
37875
38387
|
if (continuation.previousSession) {
|
|
37876
38388
|
const session = continuation.previousSession;
|
|
@@ -37885,6 +38397,12 @@ function formatAutoProjectContextSummary(context) {
|
|
|
37885
38397
|
"- #" + memory.id + " " + memory.type + ": " + compactContinuationText(memory.title, 18) + detail
|
|
37886
38398
|
);
|
|
37887
38399
|
}
|
|
38400
|
+
if (continuation.compactCheckpoint) {
|
|
38401
|
+
const checkpoint = continuation.compactCheckpoint;
|
|
38402
|
+
lines.push(
|
|
38403
|
+
"- Recent host compact checkpoint (" + [checkpoint.agent, checkpoint.captureKind, checkpoint.reason].join(", ") + "): " + compactContinuationText(checkpoint.summary, 36)
|
|
38404
|
+
);
|
|
38405
|
+
}
|
|
37888
38406
|
}
|
|
37889
38407
|
return lines.join("\n");
|
|
37890
38408
|
}
|
|
@@ -37951,7 +38469,7 @@ function formatLegacyAutoProjectContextPrompt(context) {
|
|
|
37951
38469
|
);
|
|
37952
38470
|
return lines.join("\n");
|
|
37953
38471
|
}
|
|
37954
|
-
var DEFAULT_MAX_AGE_MS;
|
|
38472
|
+
var DEFAULT_MAX_AGE_MS, COMPACT_CHECKPOINT_MAX_AGE_MS;
|
|
37955
38473
|
var init_auto_context = __esm({
|
|
37956
38474
|
"src/codegraph/auto-context.ts"() {
|
|
37957
38475
|
"use strict";
|
|
@@ -37971,6 +38489,7 @@ var init_auto_context = __esm({
|
|
|
37971
38489
|
init_session_store();
|
|
37972
38490
|
init_task_lens();
|
|
37973
38491
|
DEFAULT_MAX_AGE_MS = 10 * 60 * 1e3;
|
|
38492
|
+
COMPACT_CHECKPOINT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
37974
38493
|
}
|
|
37975
38494
|
});
|
|
37976
38495
|
|
|
@@ -38235,7 +38754,7 @@ function addDefaultVerificationHints(input) {
|
|
|
38235
38754
|
return uniq2(hints);
|
|
38236
38755
|
}
|
|
38237
38756
|
function selectRelevantObservations(observations2, task, limit) {
|
|
38238
|
-
const
|
|
38757
|
+
const safeLimit2 = Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : 20;
|
|
38239
38758
|
const taskTokens2 = tokenize4(task);
|
|
38240
38759
|
const ranked = observations2.map((observation, index) => ({
|
|
38241
38760
|
observation,
|
|
@@ -38245,7 +38764,7 @@ function selectRelevantObservations(observations2, task, limit) {
|
|
|
38245
38764
|
}));
|
|
38246
38765
|
const positives = ranked.filter((item) => item.score > 0);
|
|
38247
38766
|
const pool = positives.length > 0 ? positives : ranked;
|
|
38248
|
-
return pool.sort((a3, b3) => b3.score - a3.score || b3.time - a3.time || b3.index - a3.index).slice(0,
|
|
38767
|
+
return pool.sort((a3, b3) => b3.score - a3.score || b3.time - a3.time || b3.index - a3.index).slice(0, safeLimit2).map((item) => item.observation);
|
|
38249
38768
|
}
|
|
38250
38769
|
function assembleContextPackForTask(input) {
|
|
38251
38770
|
const selected = selectRelevantObservations(input.observations, input.task, input.limit ?? 20);
|
|
@@ -38642,12 +39161,277 @@ ${formatUsageHint()}`;
|
|
|
38642
39161
|
}
|
|
38643
39162
|
});
|
|
38644
39163
|
|
|
39164
|
+
// src/memory/compaction.ts
|
|
39165
|
+
var compaction_exports = {};
|
|
39166
|
+
__export(compaction_exports, {
|
|
39167
|
+
buildCompactionWorkset: () => buildCompactionWorkset,
|
|
39168
|
+
captureCompactionCheckpoint: () => captureCompactionCheckpoint,
|
|
39169
|
+
consumeCompactionWorkset: () => consumeCompactionWorkset
|
|
39170
|
+
});
|
|
39171
|
+
function normalizeBudget(value) {
|
|
39172
|
+
if (!Number.isFinite(value) || value == null) return DEFAULT_WORKSET_BUDGET;
|
|
39173
|
+
return Math.max(MIN_WORKSET_BUDGET, Math.min(2e3, Math.floor(value)));
|
|
39174
|
+
}
|
|
39175
|
+
function sourceLabel(checkpoint) {
|
|
39176
|
+
if (checkpoint.captureKind === "native-summary") return "native host summary";
|
|
39177
|
+
if (checkpoint.captureKind === "preflight") return "pre-compact lifecycle marker";
|
|
39178
|
+
return "host lifecycle marker";
|
|
39179
|
+
}
|
|
39180
|
+
function buildCompactionWorkset(checkpoint, options2 = {}) {
|
|
39181
|
+
const budget = normalizeBudget(options2.maxTokens);
|
|
39182
|
+
const task = options2.task?.trim() ? truncateToTokenBudget(sanitizeCredentials(options2.task.trim()), Math.max(8, Math.floor(budget * 0.25))) : "";
|
|
39183
|
+
const headerLines = [
|
|
39184
|
+
"## Compact Continuation",
|
|
39185
|
+
`- Host: ${checkpoint.agent} (${sourceLabel(checkpoint)})`,
|
|
39186
|
+
`- Trigger: ${checkpoint.reason}`,
|
|
39187
|
+
task ? `- Task now: ${task}` : "",
|
|
39188
|
+
"- Current code remains authoritative."
|
|
39189
|
+
].filter(Boolean);
|
|
39190
|
+
const header = `${headerLines.join("\n")}
|
|
39191
|
+
|
|
39192
|
+
`;
|
|
39193
|
+
const fallback = checkpoint.captureKind === "native-summary" ? "" : "The host did not expose a native compact summary. Reconstruct only what the current task needs from current code and Memorix evidence.";
|
|
39194
|
+
const source = sanitizeCredentials(checkpoint.summary?.trim() || fallback);
|
|
39195
|
+
const available = Math.max(0, budget - countTextTokens(header) - 4);
|
|
39196
|
+
let excerpt = source ? truncateToTokenBudget(source, available) : "";
|
|
39197
|
+
let text = `${header}${excerpt ? `### Host checkpoint
|
|
39198
|
+
${excerpt}` : ""}`.trim();
|
|
39199
|
+
while (excerpt && countTextTokens(text) > budget) {
|
|
39200
|
+
const nextExcerptBudget = Math.max(1, Math.floor(countTextTokens(excerpt) * 0.8));
|
|
39201
|
+
excerpt = truncateToTokenBudget(excerpt, nextExcerptBudget);
|
|
39202
|
+
text = `${header}${excerpt ? `### Host checkpoint
|
|
39203
|
+
${excerpt}` : ""}`.trim();
|
|
39204
|
+
}
|
|
39205
|
+
if (countTextTokens(text) > budget) text = truncateToTokenBudget(text, budget);
|
|
39206
|
+
return {
|
|
39207
|
+
checkpointId: checkpoint.id,
|
|
39208
|
+
text,
|
|
39209
|
+
tokens: countTextTokens(text)
|
|
39210
|
+
};
|
|
39211
|
+
}
|
|
39212
|
+
function sourceEvent(input) {
|
|
39213
|
+
const raw = input.raw;
|
|
39214
|
+
const event = raw.hook_event_name ?? raw.event ?? raw.type;
|
|
39215
|
+
return typeof event === "string" && event ? event : input.event;
|
|
39216
|
+
}
|
|
39217
|
+
async function captureCompactionCheckpoint(input) {
|
|
39218
|
+
const isCompactResume = input.event === "session_start" && input.sessionStartReason?.trim().toLowerCase() === "compact";
|
|
39219
|
+
if (input.event !== "pre_compact" && input.event !== "post_compact" && !isCompactResume) return null;
|
|
39220
|
+
if (!input.sessionId || !input.cwd) return null;
|
|
39221
|
+
const [
|
|
39222
|
+
{ detectProject: detectProject2 },
|
|
39223
|
+
{ getProjectDataDir: getProjectDataDir2 },
|
|
39224
|
+
{ initAliasRegistry: initAliasRegistry2, registerAlias: registerAlias2 }
|
|
39225
|
+
] = await Promise.all([
|
|
39226
|
+
Promise.resolve().then(() => (init_detector(), detector_exports)),
|
|
39227
|
+
Promise.resolve().then(() => (init_persistence(), persistence_exports)),
|
|
39228
|
+
Promise.resolve().then(() => (init_aliases(), aliases_exports))
|
|
39229
|
+
]);
|
|
39230
|
+
const project = detectProject2(input.cwd);
|
|
39231
|
+
if (!project) return null;
|
|
39232
|
+
const dataDir = await getProjectDataDir2(project.id);
|
|
39233
|
+
initAliasRegistry2(dataDir);
|
|
39234
|
+
const projectId = await registerAlias2(project);
|
|
39235
|
+
const store2 = new CompactionCheckpointStore(dataDir);
|
|
39236
|
+
if (input.event === "pre_compact") {
|
|
39237
|
+
return store2.recordPreflight({
|
|
39238
|
+
projectId,
|
|
39239
|
+
sessionId: input.sessionId,
|
|
39240
|
+
agent: input.agent,
|
|
39241
|
+
reason: input.compaction?.reason,
|
|
39242
|
+
sourceEvent: sourceEvent(input),
|
|
39243
|
+
transcriptAvailable: Boolean(input.transcriptPath),
|
|
39244
|
+
capturedAt: input.timestamp
|
|
39245
|
+
});
|
|
39246
|
+
}
|
|
39247
|
+
return store2.complete({
|
|
39248
|
+
projectId,
|
|
39249
|
+
sessionId: input.sessionId,
|
|
39250
|
+
agent: input.agent,
|
|
39251
|
+
reason: input.compaction?.reason,
|
|
39252
|
+
sourceEvent: sourceEvent(input),
|
|
39253
|
+
sourceKey: input.compaction?.sourceKey,
|
|
39254
|
+
summary: input.compaction?.summary,
|
|
39255
|
+
tokensBefore: input.compaction?.tokensBefore,
|
|
39256
|
+
firstKeptEntryId: input.compaction?.firstKeptEntryId,
|
|
39257
|
+
details: input.compaction?.details,
|
|
39258
|
+
completedAt: input.timestamp
|
|
39259
|
+
});
|
|
39260
|
+
}
|
|
39261
|
+
async function consumeCompactionWorkset(input, options2 = {}) {
|
|
39262
|
+
if (!input.sessionId || !input.cwd) return null;
|
|
39263
|
+
const [
|
|
39264
|
+
{ detectProject: detectProject2 },
|
|
39265
|
+
{ getProjectDataDir: getProjectDataDir2 },
|
|
39266
|
+
{ initAliasRegistry: initAliasRegistry2, registerAlias: registerAlias2 }
|
|
39267
|
+
] = await Promise.all([
|
|
39268
|
+
Promise.resolve().then(() => (init_detector(), detector_exports)),
|
|
39269
|
+
Promise.resolve().then(() => (init_persistence(), persistence_exports)),
|
|
39270
|
+
Promise.resolve().then(() => (init_aliases(), aliases_exports))
|
|
39271
|
+
]);
|
|
39272
|
+
const project = detectProject2(input.cwd);
|
|
39273
|
+
if (!project) return null;
|
|
39274
|
+
const dataDir = await getProjectDataDir2(project.id);
|
|
39275
|
+
initAliasRegistry2(dataDir);
|
|
39276
|
+
const projectId = await registerAlias2(project);
|
|
39277
|
+
const store2 = new CompactionCheckpointStore(dataDir);
|
|
39278
|
+
const checkpoint = store2.findUndelivered(projectId, input.sessionId, input.agent);
|
|
39279
|
+
if (!checkpoint) return null;
|
|
39280
|
+
const workset = buildCompactionWorkset(checkpoint, options2);
|
|
39281
|
+
if (!workset.text) return null;
|
|
39282
|
+
store2.markDelivered(checkpoint.id);
|
|
39283
|
+
return workset;
|
|
39284
|
+
}
|
|
39285
|
+
var DEFAULT_WORKSET_BUDGET, MIN_WORKSET_BUDGET;
|
|
39286
|
+
var init_compaction = __esm({
|
|
39287
|
+
"src/memory/compaction.ts"() {
|
|
39288
|
+
"use strict";
|
|
39289
|
+
init_esm_shims();
|
|
39290
|
+
init_token_budget();
|
|
39291
|
+
init_secret_filter();
|
|
39292
|
+
init_compaction_checkpoint_store();
|
|
39293
|
+
DEFAULT_WORKSET_BUDGET = 420;
|
|
39294
|
+
MIN_WORKSET_BUDGET = 48;
|
|
39295
|
+
}
|
|
39296
|
+
});
|
|
39297
|
+
|
|
39298
|
+
// src/cli/commands/checkpoint.ts
|
|
39299
|
+
var checkpoint_exports = {};
|
|
39300
|
+
__export(checkpoint_exports, {
|
|
39301
|
+
default: () => checkpoint_default
|
|
39302
|
+
});
|
|
39303
|
+
async function getCheckpointContext() {
|
|
39304
|
+
const context = await getCliProjectContext();
|
|
39305
|
+
const { initAliasRegistry: initAliasRegistry2, registerAlias: registerAlias2 } = await Promise.resolve().then(() => (init_aliases(), aliases_exports));
|
|
39306
|
+
initAliasRegistry2(context.dataDir);
|
|
39307
|
+
const canonicalId = await registerAlias2(context.project);
|
|
39308
|
+
return {
|
|
39309
|
+
...context,
|
|
39310
|
+
project: { ...context.project, id: canonicalId },
|
|
39311
|
+
store: new CompactionCheckpointStore(context.dataDir)
|
|
39312
|
+
};
|
|
39313
|
+
}
|
|
39314
|
+
function assertProjectCheckpoint(checkpoint, projectId, id) {
|
|
39315
|
+
if (!checkpoint || checkpoint.projectId !== projectId) {
|
|
39316
|
+
throw new Error(`No compact checkpoint "${id}" exists for this project.`);
|
|
39317
|
+
}
|
|
39318
|
+
return checkpoint;
|
|
39319
|
+
}
|
|
39320
|
+
function formatCheckpoint(checkpoint) {
|
|
39321
|
+
const completion = checkpoint.completedAt ? `, completed ${checkpoint.completedAt}` : "";
|
|
39322
|
+
const delivery = checkpoint.deliveredAt ? `, delivered ${checkpoint.deliveryCount}x` : "";
|
|
39323
|
+
return [
|
|
39324
|
+
`${shortId(checkpoint.id)} ${checkpoint.phase} ${checkpoint.agent} (${checkpoint.captureKind}, ${checkpoint.reason})`,
|
|
39325
|
+
` session: ${checkpoint.sessionId}`,
|
|
39326
|
+
` source: ${checkpoint.sourceEvent}${completion}${delivery}`,
|
|
39327
|
+
` status: ${checkpoint.status}${checkpoint.transcriptAvailable ? ", transcript marker available" : ""}`,
|
|
39328
|
+
...checkpoint.summary ? [` summary: ${checkpoint.summary.replace(/\s+/g, " ").slice(0, 220)}`] : []
|
|
39329
|
+
].join("\n");
|
|
39330
|
+
}
|
|
39331
|
+
function usage() {
|
|
39332
|
+
console.log("Memorix Compact Checkpoints");
|
|
39333
|
+
console.log("");
|
|
39334
|
+
console.log("Usage:");
|
|
39335
|
+
console.log(" memorix checkpoint list [--session <id>] [--agent <name>] [--all]");
|
|
39336
|
+
console.log(" memorix checkpoint show --id <checkpoint-id>");
|
|
39337
|
+
console.log(' memorix checkpoint context [--id <checkpoint-id>] [--task "..."] [--budget 420]');
|
|
39338
|
+
console.log(" memorix checkpoint archive --id <checkpoint-id>");
|
|
39339
|
+
}
|
|
39340
|
+
var checkpoint_default;
|
|
39341
|
+
var init_checkpoint = __esm({
|
|
39342
|
+
"src/cli/commands/checkpoint.ts"() {
|
|
39343
|
+
"use strict";
|
|
39344
|
+
init_esm_shims();
|
|
39345
|
+
init_dist2();
|
|
39346
|
+
init_compaction();
|
|
39347
|
+
init_compaction_checkpoint_store();
|
|
39348
|
+
init_operator_shared();
|
|
39349
|
+
checkpoint_default = defineCommand({
|
|
39350
|
+
meta: {
|
|
39351
|
+
name: "checkpoint",
|
|
39352
|
+
description: "Inspect and manage native compact continuity checkpoints"
|
|
39353
|
+
},
|
|
39354
|
+
args: {
|
|
39355
|
+
id: { type: "string", description: "Checkpoint ID" },
|
|
39356
|
+
session: { type: "string", description: "Filter by host session ID" },
|
|
39357
|
+
agent: { type: "string", description: "Filter by host agent name" },
|
|
39358
|
+
task: { type: "string", description: "Current task for a bounded continuation workset" },
|
|
39359
|
+
budget: { type: "string", description: "Maximum workset token budget (default: 420)" },
|
|
39360
|
+
limit: { type: "string", description: "Maximum checkpoints to list (default: 20)" },
|
|
39361
|
+
all: { type: "boolean", description: "Include archived checkpoints in list output" },
|
|
39362
|
+
json: { type: "boolean", description: "Emit machine-readable JSON output" }
|
|
39363
|
+
},
|
|
39364
|
+
run: async ({ args }) => {
|
|
39365
|
+
const positional = args._ ?? [];
|
|
39366
|
+
const action = (positional[0] ?? "list").toLowerCase();
|
|
39367
|
+
const asJson = Boolean(args.json);
|
|
39368
|
+
try {
|
|
39369
|
+
const { project, store: store2 } = await getCheckpointContext();
|
|
39370
|
+
const id = args.id?.trim();
|
|
39371
|
+
switch (action) {
|
|
39372
|
+
case "list": {
|
|
39373
|
+
const checkpoints = store2.list({
|
|
39374
|
+
projectId: project.id,
|
|
39375
|
+
sessionId: args.session?.trim() || void 0,
|
|
39376
|
+
agent: args.agent?.trim() || void 0,
|
|
39377
|
+
includeArchived: Boolean(args.all),
|
|
39378
|
+
limit: parsePositiveInt(args.limit, 20)
|
|
39379
|
+
});
|
|
39380
|
+
emitResult(
|
|
39381
|
+
{ project, checkpoints },
|
|
39382
|
+
checkpoints.length ? checkpoints.map(formatCheckpoint).join("\n\n") : "No compact checkpoints for this project.",
|
|
39383
|
+
asJson
|
|
39384
|
+
);
|
|
39385
|
+
return;
|
|
39386
|
+
}
|
|
39387
|
+
case "show": {
|
|
39388
|
+
if (!id) throw new Error('id is required for "memorix checkpoint show".');
|
|
39389
|
+
const checkpoint = assertProjectCheckpoint(store2.get(id), project.id, id);
|
|
39390
|
+
emitResult({ project, checkpoint }, formatCheckpoint(checkpoint), asJson);
|
|
39391
|
+
return;
|
|
39392
|
+
}
|
|
39393
|
+
case "context": {
|
|
39394
|
+
const checkpoint = id ? assertProjectCheckpoint(store2.get(id), project.id, id) : store2.list({
|
|
39395
|
+
projectId: project.id,
|
|
39396
|
+
sessionId: args.session?.trim() || void 0,
|
|
39397
|
+
agent: args.agent?.trim() || void 0,
|
|
39398
|
+
limit: parsePositiveInt(args.limit, 20)
|
|
39399
|
+
}).find((entry) => entry.phase === "complete");
|
|
39400
|
+
if (!checkpoint) {
|
|
39401
|
+
throw new Error("No completed compact checkpoint is available for this project and filter.");
|
|
39402
|
+
}
|
|
39403
|
+
const workset = buildCompactionWorkset(checkpoint, {
|
|
39404
|
+
task: args.task?.trim(),
|
|
39405
|
+
maxTokens: parsePositiveInt(args.budget, 420)
|
|
39406
|
+
});
|
|
39407
|
+
emitResult({ project, checkpoint, workset }, workset.text, asJson);
|
|
39408
|
+
return;
|
|
39409
|
+
}
|
|
39410
|
+
case "archive": {
|
|
39411
|
+
if (!id) throw new Error('id is required for "memorix checkpoint archive".');
|
|
39412
|
+
assertProjectCheckpoint(store2.get(id), project.id, id);
|
|
39413
|
+
const checkpoint = store2.archive(id);
|
|
39414
|
+
if (!checkpoint) throw new Error(`Compact checkpoint "${id}" is already archived.`);
|
|
39415
|
+
emitResult({ project, checkpoint }, `Archived compact checkpoint ${shortId(checkpoint.id)}.`, asJson);
|
|
39416
|
+
return;
|
|
39417
|
+
}
|
|
39418
|
+
default:
|
|
39419
|
+
usage();
|
|
39420
|
+
}
|
|
39421
|
+
} catch (error2) {
|
|
39422
|
+
emitError(error2 instanceof Error ? error2.message : String(error2), asJson);
|
|
39423
|
+
}
|
|
39424
|
+
}
|
|
39425
|
+
});
|
|
39426
|
+
}
|
|
39427
|
+
});
|
|
39428
|
+
|
|
38645
39429
|
// src/knowledge/markdown.ts
|
|
38646
|
-
import { createHash as
|
|
39430
|
+
import { createHash as createHash11 } from "crypto";
|
|
38647
39431
|
import { promises as fs16 } from "fs";
|
|
38648
39432
|
import path23 from "path";
|
|
38649
39433
|
function hashContent(content) {
|
|
38650
|
-
return
|
|
39434
|
+
return createHash11("sha256").update(content).digest("hex");
|
|
38651
39435
|
}
|
|
38652
39436
|
function stringField(data, key) {
|
|
38653
39437
|
const value = data[key];
|
|
@@ -38773,11 +39557,11 @@ __export(wiki_exports, {
|
|
|
38773
39557
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
38774
39558
|
readKnowledgePage: () => readKnowledgePage
|
|
38775
39559
|
});
|
|
38776
|
-
import { createHash as
|
|
39560
|
+
import { createHash as createHash12 } from "crypto";
|
|
38777
39561
|
import { promises as fs17 } from "fs";
|
|
38778
39562
|
import path24 from "path";
|
|
38779
39563
|
function hash3(value) {
|
|
38780
|
-
return
|
|
39564
|
+
return createHash12("sha256").update(value).digest("hex");
|
|
38781
39565
|
}
|
|
38782
39566
|
function now2() {
|
|
38783
39567
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -39218,7 +40002,7 @@ function modeFrom(value) {
|
|
|
39218
40002
|
if (value === "versioned") return "versioned";
|
|
39219
40003
|
throw new Error("knowledge mode must be local or versioned");
|
|
39220
40004
|
}
|
|
39221
|
-
function
|
|
40005
|
+
function usage2() {
|
|
39222
40006
|
return [
|
|
39223
40007
|
"Memorix Knowledge Commands",
|
|
39224
40008
|
"",
|
|
@@ -39439,7 +40223,7 @@ var init_knowledge = __esm({
|
|
|
39439
40223
|
);
|
|
39440
40224
|
return;
|
|
39441
40225
|
}
|
|
39442
|
-
emitResult({ usage:
|
|
40226
|
+
emitResult({ usage: usage2() }, usage2(), asJson);
|
|
39443
40227
|
return;
|
|
39444
40228
|
}
|
|
39445
40229
|
switch (action) {
|
|
@@ -39498,7 +40282,7 @@ var init_knowledge = __esm({
|
|
|
39498
40282
|
return;
|
|
39499
40283
|
}
|
|
39500
40284
|
default:
|
|
39501
|
-
emitResult({ usage:
|
|
40285
|
+
emitResult({ usage: usage2() }, usage2(), asJson);
|
|
39502
40286
|
}
|
|
39503
40287
|
} catch (error2) {
|
|
39504
40288
|
emitError(error2 instanceof Error ? error2.message : String(error2), asJson);
|
|
@@ -46812,7 +47596,7 @@ __export(planner_exports, {
|
|
|
46812
47596
|
materializeTaskGraph: () => materializeTaskGraph,
|
|
46813
47597
|
seedAutonomousPipeline: () => seedAutonomousPipeline
|
|
46814
47598
|
});
|
|
46815
|
-
import { randomUUID as
|
|
47599
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
46816
47600
|
function isPlannerTask(metadata) {
|
|
46817
47601
|
if (!metadata) return null;
|
|
46818
47602
|
try {
|
|
@@ -46870,7 +47654,7 @@ function seedAutonomousPipeline(teamStore, projectId, config2, opts) {
|
|
|
46870
47654
|
const maxIterations = config2.maxIterations ?? 3;
|
|
46871
47655
|
const taskBudget = config2.taskBudget ?? 15;
|
|
46872
47656
|
const structuredPlan = opts?.structuredPlan ?? true;
|
|
46873
|
-
const pipelineId =
|
|
47657
|
+
const pipelineId = randomUUID10();
|
|
46874
47658
|
const meta = {
|
|
46875
47659
|
plannerType: "plan",
|
|
46876
47660
|
pipelineId,
|
|
@@ -47789,11 +48573,11 @@ __export(receipt_service_exports, {
|
|
|
47789
48573
|
buildHandoffReceipt: () => buildHandoffReceipt,
|
|
47790
48574
|
formatHandoffReceipt: () => formatHandoffReceipt
|
|
47791
48575
|
});
|
|
47792
|
-
import { createHash as
|
|
48576
|
+
import { createHash as createHash13 } from "crypto";
|
|
47793
48577
|
import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
|
|
47794
48578
|
import path26 from "path";
|
|
47795
48579
|
function sha256(value) {
|
|
47796
|
-
return `sha256:${
|
|
48580
|
+
return `sha256:${createHash13("sha256").update(value).digest("hex")}`;
|
|
47797
48581
|
}
|
|
47798
48582
|
function hashId(projectId, id) {
|
|
47799
48583
|
return sha256(`${projectId}:obs:${id}`);
|
|
@@ -48039,6 +48823,7 @@ var init_tool_profile = __esm({
|
|
|
48039
48823
|
memorix_rules_sync: ["full"],
|
|
48040
48824
|
memorix_workspace_sync: ["full"],
|
|
48041
48825
|
memorix_ingest_image: ["full"],
|
|
48826
|
+
memorix_compaction_checkpoint: ["full"],
|
|
48042
48827
|
// ── MCP Official Memory Server compatibility (KG tools) ──────────
|
|
48043
48828
|
// These are only useful to users specifically migrating from the
|
|
48044
48829
|
// reference mcp-memory server. Hide them unless explicitly enabled.
|
|
@@ -66294,9 +67079,9 @@ var init_graph_scope = __esm({
|
|
|
66294
67079
|
});
|
|
66295
67080
|
|
|
66296
67081
|
// src/rules/utils.ts
|
|
66297
|
-
import { createHash as
|
|
67082
|
+
import { createHash as createHash14 } from "crypto";
|
|
66298
67083
|
function hashContent2(content) {
|
|
66299
|
-
return
|
|
67084
|
+
return createHash14("sha256").update(content.trim()).digest("hex").substring(0, 16);
|
|
66300
67085
|
}
|
|
66301
67086
|
function generateRuleId(source, filePath) {
|
|
66302
67087
|
const sanitized = filePath.replace(/[\/\\]/g, "-").replace(/^\./, "");
|
|
@@ -67875,6 +68660,26 @@ function vectorBatchSize(payload) {
|
|
|
67875
68660
|
if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_VECTOR_BATCH_SIZE;
|
|
67876
68661
|
return Math.min(100, Math.max(1, Math.floor(value)));
|
|
67877
68662
|
}
|
|
68663
|
+
function vectorBackfillFailureStreak(payload) {
|
|
68664
|
+
const value = payload.vectorBackfillFailureStreak;
|
|
68665
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.min(16, Math.max(0, Math.floor(value))) : 0;
|
|
68666
|
+
}
|
|
68667
|
+
function vectorBackfillRetryDelayMs(streak) {
|
|
68668
|
+
return Math.min(
|
|
68669
|
+
VECTOR_FAILURE_MAX_RETRY_DELAY_MS,
|
|
68670
|
+
VECTOR_FAILURE_BASE_RETRY_DELAY_MS * 2 ** Math.max(0, streak - 1)
|
|
68671
|
+
);
|
|
68672
|
+
}
|
|
68673
|
+
function withoutVectorBackfillFailureStreak(payload) {
|
|
68674
|
+
const { vectorBackfillFailureStreak: _streak, ...rest } = payload;
|
|
68675
|
+
return rest;
|
|
68676
|
+
}
|
|
68677
|
+
function resolveSupersededVectorFailures(projectDir2, projectId) {
|
|
68678
|
+
try {
|
|
68679
|
+
new MaintenanceJobStore(projectDir2).resolveFailedVectorBackfills(projectId);
|
|
68680
|
+
} catch {
|
|
68681
|
+
}
|
|
68682
|
+
}
|
|
67878
68683
|
function retentionBatchSize(payload) {
|
|
67879
68684
|
const value = payload.limit;
|
|
67880
68685
|
if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_RETENTION_BATCH_SIZE;
|
|
@@ -68283,20 +69088,45 @@ function createProjectMaintenanceHandler(projectId, projectDir2, projectRoot, op
|
|
|
68283
69088
|
if (isEmbeddingExplicitlyDisabled2()) return { action: "complete" };
|
|
68284
69089
|
const { backfillVectorEmbeddings: backfillVectorEmbeddings2, getVectorStatus: getVectorStatus2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
|
|
68285
69090
|
const before = getVectorStatus2(projectId);
|
|
68286
|
-
if (before.missing === 0)
|
|
69091
|
+
if (before.missing === 0) {
|
|
69092
|
+
resolveSupersededVectorFailures(projectDir2, projectId);
|
|
69093
|
+
return { action: "complete" };
|
|
69094
|
+
}
|
|
68287
69095
|
const result = await backfillVectorEmbeddings2({
|
|
68288
69096
|
projectId,
|
|
68289
69097
|
limit: vectorBatchSize(job.payload)
|
|
68290
69098
|
});
|
|
68291
69099
|
const after = getVectorStatus2(projectId);
|
|
68292
|
-
if (after.missing === 0)
|
|
69100
|
+
if (after.missing === 0) {
|
|
69101
|
+
resolveSupersededVectorFailures(projectDir2, projectId);
|
|
69102
|
+
return { action: "complete" };
|
|
69103
|
+
}
|
|
68293
69104
|
if (result.failed > 0 && result.succeeded === 0) {
|
|
68294
|
-
|
|
69105
|
+
const streak = vectorBackfillFailureStreak(job.payload) + 1;
|
|
69106
|
+
return {
|
|
69107
|
+
action: "reschedule",
|
|
69108
|
+
status: "retry",
|
|
69109
|
+
delayMs: vectorBackfillRetryDelayMs(streak),
|
|
69110
|
+
// This is a recoverable provider/index state, not a terminal job error.
|
|
69111
|
+
// Keeping one retry row prevents new MCP processes from creating a storm.
|
|
69112
|
+
resetAttempts: true,
|
|
69113
|
+
payload: {
|
|
69114
|
+
...job.payload,
|
|
69115
|
+
vectorBackfillFailureStreak: streak
|
|
69116
|
+
},
|
|
69117
|
+
lastError: result.lastError ?? `vector backfill made no progress (${result.failed}/${result.attempted} failed)`
|
|
69118
|
+
};
|
|
68295
69119
|
}
|
|
69120
|
+
const priorFailureStreak = vectorBackfillFailureStreak(job.payload);
|
|
69121
|
+
const payload = withoutVectorBackfillFailureStreak(job.payload);
|
|
68296
69122
|
return {
|
|
68297
69123
|
action: "reschedule",
|
|
68298
69124
|
delayMs: result.attempted === 0 ? VECTOR_RETRY_DELAY_MS : 0,
|
|
68299
|
-
resetAttempts: result.succeeded > 0
|
|
69125
|
+
resetAttempts: result.succeeded > 0,
|
|
69126
|
+
...result.succeeded > 0 ? {
|
|
69127
|
+
...priorFailureStreak > 0 ? { payload } : {},
|
|
69128
|
+
...result.failed > 0 && result.lastError ? { lastError: result.lastError } : priorFailureStreak > 0 ? { clearLastError: true } : {}
|
|
69129
|
+
} : {}
|
|
68300
69130
|
};
|
|
68301
69131
|
};
|
|
68302
69132
|
}
|
|
@@ -68309,11 +69139,12 @@ function createProjectMaintenanceDispatcher(projectId, projectDir2, projectRoot,
|
|
|
68309
69139
|
return isolatedRunner({ job, projectRoot, dataDir: projectDir2 });
|
|
68310
69140
|
};
|
|
68311
69141
|
}
|
|
68312
|
-
var DEFAULT_VECTOR_BATCH_SIZE, DEFAULT_RETENTION_BATCH_SIZE, DEFAULT_CONSOLIDATION_BATCH_SIZE, DEFAULT_CODEGRAPH_MAX_FILES, DEFAULT_CLAIM_DERIVATION_BATCH_SIZE, DEFAULT_OBSERVATION_QUALIFICATION_BATCH_SIZE, VECTOR_RETRY_DELAY_MS, DEDUP_PER_PAIR_TIMEOUT_MS;
|
|
69142
|
+
var DEFAULT_VECTOR_BATCH_SIZE, DEFAULT_RETENTION_BATCH_SIZE, DEFAULT_CONSOLIDATION_BATCH_SIZE, DEFAULT_CODEGRAPH_MAX_FILES, DEFAULT_CLAIM_DERIVATION_BATCH_SIZE, DEFAULT_OBSERVATION_QUALIFICATION_BATCH_SIZE, VECTOR_RETRY_DELAY_MS, VECTOR_FAILURE_BASE_RETRY_DELAY_MS, VECTOR_FAILURE_MAX_RETRY_DELAY_MS, DEDUP_PER_PAIR_TIMEOUT_MS;
|
|
68313
69143
|
var init_project_maintenance = __esm({
|
|
68314
69144
|
"src/runtime/project-maintenance.ts"() {
|
|
68315
69145
|
"use strict";
|
|
68316
69146
|
init_esm_shims();
|
|
69147
|
+
init_maintenance_jobs();
|
|
68317
69148
|
init_isolated_maintenance();
|
|
68318
69149
|
init_lifecycle();
|
|
68319
69150
|
init_timeout();
|
|
@@ -68324,6 +69155,8 @@ var init_project_maintenance = __esm({
|
|
|
68324
69155
|
DEFAULT_CLAIM_DERIVATION_BATCH_SIZE = 100;
|
|
68325
69156
|
DEFAULT_OBSERVATION_QUALIFICATION_BATCH_SIZE = 100;
|
|
68326
69157
|
VECTOR_RETRY_DELAY_MS = 5e3;
|
|
69158
|
+
VECTOR_FAILURE_BASE_RETRY_DELAY_MS = 6e4;
|
|
69159
|
+
VECTOR_FAILURE_MAX_RETRY_DELAY_MS = 15 * 6e4;
|
|
68327
69160
|
DEDUP_PER_PAIR_TIMEOUT_MS = 5e3;
|
|
68328
69161
|
}
|
|
68329
69162
|
});
|
|
@@ -69206,6 +70039,17 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
69206
70039
|
sourceCounts,
|
|
69207
70040
|
recentObservations: sorted,
|
|
69208
70041
|
embedding: embeddingStatus,
|
|
70042
|
+
// A standalone dashboard has no access to an active MCP
|
|
70043
|
+
// process's in-memory Orama index. Keep this explicit so the
|
|
70044
|
+
// UI never presents an empty local singleton as a healthy
|
|
70045
|
+
// all-vectors-indexed result.
|
|
70046
|
+
vectorStatus: {
|
|
70047
|
+
available: false,
|
|
70048
|
+
total: 0,
|
|
70049
|
+
missing: 0,
|
|
70050
|
+
missingIds: [],
|
|
70051
|
+
backfillRunning: false
|
|
70052
|
+
},
|
|
69209
70053
|
storage: storageInfo,
|
|
69210
70054
|
maintenance,
|
|
69211
70055
|
...lifecycle ? { lifecycle } : {},
|
|
@@ -70075,7 +70919,7 @@ __export(server_exports2, {
|
|
|
70075
70919
|
createMemorixServer: () => createMemorixServer,
|
|
70076
70920
|
shouldAwaitProjectRuntime: () => shouldAwaitProjectRuntime
|
|
70077
70921
|
});
|
|
70078
|
-
import { createHash as
|
|
70922
|
+
import { createHash as createHash15 } from "crypto";
|
|
70079
70923
|
function formatFormationStageDurations(stageDurationsMs) {
|
|
70080
70924
|
const orderedStages = ["extract", "resolve", "evaluate"];
|
|
70081
70925
|
const parts = orderedStages.filter((stage) => stageDurationsMs[stage] !== void 0).map((stage) => `${stage}=${stageDurationsMs[stage]}ms`);
|
|
@@ -70157,7 +71001,7 @@ function coerceObjectArray(val) {
|
|
|
70157
71001
|
return [];
|
|
70158
71002
|
}
|
|
70159
71003
|
function createDeterministicInstanceId(projectId, agentType, agentName) {
|
|
70160
|
-
const digest2 =
|
|
71004
|
+
const digest2 = createHash15("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
|
|
70161
71005
|
return `auto-${digest2}`;
|
|
70162
71006
|
}
|
|
70163
71007
|
function shouldAwaitProjectRuntime(toolName) {
|
|
@@ -70430,7 +71274,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
70430
71274
|
};
|
|
70431
71275
|
const server = existingServer ?? new McpServer({
|
|
70432
71276
|
name: "memorix",
|
|
70433
|
-
version: true ? "1.2.
|
|
71277
|
+
version: true ? "1.2.8" : "1.0.1"
|
|
70434
71278
|
});
|
|
70435
71279
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
70436
71280
|
server.registerTool = ((name, ...args) => {
|
|
@@ -71078,12 +71922,12 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
71078
71922
|
if (boundary) return boundary;
|
|
71079
71923
|
}
|
|
71080
71924
|
return withFreshIndex(async () => {
|
|
71081
|
-
const
|
|
71925
|
+
const safeLimit2 = limit != null ? coerceNumber(limit, 20) : void 0;
|
|
71082
71926
|
const safeMaxTokens = maxTokens != null ? coerceNumber(maxTokens, 0) : void 0;
|
|
71083
71927
|
const TIMEOUT_MS = 3e4;
|
|
71084
71928
|
const searchPromise = compactSearch({
|
|
71085
71929
|
query,
|
|
71086
|
-
limit:
|
|
71930
|
+
limit: safeLimit2,
|
|
71087
71931
|
type,
|
|
71088
71932
|
maxTokens: safeMaxTokens,
|
|
71089
71933
|
since,
|
|
@@ -71884,10 +72728,10 @@ Entity: ${entityName} | ${facts.length} facts | ${obs.tokens} tokens${reasoningA
|
|
|
71884
72728
|
const unresolved = requireResolvedProject("search reasoning in the current project");
|
|
71885
72729
|
if (unresolved) return unresolved;
|
|
71886
72730
|
}
|
|
71887
|
-
const
|
|
72731
|
+
const safeLimit2 = limit != null ? coerceNumber(limit, 10) : 10;
|
|
71888
72732
|
const result = await withFreshIndex(() => compactSearch({
|
|
71889
72733
|
query,
|
|
71890
|
-
limit:
|
|
72734
|
+
limit: safeLimit2,
|
|
71891
72735
|
type: "reasoning",
|
|
71892
72736
|
projectId: scope === "global" ? void 0 : project.id,
|
|
71893
72737
|
status: "active",
|
|
@@ -73210,9 +74054,9 @@ ${summary ? "Summary saved for next session context injection." : "No summary pr
|
|
|
73210
74054
|
}
|
|
73211
74055
|
},
|
|
73212
74056
|
async ({ limit }) => {
|
|
73213
|
-
const
|
|
74057
|
+
const safeLimit2 = limit != null ? coerceNumber(limit, 3) : 3;
|
|
73214
74058
|
const { getSessionContext: getSessionContext2, listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session(), session_exports));
|
|
73215
|
-
const context = await getSessionContext2(projectDir2, project.id,
|
|
74059
|
+
const context = await getSessionContext2(projectDir2, project.id, safeLimit2, getObservationReader());
|
|
73216
74060
|
const sessions = await listSessions2(projectDir2, project.id);
|
|
73217
74061
|
const activeSessions = sessions.filter((s2) => s2.status === "active");
|
|
73218
74062
|
const completedSessions = sessions.filter((s2) => s2.status === "completed");
|
|
@@ -73233,6 +74077,86 @@ ${summary ? "Summary saved for next session context injection." : "No summary pr
|
|
|
73233
74077
|
};
|
|
73234
74078
|
}
|
|
73235
74079
|
);
|
|
74080
|
+
server.registerTool(
|
|
74081
|
+
"memorix_compaction_checkpoint",
|
|
74082
|
+
{
|
|
74083
|
+
title: "Compact Continuity Checkpoints",
|
|
74084
|
+
description: "Inspect, preview, or archive bounded checkpoints recorded around a host-native context compaction. Use only to debug or explicitly review compaction continuity. These are lifecycle records, not durable memories or transcript backups. CLI equivalent: memorix checkpoint list|show|context|archive.",
|
|
74085
|
+
inputSchema: {
|
|
74086
|
+
action: external_exports.enum(["list", "show", "context", "archive"]).default("list"),
|
|
74087
|
+
id: external_exports.string().optional().describe("Checkpoint ID for show, context, or archive"),
|
|
74088
|
+
sessionId: external_exports.string().optional().describe("Optional host session ID filter"),
|
|
74089
|
+
agent: external_exports.string().optional().describe("Optional host agent filter"),
|
|
74090
|
+
task: external_exports.string().optional().describe("Current task for a bounded context preview"),
|
|
74091
|
+
maxTokens: external_exports.number().optional().describe("Maximum tokens for action=context (default: 420)"),
|
|
74092
|
+
limit: external_exports.number().optional().describe("Maximum records for action=list (default: 20)"),
|
|
74093
|
+
includeArchived: external_exports.boolean().optional().default(false).describe("Include archived records in action=list")
|
|
74094
|
+
}
|
|
74095
|
+
},
|
|
74096
|
+
async ({ action, id, sessionId, agent, task, maxTokens, limit, includeArchived }) => {
|
|
74097
|
+
const unresolved = requireResolvedProject("inspect compact continuity checkpoints");
|
|
74098
|
+
if (unresolved) return unresolved;
|
|
74099
|
+
const [{ CompactionCheckpointStore: CompactionCheckpointStore2 }, { buildCompactionWorkset: buildCompactionWorkset2 }] = await Promise.all([
|
|
74100
|
+
Promise.resolve().then(() => (init_compaction_checkpoint_store(), compaction_checkpoint_store_exports)),
|
|
74101
|
+
Promise.resolve().then(() => (init_compaction(), compaction_exports))
|
|
74102
|
+
]);
|
|
74103
|
+
const store2 = new CompactionCheckpointStore2(projectDir2);
|
|
74104
|
+
const assertCheckpoint = (checkpointId) => {
|
|
74105
|
+
const checkpoint2 = store2.get(checkpointId);
|
|
74106
|
+
if (!checkpoint2 || checkpoint2.projectId !== project.id) return null;
|
|
74107
|
+
return checkpoint2;
|
|
74108
|
+
};
|
|
74109
|
+
if (action === "list") {
|
|
74110
|
+
const checkpoints = store2.list({
|
|
74111
|
+
projectId: project.id,
|
|
74112
|
+
sessionId: sessionId?.trim() || void 0,
|
|
74113
|
+
agent: agent?.trim() || void 0,
|
|
74114
|
+
includeArchived: Boolean(includeArchived),
|
|
74115
|
+
limit: limit != null ? Math.max(1, Math.min(100, coerceNumber(limit, 20))) : 20
|
|
74116
|
+
});
|
|
74117
|
+
return {
|
|
74118
|
+
content: [{ type: "text", text: JSON.stringify({ projectId: project.id, checkpoints }, null, 2) }]
|
|
74119
|
+
};
|
|
74120
|
+
}
|
|
74121
|
+
if (!id?.trim()) {
|
|
74122
|
+
return {
|
|
74123
|
+
content: [{ type: "text", text: "id is required for this checkpoint action." }],
|
|
74124
|
+
isError: true
|
|
74125
|
+
};
|
|
74126
|
+
}
|
|
74127
|
+
const checkpoint = assertCheckpoint(id.trim());
|
|
74128
|
+
if (!checkpoint) {
|
|
74129
|
+
return {
|
|
74130
|
+
content: [{ type: "text", text: `Checkpoint "${id.trim()}" was not found for the current project.` }],
|
|
74131
|
+
isError: true
|
|
74132
|
+
};
|
|
74133
|
+
}
|
|
74134
|
+
if (action === "show") {
|
|
74135
|
+
return {
|
|
74136
|
+
content: [{ type: "text", text: JSON.stringify({ projectId: project.id, checkpoint }, null, 2) }]
|
|
74137
|
+
};
|
|
74138
|
+
}
|
|
74139
|
+
if (action === "context") {
|
|
74140
|
+
const workset = buildCompactionWorkset2(checkpoint, {
|
|
74141
|
+
task: task?.trim(),
|
|
74142
|
+
maxTokens: maxTokens != null ? coerceNumber(maxTokens, 420) : 420
|
|
74143
|
+
});
|
|
74144
|
+
return {
|
|
74145
|
+
content: [{ type: "text", text: workset.text }]
|
|
74146
|
+
};
|
|
74147
|
+
}
|
|
74148
|
+
const archived = store2.archive(checkpoint.id);
|
|
74149
|
+
if (!archived) {
|
|
74150
|
+
return {
|
|
74151
|
+
content: [{ type: "text", text: `Checkpoint "${checkpoint.id}" is already archived.` }],
|
|
74152
|
+
isError: true
|
|
74153
|
+
};
|
|
74154
|
+
}
|
|
74155
|
+
return {
|
|
74156
|
+
content: [{ type: "text", text: `Archived compact checkpoint ${archived.id}.` }]
|
|
74157
|
+
};
|
|
74158
|
+
}
|
|
74159
|
+
);
|
|
73236
74160
|
server.registerTool(
|
|
73237
74161
|
"memorix_transfer",
|
|
73238
74162
|
{
|
|
@@ -76147,7 +77071,7 @@ var init_serve_http = __esm({
|
|
|
76147
77071
|
},
|
|
76148
77072
|
run: async ({ args }) => {
|
|
76149
77073
|
const { createServer: createServer2 } = await import("http");
|
|
76150
|
-
const { randomUUID:
|
|
77074
|
+
const { randomUUID: randomUUID11 } = await import("crypto");
|
|
76151
77075
|
const { StreamableHTTPServerTransport: StreamableHTTPServerTransport2 } = await Promise.resolve().then(() => (init_streamableHttp(), streamableHttp_exports));
|
|
76152
77076
|
const { isInitializeRequest: isInitializeRequest2 } = await Promise.resolve().then(() => (init_types4(), types_exports));
|
|
76153
77077
|
const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server4(), server_exports2));
|
|
@@ -76331,7 +77255,7 @@ var init_serve_http = __esm({
|
|
|
76331
77255
|
if (!sessionId && isInitializeRequest2(body)) {
|
|
76332
77256
|
let createdState = null;
|
|
76333
77257
|
const transport = new StreamableHTTPServerTransport2({
|
|
76334
|
-
sessionIdGenerator: () =>
|
|
77258
|
+
sessionIdGenerator: () => randomUUID11(),
|
|
76335
77259
|
enableJsonResponse: true,
|
|
76336
77260
|
onsessioninitialized: (sid) => {
|
|
76337
77261
|
if (createdState) sessions.set(sid, createdState);
|
|
@@ -76726,10 +77650,18 @@ var init_serve_http = __esm({
|
|
|
76726
77650
|
};
|
|
76727
77651
|
} catch {
|
|
76728
77652
|
}
|
|
76729
|
-
let vectorStatus = {
|
|
77653
|
+
let vectorStatus = {
|
|
77654
|
+
available: false,
|
|
77655
|
+
total: 0,
|
|
77656
|
+
missing: 0,
|
|
77657
|
+
missingIds: [],
|
|
77658
|
+
backfillRunning: false
|
|
77659
|
+
};
|
|
76730
77660
|
try {
|
|
76731
|
-
const { getVectorStatus: getVectorStatus2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
|
|
76732
|
-
|
|
77661
|
+
const { getSearchIndexStatus: getSearchIndexStatus2, getVectorStatus: getVectorStatus2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
|
|
77662
|
+
if (getSearchIndexStatus2(statsProjectId).prepared) {
|
|
77663
|
+
vectorStatus = { available: true, ...getVectorStatus2(statsProjectId) };
|
|
77664
|
+
}
|
|
76733
77665
|
} catch {
|
|
76734
77666
|
}
|
|
76735
77667
|
let searchMode = "fulltext";
|
|
@@ -78121,6 +79053,44 @@ function stringifyValue(value) {
|
|
|
78121
79053
|
return String(value);
|
|
78122
79054
|
}
|
|
78123
79055
|
}
|
|
79056
|
+
function firstNumber2(...values) {
|
|
79057
|
+
for (const value of values) {
|
|
79058
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
79059
|
+
if (typeof value === "string" && value.trim()) {
|
|
79060
|
+
const parsed = Number(value);
|
|
79061
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
79062
|
+
}
|
|
79063
|
+
}
|
|
79064
|
+
return void 0;
|
|
79065
|
+
}
|
|
79066
|
+
function normalizeCompactionReason(value) {
|
|
79067
|
+
const normalized = value?.trim().toLowerCase();
|
|
79068
|
+
if (normalized === "manual" || normalized === "auto") return normalized;
|
|
79069
|
+
return "unknown";
|
|
79070
|
+
}
|
|
79071
|
+
function normalizeCompactionMetadata(payload, ...records) {
|
|
79072
|
+
const nestedSources = records.filter((record2) => Boolean(record2));
|
|
79073
|
+
const sources = [payload, ...nestedSources];
|
|
79074
|
+
const from = (field) => sources.map((source) => source[field]);
|
|
79075
|
+
const fromNested = (field) => nestedSources.map((source) => source[field]);
|
|
79076
|
+
const summary = firstString(...from("summary"), ...from("compaction_summary"));
|
|
79077
|
+
const sourceKey = firstString(...from("compaction_id"), ...from("entry_id"), ...fromNested("id"));
|
|
79078
|
+
const reasonValue = firstString(...from("trigger"), ...from("reason"), ...from("compaction_reason"));
|
|
79079
|
+
const tokensBefore = firstNumber2(...from("tokensBefore"), ...from("tokens_before"));
|
|
79080
|
+
const firstKeptEntryId = firstString(...from("firstKeptEntryId"), ...from("first_kept_entry_id"));
|
|
79081
|
+
const details = sources.map((source) => asRecord(source.details)).find((value) => Boolean(value));
|
|
79082
|
+
if (!summary && !sourceKey && !tokensBefore && !firstKeptEntryId && !details && !reasonValue) {
|
|
79083
|
+
return void 0;
|
|
79084
|
+
}
|
|
79085
|
+
return {
|
|
79086
|
+
...reasonValue ? { reason: normalizeCompactionReason(reasonValue) } : {},
|
|
79087
|
+
...sourceKey ? { sourceKey } : {},
|
|
79088
|
+
...summary ? { summary } : {},
|
|
79089
|
+
...tokensBefore !== void 0 ? { tokensBefore } : {},
|
|
79090
|
+
...firstKeptEntryId ? { firstKeptEntryId } : {},
|
|
79091
|
+
...details ? { details } : {}
|
|
79092
|
+
};
|
|
79093
|
+
}
|
|
78124
79094
|
function detectAgent(payload) {
|
|
78125
79095
|
if (typeof payload._memorix_agent === "string") {
|
|
78126
79096
|
return payload._memorix_agent;
|
|
@@ -78206,6 +79176,10 @@ function normalizeClaude(payload, event) {
|
|
|
78206
79176
|
if (assistantMessage) {
|
|
78207
79177
|
result.aiResponse = assistantMessage;
|
|
78208
79178
|
}
|
|
79179
|
+
if (event === "session_start") {
|
|
79180
|
+
const source = firstString(payload.source, payload.session_start_reason, payload.reason);
|
|
79181
|
+
if (source) result.sessionStartReason = source;
|
|
79182
|
+
}
|
|
78209
79183
|
return result;
|
|
78210
79184
|
}
|
|
78211
79185
|
function normalizeWindsurf(payload, event) {
|
|
@@ -78344,6 +79318,10 @@ function normalizeGemini(payload, event) {
|
|
|
78344
79318
|
if (event === "user_prompt") {
|
|
78345
79319
|
result.userPrompt = payload.prompt ?? "";
|
|
78346
79320
|
}
|
|
79321
|
+
if (event === "session_start") {
|
|
79322
|
+
const source = firstString(payload.source, payload.session_start_reason, payload.reason);
|
|
79323
|
+
if (source) result.sessionStartReason = source;
|
|
79324
|
+
}
|
|
78347
79325
|
return result;
|
|
78348
79326
|
}
|
|
78349
79327
|
function normalizeOpenCode(payload, event) {
|
|
@@ -78380,7 +79358,8 @@ function normalizeOpenCode(payload, event) {
|
|
|
78380
79358
|
function normalizePi(payload, event) {
|
|
78381
79359
|
const result = {
|
|
78382
79360
|
sessionId: payload.session_id ?? payload.sessionId ?? "",
|
|
78383
|
-
cwd: payload.cwd ?? ""
|
|
79361
|
+
cwd: payload.cwd ?? "",
|
|
79362
|
+
transcriptPath: payload.transcript_path ?? payload.transcriptPath
|
|
78384
79363
|
};
|
|
78385
79364
|
const toolName = payload.tool_name ?? "";
|
|
78386
79365
|
if (toolName) {
|
|
@@ -78402,6 +79381,10 @@ function normalizePi(payload, event) {
|
|
|
78402
79381
|
if (event === "post_command") {
|
|
78403
79382
|
result.command = payload.command ?? "";
|
|
78404
79383
|
}
|
|
79384
|
+
if (event === "session_start") {
|
|
79385
|
+
const source = firstString(payload.source, payload.reason);
|
|
79386
|
+
if (source) result.sessionStartReason = source;
|
|
79387
|
+
}
|
|
78405
79388
|
if (result.toolInput && typeof result.toolInput === "object") {
|
|
78406
79389
|
const filePath = result.toolInput.file_path ?? result.toolInput.filePath ?? result.toolInput.path;
|
|
78407
79390
|
if (filePath) result.filePath = filePath;
|
|
@@ -78454,6 +79437,10 @@ function normalizeBridgePayload(payload, event) {
|
|
|
78454
79437
|
openclawContext?.message
|
|
78455
79438
|
) ?? stringifyValue(openclawEvent?.message) ?? "";
|
|
78456
79439
|
}
|
|
79440
|
+
if (event === "session_start") {
|
|
79441
|
+
const source = firstString(payload.source, bridgePayload?.source, bridgeKwargs?.source, openclawEvent?.reason);
|
|
79442
|
+
if (source) result.sessionStartReason = source;
|
|
79443
|
+
}
|
|
78457
79444
|
return result;
|
|
78458
79445
|
}
|
|
78459
79446
|
function normalizeHookInput(payload) {
|
|
@@ -78499,6 +79486,15 @@ function normalizeHookInput(payload) {
|
|
|
78499
79486
|
default:
|
|
78500
79487
|
agentSpecific = { sessionId: "", cwd: "" };
|
|
78501
79488
|
}
|
|
79489
|
+
const openclawEvent = asRecord(payload.openclaw_event);
|
|
79490
|
+
const genericCompaction = event === "pre_compact" || event === "post_compact" ? normalizeCompactionMetadata(
|
|
79491
|
+
payload,
|
|
79492
|
+
asRecord(payload.compaction),
|
|
79493
|
+
asRecord(payload.compaction_entry),
|
|
79494
|
+
asRecord(payload.compactionEntry),
|
|
79495
|
+
asRecord(openclawEvent?.compaction),
|
|
79496
|
+
asRecord(openclawEvent?.compaction_entry)
|
|
79497
|
+
) : void 0;
|
|
78502
79498
|
return {
|
|
78503
79499
|
event,
|
|
78504
79500
|
agent,
|
|
@@ -78506,7 +79502,8 @@ function normalizeHookInput(payload) {
|
|
|
78506
79502
|
sessionId: agentSpecific.sessionId ?? "",
|
|
78507
79503
|
cwd: agentSpecific.cwd ?? "",
|
|
78508
79504
|
raw: payload,
|
|
78509
|
-
...agentSpecific
|
|
79505
|
+
...agentSpecific,
|
|
79506
|
+
...genericCompaction ? { compaction: genericCompaction } : {}
|
|
78510
79507
|
};
|
|
78511
79508
|
}
|
|
78512
79509
|
var EVENT_MAP;
|
|
@@ -78760,10 +79757,10 @@ __export(handler_exports, {
|
|
|
78760
79757
|
resetCooldowns: () => resetCooldowns,
|
|
78761
79758
|
runHook: () => runHook
|
|
78762
79759
|
});
|
|
78763
|
-
import { createHash as
|
|
79760
|
+
import { createHash as createHash16 } from "crypto";
|
|
78764
79761
|
function deriveHookActorId(input) {
|
|
78765
79762
|
const material = `${input.agent ?? "unknown"}\0${input.sessionId ?? "unknown"}`;
|
|
78766
|
-
return `hook:${
|
|
79763
|
+
return `hook:${createHash16("sha256").update(material).digest("hex").slice(0, 24)}`;
|
|
78767
79764
|
}
|
|
78768
79765
|
function classifyTool(input) {
|
|
78769
79766
|
if (input.event === "post_edit") return "file_modify";
|
|
@@ -78944,6 +79941,15 @@ async function buildHookProjectContext(input, task, target) {
|
|
|
78944
79941
|
refresh: "auto",
|
|
78945
79942
|
reader: { projectId: canonicalId },
|
|
78946
79943
|
continuation: "always",
|
|
79944
|
+
...input.sessionId ? {
|
|
79945
|
+
// A native compact recovery is delivered once per host session.
|
|
79946
|
+
// Do not echo that same checkpoint back through the generic
|
|
79947
|
+
// continuation brief on later events from this session.
|
|
79948
|
+
excludeCompactionCheckpointFor: {
|
|
79949
|
+
sessionId: input.sessionId,
|
|
79950
|
+
agent: input.agent
|
|
79951
|
+
}
|
|
79952
|
+
} : {},
|
|
78947
79953
|
enqueueRefresh: () => Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports)).then(({ enqueueCodegraphRefresh: enqueueCodegraphRefresh2 }) => {
|
|
78948
79954
|
enqueueCodegraphRefresh2({
|
|
78949
79955
|
dataDir,
|
|
@@ -78965,27 +79971,80 @@ async function buildHookProjectContext(input, task, target) {
|
|
|
78965
79971
|
return null;
|
|
78966
79972
|
}
|
|
78967
79973
|
}
|
|
79974
|
+
function isCompactSessionStart(input) {
|
|
79975
|
+
return input.event === "session_start" && input.sessionStartReason?.trim().toLowerCase() === "compact";
|
|
79976
|
+
}
|
|
79977
|
+
async function consumeCompactContinuation(input, task) {
|
|
79978
|
+
try {
|
|
79979
|
+
const { consumeCompactionWorkset: consumeCompactionWorkset2 } = await Promise.resolve().then(() => (init_compaction(), compaction_exports));
|
|
79980
|
+
const workset = await consumeCompactionWorkset2(input, { task, maxTokens: 420 });
|
|
79981
|
+
return workset?.text;
|
|
79982
|
+
} catch (error2) {
|
|
79983
|
+
console.error("[memorix] compact continuation failed:", error2?.message ?? error2);
|
|
79984
|
+
return void 0;
|
|
79985
|
+
}
|
|
79986
|
+
}
|
|
78968
79987
|
async function buildClaudeContinuationPromptContext(input) {
|
|
78969
79988
|
if (input.agent !== "claude" || input.event !== "user_prompt" || !input.userPrompt?.trim()) {
|
|
78970
79989
|
return void 0;
|
|
78971
79990
|
}
|
|
78972
|
-
const { isContinuationTask: isContinuationTask2 } = await Promise.resolve().then(() => (init_task_lens(), task_lens_exports));
|
|
78973
|
-
if (!isContinuationTask2(input.userPrompt)) return void 0;
|
|
78974
79991
|
if (await getHookInjectionMode(input) === "silent") return void 0;
|
|
78975
|
-
const
|
|
78976
|
-
if (
|
|
78977
|
-
|
|
78978
|
-
|
|
78979
|
-
|
|
78980
|
-
|
|
78981
|
-
|
|
78982
|
-
|
|
79992
|
+
const compactContinuation = await consumeCompactContinuation(input, input.userPrompt);
|
|
79993
|
+
if (compactContinuation) {
|
|
79994
|
+
return [
|
|
79995
|
+
"Memorix recovered one bounded checkpoint after the host compacted this session.",
|
|
79996
|
+
"Treat it as background context; current code and the user request win.",
|
|
79997
|
+
"",
|
|
79998
|
+
compactContinuation
|
|
79999
|
+
].join("\n");
|
|
80000
|
+
}
|
|
80001
|
+
const { isContinuationTask: isContinuationTask2, resolveTaskLens: resolveTaskLens2 } = await Promise.resolve().then(() => (init_task_lens(), task_lens_exports));
|
|
80002
|
+
const continuationRequested = isContinuationTask2(input.userPrompt);
|
|
80003
|
+
if (continuationRequested) {
|
|
80004
|
+
const context = await buildHookProjectContext(input, input.userPrompt, "hook-user-prompt");
|
|
80005
|
+
if (context?.hasContinuation) {
|
|
80006
|
+
return [
|
|
80007
|
+
"Memorix prepared a bounded prior-work brief for this explicit continuation request.",
|
|
80008
|
+
"Treat it as background context; current code wins. Use it before broad Git or file-history archaeology.",
|
|
80009
|
+
"",
|
|
80010
|
+
context.prompt
|
|
80011
|
+
].join("\n");
|
|
80012
|
+
}
|
|
80013
|
+
}
|
|
80014
|
+
if (continuationRequested || resolveTaskLens2(input.userPrompt).id === "onboarding") {
|
|
80015
|
+
return [
|
|
80016
|
+
"Memorix is available for this handoff or continuation.",
|
|
80017
|
+
"Before broad file or Git exploration, call memorix_project_context with the user's actual task.",
|
|
80018
|
+
"If it is not visible yet, use Claude Code tool search for memorix_project_context; use CLI only when MCP discovery is unavailable."
|
|
80019
|
+
].join(" ");
|
|
80020
|
+
}
|
|
80021
|
+
return void 0;
|
|
78983
80022
|
}
|
|
78984
80023
|
async function handleSessionStart(input) {
|
|
78985
80024
|
const injectMode = await getHookInjectionMode(input);
|
|
78986
80025
|
if (injectMode === "silent") {
|
|
78987
80026
|
return { observation: null, output: { continue: true } };
|
|
78988
80027
|
}
|
|
80028
|
+
if (input.agent === "codex" && isCompactSessionStart(input)) {
|
|
80029
|
+
const compactContinuation = await consumeCompactContinuation(
|
|
80030
|
+
input,
|
|
80031
|
+
"Continue after the host compacted the current session."
|
|
80032
|
+
);
|
|
80033
|
+
if (compactContinuation) {
|
|
80034
|
+
return {
|
|
80035
|
+
observation: null,
|
|
80036
|
+
output: {
|
|
80037
|
+
continue: true,
|
|
80038
|
+
systemMessage: [
|
|
80039
|
+
"Memorix recovered one bounded checkpoint after the host compacted this session.",
|
|
80040
|
+
"Treat it as background context; current code and the user request win.",
|
|
80041
|
+
"",
|
|
80042
|
+
compactContinuation
|
|
80043
|
+
].join("\n")
|
|
80044
|
+
}
|
|
80045
|
+
};
|
|
80046
|
+
}
|
|
80047
|
+
}
|
|
78989
80048
|
let contextSummary = "";
|
|
78990
80049
|
if (injectMode === "full") {
|
|
78991
80050
|
const context = await buildHookProjectContext(input, "Continue the current task.", "hook-session-start");
|
|
@@ -79194,6 +80253,12 @@ async function runHook(agentOverride, eventOverride) {
|
|
|
79194
80253
|
payload._memorix_event = eventOverride;
|
|
79195
80254
|
}
|
|
79196
80255
|
const input = normalizeHookInput(payload);
|
|
80256
|
+
try {
|
|
80257
|
+
const { captureCompactionCheckpoint: captureCompactionCheckpoint2 } = await Promise.resolve().then(() => (init_compaction(), compaction_exports));
|
|
80258
|
+
await captureCompactionCheckpoint2(input);
|
|
80259
|
+
} catch (checkpointError) {
|
|
80260
|
+
console.error("[memorix] compact checkpoint failed:", checkpointError?.message ?? checkpointError);
|
|
80261
|
+
}
|
|
79197
80262
|
const { observation, output } = await handleHookEvent(input, { deferMaintenance: true });
|
|
79198
80263
|
if (observation) {
|
|
79199
80264
|
try {
|
|
@@ -81341,6 +82406,9 @@ function asRecordArray(value) {
|
|
|
81341
82406
|
function codexPluginPath() {
|
|
81342
82407
|
return `${homedir32()}/.codex/plugins/${CODEX_PLUGIN_NAME}`;
|
|
81343
82408
|
}
|
|
82409
|
+
function codexPluginMcpPath() {
|
|
82410
|
+
return `${codexPluginPath()}/.mcp.json`;
|
|
82411
|
+
}
|
|
81344
82412
|
function codexMarketplacePath() {
|
|
81345
82413
|
return `${homedir32()}/.agents/plugins/marketplace.json`;
|
|
81346
82414
|
}
|
|
@@ -81373,6 +82441,7 @@ async function inspectCodexPluginBundle() {
|
|
|
81373
82441
|
const pluginPath = codexPluginPath();
|
|
81374
82442
|
const manifestPath = `${pluginPath}/.codex-plugin/plugin.json`;
|
|
81375
82443
|
const hooksPath = `${pluginPath}/hooks/hooks.json`;
|
|
82444
|
+
const mcpPath = codexPluginMcpPath();
|
|
81376
82445
|
if (!existsSync25(pluginPath)) {
|
|
81377
82446
|
return {
|
|
81378
82447
|
scope: "global",
|
|
@@ -81420,6 +82489,19 @@ async function inspectCodexPluginBundle() {
|
|
|
81420
82489
|
const issues = [];
|
|
81421
82490
|
if (version2 !== getCliVersion()) issues.push("codex-plugin-version-mismatch");
|
|
81422
82491
|
if (manifest.hooks !== "./hooks/hooks.json") issues.push("codex-hook-manifest-missing");
|
|
82492
|
+
if (!existsSync25(mcpPath)) {
|
|
82493
|
+
issues.push("codex-plugin-mcp-manifest-missing");
|
|
82494
|
+
} else {
|
|
82495
|
+
try {
|
|
82496
|
+
const mcpConfig = asRecord2(JSON.parse(await readFile7(mcpPath, "utf-8")));
|
|
82497
|
+
const server = coerceMcpServer("memorix", asRecord2(mcpConfig?.mcpServers)?.memorix);
|
|
82498
|
+
if (!server || !isRecommendedStdioServer(server)) {
|
|
82499
|
+
issues.push("codex-plugin-mcp-manifest-invalid");
|
|
82500
|
+
}
|
|
82501
|
+
} catch {
|
|
82502
|
+
issues.push("codex-plugin-mcp-manifest-unreadable");
|
|
82503
|
+
}
|
|
82504
|
+
}
|
|
81423
82505
|
let declared = [];
|
|
81424
82506
|
if (!existsSync25(hooksPath)) {
|
|
81425
82507
|
issues.push("codex-hook-manifest-missing");
|
|
@@ -81569,7 +82651,9 @@ async function inspectCodexHookTrust() {
|
|
|
81569
82651
|
kind: "hook-trust",
|
|
81570
82652
|
path: configPath,
|
|
81571
82653
|
exists: true,
|
|
81572
|
-
|
|
82654
|
+
// Codex records hook approval only after the user has reviewed it. Memorix
|
|
82655
|
+
// must not treat an intentional, host-owned consent step as a broken setup.
|
|
82656
|
+
status: issues.length > 0 ? "skipped" : "ok",
|
|
81573
82657
|
issues,
|
|
81574
82658
|
hookTrust: { trusted, expected: [...CODEX_HOOK_STATE_NAMES] }
|
|
81575
82659
|
};
|
|
@@ -81637,7 +82721,7 @@ function defaultClaudeProjectKey(projectRoot) {
|
|
|
81637
82721
|
function getClaudeLocalConfigPath() {
|
|
81638
82722
|
return `${homedir32()}/.claude.json`;
|
|
81639
82723
|
}
|
|
81640
|
-
function
|
|
82724
|
+
function coerceMcpServer(name, value) {
|
|
81641
82725
|
const entry = asRecord2(value);
|
|
81642
82726
|
if (!entry) return null;
|
|
81643
82727
|
const args = Array.isArray(entry.args) ? entry.args.map(String) : [];
|
|
@@ -81696,7 +82780,7 @@ async function inspectClaudeLocalMcp(projectRoot) {
|
|
|
81696
82780
|
};
|
|
81697
82781
|
}
|
|
81698
82782
|
const servers = asRecord2(localProject.project.mcpServers);
|
|
81699
|
-
const server =
|
|
82783
|
+
const server = coerceMcpServer("memorix", servers?.memorix);
|
|
81700
82784
|
if (!server) {
|
|
81701
82785
|
return {
|
|
81702
82786
|
scope: "local",
|
|
@@ -81747,6 +82831,56 @@ async function installClaudeLocalMcpConfig(projectRoot) {
|
|
|
81747
82831
|
await writeFile7(configPath, `${JSON.stringify(config2, null, 2)}
|
|
81748
82832
|
`, "utf-8");
|
|
81749
82833
|
}
|
|
82834
|
+
async function inspectCodexPluginMcp() {
|
|
82835
|
+
const runtime = inspectCodexPluginRuntime();
|
|
82836
|
+
if (!runtime.runtime?.installed || !runtime.runtime.enabled) return null;
|
|
82837
|
+
const mcpPath = codexPluginMcpPath();
|
|
82838
|
+
if (!existsSync25(mcpPath)) {
|
|
82839
|
+
return {
|
|
82840
|
+
scope: "global",
|
|
82841
|
+
path: mcpPath,
|
|
82842
|
+
exists: false,
|
|
82843
|
+
status: "repairable",
|
|
82844
|
+
issues: ["codex-plugin-mcp-manifest-missing"],
|
|
82845
|
+
managedByPlugin: true
|
|
82846
|
+
};
|
|
82847
|
+
}
|
|
82848
|
+
try {
|
|
82849
|
+
const config2 = asRecord2(JSON.parse(await readFile7(mcpPath, "utf-8")));
|
|
82850
|
+
const server = coerceMcpServer("memorix", asRecord2(config2?.mcpServers)?.memorix);
|
|
82851
|
+
if (!server) {
|
|
82852
|
+
return {
|
|
82853
|
+
scope: "global",
|
|
82854
|
+
path: mcpPath,
|
|
82855
|
+
exists: true,
|
|
82856
|
+
status: "repairable",
|
|
82857
|
+
issues: ["codex-plugin-mcp-manifest-invalid"],
|
|
82858
|
+
managedByPlugin: true
|
|
82859
|
+
};
|
|
82860
|
+
}
|
|
82861
|
+
const issues = [];
|
|
82862
|
+
if (looksLikeStaleMemorixCommand(server)) issues.push("stale-command-path");
|
|
82863
|
+
if (!isRecommendedStdioServer(server)) issues.push("nonstandard-mcp-command");
|
|
82864
|
+
return {
|
|
82865
|
+
scope: "global",
|
|
82866
|
+
path: mcpPath,
|
|
82867
|
+
exists: true,
|
|
82868
|
+
status: issues.length > 0 ? "repairable" : "ok",
|
|
82869
|
+
issues,
|
|
82870
|
+
managedByPlugin: true,
|
|
82871
|
+
server: sanitizeServer(server)
|
|
82872
|
+
};
|
|
82873
|
+
} catch {
|
|
82874
|
+
return {
|
|
82875
|
+
scope: "global",
|
|
82876
|
+
path: mcpPath,
|
|
82877
|
+
exists: true,
|
|
82878
|
+
status: "repairable",
|
|
82879
|
+
issues: ["codex-plugin-mcp-manifest-unreadable"],
|
|
82880
|
+
managedByPlugin: true
|
|
82881
|
+
};
|
|
82882
|
+
}
|
|
82883
|
+
}
|
|
81750
82884
|
async function inspectMcp(agent, projectRoot, scope) {
|
|
81751
82885
|
if (!isMcpConfigAgent(agent)) {
|
|
81752
82886
|
return { status: "skipped", issues: ["mcp-managed-by-package"], checks: [] };
|
|
@@ -81758,6 +82892,13 @@ async function inspectMcp(agent, projectRoot, scope) {
|
|
|
81758
82892
|
checks.push(await inspectClaudeLocalMcp(projectRoot));
|
|
81759
82893
|
continue;
|
|
81760
82894
|
}
|
|
82895
|
+
if (agent === "codex" && targetScope === "global") {
|
|
82896
|
+
const pluginCheck = await inspectCodexPluginMcp();
|
|
82897
|
+
if (pluginCheck) {
|
|
82898
|
+
checks.push(pluginCheck);
|
|
82899
|
+
continue;
|
|
82900
|
+
}
|
|
82901
|
+
}
|
|
81761
82902
|
const configPath = adapter.getConfigPath(targetScope === "project" ? projectRoot : void 0);
|
|
81762
82903
|
if (targetScope === "global" && configPath === adapter.getConfigPath(projectRoot)) continue;
|
|
81763
82904
|
if (!existsSync25(configPath)) {
|
|
@@ -81902,10 +83043,19 @@ function formatAgentIntegrationReport(report) {
|
|
|
81902
83043
|
lines.push(`${entry.agent}: ${status}`);
|
|
81903
83044
|
if (entry.mcp.issues.length > 0) lines.push(` MCP: ${entry.mcp.issues.join(", ")}`);
|
|
81904
83045
|
if (entry.guidance.issues.length > 0) lines.push(` Guidance: ${entry.guidance.issues.join(", ")}`);
|
|
81905
|
-
|
|
83046
|
+
const hookTrustPending = entry.plugin.issues.includes("codex-hook-trust-pending");
|
|
83047
|
+
const pluginIssues = entry.plugin.issues.filter((issue2) => issue2 !== "codex-hook-trust-pending");
|
|
83048
|
+
if (pluginIssues.length > 0) lines.push(` Plugin: ${pluginIssues.join(", ")}`);
|
|
83049
|
+
if (hookTrustPending) {
|
|
83050
|
+
lines.push(" Hooks: waiting for Codex approval on first use; MCP remains available.");
|
|
83051
|
+
}
|
|
81906
83052
|
}
|
|
81907
83053
|
lines.push("");
|
|
81908
|
-
|
|
83054
|
+
if (report.summary.missing > 0 || report.summary.repairable > 0) {
|
|
83055
|
+
lines.push(`Repair: ${report.repairCommand}`);
|
|
83056
|
+
} else {
|
|
83057
|
+
lines.push("No file repair needed.");
|
|
83058
|
+
}
|
|
81909
83059
|
return lines.join("\n");
|
|
81910
83060
|
}
|
|
81911
83061
|
async function repairAgentIntegrations(options2 = {}) {
|
|
@@ -81919,6 +83069,10 @@ async function repairAgentIntegrations(options2 = {}) {
|
|
|
81919
83069
|
if (isMcpConfigAgent(entry.agent)) {
|
|
81920
83070
|
for (const check2 of entry.mcp.checks) {
|
|
81921
83071
|
if (check2.status === "ok" || check2.status === "skipped") continue;
|
|
83072
|
+
if (check2.managedByPlugin) {
|
|
83073
|
+
skipped.push(`${entry.agent}:mcp:${check2.scope}:plugin-managed`);
|
|
83074
|
+
continue;
|
|
83075
|
+
}
|
|
81922
83076
|
if (check2.status === "missing" && !canInstallMissing) {
|
|
81923
83077
|
skipped.push(`${entry.agent}:mcp:${check2.scope}:missing`);
|
|
81924
83078
|
continue;
|
|
@@ -84986,32 +86140,32 @@ __export(cost_tracker_exports, {
|
|
|
84986
86140
|
formatCostSummary: () => formatCostSummary,
|
|
84987
86141
|
isBudgetExceeded: () => isBudgetExceeded
|
|
84988
86142
|
});
|
|
84989
|
-
function calculateModelCost(model,
|
|
86143
|
+
function calculateModelCost(model, usage3, customPrices) {
|
|
84990
86144
|
const prices = { ...DEFAULT_PRICES, ...customPrices };
|
|
84991
86145
|
const price = findPrice(model, prices);
|
|
84992
86146
|
if (!price) return null;
|
|
84993
|
-
const inputCost =
|
|
84994
|
-
const outputCost =
|
|
84995
|
-
const cacheReadCost =
|
|
84996
|
-
const cacheWriteCost =
|
|
86147
|
+
const inputCost = usage3.inputTokens / 1e6 * price.inputPer1M;
|
|
86148
|
+
const outputCost = usage3.outputTokens / 1e6 * price.outputPer1M;
|
|
86149
|
+
const cacheReadCost = usage3.cacheReadTokens / 1e6 * (price.cacheReadPer1M ?? 0);
|
|
86150
|
+
const cacheWriteCost = usage3.cacheWriteTokens / 1e6 * (price.cacheWritePer1M ?? 0);
|
|
84997
86151
|
return inputCost + outputCost + cacheReadCost + cacheWriteCost;
|
|
84998
86152
|
}
|
|
84999
86153
|
function calculatePipelineCost(tokenUsage, budgetUSD, customPrices) {
|
|
85000
86154
|
const models2 = [];
|
|
85001
86155
|
let totalUSD = 0;
|
|
85002
86156
|
let hasAnyPrice = false;
|
|
85003
|
-
for (const [model,
|
|
85004
|
-
const cost = calculateModelCost(model,
|
|
86157
|
+
for (const [model, usage3] of Object.entries(tokenUsage)) {
|
|
86158
|
+
const cost = calculateModelCost(model, usage3, customPrices);
|
|
85005
86159
|
if (cost !== null) {
|
|
85006
86160
|
hasAnyPrice = true;
|
|
85007
86161
|
totalUSD = (totalUSD ?? 0) + cost;
|
|
85008
86162
|
}
|
|
85009
86163
|
models2.push({
|
|
85010
86164
|
model,
|
|
85011
|
-
inputTokens:
|
|
85012
|
-
outputTokens:
|
|
85013
|
-
cacheReadTokens:
|
|
85014
|
-
cacheWriteTokens:
|
|
86165
|
+
inputTokens: usage3.inputTokens,
|
|
86166
|
+
outputTokens: usage3.outputTokens,
|
|
86167
|
+
cacheReadTokens: usage3.cacheReadTokens,
|
|
86168
|
+
cacheWriteTokens: usage3.cacheWriteTokens,
|
|
85015
86169
|
costUSD: cost !== null ? Math.round(cost * 1e4) / 1e4 : null
|
|
85016
86170
|
// Round to 4 decimals
|
|
85017
86171
|
});
|
|
@@ -85310,7 +86464,7 @@ var init_permission = __esm({
|
|
|
85310
86464
|
});
|
|
85311
86465
|
|
|
85312
86466
|
// src/orchestrate/memorix-bridge.ts
|
|
85313
|
-
import { createHash as
|
|
86467
|
+
import { createHash as createHash17 } from "crypto";
|
|
85314
86468
|
async function getStoreObservation() {
|
|
85315
86469
|
if (!_storeObservation) {
|
|
85316
86470
|
const mod = await Promise.resolve().then(() => (init_observations(), observations_exports));
|
|
@@ -85326,7 +86480,7 @@ async function getSearchObservations() {
|
|
|
85326
86480
|
return _searchObservations;
|
|
85327
86481
|
}
|
|
85328
86482
|
function automaticActorId(...parts) {
|
|
85329
|
-
return `orchestrator:${
|
|
86483
|
+
return `orchestrator:${createHash17("sha256").update(parts.join("\0")).digest("hex").slice(0, 24)}`;
|
|
85330
86484
|
}
|
|
85331
86485
|
function isEligibleAutomaticLesson(entry) {
|
|
85332
86486
|
return entry.admissionState !== "candidate" && entry.admissionState !== "ephemeral";
|
|
@@ -85473,7 +86627,7 @@ function sanitizeErrorPattern(text) {
|
|
|
85473
86627
|
}
|
|
85474
86628
|
function hashErrorPattern(errorOutput) {
|
|
85475
86629
|
const sanitized = sanitizeErrorPattern(errorOutput).slice(0, 500);
|
|
85476
|
-
return
|
|
86630
|
+
return createHash17("sha256").update(sanitized).digest("hex").slice(0, 12);
|
|
85477
86631
|
}
|
|
85478
86632
|
function sleep2(ms) {
|
|
85479
86633
|
return new Promise((resolve6) => setTimeout(() => resolve6([]), ms));
|
|
@@ -85934,12 +87088,12 @@ ${formatCostSummary(costSummary)}`);
|
|
|
85934
87088
|
activeDispatches.splice(settled.idx, 1);
|
|
85935
87089
|
const { dispatch, result } = settled;
|
|
85936
87090
|
if (result.tokenUsage) {
|
|
85937
|
-
for (const [model,
|
|
87091
|
+
for (const [model, usage3] of Object.entries(result.tokenUsage)) {
|
|
85938
87092
|
const prev = pipelineUsage[model] ?? { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, model };
|
|
85939
|
-
prev.inputTokens +=
|
|
85940
|
-
prev.outputTokens +=
|
|
85941
|
-
prev.cacheReadTokens +=
|
|
85942
|
-
prev.cacheWriteTokens +=
|
|
87093
|
+
prev.inputTokens += usage3.inputTokens;
|
|
87094
|
+
prev.outputTokens += usage3.outputTokens;
|
|
87095
|
+
prev.cacheReadTokens += usage3.cacheReadTokens;
|
|
87096
|
+
prev.cacheWriteTokens += usage3.cacheWriteTokens;
|
|
85943
87097
|
pipelineUsage[model] = prev;
|
|
85944
87098
|
}
|
|
85945
87099
|
if (traceDb && pipelineId) {
|
|
@@ -86885,10 +88039,10 @@ ${"\u2550".repeat(60)}`);
|
|
|
86885
88039
|
if (result.tokenUsage) {
|
|
86886
88040
|
console.error(`
|
|
86887
88041
|
[COST] Token Usage:`);
|
|
86888
|
-
for (const [model,
|
|
86889
|
-
const total =
|
|
86890
|
-
const cacheHits =
|
|
86891
|
-
console.error(` ${model}: ${total.toLocaleString()} tokens (in: ${
|
|
88042
|
+
for (const [model, usage3] of Object.entries(result.tokenUsage)) {
|
|
88043
|
+
const total = usage3.inputTokens + usage3.outputTokens;
|
|
88044
|
+
const cacheHits = usage3.cacheReadTokens;
|
|
88045
|
+
console.error(` ${model}: ${total.toLocaleString()} tokens (in: ${usage3.inputTokens.toLocaleString()}, out: ${usage3.outputTokens.toLocaleString()}${cacheHits > 0 ? `, cache: ${cacheHits.toLocaleString()}` : ""})`);
|
|
86892
88046
|
}
|
|
86893
88047
|
}
|
|
86894
88048
|
if (result.costSummary) {
|
|
@@ -91394,6 +92548,16 @@ var GUIDES = {
|
|
|
91394
92548
|
'memorix codegraph context-pack --task "trace the auth flow" [--limit 20]'
|
|
91395
92549
|
]
|
|
91396
92550
|
},
|
|
92551
|
+
checkpoint: {
|
|
92552
|
+
summary: "Inspect bounded recovery checkpoints created around host-native context compaction.",
|
|
92553
|
+
usage: [
|
|
92554
|
+
"memorix checkpoint list [--session <id>] [--agent <name>]",
|
|
92555
|
+
"memorix checkpoint show --id <checkpoint-id>",
|
|
92556
|
+
'memorix checkpoint context [--id <checkpoint-id>] [--task "continue auth fix"]',
|
|
92557
|
+
"memorix checkpoint archive --id <checkpoint-id>"
|
|
92558
|
+
],
|
|
92559
|
+
notes: ["Checkpoints are host lifecycle evidence, not durable project memory and not transcript backups."]
|
|
92560
|
+
},
|
|
91397
92561
|
knowledge: {
|
|
91398
92562
|
summary: "Manage the reviewed, source-backed Knowledge Workspace and project workflows.",
|
|
91399
92563
|
usage: [
|
|
@@ -91709,6 +92873,7 @@ var main = defineCommand({
|
|
|
91709
92873
|
resume: () => Promise.resolve().then(() => (init_resume(), resume_exports)).then((m4) => m4.default),
|
|
91710
92874
|
explain: () => Promise.resolve().then(() => (init_explain(), explain_exports)).then((m4) => m4.default),
|
|
91711
92875
|
codegraph: () => Promise.resolve().then(() => (init_codegraph(), codegraph_exports)).then((m4) => m4.default),
|
|
92876
|
+
checkpoint: () => Promise.resolve().then(() => (init_checkpoint(), checkpoint_exports)).then((m4) => m4.default),
|
|
91712
92877
|
knowledge: () => Promise.resolve().then(() => (init_knowledge(), knowledge_exports)).then((m4) => m4.default),
|
|
91713
92878
|
reasoning: () => Promise.resolve().then(() => (init_reasoning(), reasoning_exports)).then((m4) => m4.default),
|
|
91714
92879
|
retention: () => Promise.resolve().then(() => (init_retention2(), retention_exports2)).then((m4) => m4.default),
|
|
@@ -91790,6 +92955,7 @@ var main = defineCommand({
|
|
|
91790
92955
|
"resume",
|
|
91791
92956
|
"explain",
|
|
91792
92957
|
"codegraph",
|
|
92958
|
+
"checkpoint",
|
|
91793
92959
|
"knowledge",
|
|
91794
92960
|
"reasoning",
|
|
91795
92961
|
"retention",
|
|
@@ -91858,6 +93024,7 @@ var main = defineCommand({
|
|
|
91858
93024
|
console.error(" resume Resume prior work with one bounded project brief");
|
|
91859
93025
|
console.error(" explain Explain where Memorix project context comes from");
|
|
91860
93026
|
console.error(" codegraph Refresh/status/context-pack for CodeGraph Memory");
|
|
93027
|
+
console.error(" checkpoint Inspect native compact continuity checkpoints");
|
|
91861
93028
|
console.error(" knowledge Review source-backed knowledge pages and project workflows");
|
|
91862
93029
|
console.error(" reasoning Store/search decision rationale");
|
|
91863
93030
|
console.error(" retention Inspect stale/archive status");
|