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/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
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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 ||
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 ??
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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.
|
|
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
|
|
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:
|
|
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
|
|
29315
|
+
const safeLimit2 = limit != null ? coerceNumber(limit, 10) : 10;
|
|
28791
29316
|
const result = await withFreshIndex(() => compactSearch({
|
|
28792
29317
|
query,
|
|
28793
|
-
limit:
|
|
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
|
|
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,
|
|
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
|
{
|