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.
- package/CHANGELOG.md +12 -0
- package/README.md +6 -3
- package/README.zh-CN.md +5 -2
- package/dist/cli/index.js +954 -72
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/memcode.js +0 -0
- package/dist/index.js +632 -27
- package/dist/index.js.map +1 -1
- package/dist/maintenance-runner.js +39 -1
- package/dist/maintenance-runner.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +12 -0
- package/dist/sdk.d.ts +1 -1
- package/dist/sdk.js +632 -27
- 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 +23 -0
- package/docs/hooks-architecture.md +2 -1
- package/package.json +1 -1
- 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/checkpoint.ts +144 -0
- package/src/cli/index.ts +3 -1
- package/src/codegraph/auto-context.ts +51 -5
- 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/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/sdk.js
CHANGED
|
@@ -285,6 +285,7 @@ function getDatabase(dataDir) {
|
|
|
285
285
|
db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
|
|
286
286
|
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
287
287
|
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
288
|
+
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
288
289
|
try {
|
|
289
290
|
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
290
291
|
} catch {
|
|
@@ -325,7 +326,7 @@ function getDatabase(dataDir) {
|
|
|
325
326
|
_dbCache.set(normalized, db2);
|
|
326
327
|
return db2;
|
|
327
328
|
}
|
|
328
|
-
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;
|
|
329
|
+
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;
|
|
329
330
|
var init_sqlite_db = __esm({
|
|
330
331
|
"src/store/sqlite-db.ts"() {
|
|
331
332
|
"use strict";
|
|
@@ -777,6 +778,31 @@ CREATE TABLE IF NOT EXISTS maintenance_targets (
|
|
|
777
778
|
data_dir TEXT NOT NULL,
|
|
778
779
|
updated_at INTEGER NOT NULL
|
|
779
780
|
);
|
|
781
|
+
`;
|
|
782
|
+
CREATE_COMPACTION_CHECKPOINTS_TABLE = `
|
|
783
|
+
CREATE TABLE IF NOT EXISTS compaction_checkpoints (
|
|
784
|
+
id TEXT PRIMARY KEY,
|
|
785
|
+
project_id TEXT NOT NULL,
|
|
786
|
+
session_id TEXT NOT NULL,
|
|
787
|
+
agent TEXT NOT NULL,
|
|
788
|
+
phase TEXT NOT NULL,
|
|
789
|
+
capture_kind TEXT NOT NULL,
|
|
790
|
+
reason TEXT NOT NULL DEFAULT 'unknown',
|
|
791
|
+
source_event TEXT NOT NULL,
|
|
792
|
+
source_key TEXT NOT NULL,
|
|
793
|
+
summary TEXT,
|
|
794
|
+
tokens_before INTEGER,
|
|
795
|
+
first_kept_entry_id TEXT,
|
|
796
|
+
details_json TEXT NOT NULL DEFAULT '{}',
|
|
797
|
+
transcript_available INTEGER NOT NULL DEFAULT 0,
|
|
798
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
799
|
+
pre_captured_at TEXT NOT NULL,
|
|
800
|
+
completed_at TEXT,
|
|
801
|
+
delivered_at TEXT,
|
|
802
|
+
delivery_count INTEGER NOT NULL DEFAULT 0,
|
|
803
|
+
created_at TEXT NOT NULL,
|
|
804
|
+
updated_at TEXT NOT NULL
|
|
805
|
+
);
|
|
780
806
|
`;
|
|
781
807
|
CREATE_INDEXES = `
|
|
782
808
|
CREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);
|
|
@@ -824,6 +850,9 @@ CREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowl
|
|
|
824
850
|
CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_ready ON maintenance_jobs(status, run_after);
|
|
825
851
|
CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_project ON maintenance_jobs(project_id, status, run_after);
|
|
826
852
|
CREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_targets(updated_at);
|
|
853
|
+
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_project_recent ON compaction_checkpoints(project_id, status, completed_at DESC, pre_captured_at DESC);
|
|
854
|
+
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC);
|
|
855
|
+
CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key);
|
|
827
856
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
828
857
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
829
858
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -897,6 +926,15 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
897
926
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_knowledge_workflows_workspace_status ON knowledge_workflows(workspaceId, status, updatedAt DESC)");
|
|
898
927
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowledge_workflow_runs(projectId, workflowId, startedAt DESC)");
|
|
899
928
|
}
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
id: "1.2.7-compaction-checkpoints",
|
|
932
|
+
apply: (db2) => {
|
|
933
|
+
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
934
|
+
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)");
|
|
935
|
+
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)");
|
|
936
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key)");
|
|
937
|
+
}
|
|
900
938
|
}
|
|
901
939
|
];
|
|
902
940
|
_dbCache = /* @__PURE__ */ new Map();
|
|
@@ -8127,10 +8165,10 @@ var init_store = __esm({
|
|
|
8127
8165
|
return row ? rowToSnapshot(row) : void 0;
|
|
8128
8166
|
}
|
|
8129
8167
|
listSnapshots(projectId, limit = 20) {
|
|
8130
|
-
const
|
|
8168
|
+
const safeLimit2 = Number.isFinite(limit) ? Math.max(1, Math.min(200, Math.floor(limit))) : 20;
|
|
8131
8169
|
return this.db.prepare(
|
|
8132
8170
|
"SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT ?"
|
|
8133
|
-
).all(projectId,
|
|
8171
|
+
).all(projectId, safeLimit2).map(rowToSnapshot);
|
|
8134
8172
|
}
|
|
8135
8173
|
/**
|
|
8136
8174
|
* Record a completed scan and mark all current structural facts with its
|
|
@@ -15987,7 +16025,7 @@ function renderTaskWorksetPrompt(input) {
|
|
|
15987
16025
|
});
|
|
15988
16026
|
appendLine(lines, "Task lens: " + input.lens, maxTokens, omitted, "lens");
|
|
15989
16027
|
const hasContinuation = Boolean(
|
|
15990
|
-
input.continuation?.previousSession || (input.continuation?.memories.length ?? 0) > 0
|
|
16028
|
+
input.continuation?.previousSession || (input.continuation?.memories.length ?? 0) > 0 || input.continuation?.compactCheckpoint
|
|
15991
16029
|
);
|
|
15992
16030
|
if (hasContinuation && input.continuation) {
|
|
15993
16031
|
appendLine(lines, "", maxTokens, omitted, "continuation-heading");
|
|
@@ -16027,6 +16065,24 @@ function renderTaskWorksetPrompt(input) {
|
|
|
16027
16065
|
}
|
|
16028
16066
|
);
|
|
16029
16067
|
}
|
|
16068
|
+
if (input.continuation.compactCheckpoint) {
|
|
16069
|
+
const checkpoint = input.continuation.compactCheckpoint;
|
|
16070
|
+
const source = `${checkpoint.agent}, ${checkpoint.captureKind}, ${checkpoint.reason}`;
|
|
16071
|
+
appendLine(
|
|
16072
|
+
lines,
|
|
16073
|
+
"- Recent host compact checkpoint (" + source + "): " + short(checkpoint.summary, 36),
|
|
16074
|
+
maxTokens,
|
|
16075
|
+
omitted,
|
|
16076
|
+
"continuation-compact-checkpoint",
|
|
16077
|
+
selected,
|
|
16078
|
+
{
|
|
16079
|
+
kind: "continuation",
|
|
16080
|
+
id: "compact:" + checkpoint.id,
|
|
16081
|
+
reason: "recent host-native compact lifecycle evidence",
|
|
16082
|
+
trust: "historical"
|
|
16083
|
+
}
|
|
16084
|
+
);
|
|
16085
|
+
}
|
|
16030
16086
|
}
|
|
16031
16087
|
if (input.cautions.length > 0 || input.cautionMemory.length > 0) {
|
|
16032
16088
|
appendLine(lines, "", maxTokens, omitted, "caution-heading");
|
|
@@ -16296,7 +16352,7 @@ async function buildTaskWorkset(input) {
|
|
|
16296
16352
|
...input.verificationHints
|
|
16297
16353
|
]).slice(0, 4);
|
|
16298
16354
|
const normalizedCautions = unique(cautions.map((caution) => caution.kind)).map((kind) => cautions.find((caution) => caution.kind === kind)).slice(0, 6);
|
|
16299
|
-
const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0) ? {
|
|
16355
|
+
const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0 || input.continuation.compactCheckpoint) ? {
|
|
16300
16356
|
...input.continuation.previousSession ? {
|
|
16301
16357
|
previousSession: {
|
|
16302
16358
|
...input.continuation.previousSession,
|
|
@@ -16307,7 +16363,13 @@ async function buildTaskWorkset(input) {
|
|
|
16307
16363
|
...memory,
|
|
16308
16364
|
title: short(memory.title, 20),
|
|
16309
16365
|
...memory.detail ? { detail: short(memory.detail, CONTINUATION_DETAIL_TOKEN_BUDGET) } : {}
|
|
16310
|
-
}))
|
|
16366
|
+
})),
|
|
16367
|
+
...input.continuation.compactCheckpoint ? {
|
|
16368
|
+
compactCheckpoint: {
|
|
16369
|
+
...input.continuation.compactCheckpoint,
|
|
16370
|
+
summary: short(input.continuation.compactCheckpoint.summary, 44)
|
|
16371
|
+
}
|
|
16372
|
+
} : {}
|
|
16311
16373
|
} : void 0;
|
|
16312
16374
|
const base = {
|
|
16313
16375
|
version: "1.2",
|
|
@@ -17123,6 +17185,311 @@ var init_project_context = __esm({
|
|
|
17123
17185
|
}
|
|
17124
17186
|
});
|
|
17125
17187
|
|
|
17188
|
+
// src/store/compaction-checkpoint-store.ts
|
|
17189
|
+
var compaction_checkpoint_store_exports = {};
|
|
17190
|
+
__export(compaction_checkpoint_store_exports, {
|
|
17191
|
+
CompactionCheckpointStore: () => CompactionCheckpointStore
|
|
17192
|
+
});
|
|
17193
|
+
import { createHash as createHash13, randomUUID as randomUUID8 } from "crypto";
|
|
17194
|
+
function optionalText5(value) {
|
|
17195
|
+
return typeof value === "string" && value ? value : void 0;
|
|
17196
|
+
}
|
|
17197
|
+
function optionalNumber2(value) {
|
|
17198
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
17199
|
+
}
|
|
17200
|
+
function parseDetails(value) {
|
|
17201
|
+
if (typeof value !== "string" || !value) return void 0;
|
|
17202
|
+
try {
|
|
17203
|
+
const parsed = JSON.parse(value);
|
|
17204
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
17205
|
+
} catch {
|
|
17206
|
+
return void 0;
|
|
17207
|
+
}
|
|
17208
|
+
}
|
|
17209
|
+
function sanitizeSummary(value) {
|
|
17210
|
+
if (!value?.trim()) return void 0;
|
|
17211
|
+
return sanitizeCredentials(value).slice(0, MAX_SUMMARY_CHARS).trim() || void 0;
|
|
17212
|
+
}
|
|
17213
|
+
function sanitizeDetails(value) {
|
|
17214
|
+
if (!value) return void 0;
|
|
17215
|
+
try {
|
|
17216
|
+
const sanitized = sanitizeCredentials(JSON.stringify(value));
|
|
17217
|
+
if (sanitized.length > MAX_DETAILS_CHARS) return { truncated: true };
|
|
17218
|
+
const parsed = JSON.parse(sanitized);
|
|
17219
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
17220
|
+
} catch {
|
|
17221
|
+
return { unavailable: true };
|
|
17222
|
+
}
|
|
17223
|
+
}
|
|
17224
|
+
function sourceKeyFor(input, summary) {
|
|
17225
|
+
if (input.sourceKey?.trim()) return input.sourceKey.trim().slice(0, 300);
|
|
17226
|
+
const material = [
|
|
17227
|
+
input.projectId,
|
|
17228
|
+
input.sessionId,
|
|
17229
|
+
input.agent,
|
|
17230
|
+
input.sourceEvent,
|
|
17231
|
+
summary ?? "",
|
|
17232
|
+
input.tokensBefore ?? "",
|
|
17233
|
+
input.firstKeptEntryId ?? ""
|
|
17234
|
+
].join("\0");
|
|
17235
|
+
return `derived:${createHash13("sha256").update(material).digest("hex").slice(0, 32)}`;
|
|
17236
|
+
}
|
|
17237
|
+
function rowToCheckpoint(row) {
|
|
17238
|
+
return {
|
|
17239
|
+
id: row.id,
|
|
17240
|
+
projectId: row.project_id,
|
|
17241
|
+
sessionId: row.session_id,
|
|
17242
|
+
agent: row.agent,
|
|
17243
|
+
phase: row.phase,
|
|
17244
|
+
captureKind: row.capture_kind,
|
|
17245
|
+
reason: row.reason,
|
|
17246
|
+
sourceEvent: row.source_event,
|
|
17247
|
+
sourceKey: row.source_key,
|
|
17248
|
+
...optionalText5(row.summary) ? { summary: row.summary } : {},
|
|
17249
|
+
...optionalNumber2(row.tokens_before) !== void 0 ? { tokensBefore: Number(row.tokens_before) } : {},
|
|
17250
|
+
...optionalText5(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
|
|
17251
|
+
...parseDetails(row.details_json) ? { details: parseDetails(row.details_json) } : {},
|
|
17252
|
+
transcriptAvailable: Boolean(row.transcript_available),
|
|
17253
|
+
status: row.status,
|
|
17254
|
+
preCapturedAt: row.pre_captured_at,
|
|
17255
|
+
...optionalText5(row.completed_at) ? { completedAt: row.completed_at } : {},
|
|
17256
|
+
...optionalText5(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
|
|
17257
|
+
deliveryCount: Number(row.delivery_count ?? 0),
|
|
17258
|
+
createdAt: row.created_at,
|
|
17259
|
+
updatedAt: row.updated_at
|
|
17260
|
+
};
|
|
17261
|
+
}
|
|
17262
|
+
function safeReason(value) {
|
|
17263
|
+
return value === "manual" || value === "auto" ? value : "unknown";
|
|
17264
|
+
}
|
|
17265
|
+
function safeLimit(value, fallback) {
|
|
17266
|
+
if (!Number.isFinite(value) || value == null) return fallback;
|
|
17267
|
+
return Math.max(1, Math.min(500, Math.floor(value)));
|
|
17268
|
+
}
|
|
17269
|
+
var MAX_SUMMARY_CHARS, MAX_DETAILS_CHARS, CompactionCheckpointStore;
|
|
17270
|
+
var init_compaction_checkpoint_store = __esm({
|
|
17271
|
+
"src/store/compaction-checkpoint-store.ts"() {
|
|
17272
|
+
"use strict";
|
|
17273
|
+
init_esm_shims();
|
|
17274
|
+
init_secret_filter();
|
|
17275
|
+
init_sqlite_db();
|
|
17276
|
+
MAX_SUMMARY_CHARS = 24e3;
|
|
17277
|
+
MAX_DETAILS_CHARS = 4e3;
|
|
17278
|
+
CompactionCheckpointStore = class {
|
|
17279
|
+
db;
|
|
17280
|
+
constructor(dataDir) {
|
|
17281
|
+
this.db = getDatabase(dataDir);
|
|
17282
|
+
}
|
|
17283
|
+
recordPreflight(input) {
|
|
17284
|
+
const pending = this.db.prepare(`
|
|
17285
|
+
SELECT * FROM compaction_checkpoints
|
|
17286
|
+
WHERE project_id = ? AND session_id = ? AND agent = ?
|
|
17287
|
+
AND phase = 'pre' AND status = 'active'
|
|
17288
|
+
ORDER BY pre_captured_at DESC, created_at DESC
|
|
17289
|
+
LIMIT 1
|
|
17290
|
+
`).get(input.projectId, input.sessionId, input.agent);
|
|
17291
|
+
if (pending) return rowToCheckpoint(pending);
|
|
17292
|
+
const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
17293
|
+
const checkpoint = {
|
|
17294
|
+
id: randomUUID8(),
|
|
17295
|
+
projectId: input.projectId,
|
|
17296
|
+
sessionId: input.sessionId,
|
|
17297
|
+
agent: input.agent,
|
|
17298
|
+
phase: "pre",
|
|
17299
|
+
captureKind: "preflight",
|
|
17300
|
+
reason: safeReason(input.reason),
|
|
17301
|
+
sourceEvent: input.sourceEvent,
|
|
17302
|
+
sourceKey: `pre:${randomUUID8()}`,
|
|
17303
|
+
transcriptAvailable: Boolean(input.transcriptAvailable),
|
|
17304
|
+
status: "active",
|
|
17305
|
+
preCapturedAt: now3,
|
|
17306
|
+
deliveryCount: 0,
|
|
17307
|
+
createdAt: now3,
|
|
17308
|
+
updatedAt: now3
|
|
17309
|
+
};
|
|
17310
|
+
this.insert(checkpoint);
|
|
17311
|
+
return checkpoint;
|
|
17312
|
+
}
|
|
17313
|
+
complete(input) {
|
|
17314
|
+
const completedAt = input.completedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
17315
|
+
const summary = sanitizeSummary(input.summary);
|
|
17316
|
+
const pending = this.db.prepare(`
|
|
17317
|
+
SELECT * FROM compaction_checkpoints
|
|
17318
|
+
WHERE project_id = ? AND session_id = ? AND agent = ?
|
|
17319
|
+
AND phase = 'pre' AND status = 'active'
|
|
17320
|
+
ORDER BY pre_captured_at DESC, created_at DESC
|
|
17321
|
+
LIMIT 1
|
|
17322
|
+
`).get(input.projectId, input.sessionId, input.agent);
|
|
17323
|
+
if (!input.sourceKey?.trim() && !summary && input.tokensBefore === void 0 && !input.firstKeptEntryId && !pending) {
|
|
17324
|
+
const priorLifecycle = this.db.prepare(`
|
|
17325
|
+
SELECT * FROM compaction_checkpoints
|
|
17326
|
+
WHERE project_id = ? AND session_id = ? AND agent = ?
|
|
17327
|
+
AND phase = 'complete' AND capture_kind = 'lifecycle'
|
|
17328
|
+
AND source_event = ? AND status = 'active'
|
|
17329
|
+
ORDER BY completed_at DESC, created_at DESC
|
|
17330
|
+
LIMIT 1
|
|
17331
|
+
`).get(input.projectId, input.sessionId, input.agent, input.sourceEvent);
|
|
17332
|
+
if (priorLifecycle) return rowToCheckpoint(priorLifecycle);
|
|
17333
|
+
}
|
|
17334
|
+
const sourceKey = input.sourceKey?.trim() ? input.sourceKey.trim().slice(0, 300) : pending ? `lifecycle:${pending.id}` : sourceKeyFor(input, summary);
|
|
17335
|
+
const existing = this.db.prepare(`
|
|
17336
|
+
SELECT * FROM compaction_checkpoints
|
|
17337
|
+
WHERE project_id = ? AND source_key = ?
|
|
17338
|
+
LIMIT 1
|
|
17339
|
+
`).get(input.projectId, sourceKey);
|
|
17340
|
+
if (existing) return rowToCheckpoint(existing);
|
|
17341
|
+
const captureKind = summary ? "native-summary" : "lifecycle";
|
|
17342
|
+
const details = sanitizeDetails(input.details);
|
|
17343
|
+
if (pending) {
|
|
17344
|
+
const checkpoint2 = rowToCheckpoint(pending);
|
|
17345
|
+
const nextReason = safeReason(input.reason) === "unknown" ? checkpoint2.reason : safeReason(input.reason);
|
|
17346
|
+
this.db.prepare(`
|
|
17347
|
+
UPDATE compaction_checkpoints
|
|
17348
|
+
SET phase = 'complete', capture_kind = ?, reason = ?, source_event = ?, source_key = ?,
|
|
17349
|
+
summary = ?, tokens_before = ?, first_kept_entry_id = ?, details_json = ?,
|
|
17350
|
+
completed_at = ?, updated_at = ?
|
|
17351
|
+
WHERE id = ?
|
|
17352
|
+
`).run(
|
|
17353
|
+
captureKind,
|
|
17354
|
+
nextReason,
|
|
17355
|
+
input.sourceEvent,
|
|
17356
|
+
sourceKey,
|
|
17357
|
+
summary ?? null,
|
|
17358
|
+
input.tokensBefore ?? null,
|
|
17359
|
+
input.firstKeptEntryId ?? null,
|
|
17360
|
+
JSON.stringify(details ?? {}),
|
|
17361
|
+
completedAt,
|
|
17362
|
+
completedAt,
|
|
17363
|
+
checkpoint2.id
|
|
17364
|
+
);
|
|
17365
|
+
return this.get(checkpoint2.id);
|
|
17366
|
+
}
|
|
17367
|
+
const checkpoint = {
|
|
17368
|
+
id: randomUUID8(),
|
|
17369
|
+
projectId: input.projectId,
|
|
17370
|
+
sessionId: input.sessionId,
|
|
17371
|
+
agent: input.agent,
|
|
17372
|
+
phase: "complete",
|
|
17373
|
+
captureKind,
|
|
17374
|
+
reason: safeReason(input.reason),
|
|
17375
|
+
sourceEvent: input.sourceEvent,
|
|
17376
|
+
sourceKey,
|
|
17377
|
+
...summary ? { summary } : {},
|
|
17378
|
+
...input.tokensBefore !== void 0 ? { tokensBefore: input.tokensBefore } : {},
|
|
17379
|
+
...input.firstKeptEntryId ? { firstKeptEntryId: input.firstKeptEntryId } : {},
|
|
17380
|
+
...details ? { details } : {},
|
|
17381
|
+
transcriptAvailable: false,
|
|
17382
|
+
status: "active",
|
|
17383
|
+
preCapturedAt: completedAt,
|
|
17384
|
+
completedAt,
|
|
17385
|
+
deliveryCount: 0,
|
|
17386
|
+
createdAt: completedAt,
|
|
17387
|
+
updatedAt: completedAt
|
|
17388
|
+
};
|
|
17389
|
+
this.insert(checkpoint);
|
|
17390
|
+
return checkpoint;
|
|
17391
|
+
}
|
|
17392
|
+
get(id) {
|
|
17393
|
+
const row = this.db.prepare("SELECT * FROM compaction_checkpoints WHERE id = ?").get(id);
|
|
17394
|
+
return row ? rowToCheckpoint(row) : void 0;
|
|
17395
|
+
}
|
|
17396
|
+
list(options) {
|
|
17397
|
+
const conditions = ["project_id = ?"];
|
|
17398
|
+
const values = [options.projectId];
|
|
17399
|
+
if (options.sessionId) {
|
|
17400
|
+
conditions.push("session_id = ?");
|
|
17401
|
+
values.push(options.sessionId);
|
|
17402
|
+
}
|
|
17403
|
+
if (options.agent) {
|
|
17404
|
+
conditions.push("agent = ?");
|
|
17405
|
+
values.push(options.agent);
|
|
17406
|
+
}
|
|
17407
|
+
if (!options.includeArchived) {
|
|
17408
|
+
conditions.push("status = 'active'");
|
|
17409
|
+
}
|
|
17410
|
+
const rows = this.db.prepare(`
|
|
17411
|
+
SELECT * FROM compaction_checkpoints
|
|
17412
|
+
WHERE ${conditions.join(" AND ")}
|
|
17413
|
+
ORDER BY COALESCE(completed_at, pre_captured_at) DESC, created_at DESC
|
|
17414
|
+
LIMIT ?
|
|
17415
|
+
`).all(...values, safeLimit(options.limit, 20));
|
|
17416
|
+
return rows.map(rowToCheckpoint);
|
|
17417
|
+
}
|
|
17418
|
+
findUndelivered(projectId, sessionId, agent) {
|
|
17419
|
+
const row = this.db.prepare(`
|
|
17420
|
+
SELECT * FROM compaction_checkpoints
|
|
17421
|
+
WHERE project_id = ? AND session_id = ? AND agent = ?
|
|
17422
|
+
AND phase = 'complete' AND status = 'active' AND delivered_at IS NULL
|
|
17423
|
+
ORDER BY completed_at DESC, created_at DESC
|
|
17424
|
+
LIMIT 1
|
|
17425
|
+
`).get(projectId, sessionId, agent);
|
|
17426
|
+
return row ? rowToCheckpoint(row) : void 0;
|
|
17427
|
+
}
|
|
17428
|
+
findLatestCompleted(projectId, options = {}) {
|
|
17429
|
+
const excludeSession = options.excludeSession;
|
|
17430
|
+
const exclusion = excludeSession ? " AND NOT (session_id = ? AND agent = ? )" : "";
|
|
17431
|
+
const values = excludeSession ? [projectId, excludeSession.sessionId, excludeSession.agent] : [projectId];
|
|
17432
|
+
const row = this.db.prepare(`
|
|
17433
|
+
SELECT * FROM compaction_checkpoints
|
|
17434
|
+
WHERE project_id = ? AND phase = 'complete' AND status = 'active'
|
|
17435
|
+
${exclusion}
|
|
17436
|
+
ORDER BY completed_at DESC, created_at DESC
|
|
17437
|
+
LIMIT 1
|
|
17438
|
+
`).get(...values);
|
|
17439
|
+
return row ? rowToCheckpoint(row) : void 0;
|
|
17440
|
+
}
|
|
17441
|
+
archive(id, archivedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
17442
|
+
const result = this.db.prepare(`
|
|
17443
|
+
UPDATE compaction_checkpoints
|
|
17444
|
+
SET status = 'archived', updated_at = ?
|
|
17445
|
+
WHERE id = ? AND status = 'active'
|
|
17446
|
+
`).run(archivedAt, id);
|
|
17447
|
+
return Number(result.changes ?? 0) > 0 ? this.get(id) : void 0;
|
|
17448
|
+
}
|
|
17449
|
+
markDelivered(id, deliveredAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
17450
|
+
const result = this.db.prepare(`
|
|
17451
|
+
UPDATE compaction_checkpoints
|
|
17452
|
+
SET delivered_at = ?, delivery_count = delivery_count + 1, updated_at = ?
|
|
17453
|
+
WHERE id = ? AND phase = 'complete' AND status = 'active' AND delivered_at IS NULL
|
|
17454
|
+
`).run(deliveredAt, deliveredAt, id);
|
|
17455
|
+
return Number(result.changes ?? 0) > 0 ? this.get(id) : void 0;
|
|
17456
|
+
}
|
|
17457
|
+
insert(checkpoint) {
|
|
17458
|
+
this.db.prepare(`
|
|
17459
|
+
INSERT INTO compaction_checkpoints (
|
|
17460
|
+
id, project_id, session_id, agent, phase, capture_kind, reason,
|
|
17461
|
+
source_event, source_key, summary, tokens_before, first_kept_entry_id,
|
|
17462
|
+
details_json, transcript_available, status, pre_captured_at, completed_at,
|
|
17463
|
+
delivered_at, delivery_count, created_at, updated_at
|
|
17464
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
17465
|
+
`).run(
|
|
17466
|
+
checkpoint.id,
|
|
17467
|
+
checkpoint.projectId,
|
|
17468
|
+
checkpoint.sessionId,
|
|
17469
|
+
checkpoint.agent,
|
|
17470
|
+
checkpoint.phase,
|
|
17471
|
+
checkpoint.captureKind,
|
|
17472
|
+
checkpoint.reason,
|
|
17473
|
+
checkpoint.sourceEvent,
|
|
17474
|
+
checkpoint.sourceKey,
|
|
17475
|
+
checkpoint.summary ?? null,
|
|
17476
|
+
checkpoint.tokensBefore ?? null,
|
|
17477
|
+
checkpoint.firstKeptEntryId ?? null,
|
|
17478
|
+
JSON.stringify(checkpoint.details ?? {}),
|
|
17479
|
+
checkpoint.transcriptAvailable ? 1 : 0,
|
|
17480
|
+
checkpoint.status,
|
|
17481
|
+
checkpoint.preCapturedAt,
|
|
17482
|
+
checkpoint.completedAt ?? null,
|
|
17483
|
+
checkpoint.deliveredAt ?? null,
|
|
17484
|
+
checkpoint.deliveryCount,
|
|
17485
|
+
checkpoint.createdAt,
|
|
17486
|
+
checkpoint.updatedAt
|
|
17487
|
+
);
|
|
17488
|
+
}
|
|
17489
|
+
};
|
|
17490
|
+
}
|
|
17491
|
+
});
|
|
17492
|
+
|
|
17126
17493
|
// src/codegraph/auto-context.ts
|
|
17127
17494
|
var auto_context_exports = {};
|
|
17128
17495
|
__export(auto_context_exports, {
|
|
@@ -17308,6 +17675,22 @@ async function buildAutoProjectContext(input) {
|
|
|
17308
17675
|
if (continuationRequested) {
|
|
17309
17676
|
await initSessionStore(input.dataDir);
|
|
17310
17677
|
continuation = await getSessionResumeBrief(input.project.id, task, input.reader);
|
|
17678
|
+
const { CompactionCheckpointStore: CompactionCheckpointStore2 } = await Promise.resolve().then(() => (init_compaction_checkpoint_store(), compaction_checkpoint_store_exports));
|
|
17679
|
+
const checkpoint = new CompactionCheckpointStore2(input.dataDir).findLatestCompleted(
|
|
17680
|
+
input.project.id,
|
|
17681
|
+
input.excludeCompactionCheckpointFor ? { excludeSession: input.excludeCompactionCheckpointFor } : void 0
|
|
17682
|
+
);
|
|
17683
|
+
const completedAtMs = checkpoint ? Date.parse(checkpoint.completedAt ?? checkpoint.preCapturedAt) : Number.NaN;
|
|
17684
|
+
if (checkpoint && Number.isFinite(completedAtMs) && completedAtMs <= now3.getTime() && now3.getTime() - completedAtMs <= COMPACT_CHECKPOINT_MAX_AGE_MS) {
|
|
17685
|
+
continuation.compactCheckpoint = {
|
|
17686
|
+
id: checkpoint.id,
|
|
17687
|
+
agent: checkpoint.agent,
|
|
17688
|
+
captureKind: checkpoint.captureKind === "native-summary" ? "native-summary" : "lifecycle",
|
|
17689
|
+
reason: checkpoint.reason,
|
|
17690
|
+
...checkpoint.completedAt ? { completedAt: checkpoint.completedAt } : {},
|
|
17691
|
+
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."
|
|
17692
|
+
};
|
|
17693
|
+
}
|
|
17311
17694
|
}
|
|
17312
17695
|
const workset = await buildTaskWorkset({
|
|
17313
17696
|
projectId: input.project.id,
|
|
@@ -17516,7 +17899,7 @@ function formatAutoProjectContextSummary(context) {
|
|
|
17516
17899
|
reliableSources.length > 0 ? `- ${reliableSources.length} current code-bound memory link(s)` : "- none yet"
|
|
17517
17900
|
);
|
|
17518
17901
|
const continuation = context.workset.continuation;
|
|
17519
|
-
if (continuation?.previousSession || continuation?.memories.length) {
|
|
17902
|
+
if (continuation?.previousSession || continuation?.memories.length || continuation?.compactCheckpoint) {
|
|
17520
17903
|
lines.push("", "Resume from prior work");
|
|
17521
17904
|
if (continuation.previousSession) {
|
|
17522
17905
|
const session = continuation.previousSession;
|
|
@@ -17531,6 +17914,12 @@ function formatAutoProjectContextSummary(context) {
|
|
|
17531
17914
|
"- #" + memory.id + " " + memory.type + ": " + compactContinuationText(memory.title, 18) + detail
|
|
17532
17915
|
);
|
|
17533
17916
|
}
|
|
17917
|
+
if (continuation.compactCheckpoint) {
|
|
17918
|
+
const checkpoint = continuation.compactCheckpoint;
|
|
17919
|
+
lines.push(
|
|
17920
|
+
"- Recent host compact checkpoint (" + [checkpoint.agent, checkpoint.captureKind, checkpoint.reason].join(", ") + "): " + compactContinuationText(checkpoint.summary, 36)
|
|
17921
|
+
);
|
|
17922
|
+
}
|
|
17534
17923
|
}
|
|
17535
17924
|
return lines.join("\n");
|
|
17536
17925
|
}
|
|
@@ -17597,7 +17986,7 @@ function formatLegacyAutoProjectContextPrompt(context) {
|
|
|
17597
17986
|
);
|
|
17598
17987
|
return lines.join("\n");
|
|
17599
17988
|
}
|
|
17600
|
-
var DEFAULT_MAX_AGE_MS;
|
|
17989
|
+
var DEFAULT_MAX_AGE_MS, COMPACT_CHECKPOINT_MAX_AGE_MS;
|
|
17601
17990
|
var init_auto_context = __esm({
|
|
17602
17991
|
"src/codegraph/auto-context.ts"() {
|
|
17603
17992
|
"use strict";
|
|
@@ -17617,6 +18006,7 @@ var init_auto_context = __esm({
|
|
|
17617
18006
|
init_session_store();
|
|
17618
18007
|
init_task_lens();
|
|
17619
18008
|
DEFAULT_MAX_AGE_MS = 10 * 60 * 1e3;
|
|
18009
|
+
COMPACT_CHECKPOINT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
17620
18010
|
}
|
|
17621
18011
|
});
|
|
17622
18012
|
|
|
@@ -17664,7 +18054,7 @@ function addDefaultVerificationHints(input) {
|
|
|
17664
18054
|
return uniq2(hints);
|
|
17665
18055
|
}
|
|
17666
18056
|
function selectRelevantObservations(observations2, task, limit) {
|
|
17667
|
-
const
|
|
18057
|
+
const safeLimit2 = Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : 20;
|
|
17668
18058
|
const taskTokens2 = tokenize3(task);
|
|
17669
18059
|
const ranked = observations2.map((observation, index) => ({
|
|
17670
18060
|
observation,
|
|
@@ -17674,7 +18064,7 @@ function selectRelevantObservations(observations2, task, limit) {
|
|
|
17674
18064
|
}));
|
|
17675
18065
|
const positives = ranked.filter((item) => item.score > 0);
|
|
17676
18066
|
const pool = positives.length > 0 ? positives : ranked;
|
|
17677
|
-
return pool.sort((a, b) => b.score - a.score || b.time - a.time || b.index - a.index).slice(0,
|
|
18067
|
+
return pool.sort((a, b) => b.score - a.score || b.time - a.time || b.index - a.index).slice(0, safeLimit2).map((item) => item.observation);
|
|
17678
18068
|
}
|
|
17679
18069
|
function assembleContextPackForTask(input) {
|
|
17680
18070
|
const selected = selectRelevantObservations(input.observations, input.task, input.limit ?? 20);
|
|
@@ -18234,7 +18624,7 @@ __export(team_store_exports, {
|
|
|
18234
18624
|
isTeamStoreInitialized: () => isTeamStoreInitialized,
|
|
18235
18625
|
resetTeamStore: () => resetTeamStore
|
|
18236
18626
|
});
|
|
18237
|
-
import { randomUUID as
|
|
18627
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
18238
18628
|
import path20 from "path";
|
|
18239
18629
|
import fs15 from "fs";
|
|
18240
18630
|
function getTeamStore() {
|
|
@@ -18523,7 +18913,7 @@ var init_team_store = __esm({
|
|
|
18523
18913
|
* reactivate it (preserving agent_id). Otherwise create a new one.
|
|
18524
18914
|
*/
|
|
18525
18915
|
registerAgent(input) {
|
|
18526
|
-
const instanceId = input.instanceId ||
|
|
18916
|
+
const instanceId = input.instanceId || randomUUID9();
|
|
18527
18917
|
const now3 = Date.now();
|
|
18528
18918
|
const existing = this.stmtAgentFindByInstance.get(
|
|
18529
18919
|
input.projectId,
|
|
@@ -18549,7 +18939,7 @@ var init_team_store = __esm({
|
|
|
18549
18939
|
this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
|
|
18550
18940
|
return row2;
|
|
18551
18941
|
}
|
|
18552
|
-
const agentId =
|
|
18942
|
+
const agentId = randomUUID9();
|
|
18553
18943
|
this.stmtAgentUpsert.run({
|
|
18554
18944
|
agent_id: agentId,
|
|
18555
18945
|
project_id: input.projectId,
|
|
@@ -18651,7 +19041,7 @@ var init_team_store = __esm({
|
|
|
18651
19041
|
return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
|
|
18652
19042
|
}
|
|
18653
19043
|
}
|
|
18654
|
-
const id =
|
|
19044
|
+
const id = randomUUID9();
|
|
18655
19045
|
const now3 = Date.now();
|
|
18656
19046
|
const row = {
|
|
18657
19047
|
id,
|
|
@@ -18701,7 +19091,7 @@ var init_team_store = __esm({
|
|
|
18701
19091
|
// Task Operations (with atomic claim semantics)
|
|
18702
19092
|
// ═══════════════════════════════════════════════════════════════════
|
|
18703
19093
|
createTask(input) {
|
|
18704
|
-
const taskId =
|
|
19094
|
+
const taskId = randomUUID9();
|
|
18705
19095
|
const now3 = Date.now();
|
|
18706
19096
|
const row = {
|
|
18707
19097
|
task_id: taskId,
|
|
@@ -18973,7 +19363,7 @@ var init_team_store = __esm({
|
|
|
18973
19363
|
for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
|
|
18974
19364
|
for (const msg of msgs) {
|
|
18975
19365
|
this.stmtMsgInsert.run({
|
|
18976
|
-
id: msg.id ??
|
|
19366
|
+
id: msg.id ?? randomUUID9(),
|
|
18977
19367
|
project_id: "migrated",
|
|
18978
19368
|
sender_agent_id: msg.from ?? "unknown",
|
|
18979
19369
|
recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
|
|
@@ -19213,6 +19603,140 @@ var init_poll = __esm({
|
|
|
19213
19603
|
}
|
|
19214
19604
|
});
|
|
19215
19605
|
|
|
19606
|
+
// src/memory/compaction.ts
|
|
19607
|
+
var compaction_exports = {};
|
|
19608
|
+
__export(compaction_exports, {
|
|
19609
|
+
buildCompactionWorkset: () => buildCompactionWorkset,
|
|
19610
|
+
captureCompactionCheckpoint: () => captureCompactionCheckpoint,
|
|
19611
|
+
consumeCompactionWorkset: () => consumeCompactionWorkset
|
|
19612
|
+
});
|
|
19613
|
+
function normalizeBudget(value) {
|
|
19614
|
+
if (!Number.isFinite(value) || value == null) return DEFAULT_WORKSET_BUDGET;
|
|
19615
|
+
return Math.max(MIN_WORKSET_BUDGET, Math.min(2e3, Math.floor(value)));
|
|
19616
|
+
}
|
|
19617
|
+
function sourceLabel(checkpoint) {
|
|
19618
|
+
if (checkpoint.captureKind === "native-summary") return "native host summary";
|
|
19619
|
+
if (checkpoint.captureKind === "preflight") return "pre-compact lifecycle marker";
|
|
19620
|
+
return "host lifecycle marker";
|
|
19621
|
+
}
|
|
19622
|
+
function buildCompactionWorkset(checkpoint, options = {}) {
|
|
19623
|
+
const budget = normalizeBudget(options.maxTokens);
|
|
19624
|
+
const task = options.task?.trim() ? truncateToTokenBudget(sanitizeCredentials(options.task.trim()), Math.max(8, Math.floor(budget * 0.25))) : "";
|
|
19625
|
+
const headerLines = [
|
|
19626
|
+
"## Compact Continuation",
|
|
19627
|
+
`- Host: ${checkpoint.agent} (${sourceLabel(checkpoint)})`,
|
|
19628
|
+
`- Trigger: ${checkpoint.reason}`,
|
|
19629
|
+
task ? `- Task now: ${task}` : "",
|
|
19630
|
+
"- Current code remains authoritative."
|
|
19631
|
+
].filter(Boolean);
|
|
19632
|
+
const header = `${headerLines.join("\n")}
|
|
19633
|
+
|
|
19634
|
+
`;
|
|
19635
|
+
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.";
|
|
19636
|
+
const source = sanitizeCredentials(checkpoint.summary?.trim() || fallback);
|
|
19637
|
+
const available = Math.max(0, budget - countTextTokens(header) - 4);
|
|
19638
|
+
let excerpt = source ? truncateToTokenBudget(source, available) : "";
|
|
19639
|
+
let text = `${header}${excerpt ? `### Host checkpoint
|
|
19640
|
+
${excerpt}` : ""}`.trim();
|
|
19641
|
+
while (excerpt && countTextTokens(text) > budget) {
|
|
19642
|
+
const nextExcerptBudget = Math.max(1, Math.floor(countTextTokens(excerpt) * 0.8));
|
|
19643
|
+
excerpt = truncateToTokenBudget(excerpt, nextExcerptBudget);
|
|
19644
|
+
text = `${header}${excerpt ? `### Host checkpoint
|
|
19645
|
+
${excerpt}` : ""}`.trim();
|
|
19646
|
+
}
|
|
19647
|
+
if (countTextTokens(text) > budget) text = truncateToTokenBudget(text, budget);
|
|
19648
|
+
return {
|
|
19649
|
+
checkpointId: checkpoint.id,
|
|
19650
|
+
text,
|
|
19651
|
+
tokens: countTextTokens(text)
|
|
19652
|
+
};
|
|
19653
|
+
}
|
|
19654
|
+
function sourceEvent(input) {
|
|
19655
|
+
const raw = input.raw;
|
|
19656
|
+
const event = raw.hook_event_name ?? raw.event ?? raw.type;
|
|
19657
|
+
return typeof event === "string" && event ? event : input.event;
|
|
19658
|
+
}
|
|
19659
|
+
async function captureCompactionCheckpoint(input) {
|
|
19660
|
+
const isCompactResume = input.event === "session_start" && input.sessionStartReason?.trim().toLowerCase() === "compact";
|
|
19661
|
+
if (input.event !== "pre_compact" && input.event !== "post_compact" && !isCompactResume) return null;
|
|
19662
|
+
if (!input.sessionId || !input.cwd) return null;
|
|
19663
|
+
const [
|
|
19664
|
+
{ detectProject: detectProject2 },
|
|
19665
|
+
{ getProjectDataDir: getProjectDataDir2 },
|
|
19666
|
+
{ initAliasRegistry: initAliasRegistry2, registerAlias: registerAlias2 }
|
|
19667
|
+
] = await Promise.all([
|
|
19668
|
+
Promise.resolve().then(() => (init_detector(), detector_exports)),
|
|
19669
|
+
Promise.resolve().then(() => (init_persistence(), persistence_exports)),
|
|
19670
|
+
Promise.resolve().then(() => (init_aliases(), aliases_exports))
|
|
19671
|
+
]);
|
|
19672
|
+
const project = detectProject2(input.cwd);
|
|
19673
|
+
if (!project) return null;
|
|
19674
|
+
const dataDir = await getProjectDataDir2(project.id);
|
|
19675
|
+
initAliasRegistry2(dataDir);
|
|
19676
|
+
const projectId = await registerAlias2(project);
|
|
19677
|
+
const store = new CompactionCheckpointStore(dataDir);
|
|
19678
|
+
if (input.event === "pre_compact") {
|
|
19679
|
+
return store.recordPreflight({
|
|
19680
|
+
projectId,
|
|
19681
|
+
sessionId: input.sessionId,
|
|
19682
|
+
agent: input.agent,
|
|
19683
|
+
reason: input.compaction?.reason,
|
|
19684
|
+
sourceEvent: sourceEvent(input),
|
|
19685
|
+
transcriptAvailable: Boolean(input.transcriptPath),
|
|
19686
|
+
capturedAt: input.timestamp
|
|
19687
|
+
});
|
|
19688
|
+
}
|
|
19689
|
+
return store.complete({
|
|
19690
|
+
projectId,
|
|
19691
|
+
sessionId: input.sessionId,
|
|
19692
|
+
agent: input.agent,
|
|
19693
|
+
reason: input.compaction?.reason,
|
|
19694
|
+
sourceEvent: sourceEvent(input),
|
|
19695
|
+
sourceKey: input.compaction?.sourceKey,
|
|
19696
|
+
summary: input.compaction?.summary,
|
|
19697
|
+
tokensBefore: input.compaction?.tokensBefore,
|
|
19698
|
+
firstKeptEntryId: input.compaction?.firstKeptEntryId,
|
|
19699
|
+
details: input.compaction?.details,
|
|
19700
|
+
completedAt: input.timestamp
|
|
19701
|
+
});
|
|
19702
|
+
}
|
|
19703
|
+
async function consumeCompactionWorkset(input, options = {}) {
|
|
19704
|
+
if (!input.sessionId || !input.cwd) return null;
|
|
19705
|
+
const [
|
|
19706
|
+
{ detectProject: detectProject2 },
|
|
19707
|
+
{ getProjectDataDir: getProjectDataDir2 },
|
|
19708
|
+
{ initAliasRegistry: initAliasRegistry2, registerAlias: registerAlias2 }
|
|
19709
|
+
] = await Promise.all([
|
|
19710
|
+
Promise.resolve().then(() => (init_detector(), detector_exports)),
|
|
19711
|
+
Promise.resolve().then(() => (init_persistence(), persistence_exports)),
|
|
19712
|
+
Promise.resolve().then(() => (init_aliases(), aliases_exports))
|
|
19713
|
+
]);
|
|
19714
|
+
const project = detectProject2(input.cwd);
|
|
19715
|
+
if (!project) return null;
|
|
19716
|
+
const dataDir = await getProjectDataDir2(project.id);
|
|
19717
|
+
initAliasRegistry2(dataDir);
|
|
19718
|
+
const projectId = await registerAlias2(project);
|
|
19719
|
+
const store = new CompactionCheckpointStore(dataDir);
|
|
19720
|
+
const checkpoint = store.findUndelivered(projectId, input.sessionId, input.agent);
|
|
19721
|
+
if (!checkpoint) return null;
|
|
19722
|
+
const workset = buildCompactionWorkset(checkpoint, options);
|
|
19723
|
+
if (!workset.text) return null;
|
|
19724
|
+
store.markDelivered(checkpoint.id);
|
|
19725
|
+
return workset;
|
|
19726
|
+
}
|
|
19727
|
+
var DEFAULT_WORKSET_BUDGET, MIN_WORKSET_BUDGET;
|
|
19728
|
+
var init_compaction = __esm({
|
|
19729
|
+
"src/memory/compaction.ts"() {
|
|
19730
|
+
"use strict";
|
|
19731
|
+
init_esm_shims();
|
|
19732
|
+
init_token_budget();
|
|
19733
|
+
init_secret_filter();
|
|
19734
|
+
init_compaction_checkpoint_store();
|
|
19735
|
+
DEFAULT_WORKSET_BUDGET = 420;
|
|
19736
|
+
MIN_WORKSET_BUDGET = 48;
|
|
19737
|
+
}
|
|
19738
|
+
});
|
|
19739
|
+
|
|
19216
19740
|
// src/memory/export-import.ts
|
|
19217
19741
|
var export_import_exports = {};
|
|
19218
19742
|
__export(export_import_exports, {
|
|
@@ -21291,7 +21815,7 @@ __export(planner_exports, {
|
|
|
21291
21815
|
materializeTaskGraph: () => materializeTaskGraph,
|
|
21292
21816
|
seedAutonomousPipeline: () => seedAutonomousPipeline
|
|
21293
21817
|
});
|
|
21294
|
-
import { randomUUID as
|
|
21818
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
21295
21819
|
function isPlannerTask(metadata) {
|
|
21296
21820
|
if (!metadata) return null;
|
|
21297
21821
|
try {
|
|
@@ -21349,7 +21873,7 @@ function seedAutonomousPipeline(teamStore, projectId, config, opts) {
|
|
|
21349
21873
|
const maxIterations = config.maxIterations ?? 3;
|
|
21350
21874
|
const taskBudget = config.taskBudget ?? 15;
|
|
21351
21875
|
const structuredPlan = opts?.structuredPlan ?? true;
|
|
21352
|
-
const pipelineId =
|
|
21876
|
+
const pipelineId = randomUUID10();
|
|
21353
21877
|
const meta = {
|
|
21354
21878
|
plannerType: "plan",
|
|
21355
21879
|
pipelineId,
|
|
@@ -23332,7 +23856,7 @@ init_freshness();
|
|
|
23332
23856
|
init_obs_store();
|
|
23333
23857
|
init_mini_skill_store();
|
|
23334
23858
|
init_session_store();
|
|
23335
|
-
import { createHash as
|
|
23859
|
+
import { createHash as createHash14 } from "crypto";
|
|
23336
23860
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
23337
23861
|
import { z as z2 } from "zod";
|
|
23338
23862
|
|
|
@@ -26802,6 +27326,7 @@ var TOOL_PROFILES = Object.freeze({
|
|
|
26802
27326
|
memorix_rules_sync: ["full"],
|
|
26803
27327
|
memorix_workspace_sync: ["full"],
|
|
26804
27328
|
memorix_ingest_image: ["full"],
|
|
27329
|
+
memorix_compaction_checkpoint: ["full"],
|
|
26805
27330
|
// ── MCP Official Memory Server compatibility (KG tools) ──────────
|
|
26806
27331
|
// These are only useful to users specifically migrating from the
|
|
26807
27332
|
// reference mcp-memory server. Hide them unless explicitly enabled.
|
|
@@ -26968,7 +27493,7 @@ function coerceObjectArray(val) {
|
|
|
26968
27493
|
return [];
|
|
26969
27494
|
}
|
|
26970
27495
|
function createDeterministicInstanceId(projectId, agentType, agentName) {
|
|
26971
|
-
const digest2 =
|
|
27496
|
+
const digest2 = createHash14("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
|
|
26972
27497
|
return `auto-${digest2}`;
|
|
26973
27498
|
}
|
|
26974
27499
|
var BOOTSTRAP_SAFE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -27249,7 +27774,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
27249
27774
|
};
|
|
27250
27775
|
const server = existingServer ?? new McpServer({
|
|
27251
27776
|
name: "memorix",
|
|
27252
|
-
version: true ? "1.2.
|
|
27777
|
+
version: true ? "1.2.7" : "1.0.1"
|
|
27253
27778
|
});
|
|
27254
27779
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
27255
27780
|
server.registerTool = ((name, ...args) => {
|
|
@@ -27897,12 +28422,12 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
27897
28422
|
if (boundary) return boundary;
|
|
27898
28423
|
}
|
|
27899
28424
|
return withFreshIndex(async () => {
|
|
27900
|
-
const
|
|
28425
|
+
const safeLimit2 = limit != null ? coerceNumber(limit, 20) : void 0;
|
|
27901
28426
|
const safeMaxTokens = maxTokens != null ? coerceNumber(maxTokens, 0) : void 0;
|
|
27902
28427
|
const TIMEOUT_MS = 3e4;
|
|
27903
28428
|
const searchPromise = compactSearch({
|
|
27904
28429
|
query,
|
|
27905
|
-
limit:
|
|
28430
|
+
limit: safeLimit2,
|
|
27906
28431
|
type,
|
|
27907
28432
|
maxTokens: safeMaxTokens,
|
|
27908
28433
|
since,
|
|
@@ -28703,10 +29228,10 @@ Entity: ${entityName} | ${facts.length} facts | ${obs.tokens} tokens${reasoningA
|
|
|
28703
29228
|
const unresolved = requireResolvedProject("search reasoning in the current project");
|
|
28704
29229
|
if (unresolved) return unresolved;
|
|
28705
29230
|
}
|
|
28706
|
-
const
|
|
29231
|
+
const safeLimit2 = limit != null ? coerceNumber(limit, 10) : 10;
|
|
28707
29232
|
const result = await withFreshIndex(() => compactSearch({
|
|
28708
29233
|
query,
|
|
28709
|
-
limit:
|
|
29234
|
+
limit: safeLimit2,
|
|
28710
29235
|
type: "reasoning",
|
|
28711
29236
|
projectId: scope === "global" ? void 0 : project.id,
|
|
28712
29237
|
status: "active",
|
|
@@ -30029,9 +30554,9 @@ ${summary ? "Summary saved for next session context injection." : "No summary pr
|
|
|
30029
30554
|
}
|
|
30030
30555
|
},
|
|
30031
30556
|
async ({ limit }) => {
|
|
30032
|
-
const
|
|
30557
|
+
const safeLimit2 = limit != null ? coerceNumber(limit, 3) : 3;
|
|
30033
30558
|
const { getSessionContext: getSessionContext2, listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session(), session_exports));
|
|
30034
|
-
const context = await getSessionContext2(projectDir2, project.id,
|
|
30559
|
+
const context = await getSessionContext2(projectDir2, project.id, safeLimit2, getObservationReader());
|
|
30035
30560
|
const sessions = await listSessions2(projectDir2, project.id);
|
|
30036
30561
|
const activeSessions = sessions.filter((s) => s.status === "active");
|
|
30037
30562
|
const completedSessions = sessions.filter((s) => s.status === "completed");
|
|
@@ -30052,6 +30577,86 @@ ${summary ? "Summary saved for next session context injection." : "No summary pr
|
|
|
30052
30577
|
};
|
|
30053
30578
|
}
|
|
30054
30579
|
);
|
|
30580
|
+
server.registerTool(
|
|
30581
|
+
"memorix_compaction_checkpoint",
|
|
30582
|
+
{
|
|
30583
|
+
title: "Compact Continuity Checkpoints",
|
|
30584
|
+
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.",
|
|
30585
|
+
inputSchema: {
|
|
30586
|
+
action: z2.enum(["list", "show", "context", "archive"]).default("list"),
|
|
30587
|
+
id: z2.string().optional().describe("Checkpoint ID for show, context, or archive"),
|
|
30588
|
+
sessionId: z2.string().optional().describe("Optional host session ID filter"),
|
|
30589
|
+
agent: z2.string().optional().describe("Optional host agent filter"),
|
|
30590
|
+
task: z2.string().optional().describe("Current task for a bounded context preview"),
|
|
30591
|
+
maxTokens: z2.number().optional().describe("Maximum tokens for action=context (default: 420)"),
|
|
30592
|
+
limit: z2.number().optional().describe("Maximum records for action=list (default: 20)"),
|
|
30593
|
+
includeArchived: z2.boolean().optional().default(false).describe("Include archived records in action=list")
|
|
30594
|
+
}
|
|
30595
|
+
},
|
|
30596
|
+
async ({ action, id, sessionId, agent, task, maxTokens, limit, includeArchived }) => {
|
|
30597
|
+
const unresolved = requireResolvedProject("inspect compact continuity checkpoints");
|
|
30598
|
+
if (unresolved) return unresolved;
|
|
30599
|
+
const [{ CompactionCheckpointStore: CompactionCheckpointStore2 }, { buildCompactionWorkset: buildCompactionWorkset2 }] = await Promise.all([
|
|
30600
|
+
Promise.resolve().then(() => (init_compaction_checkpoint_store(), compaction_checkpoint_store_exports)),
|
|
30601
|
+
Promise.resolve().then(() => (init_compaction(), compaction_exports))
|
|
30602
|
+
]);
|
|
30603
|
+
const store = new CompactionCheckpointStore2(projectDir2);
|
|
30604
|
+
const assertCheckpoint = (checkpointId) => {
|
|
30605
|
+
const checkpoint2 = store.get(checkpointId);
|
|
30606
|
+
if (!checkpoint2 || checkpoint2.projectId !== project.id) return null;
|
|
30607
|
+
return checkpoint2;
|
|
30608
|
+
};
|
|
30609
|
+
if (action === "list") {
|
|
30610
|
+
const checkpoints = store.list({
|
|
30611
|
+
projectId: project.id,
|
|
30612
|
+
sessionId: sessionId?.trim() || void 0,
|
|
30613
|
+
agent: agent?.trim() || void 0,
|
|
30614
|
+
includeArchived: Boolean(includeArchived),
|
|
30615
|
+
limit: limit != null ? Math.max(1, Math.min(100, coerceNumber(limit, 20))) : 20
|
|
30616
|
+
});
|
|
30617
|
+
return {
|
|
30618
|
+
content: [{ type: "text", text: JSON.stringify({ projectId: project.id, checkpoints }, null, 2) }]
|
|
30619
|
+
};
|
|
30620
|
+
}
|
|
30621
|
+
if (!id?.trim()) {
|
|
30622
|
+
return {
|
|
30623
|
+
content: [{ type: "text", text: "id is required for this checkpoint action." }],
|
|
30624
|
+
isError: true
|
|
30625
|
+
};
|
|
30626
|
+
}
|
|
30627
|
+
const checkpoint = assertCheckpoint(id.trim());
|
|
30628
|
+
if (!checkpoint) {
|
|
30629
|
+
return {
|
|
30630
|
+
content: [{ type: "text", text: `Checkpoint "${id.trim()}" was not found for the current project.` }],
|
|
30631
|
+
isError: true
|
|
30632
|
+
};
|
|
30633
|
+
}
|
|
30634
|
+
if (action === "show") {
|
|
30635
|
+
return {
|
|
30636
|
+
content: [{ type: "text", text: JSON.stringify({ projectId: project.id, checkpoint }, null, 2) }]
|
|
30637
|
+
};
|
|
30638
|
+
}
|
|
30639
|
+
if (action === "context") {
|
|
30640
|
+
const workset = buildCompactionWorkset2(checkpoint, {
|
|
30641
|
+
task: task?.trim(),
|
|
30642
|
+
maxTokens: maxTokens != null ? coerceNumber(maxTokens, 420) : 420
|
|
30643
|
+
});
|
|
30644
|
+
return {
|
|
30645
|
+
content: [{ type: "text", text: workset.text }]
|
|
30646
|
+
};
|
|
30647
|
+
}
|
|
30648
|
+
const archived = store.archive(checkpoint.id);
|
|
30649
|
+
if (!archived) {
|
|
30650
|
+
return {
|
|
30651
|
+
content: [{ type: "text", text: `Checkpoint "${checkpoint.id}" is already archived.` }],
|
|
30652
|
+
isError: true
|
|
30653
|
+
};
|
|
30654
|
+
}
|
|
30655
|
+
return {
|
|
30656
|
+
content: [{ type: "text", text: `Archived compact checkpoint ${archived.id}.` }]
|
|
30657
|
+
};
|
|
30658
|
+
}
|
|
30659
|
+
);
|
|
30055
30660
|
server.registerTool(
|
|
30056
30661
|
"memorix_transfer",
|
|
30057
30662
|
{
|