memorix 1.2.6 → 1.2.7

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +6 -3
  3. package/README.zh-CN.md +5 -2
  4. package/dist/cli/index.js +954 -72
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/cli/memcode.js +0 -0
  7. package/dist/index.js +632 -27
  8. package/dist/index.js.map +1 -1
  9. package/dist/maintenance-runner.js +39 -1
  10. package/dist/maintenance-runner.js.map +1 -1
  11. package/dist/memcode-runtime/CHANGELOG.md +12 -0
  12. package/dist/sdk.d.ts +1 -1
  13. package/dist/sdk.js +632 -27
  14. package/dist/sdk.js.map +1 -1
  15. package/dist/types.d.ts +38 -1
  16. package/dist/types.js.map +1 -1
  17. package/docs/1.2.7-CONTEXT-CONTINUITY.md +68 -0
  18. package/docs/API_REFERENCE.md +6 -2
  19. package/docs/dev-log/progress.txt +23 -0
  20. package/docs/hooks-architecture.md +2 -1
  21. package/package.json +1 -1
  22. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  23. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  24. package/plugins/copilot/memorix/plugin.json +1 -1
  25. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  26. package/plugins/omp/memorix/extensions/memorix.js +17 -0
  27. package/plugins/omp/memorix/package.json +1 -1
  28. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  29. package/plugins/pi/memorix/extensions/memorix.js +17 -0
  30. package/plugins/pi/memorix/package.json +1 -1
  31. package/src/cli/capability-map.ts +1 -0
  32. package/src/cli/command-guide.ts +10 -0
  33. package/src/cli/commands/checkpoint.ts +144 -0
  34. package/src/cli/index.ts +3 -1
  35. package/src/codegraph/auto-context.ts +51 -5
  36. package/src/hooks/handler.ts +103 -11
  37. package/src/hooks/normalizer.ts +85 -1
  38. package/src/hooks/types.ts +16 -0
  39. package/src/knowledge/workset.ts +43 -2
  40. package/src/memory/compaction.ts +165 -0
  41. package/src/server/tool-profile.ts +1 -0
  42. package/src/server.ts +94 -0
  43. package/src/store/compaction-checkpoint-store.ts +397 -0
  44. package/src/store/sqlite-db.ts +41 -0
  45. package/src/types.ts +46 -0
package/dist/index.js CHANGED
@@ -234,6 +234,7 @@ function getDatabase(dataDir) {
234
234
  db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
235
235
  db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
236
236
  db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
237
+ db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
237
238
  try {
238
239
  db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
239
240
  } catch {
@@ -274,7 +275,7 @@ function getDatabase(dataDir) {
274
275
  _dbCache.set(normalized, db2);
275
276
  return db2;
276
277
  }
277
- 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;
278
+ 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;
278
279
  var init_sqlite_db = __esm({
279
280
  "src/store/sqlite-db.ts"() {
280
281
  "use strict";
@@ -726,6 +727,31 @@ CREATE TABLE IF NOT EXISTS maintenance_targets (
726
727
  data_dir TEXT NOT NULL,
727
728
  updated_at INTEGER NOT NULL
728
729
  );
730
+ `;
731
+ CREATE_COMPACTION_CHECKPOINTS_TABLE = `
732
+ CREATE TABLE IF NOT EXISTS compaction_checkpoints (
733
+ id TEXT PRIMARY KEY,
734
+ project_id TEXT NOT NULL,
735
+ session_id TEXT NOT NULL,
736
+ agent TEXT NOT NULL,
737
+ phase TEXT NOT NULL,
738
+ capture_kind TEXT NOT NULL,
739
+ reason TEXT NOT NULL DEFAULT 'unknown',
740
+ source_event TEXT NOT NULL,
741
+ source_key TEXT NOT NULL,
742
+ summary TEXT,
743
+ tokens_before INTEGER,
744
+ first_kept_entry_id TEXT,
745
+ details_json TEXT NOT NULL DEFAULT '{}',
746
+ transcript_available INTEGER NOT NULL DEFAULT 0,
747
+ status TEXT NOT NULL DEFAULT 'active',
748
+ pre_captured_at TEXT NOT NULL,
749
+ completed_at TEXT,
750
+ delivered_at TEXT,
751
+ delivery_count INTEGER NOT NULL DEFAULT 0,
752
+ created_at TEXT NOT NULL,
753
+ updated_at TEXT NOT NULL
754
+ );
729
755
  `;
730
756
  CREATE_INDEXES = `
731
757
  CREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);
@@ -773,6 +799,9 @@ CREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowl
773
799
  CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_ready ON maintenance_jobs(status, run_after);
774
800
  CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_project ON maintenance_jobs(project_id, status, run_after);
775
801
  CREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_targets(updated_at);
802
+ CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_project_recent ON compaction_checkpoints(project_id, status, completed_at DESC, pre_captured_at DESC);
803
+ CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC);
804
+ CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key);
776
805
  CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
777
806
  ON maintenance_jobs(project_id, kind, dedupe_key)
778
807
  WHERE status IN ('pending', 'running', 'retry');
@@ -846,6 +875,15 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
846
875
  db2.exec("CREATE INDEX IF NOT EXISTS idx_knowledge_workflows_workspace_status ON knowledge_workflows(workspaceId, status, updatedAt DESC)");
847
876
  db2.exec("CREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowledge_workflow_runs(projectId, workflowId, startedAt DESC)");
848
877
  }
878
+ },
879
+ {
880
+ id: "1.2.7-compaction-checkpoints",
881
+ apply: (db2) => {
882
+ db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
883
+ 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)");
884
+ 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)");
885
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key)");
886
+ }
849
887
  }
850
888
  ];
851
889
  _dbCache = /* @__PURE__ */ new Map();
@@ -8123,10 +8161,10 @@ var init_store = __esm({
8123
8161
  return row ? rowToSnapshot(row) : void 0;
8124
8162
  }
8125
8163
  listSnapshots(projectId, limit = 20) {
8126
- const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(200, Math.floor(limit))) : 20;
8164
+ const safeLimit2 = Number.isFinite(limit) ? Math.max(1, Math.min(200, Math.floor(limit))) : 20;
8127
8165
  return this.db.prepare(
8128
8166
  "SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT ?"
8129
- ).all(projectId, safeLimit).map(rowToSnapshot);
8167
+ ).all(projectId, safeLimit2).map(rowToSnapshot);
8130
8168
  }
8131
8169
  /**
8132
8170
  * Record a completed scan and mark all current structural facts with its
@@ -15983,7 +16021,7 @@ function renderTaskWorksetPrompt(input) {
15983
16021
  });
15984
16022
  appendLine(lines, "Task lens: " + input.lens, maxTokens, omitted, "lens");
15985
16023
  const hasContinuation = Boolean(
15986
- input.continuation?.previousSession || (input.continuation?.memories.length ?? 0) > 0
16024
+ input.continuation?.previousSession || (input.continuation?.memories.length ?? 0) > 0 || input.continuation?.compactCheckpoint
15987
16025
  );
15988
16026
  if (hasContinuation && input.continuation) {
15989
16027
  appendLine(lines, "", maxTokens, omitted, "continuation-heading");
@@ -16023,6 +16061,24 @@ function renderTaskWorksetPrompt(input) {
16023
16061
  }
16024
16062
  );
16025
16063
  }
16064
+ if (input.continuation.compactCheckpoint) {
16065
+ const checkpoint = input.continuation.compactCheckpoint;
16066
+ const source = `${checkpoint.agent}, ${checkpoint.captureKind}, ${checkpoint.reason}`;
16067
+ appendLine(
16068
+ lines,
16069
+ "- Recent host compact checkpoint (" + source + "): " + short(checkpoint.summary, 36),
16070
+ maxTokens,
16071
+ omitted,
16072
+ "continuation-compact-checkpoint",
16073
+ selected,
16074
+ {
16075
+ kind: "continuation",
16076
+ id: "compact:" + checkpoint.id,
16077
+ reason: "recent host-native compact lifecycle evidence",
16078
+ trust: "historical"
16079
+ }
16080
+ );
16081
+ }
16026
16082
  }
16027
16083
  if (input.cautions.length > 0 || input.cautionMemory.length > 0) {
16028
16084
  appendLine(lines, "", maxTokens, omitted, "caution-heading");
@@ -16292,7 +16348,7 @@ async function buildTaskWorkset(input) {
16292
16348
  ...input.verificationHints
16293
16349
  ]).slice(0, 4);
16294
16350
  const normalizedCautions = unique(cautions.map((caution) => caution.kind)).map((kind) => cautions.find((caution) => caution.kind === kind)).slice(0, 6);
16295
- const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0) ? {
16351
+ const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0 || input.continuation.compactCheckpoint) ? {
16296
16352
  ...input.continuation.previousSession ? {
16297
16353
  previousSession: {
16298
16354
  ...input.continuation.previousSession,
@@ -16303,7 +16359,13 @@ async function buildTaskWorkset(input) {
16303
16359
  ...memory,
16304
16360
  title: short(memory.title, 20),
16305
16361
  ...memory.detail ? { detail: short(memory.detail, CONTINUATION_DETAIL_TOKEN_BUDGET) } : {}
16306
- }))
16362
+ })),
16363
+ ...input.continuation.compactCheckpoint ? {
16364
+ compactCheckpoint: {
16365
+ ...input.continuation.compactCheckpoint,
16366
+ summary: short(input.continuation.compactCheckpoint.summary, 44)
16367
+ }
16368
+ } : {}
16307
16369
  } : void 0;
16308
16370
  const base = {
16309
16371
  version: "1.2",
@@ -17119,6 +17181,311 @@ var init_project_context = __esm({
17119
17181
  }
17120
17182
  });
17121
17183
 
17184
+ // src/store/compaction-checkpoint-store.ts
17185
+ var compaction_checkpoint_store_exports = {};
17186
+ __export(compaction_checkpoint_store_exports, {
17187
+ CompactionCheckpointStore: () => CompactionCheckpointStore
17188
+ });
17189
+ import { createHash as createHash13, randomUUID as randomUUID8 } from "crypto";
17190
+ function optionalText5(value) {
17191
+ return typeof value === "string" && value ? value : void 0;
17192
+ }
17193
+ function optionalNumber2(value) {
17194
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
17195
+ }
17196
+ function parseDetails(value) {
17197
+ if (typeof value !== "string" || !value) return void 0;
17198
+ try {
17199
+ const parsed = JSON.parse(value);
17200
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
17201
+ } catch {
17202
+ return void 0;
17203
+ }
17204
+ }
17205
+ function sanitizeSummary(value) {
17206
+ if (!value?.trim()) return void 0;
17207
+ return sanitizeCredentials(value).slice(0, MAX_SUMMARY_CHARS).trim() || void 0;
17208
+ }
17209
+ function sanitizeDetails(value) {
17210
+ if (!value) return void 0;
17211
+ try {
17212
+ const sanitized = sanitizeCredentials(JSON.stringify(value));
17213
+ if (sanitized.length > MAX_DETAILS_CHARS) return { truncated: true };
17214
+ const parsed = JSON.parse(sanitized);
17215
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
17216
+ } catch {
17217
+ return { unavailable: true };
17218
+ }
17219
+ }
17220
+ function sourceKeyFor(input, summary) {
17221
+ if (input.sourceKey?.trim()) return input.sourceKey.trim().slice(0, 300);
17222
+ const material = [
17223
+ input.projectId,
17224
+ input.sessionId,
17225
+ input.agent,
17226
+ input.sourceEvent,
17227
+ summary ?? "",
17228
+ input.tokensBefore ?? "",
17229
+ input.firstKeptEntryId ?? ""
17230
+ ].join("\0");
17231
+ return `derived:${createHash13("sha256").update(material).digest("hex").slice(0, 32)}`;
17232
+ }
17233
+ function rowToCheckpoint(row) {
17234
+ return {
17235
+ id: row.id,
17236
+ projectId: row.project_id,
17237
+ sessionId: row.session_id,
17238
+ agent: row.agent,
17239
+ phase: row.phase,
17240
+ captureKind: row.capture_kind,
17241
+ reason: row.reason,
17242
+ sourceEvent: row.source_event,
17243
+ sourceKey: row.source_key,
17244
+ ...optionalText5(row.summary) ? { summary: row.summary } : {},
17245
+ ...optionalNumber2(row.tokens_before) !== void 0 ? { tokensBefore: Number(row.tokens_before) } : {},
17246
+ ...optionalText5(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
17247
+ ...parseDetails(row.details_json) ? { details: parseDetails(row.details_json) } : {},
17248
+ transcriptAvailable: Boolean(row.transcript_available),
17249
+ status: row.status,
17250
+ preCapturedAt: row.pre_captured_at,
17251
+ ...optionalText5(row.completed_at) ? { completedAt: row.completed_at } : {},
17252
+ ...optionalText5(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
17253
+ deliveryCount: Number(row.delivery_count ?? 0),
17254
+ createdAt: row.created_at,
17255
+ updatedAt: row.updated_at
17256
+ };
17257
+ }
17258
+ function safeReason(value) {
17259
+ return value === "manual" || value === "auto" ? value : "unknown";
17260
+ }
17261
+ function safeLimit(value, fallback) {
17262
+ if (!Number.isFinite(value) || value == null) return fallback;
17263
+ return Math.max(1, Math.min(500, Math.floor(value)));
17264
+ }
17265
+ var MAX_SUMMARY_CHARS, MAX_DETAILS_CHARS, CompactionCheckpointStore;
17266
+ var init_compaction_checkpoint_store = __esm({
17267
+ "src/store/compaction-checkpoint-store.ts"() {
17268
+ "use strict";
17269
+ init_esm_shims();
17270
+ init_secret_filter();
17271
+ init_sqlite_db();
17272
+ MAX_SUMMARY_CHARS = 24e3;
17273
+ MAX_DETAILS_CHARS = 4e3;
17274
+ CompactionCheckpointStore = class {
17275
+ db;
17276
+ constructor(dataDir) {
17277
+ this.db = getDatabase(dataDir);
17278
+ }
17279
+ recordPreflight(input) {
17280
+ const pending = this.db.prepare(`
17281
+ SELECT * FROM compaction_checkpoints
17282
+ WHERE project_id = ? AND session_id = ? AND agent = ?
17283
+ AND phase = 'pre' AND status = 'active'
17284
+ ORDER BY pre_captured_at DESC, created_at DESC
17285
+ LIMIT 1
17286
+ `).get(input.projectId, input.sessionId, input.agent);
17287
+ if (pending) return rowToCheckpoint(pending);
17288
+ const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
17289
+ const checkpoint = {
17290
+ id: randomUUID8(),
17291
+ projectId: input.projectId,
17292
+ sessionId: input.sessionId,
17293
+ agent: input.agent,
17294
+ phase: "pre",
17295
+ captureKind: "preflight",
17296
+ reason: safeReason(input.reason),
17297
+ sourceEvent: input.sourceEvent,
17298
+ sourceKey: `pre:${randomUUID8()}`,
17299
+ transcriptAvailable: Boolean(input.transcriptAvailable),
17300
+ status: "active",
17301
+ preCapturedAt: now3,
17302
+ deliveryCount: 0,
17303
+ createdAt: now3,
17304
+ updatedAt: now3
17305
+ };
17306
+ this.insert(checkpoint);
17307
+ return checkpoint;
17308
+ }
17309
+ complete(input) {
17310
+ const completedAt = input.completedAt ?? (/* @__PURE__ */ new Date()).toISOString();
17311
+ const summary = sanitizeSummary(input.summary);
17312
+ const pending = this.db.prepare(`
17313
+ SELECT * FROM compaction_checkpoints
17314
+ WHERE project_id = ? AND session_id = ? AND agent = ?
17315
+ AND phase = 'pre' AND status = 'active'
17316
+ ORDER BY pre_captured_at DESC, created_at DESC
17317
+ LIMIT 1
17318
+ `).get(input.projectId, input.sessionId, input.agent);
17319
+ if (!input.sourceKey?.trim() && !summary && input.tokensBefore === void 0 && !input.firstKeptEntryId && !pending) {
17320
+ const priorLifecycle = this.db.prepare(`
17321
+ SELECT * FROM compaction_checkpoints
17322
+ WHERE project_id = ? AND session_id = ? AND agent = ?
17323
+ AND phase = 'complete' AND capture_kind = 'lifecycle'
17324
+ AND source_event = ? AND status = 'active'
17325
+ ORDER BY completed_at DESC, created_at DESC
17326
+ LIMIT 1
17327
+ `).get(input.projectId, input.sessionId, input.agent, input.sourceEvent);
17328
+ if (priorLifecycle) return rowToCheckpoint(priorLifecycle);
17329
+ }
17330
+ const sourceKey = input.sourceKey?.trim() ? input.sourceKey.trim().slice(0, 300) : pending ? `lifecycle:${pending.id}` : sourceKeyFor(input, summary);
17331
+ const existing = this.db.prepare(`
17332
+ SELECT * FROM compaction_checkpoints
17333
+ WHERE project_id = ? AND source_key = ?
17334
+ LIMIT 1
17335
+ `).get(input.projectId, sourceKey);
17336
+ if (existing) return rowToCheckpoint(existing);
17337
+ const captureKind = summary ? "native-summary" : "lifecycle";
17338
+ const details = sanitizeDetails(input.details);
17339
+ if (pending) {
17340
+ const checkpoint2 = rowToCheckpoint(pending);
17341
+ const nextReason = safeReason(input.reason) === "unknown" ? checkpoint2.reason : safeReason(input.reason);
17342
+ this.db.prepare(`
17343
+ UPDATE compaction_checkpoints
17344
+ SET phase = 'complete', capture_kind = ?, reason = ?, source_event = ?, source_key = ?,
17345
+ summary = ?, tokens_before = ?, first_kept_entry_id = ?, details_json = ?,
17346
+ completed_at = ?, updated_at = ?
17347
+ WHERE id = ?
17348
+ `).run(
17349
+ captureKind,
17350
+ nextReason,
17351
+ input.sourceEvent,
17352
+ sourceKey,
17353
+ summary ?? null,
17354
+ input.tokensBefore ?? null,
17355
+ input.firstKeptEntryId ?? null,
17356
+ JSON.stringify(details ?? {}),
17357
+ completedAt,
17358
+ completedAt,
17359
+ checkpoint2.id
17360
+ );
17361
+ return this.get(checkpoint2.id);
17362
+ }
17363
+ const checkpoint = {
17364
+ id: randomUUID8(),
17365
+ projectId: input.projectId,
17366
+ sessionId: input.sessionId,
17367
+ agent: input.agent,
17368
+ phase: "complete",
17369
+ captureKind,
17370
+ reason: safeReason(input.reason),
17371
+ sourceEvent: input.sourceEvent,
17372
+ sourceKey,
17373
+ ...summary ? { summary } : {},
17374
+ ...input.tokensBefore !== void 0 ? { tokensBefore: input.tokensBefore } : {},
17375
+ ...input.firstKeptEntryId ? { firstKeptEntryId: input.firstKeptEntryId } : {},
17376
+ ...details ? { details } : {},
17377
+ transcriptAvailable: false,
17378
+ status: "active",
17379
+ preCapturedAt: completedAt,
17380
+ completedAt,
17381
+ deliveryCount: 0,
17382
+ createdAt: completedAt,
17383
+ updatedAt: completedAt
17384
+ };
17385
+ this.insert(checkpoint);
17386
+ return checkpoint;
17387
+ }
17388
+ get(id) {
17389
+ const row = this.db.prepare("SELECT * FROM compaction_checkpoints WHERE id = ?").get(id);
17390
+ return row ? rowToCheckpoint(row) : void 0;
17391
+ }
17392
+ list(options) {
17393
+ const conditions = ["project_id = ?"];
17394
+ const values = [options.projectId];
17395
+ if (options.sessionId) {
17396
+ conditions.push("session_id = ?");
17397
+ values.push(options.sessionId);
17398
+ }
17399
+ if (options.agent) {
17400
+ conditions.push("agent = ?");
17401
+ values.push(options.agent);
17402
+ }
17403
+ if (!options.includeArchived) {
17404
+ conditions.push("status = 'active'");
17405
+ }
17406
+ const rows = this.db.prepare(`
17407
+ SELECT * FROM compaction_checkpoints
17408
+ WHERE ${conditions.join(" AND ")}
17409
+ ORDER BY COALESCE(completed_at, pre_captured_at) DESC, created_at DESC
17410
+ LIMIT ?
17411
+ `).all(...values, safeLimit(options.limit, 20));
17412
+ return rows.map(rowToCheckpoint);
17413
+ }
17414
+ findUndelivered(projectId, sessionId, agent) {
17415
+ const row = this.db.prepare(`
17416
+ SELECT * FROM compaction_checkpoints
17417
+ WHERE project_id = ? AND session_id = ? AND agent = ?
17418
+ AND phase = 'complete' AND status = 'active' AND delivered_at IS NULL
17419
+ ORDER BY completed_at DESC, created_at DESC
17420
+ LIMIT 1
17421
+ `).get(projectId, sessionId, agent);
17422
+ return row ? rowToCheckpoint(row) : void 0;
17423
+ }
17424
+ findLatestCompleted(projectId, options = {}) {
17425
+ const excludeSession = options.excludeSession;
17426
+ const exclusion = excludeSession ? " AND NOT (session_id = ? AND agent = ? )" : "";
17427
+ const values = excludeSession ? [projectId, excludeSession.sessionId, excludeSession.agent] : [projectId];
17428
+ const row = this.db.prepare(`
17429
+ SELECT * FROM compaction_checkpoints
17430
+ WHERE project_id = ? AND phase = 'complete' AND status = 'active'
17431
+ ${exclusion}
17432
+ ORDER BY completed_at DESC, created_at DESC
17433
+ LIMIT 1
17434
+ `).get(...values);
17435
+ return row ? rowToCheckpoint(row) : void 0;
17436
+ }
17437
+ archive(id, archivedAt = (/* @__PURE__ */ new Date()).toISOString()) {
17438
+ const result = this.db.prepare(`
17439
+ UPDATE compaction_checkpoints
17440
+ SET status = 'archived', updated_at = ?
17441
+ WHERE id = ? AND status = 'active'
17442
+ `).run(archivedAt, id);
17443
+ return Number(result.changes ?? 0) > 0 ? this.get(id) : void 0;
17444
+ }
17445
+ markDelivered(id, deliveredAt = (/* @__PURE__ */ new Date()).toISOString()) {
17446
+ const result = this.db.prepare(`
17447
+ UPDATE compaction_checkpoints
17448
+ SET delivered_at = ?, delivery_count = delivery_count + 1, updated_at = ?
17449
+ WHERE id = ? AND phase = 'complete' AND status = 'active' AND delivered_at IS NULL
17450
+ `).run(deliveredAt, deliveredAt, id);
17451
+ return Number(result.changes ?? 0) > 0 ? this.get(id) : void 0;
17452
+ }
17453
+ insert(checkpoint) {
17454
+ this.db.prepare(`
17455
+ INSERT INTO compaction_checkpoints (
17456
+ id, project_id, session_id, agent, phase, capture_kind, reason,
17457
+ source_event, source_key, summary, tokens_before, first_kept_entry_id,
17458
+ details_json, transcript_available, status, pre_captured_at, completed_at,
17459
+ delivered_at, delivery_count, created_at, updated_at
17460
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
17461
+ `).run(
17462
+ checkpoint.id,
17463
+ checkpoint.projectId,
17464
+ checkpoint.sessionId,
17465
+ checkpoint.agent,
17466
+ checkpoint.phase,
17467
+ checkpoint.captureKind,
17468
+ checkpoint.reason,
17469
+ checkpoint.sourceEvent,
17470
+ checkpoint.sourceKey,
17471
+ checkpoint.summary ?? null,
17472
+ checkpoint.tokensBefore ?? null,
17473
+ checkpoint.firstKeptEntryId ?? null,
17474
+ JSON.stringify(checkpoint.details ?? {}),
17475
+ checkpoint.transcriptAvailable ? 1 : 0,
17476
+ checkpoint.status,
17477
+ checkpoint.preCapturedAt,
17478
+ checkpoint.completedAt ?? null,
17479
+ checkpoint.deliveredAt ?? null,
17480
+ checkpoint.deliveryCount,
17481
+ checkpoint.createdAt,
17482
+ checkpoint.updatedAt
17483
+ );
17484
+ }
17485
+ };
17486
+ }
17487
+ });
17488
+
17122
17489
  // src/codegraph/auto-context.ts
17123
17490
  var auto_context_exports = {};
17124
17491
  __export(auto_context_exports, {
@@ -17304,6 +17671,22 @@ async function buildAutoProjectContext(input) {
17304
17671
  if (continuationRequested) {
17305
17672
  await initSessionStore(input.dataDir);
17306
17673
  continuation = await getSessionResumeBrief(input.project.id, task, input.reader);
17674
+ const { CompactionCheckpointStore: CompactionCheckpointStore2 } = await Promise.resolve().then(() => (init_compaction_checkpoint_store(), compaction_checkpoint_store_exports));
17675
+ const checkpoint = new CompactionCheckpointStore2(input.dataDir).findLatestCompleted(
17676
+ input.project.id,
17677
+ input.excludeCompactionCheckpointFor ? { excludeSession: input.excludeCompactionCheckpointFor } : void 0
17678
+ );
17679
+ const completedAtMs = checkpoint ? Date.parse(checkpoint.completedAt ?? checkpoint.preCapturedAt) : Number.NaN;
17680
+ if (checkpoint && Number.isFinite(completedAtMs) && completedAtMs <= now3.getTime() && now3.getTime() - completedAtMs <= COMPACT_CHECKPOINT_MAX_AGE_MS) {
17681
+ continuation.compactCheckpoint = {
17682
+ id: checkpoint.id,
17683
+ agent: checkpoint.agent,
17684
+ captureKind: checkpoint.captureKind === "native-summary" ? "native-summary" : "lifecycle",
17685
+ reason: checkpoint.reason,
17686
+ ...checkpoint.completedAt ? { completedAt: checkpoint.completedAt } : {},
17687
+ 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."
17688
+ };
17689
+ }
17307
17690
  }
17308
17691
  const workset = await buildTaskWorkset({
17309
17692
  projectId: input.project.id,
@@ -17512,7 +17895,7 @@ function formatAutoProjectContextSummary(context) {
17512
17895
  reliableSources.length > 0 ? `- ${reliableSources.length} current code-bound memory link(s)` : "- none yet"
17513
17896
  );
17514
17897
  const continuation = context.workset.continuation;
17515
- if (continuation?.previousSession || continuation?.memories.length) {
17898
+ if (continuation?.previousSession || continuation?.memories.length || continuation?.compactCheckpoint) {
17516
17899
  lines.push("", "Resume from prior work");
17517
17900
  if (continuation.previousSession) {
17518
17901
  const session = continuation.previousSession;
@@ -17527,6 +17910,12 @@ function formatAutoProjectContextSummary(context) {
17527
17910
  "- #" + memory.id + " " + memory.type + ": " + compactContinuationText(memory.title, 18) + detail
17528
17911
  );
17529
17912
  }
17913
+ if (continuation.compactCheckpoint) {
17914
+ const checkpoint = continuation.compactCheckpoint;
17915
+ lines.push(
17916
+ "- Recent host compact checkpoint (" + [checkpoint.agent, checkpoint.captureKind, checkpoint.reason].join(", ") + "): " + compactContinuationText(checkpoint.summary, 36)
17917
+ );
17918
+ }
17530
17919
  }
17531
17920
  return lines.join("\n");
17532
17921
  }
@@ -17593,7 +17982,7 @@ function formatLegacyAutoProjectContextPrompt(context) {
17593
17982
  );
17594
17983
  return lines.join("\n");
17595
17984
  }
17596
- var DEFAULT_MAX_AGE_MS;
17985
+ var DEFAULT_MAX_AGE_MS, COMPACT_CHECKPOINT_MAX_AGE_MS;
17597
17986
  var init_auto_context = __esm({
17598
17987
  "src/codegraph/auto-context.ts"() {
17599
17988
  "use strict";
@@ -17613,6 +18002,7 @@ var init_auto_context = __esm({
17613
18002
  init_session_store();
17614
18003
  init_task_lens();
17615
18004
  DEFAULT_MAX_AGE_MS = 10 * 60 * 1e3;
18005
+ COMPACT_CHECKPOINT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
17616
18006
  }
17617
18007
  });
17618
18008
 
@@ -17660,7 +18050,7 @@ function addDefaultVerificationHints(input) {
17660
18050
  return uniq2(hints);
17661
18051
  }
17662
18052
  function selectRelevantObservations(observations2, task, limit) {
17663
- const safeLimit = Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : 20;
18053
+ const safeLimit2 = Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : 20;
17664
18054
  const taskTokens2 = tokenize3(task);
17665
18055
  const ranked = observations2.map((observation, index) => ({
17666
18056
  observation,
@@ -17670,7 +18060,7 @@ function selectRelevantObservations(observations2, task, limit) {
17670
18060
  }));
17671
18061
  const positives = ranked.filter((item) => item.score > 0);
17672
18062
  const pool = positives.length > 0 ? positives : ranked;
17673
- return pool.sort((a, b) => b.score - a.score || b.time - a.time || b.index - a.index).slice(0, safeLimit).map((item) => item.observation);
18063
+ return pool.sort((a, b) => b.score - a.score || b.time - a.time || b.index - a.index).slice(0, safeLimit2).map((item) => item.observation);
17674
18064
  }
17675
18065
  function assembleContextPackForTask(input) {
17676
18066
  const selected = selectRelevantObservations(input.observations, input.task, input.limit ?? 20);
@@ -18230,7 +18620,7 @@ __export(team_store_exports, {
18230
18620
  isTeamStoreInitialized: () => isTeamStoreInitialized,
18231
18621
  resetTeamStore: () => resetTeamStore
18232
18622
  });
18233
- import { randomUUID as randomUUID8 } from "crypto";
18623
+ import { randomUUID as randomUUID9 } from "crypto";
18234
18624
  import path20 from "path";
18235
18625
  import fs15 from "fs";
18236
18626
  function getTeamStore() {
@@ -18519,7 +18909,7 @@ var init_team_store = __esm({
18519
18909
  * reactivate it (preserving agent_id). Otherwise create a new one.
18520
18910
  */
18521
18911
  registerAgent(input) {
18522
- const instanceId = input.instanceId || randomUUID8();
18912
+ const instanceId = input.instanceId || randomUUID9();
18523
18913
  const now3 = Date.now();
18524
18914
  const existing = this.stmtAgentFindByInstance.get(
18525
18915
  input.projectId,
@@ -18545,7 +18935,7 @@ var init_team_store = __esm({
18545
18935
  this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
18546
18936
  return row2;
18547
18937
  }
18548
- const agentId = randomUUID8();
18938
+ const agentId = randomUUID9();
18549
18939
  this.stmtAgentUpsert.run({
18550
18940
  agent_id: agentId,
18551
18941
  project_id: input.projectId,
@@ -18647,7 +19037,7 @@ var init_team_store = __esm({
18647
19037
  return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
18648
19038
  }
18649
19039
  }
18650
- const id = randomUUID8();
19040
+ const id = randomUUID9();
18651
19041
  const now3 = Date.now();
18652
19042
  const row = {
18653
19043
  id,
@@ -18697,7 +19087,7 @@ var init_team_store = __esm({
18697
19087
  // Task Operations (with atomic claim semantics)
18698
19088
  // ═══════════════════════════════════════════════════════════════════
18699
19089
  createTask(input) {
18700
- const taskId = randomUUID8();
19090
+ const taskId = randomUUID9();
18701
19091
  const now3 = Date.now();
18702
19092
  const row = {
18703
19093
  task_id: taskId,
@@ -18969,7 +19359,7 @@ var init_team_store = __esm({
18969
19359
  for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
18970
19360
  for (const msg of msgs) {
18971
19361
  this.stmtMsgInsert.run({
18972
- id: msg.id ?? randomUUID8(),
19362
+ id: msg.id ?? randomUUID9(),
18973
19363
  project_id: "migrated",
18974
19364
  sender_agent_id: msg.from ?? "unknown",
18975
19365
  recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
@@ -19209,6 +19599,140 @@ var init_poll = __esm({
19209
19599
  }
19210
19600
  });
19211
19601
 
19602
+ // src/memory/compaction.ts
19603
+ var compaction_exports = {};
19604
+ __export(compaction_exports, {
19605
+ buildCompactionWorkset: () => buildCompactionWorkset,
19606
+ captureCompactionCheckpoint: () => captureCompactionCheckpoint,
19607
+ consumeCompactionWorkset: () => consumeCompactionWorkset
19608
+ });
19609
+ function normalizeBudget(value) {
19610
+ if (!Number.isFinite(value) || value == null) return DEFAULT_WORKSET_BUDGET;
19611
+ return Math.max(MIN_WORKSET_BUDGET, Math.min(2e3, Math.floor(value)));
19612
+ }
19613
+ function sourceLabel(checkpoint) {
19614
+ if (checkpoint.captureKind === "native-summary") return "native host summary";
19615
+ if (checkpoint.captureKind === "preflight") return "pre-compact lifecycle marker";
19616
+ return "host lifecycle marker";
19617
+ }
19618
+ function buildCompactionWorkset(checkpoint, options = {}) {
19619
+ const budget = normalizeBudget(options.maxTokens);
19620
+ const task = options.task?.trim() ? truncateToTokenBudget(sanitizeCredentials(options.task.trim()), Math.max(8, Math.floor(budget * 0.25))) : "";
19621
+ const headerLines = [
19622
+ "## Compact Continuation",
19623
+ `- Host: ${checkpoint.agent} (${sourceLabel(checkpoint)})`,
19624
+ `- Trigger: ${checkpoint.reason}`,
19625
+ task ? `- Task now: ${task}` : "",
19626
+ "- Current code remains authoritative."
19627
+ ].filter(Boolean);
19628
+ const header = `${headerLines.join("\n")}
19629
+
19630
+ `;
19631
+ 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.";
19632
+ const source = sanitizeCredentials(checkpoint.summary?.trim() || fallback);
19633
+ const available = Math.max(0, budget - countTextTokens(header) - 4);
19634
+ let excerpt = source ? truncateToTokenBudget(source, available) : "";
19635
+ let text = `${header}${excerpt ? `### Host checkpoint
19636
+ ${excerpt}` : ""}`.trim();
19637
+ while (excerpt && countTextTokens(text) > budget) {
19638
+ const nextExcerptBudget = Math.max(1, Math.floor(countTextTokens(excerpt) * 0.8));
19639
+ excerpt = truncateToTokenBudget(excerpt, nextExcerptBudget);
19640
+ text = `${header}${excerpt ? `### Host checkpoint
19641
+ ${excerpt}` : ""}`.trim();
19642
+ }
19643
+ if (countTextTokens(text) > budget) text = truncateToTokenBudget(text, budget);
19644
+ return {
19645
+ checkpointId: checkpoint.id,
19646
+ text,
19647
+ tokens: countTextTokens(text)
19648
+ };
19649
+ }
19650
+ function sourceEvent(input) {
19651
+ const raw = input.raw;
19652
+ const event = raw.hook_event_name ?? raw.event ?? raw.type;
19653
+ return typeof event === "string" && event ? event : input.event;
19654
+ }
19655
+ async function captureCompactionCheckpoint(input) {
19656
+ const isCompactResume = input.event === "session_start" && input.sessionStartReason?.trim().toLowerCase() === "compact";
19657
+ if (input.event !== "pre_compact" && input.event !== "post_compact" && !isCompactResume) return null;
19658
+ if (!input.sessionId || !input.cwd) return null;
19659
+ const [
19660
+ { detectProject: detectProject2 },
19661
+ { getProjectDataDir: getProjectDataDir2 },
19662
+ { initAliasRegistry: initAliasRegistry2, registerAlias: registerAlias2 }
19663
+ ] = await Promise.all([
19664
+ Promise.resolve().then(() => (init_detector(), detector_exports)),
19665
+ Promise.resolve().then(() => (init_persistence(), persistence_exports)),
19666
+ Promise.resolve().then(() => (init_aliases(), aliases_exports))
19667
+ ]);
19668
+ const project = detectProject2(input.cwd);
19669
+ if (!project) return null;
19670
+ const dataDir = await getProjectDataDir2(project.id);
19671
+ initAliasRegistry2(dataDir);
19672
+ const projectId = await registerAlias2(project);
19673
+ const store = new CompactionCheckpointStore(dataDir);
19674
+ if (input.event === "pre_compact") {
19675
+ return store.recordPreflight({
19676
+ projectId,
19677
+ sessionId: input.sessionId,
19678
+ agent: input.agent,
19679
+ reason: input.compaction?.reason,
19680
+ sourceEvent: sourceEvent(input),
19681
+ transcriptAvailable: Boolean(input.transcriptPath),
19682
+ capturedAt: input.timestamp
19683
+ });
19684
+ }
19685
+ return store.complete({
19686
+ projectId,
19687
+ sessionId: input.sessionId,
19688
+ agent: input.agent,
19689
+ reason: input.compaction?.reason,
19690
+ sourceEvent: sourceEvent(input),
19691
+ sourceKey: input.compaction?.sourceKey,
19692
+ summary: input.compaction?.summary,
19693
+ tokensBefore: input.compaction?.tokensBefore,
19694
+ firstKeptEntryId: input.compaction?.firstKeptEntryId,
19695
+ details: input.compaction?.details,
19696
+ completedAt: input.timestamp
19697
+ });
19698
+ }
19699
+ async function consumeCompactionWorkset(input, options = {}) {
19700
+ if (!input.sessionId || !input.cwd) return null;
19701
+ const [
19702
+ { detectProject: detectProject2 },
19703
+ { getProjectDataDir: getProjectDataDir2 },
19704
+ { initAliasRegistry: initAliasRegistry2, registerAlias: registerAlias2 }
19705
+ ] = await Promise.all([
19706
+ Promise.resolve().then(() => (init_detector(), detector_exports)),
19707
+ Promise.resolve().then(() => (init_persistence(), persistence_exports)),
19708
+ Promise.resolve().then(() => (init_aliases(), aliases_exports))
19709
+ ]);
19710
+ const project = detectProject2(input.cwd);
19711
+ if (!project) return null;
19712
+ const dataDir = await getProjectDataDir2(project.id);
19713
+ initAliasRegistry2(dataDir);
19714
+ const projectId = await registerAlias2(project);
19715
+ const store = new CompactionCheckpointStore(dataDir);
19716
+ const checkpoint = store.findUndelivered(projectId, input.sessionId, input.agent);
19717
+ if (!checkpoint) return null;
19718
+ const workset = buildCompactionWorkset(checkpoint, options);
19719
+ if (!workset.text) return null;
19720
+ store.markDelivered(checkpoint.id);
19721
+ return workset;
19722
+ }
19723
+ var DEFAULT_WORKSET_BUDGET, MIN_WORKSET_BUDGET;
19724
+ var init_compaction = __esm({
19725
+ "src/memory/compaction.ts"() {
19726
+ "use strict";
19727
+ init_esm_shims();
19728
+ init_token_budget();
19729
+ init_secret_filter();
19730
+ init_compaction_checkpoint_store();
19731
+ DEFAULT_WORKSET_BUDGET = 420;
19732
+ MIN_WORKSET_BUDGET = 48;
19733
+ }
19734
+ });
19735
+
19212
19736
  // src/memory/export-import.ts
19213
19737
  var export_import_exports = {};
19214
19738
  __export(export_import_exports, {
@@ -21287,7 +21811,7 @@ __export(planner_exports, {
21287
21811
  materializeTaskGraph: () => materializeTaskGraph,
21288
21812
  seedAutonomousPipeline: () => seedAutonomousPipeline
21289
21813
  });
21290
- import { randomUUID as randomUUID9 } from "crypto";
21814
+ import { randomUUID as randomUUID10 } from "crypto";
21291
21815
  function isPlannerTask(metadata) {
21292
21816
  if (!metadata) return null;
21293
21817
  try {
@@ -21345,7 +21869,7 @@ function seedAutonomousPipeline(teamStore, projectId, config, opts) {
21345
21869
  const maxIterations = config.maxIterations ?? 3;
21346
21870
  const taskBudget = config.taskBudget ?? 15;
21347
21871
  const structuredPlan = opts?.structuredPlan ?? true;
21348
- const pipelineId = randomUUID9();
21872
+ const pipelineId = randomUUID10();
21349
21873
  const meta = {
21350
21874
  plannerType: "plan",
21351
21875
  pipelineId,
@@ -23416,7 +23940,7 @@ init_freshness();
23416
23940
  init_obs_store();
23417
23941
  init_mini_skill_store();
23418
23942
  init_session_store();
23419
- import { createHash as createHash13 } from "crypto";
23943
+ import { createHash as createHash14 } from "crypto";
23420
23944
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
23421
23945
  import { z as z2 } from "zod";
23422
23946
 
@@ -26886,6 +27410,7 @@ var TOOL_PROFILES = Object.freeze({
26886
27410
  memorix_rules_sync: ["full"],
26887
27411
  memorix_workspace_sync: ["full"],
26888
27412
  memorix_ingest_image: ["full"],
27413
+ memorix_compaction_checkpoint: ["full"],
26889
27414
  // ── MCP Official Memory Server compatibility (KG tools) ──────────
26890
27415
  // These are only useful to users specifically migrating from the
26891
27416
  // reference mcp-memory server. Hide them unless explicitly enabled.
@@ -27052,7 +27577,7 @@ function coerceObjectArray(val) {
27052
27577
  return [];
27053
27578
  }
27054
27579
  function createDeterministicInstanceId(projectId, agentType, agentName) {
27055
- const digest2 = createHash13("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
27580
+ const digest2 = createHash14("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
27056
27581
  return `auto-${digest2}`;
27057
27582
  }
27058
27583
  var BOOTSTRAP_SAFE_TOOL_NAMES = /* @__PURE__ */ new Set([
@@ -27333,7 +27858,7 @@ The path should point to a directory containing a .git folder.`
27333
27858
  };
27334
27859
  const server = existingServer ?? new McpServer({
27335
27860
  name: "memorix",
27336
- version: true ? "1.2.6" : "1.0.1"
27861
+ version: true ? "1.2.7" : "1.0.1"
27337
27862
  });
27338
27863
  const originalRegisterTool = server.registerTool.bind(server);
27339
27864
  server.registerTool = ((name, ...args) => {
@@ -27981,12 +28506,12 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
27981
28506
  if (boundary) return boundary;
27982
28507
  }
27983
28508
  return withFreshIndex(async () => {
27984
- const safeLimit = limit != null ? coerceNumber(limit, 20) : void 0;
28509
+ const safeLimit2 = limit != null ? coerceNumber(limit, 20) : void 0;
27985
28510
  const safeMaxTokens = maxTokens != null ? coerceNumber(maxTokens, 0) : void 0;
27986
28511
  const TIMEOUT_MS = 3e4;
27987
28512
  const searchPromise = compactSearch({
27988
28513
  query,
27989
- limit: safeLimit,
28514
+ limit: safeLimit2,
27990
28515
  type,
27991
28516
  maxTokens: safeMaxTokens,
27992
28517
  since,
@@ -28787,10 +29312,10 @@ Entity: ${entityName} | ${facts.length} facts | ${obs.tokens} tokens${reasoningA
28787
29312
  const unresolved = requireResolvedProject("search reasoning in the current project");
28788
29313
  if (unresolved) return unresolved;
28789
29314
  }
28790
- const safeLimit = limit != null ? coerceNumber(limit, 10) : 10;
29315
+ const safeLimit2 = limit != null ? coerceNumber(limit, 10) : 10;
28791
29316
  const result = await withFreshIndex(() => compactSearch({
28792
29317
  query,
28793
- limit: safeLimit,
29318
+ limit: safeLimit2,
28794
29319
  type: "reasoning",
28795
29320
  projectId: scope === "global" ? void 0 : project.id,
28796
29321
  status: "active",
@@ -30113,9 +30638,9 @@ ${summary ? "Summary saved for next session context injection." : "No summary pr
30113
30638
  }
30114
30639
  },
30115
30640
  async ({ limit }) => {
30116
- const safeLimit = limit != null ? coerceNumber(limit, 3) : 3;
30641
+ const safeLimit2 = limit != null ? coerceNumber(limit, 3) : 3;
30117
30642
  const { getSessionContext: getSessionContext2, listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session(), session_exports));
30118
- const context = await getSessionContext2(projectDir2, project.id, safeLimit, getObservationReader());
30643
+ const context = await getSessionContext2(projectDir2, project.id, safeLimit2, getObservationReader());
30119
30644
  const sessions = await listSessions2(projectDir2, project.id);
30120
30645
  const activeSessions = sessions.filter((s) => s.status === "active");
30121
30646
  const completedSessions = sessions.filter((s) => s.status === "completed");
@@ -30136,6 +30661,86 @@ ${summary ? "Summary saved for next session context injection." : "No summary pr
30136
30661
  };
30137
30662
  }
30138
30663
  );
30664
+ server.registerTool(
30665
+ "memorix_compaction_checkpoint",
30666
+ {
30667
+ title: "Compact Continuity Checkpoints",
30668
+ 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.",
30669
+ inputSchema: {
30670
+ action: z2.enum(["list", "show", "context", "archive"]).default("list"),
30671
+ id: z2.string().optional().describe("Checkpoint ID for show, context, or archive"),
30672
+ sessionId: z2.string().optional().describe("Optional host session ID filter"),
30673
+ agent: z2.string().optional().describe("Optional host agent filter"),
30674
+ task: z2.string().optional().describe("Current task for a bounded context preview"),
30675
+ maxTokens: z2.number().optional().describe("Maximum tokens for action=context (default: 420)"),
30676
+ limit: z2.number().optional().describe("Maximum records for action=list (default: 20)"),
30677
+ includeArchived: z2.boolean().optional().default(false).describe("Include archived records in action=list")
30678
+ }
30679
+ },
30680
+ async ({ action, id, sessionId, agent, task, maxTokens, limit, includeArchived }) => {
30681
+ const unresolved = requireResolvedProject("inspect compact continuity checkpoints");
30682
+ if (unresolved) return unresolved;
30683
+ const [{ CompactionCheckpointStore: CompactionCheckpointStore2 }, { buildCompactionWorkset: buildCompactionWorkset2 }] = await Promise.all([
30684
+ Promise.resolve().then(() => (init_compaction_checkpoint_store(), compaction_checkpoint_store_exports)),
30685
+ Promise.resolve().then(() => (init_compaction(), compaction_exports))
30686
+ ]);
30687
+ const store = new CompactionCheckpointStore2(projectDir2);
30688
+ const assertCheckpoint = (checkpointId) => {
30689
+ const checkpoint2 = store.get(checkpointId);
30690
+ if (!checkpoint2 || checkpoint2.projectId !== project.id) return null;
30691
+ return checkpoint2;
30692
+ };
30693
+ if (action === "list") {
30694
+ const checkpoints = store.list({
30695
+ projectId: project.id,
30696
+ sessionId: sessionId?.trim() || void 0,
30697
+ agent: agent?.trim() || void 0,
30698
+ includeArchived: Boolean(includeArchived),
30699
+ limit: limit != null ? Math.max(1, Math.min(100, coerceNumber(limit, 20))) : 20
30700
+ });
30701
+ return {
30702
+ content: [{ type: "text", text: JSON.stringify({ projectId: project.id, checkpoints }, null, 2) }]
30703
+ };
30704
+ }
30705
+ if (!id?.trim()) {
30706
+ return {
30707
+ content: [{ type: "text", text: "id is required for this checkpoint action." }],
30708
+ isError: true
30709
+ };
30710
+ }
30711
+ const checkpoint = assertCheckpoint(id.trim());
30712
+ if (!checkpoint) {
30713
+ return {
30714
+ content: [{ type: "text", text: `Checkpoint "${id.trim()}" was not found for the current project.` }],
30715
+ isError: true
30716
+ };
30717
+ }
30718
+ if (action === "show") {
30719
+ return {
30720
+ content: [{ type: "text", text: JSON.stringify({ projectId: project.id, checkpoint }, null, 2) }]
30721
+ };
30722
+ }
30723
+ if (action === "context") {
30724
+ const workset = buildCompactionWorkset2(checkpoint, {
30725
+ task: task?.trim(),
30726
+ maxTokens: maxTokens != null ? coerceNumber(maxTokens, 420) : 420
30727
+ });
30728
+ return {
30729
+ content: [{ type: "text", text: workset.text }]
30730
+ };
30731
+ }
30732
+ const archived = store.archive(checkpoint.id);
30733
+ if (!archived) {
30734
+ return {
30735
+ content: [{ type: "text", text: `Checkpoint "${checkpoint.id}" is already archived.` }],
30736
+ isError: true
30737
+ };
30738
+ }
30739
+ return {
30740
+ content: [{ type: "text", text: `Archived compact checkpoint ${archived.id}.` }]
30741
+ };
30742
+ }
30743
+ );
30139
30744
  server.registerTool(
30140
30745
  "memorix_transfer",
30141
30746
  {