@massu/core 2.5.0 → 2.5.1
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 +61 -0
- package/commands/massu-bearings.md +1 -1
- package/commands/massu-recap.md +16 -5
- package/dist/cli.js +138 -46
- package/dist/hooks/auto-learning-pipeline.js +53 -9
- package/dist/hooks/classify-failure.js +55 -11
- package/dist/hooks/cost-tracker.js +23 -9
- package/dist/hooks/fix-detector.js +54 -9
- package/dist/hooks/incident-pipeline.js +53 -9
- package/dist/hooks/intent-suggester.js +53 -9
- package/dist/hooks/memory-recall.js +53 -9
- package/dist/hooks/post-edit-context.js +53 -9
- package/dist/hooks/post-tool-use.js +19 -6
- package/dist/hooks/pre-compact.js +19 -6
- package/dist/hooks/pre-delete-check.js +53 -9
- package/dist/hooks/pre-tool-use-gate.js +57 -11
- package/dist/hooks/quality-event.js +23 -9
- package/dist/hooks/rule-enforcement-pipeline.js +53 -9
- package/dist/hooks/security-gate.js +53 -9
- package/dist/hooks/session-end.js +19 -6
- package/dist/hooks/session-start.js +120 -37
- package/dist/hooks/user-prompt.js +19 -6
- package/package.json +1 -1
|
@@ -1362,6 +1362,16 @@ var init_memory_vector = __esm({
|
|
|
1362
1362
|
}
|
|
1363
1363
|
});
|
|
1364
1364
|
|
|
1365
|
+
// src/lib/timestamps.ts
|
|
1366
|
+
function nowIso() {
|
|
1367
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1368
|
+
}
|
|
1369
|
+
var init_timestamps = __esm({
|
|
1370
|
+
"src/lib/timestamps.ts"() {
|
|
1371
|
+
"use strict";
|
|
1372
|
+
}
|
|
1373
|
+
});
|
|
1374
|
+
|
|
1365
1375
|
// src/db-backup.ts
|
|
1366
1376
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readdirSync, statSync, unlinkSync, copyFileSync, rmSync as rmSync4 } from "fs";
|
|
1367
1377
|
import { resolve as resolve3, join as join3, basename, dirname as dirname4 } from "path";
|
|
@@ -3693,8 +3703,8 @@ function linkSessionToTask(db, sessionId, taskId) {
|
|
|
3693
3703
|
}
|
|
3694
3704
|
function addConversationTurn(db, sessionId, turnNumber, userPrompt, assistantResponse, toolCallsJson, toolCallCount, promptTokens, responseTokens) {
|
|
3695
3705
|
const result = db.prepare(`
|
|
3696
|
-
INSERT INTO conversation_turns (session_id, turn_number, user_prompt, assistant_response, tool_calls_json, tool_call_count, prompt_tokens, response_tokens)
|
|
3697
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
3706
|
+
INSERT INTO conversation_turns (session_id, turn_number, user_prompt, assistant_response, tool_calls_json, tool_call_count, prompt_tokens, response_tokens, created_at)
|
|
3707
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
3698
3708
|
`).run(
|
|
3699
3709
|
sessionId,
|
|
3700
3710
|
turnNumber,
|
|
@@ -3703,14 +3713,15 @@ function addConversationTurn(db, sessionId, turnNumber, userPrompt, assistantRes
|
|
|
3703
3713
|
toolCallsJson,
|
|
3704
3714
|
toolCallCount,
|
|
3705
3715
|
promptTokens,
|
|
3706
|
-
responseTokens
|
|
3716
|
+
responseTokens,
|
|
3717
|
+
nowIso()
|
|
3707
3718
|
);
|
|
3708
3719
|
return Number(result.lastInsertRowid);
|
|
3709
3720
|
}
|
|
3710
3721
|
function addToolCallDetail(db, sessionId, turnNumber, toolName, inputSummary, inputSize, outputSize, success, filesInvolved) {
|
|
3711
3722
|
db.prepare(`
|
|
3712
|
-
INSERT INTO tool_call_details (session_id, turn_number, tool_name, tool_input_summary, tool_input_size, tool_output_size, tool_success, files_involved)
|
|
3713
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
3723
|
+
INSERT INTO tool_call_details (session_id, turn_number, tool_name, tool_input_summary, tool_input_size, tool_output_size, tool_success, files_involved, created_at)
|
|
3724
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
3714
3725
|
`).run(
|
|
3715
3726
|
sessionId,
|
|
3716
3727
|
turnNumber,
|
|
@@ -3719,7 +3730,8 @@ function addToolCallDetail(db, sessionId, turnNumber, toolName, inputSummary, in
|
|
|
3719
3730
|
inputSize,
|
|
3720
3731
|
outputSize,
|
|
3721
3732
|
success ? 1 : 0,
|
|
3722
|
-
filesInvolved ? JSON.stringify(filesInvolved) : null
|
|
3733
|
+
filesInvolved ? JSON.stringify(filesInvolved) : null,
|
|
3734
|
+
nowIso()
|
|
3723
3735
|
);
|
|
3724
3736
|
}
|
|
3725
3737
|
function getLastProcessedLine(db, sessionId) {
|
|
@@ -3978,6 +3990,7 @@ var init_memory_db = __esm({
|
|
|
3978
3990
|
init_db_driver();
|
|
3979
3991
|
init_config();
|
|
3980
3992
|
init_memory_vector();
|
|
3993
|
+
init_timestamps();
|
|
3981
3994
|
init_db_backup();
|
|
3982
3995
|
init_rule_delivery();
|
|
3983
3996
|
init_rule_candidate_store();
|
|
@@ -4985,6 +4998,7 @@ var init_memory_files_config = __esm({
|
|
|
4985
4998
|
// src/memory-renderer.ts
|
|
4986
4999
|
var memory_renderer_exports = {};
|
|
4987
5000
|
__export(memory_renderer_exports, {
|
|
5001
|
+
RenderAccountingLeak: () => RenderAccountingLeak,
|
|
4988
5002
|
composeFile: () => composeFile,
|
|
4989
5003
|
renderMemoryFiles: () => renderMemoryFiles,
|
|
4990
5004
|
stripFrontmatter: () => stripFrontmatter
|
|
@@ -4996,7 +5010,7 @@ import { createHash as createHash5 } from "crypto";
|
|
|
4996
5010
|
function renderMemoryFiles(db, candidates, opts) {
|
|
4997
5011
|
const config = opts.config ?? resolveMemoryFilesConfig();
|
|
4998
5012
|
if (!config.renderEnabled) {
|
|
4999
|
-
return EMPTY("render_disabled");
|
|
5013
|
+
return EMPTY("render_disabled", candidates.length);
|
|
5000
5014
|
}
|
|
5001
5015
|
const dryRun = opts.dryRun === true;
|
|
5002
5016
|
const now = opts.now ?? Date.now();
|
|
@@ -5005,7 +5019,7 @@ function renderMemoryFiles(db, candidates, opts) {
|
|
|
5005
5019
|
});
|
|
5006
5020
|
const { memoryDir } = opts;
|
|
5007
5021
|
if (!existsSync19(memoryDir)) {
|
|
5008
|
-
return EMPTY("no_memory_dir");
|
|
5022
|
+
return EMPTY("no_memory_dir", candidates.length);
|
|
5009
5023
|
}
|
|
5010
5024
|
try {
|
|
5011
5025
|
return withMemoryIndexLock(
|
|
@@ -5014,10 +5028,10 @@ function renderMemoryFiles(db, candidates, opts) {
|
|
|
5014
5028
|
);
|
|
5015
5029
|
} catch (err) {
|
|
5016
5030
|
if (err instanceof MemoryIndexLockBusy) {
|
|
5017
|
-
return EMPTY("lock_busy");
|
|
5031
|
+
return EMPTY("lock_busy", candidates.length);
|
|
5018
5032
|
}
|
|
5019
5033
|
audit("memory_file_render_refused", { reason: "unexpected_error", error: String(err) });
|
|
5020
|
-
return EMPTY("error");
|
|
5034
|
+
return EMPTY("error", candidates.length);
|
|
5021
5035
|
}
|
|
5022
5036
|
}
|
|
5023
5037
|
function renderLocked(db, candidates, o) {
|
|
@@ -5027,11 +5041,14 @@ function renderLocked(db, candidates, o) {
|
|
|
5027
5041
|
try {
|
|
5028
5042
|
tombstones = readTombstones(memoryDir);
|
|
5029
5043
|
} catch {
|
|
5030
|
-
return EMPTY("tombstone_ledger_unreadable");
|
|
5044
|
+
return EMPTY("tombstone_ledger_unreadable", candidates.length);
|
|
5031
5045
|
}
|
|
5032
5046
|
const ownerOf = relPathOwnerLookup(db);
|
|
5033
5047
|
const planned = [];
|
|
5034
|
-
|
|
5048
|
+
let unchanged = 0;
|
|
5049
|
+
let capped = 0;
|
|
5050
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
5051
|
+
const c = candidates[i];
|
|
5035
5052
|
if (!isLocalOrigin(c.origin)) {
|
|
5036
5053
|
refusals.push({ name: c.name, reason: "non_local_origin", detail: c.origin || "unknown" });
|
|
5037
5054
|
audit("memory_file_render_refused", { name: c.name, reason: "non_local_origin" });
|
|
@@ -5087,7 +5104,10 @@ function renderLocked(db, candidates, o) {
|
|
|
5087
5104
|
continue;
|
|
5088
5105
|
}
|
|
5089
5106
|
const next = composeFile(c, home);
|
|
5090
|
-
if (next !== null && next === existing)
|
|
5107
|
+
if (next !== null && next === existing) {
|
|
5108
|
+
unchanged++;
|
|
5109
|
+
continue;
|
|
5110
|
+
}
|
|
5091
5111
|
}
|
|
5092
5112
|
const content = composeFile(c, home);
|
|
5093
5113
|
if (content === null) {
|
|
@@ -5095,9 +5115,24 @@ function renderLocked(db, candidates, o) {
|
|
|
5095
5115
|
continue;
|
|
5096
5116
|
}
|
|
5097
5117
|
planned.push({ c, relPath, absPath, content });
|
|
5098
|
-
if (planned.length >= config.renderMaxFilesPerSession)
|
|
5118
|
+
if (planned.length >= config.renderMaxFilesPerSession) {
|
|
5119
|
+
capped = candidates.length - (i + 1);
|
|
5120
|
+
break;
|
|
5121
|
+
}
|
|
5122
|
+
}
|
|
5123
|
+
const accounted = planned.length + refusals.length + unchanged + capped;
|
|
5124
|
+
if (accounted !== candidates.length) {
|
|
5125
|
+
audit("memory_file_render_refused", {
|
|
5126
|
+
reason: "accounting_leak",
|
|
5127
|
+
considered: candidates.length,
|
|
5128
|
+
accounted
|
|
5129
|
+
});
|
|
5130
|
+
throw new RenderAccountingLeak(
|
|
5131
|
+
`render did not account for every candidate: considered=${candidates.length} but accounted=${accounted} (planned=${planned.length} refused=${refusals.length} unchanged=${unchanged} capped=${capped}). A candidate was dropped without a bucket.`
|
|
5132
|
+
);
|
|
5099
5133
|
}
|
|
5100
5134
|
const indexLines = buildIndexLines(db, memoryDir, planned, config);
|
|
5135
|
+
const books = { considered: candidates.length, unchanged, capped };
|
|
5101
5136
|
if (dryRun) {
|
|
5102
5137
|
return {
|
|
5103
5138
|
enabled: true,
|
|
@@ -5105,11 +5140,20 @@ function renderLocked(db, candidates, o) {
|
|
|
5105
5140
|
written: planned.map((p) => p.relPath),
|
|
5106
5141
|
refusals,
|
|
5107
5142
|
indexLines,
|
|
5108
|
-
bytesWritten: 0
|
|
5143
|
+
bytesWritten: 0,
|
|
5144
|
+
...books
|
|
5109
5145
|
};
|
|
5110
5146
|
}
|
|
5111
5147
|
if (planned.length === 0 && indexLines.length === 0) {
|
|
5112
|
-
return {
|
|
5148
|
+
return {
|
|
5149
|
+
enabled: true,
|
|
5150
|
+
dryRun: false,
|
|
5151
|
+
written: [],
|
|
5152
|
+
refusals,
|
|
5153
|
+
indexLines: [],
|
|
5154
|
+
bytesWritten: 0,
|
|
5155
|
+
...books
|
|
5156
|
+
};
|
|
5113
5157
|
}
|
|
5114
5158
|
if (!hasFreshBackup(memoryDir, home)) {
|
|
5115
5159
|
try {
|
|
@@ -5119,7 +5163,7 @@ function renderLocked(db, candidates, o) {
|
|
|
5119
5163
|
reason: "backup_failed",
|
|
5120
5164
|
error: err instanceof BackupError ? err.message : String(err)
|
|
5121
5165
|
});
|
|
5122
|
-
return EMPTY("backup_failed");
|
|
5166
|
+
return EMPTY("backup_failed", candidates.length);
|
|
5123
5167
|
}
|
|
5124
5168
|
}
|
|
5125
5169
|
const indexPath = o.indexPath ?? join13(memoryDir, "MEMORY.md");
|
|
@@ -5187,7 +5231,10 @@ function renderLocked(db, candidates, o) {
|
|
|
5187
5231
|
errors: restored.errors
|
|
5188
5232
|
});
|
|
5189
5233
|
return {
|
|
5190
|
-
...EMPTY("rollback_incomplete"),
|
|
5234
|
+
...EMPTY("rollback_incomplete", candidates.length),
|
|
5235
|
+
// The books were balanced before the write began; keep them rather than zeroing.
|
|
5236
|
+
unchanged,
|
|
5237
|
+
capped,
|
|
5191
5238
|
enabled: true,
|
|
5192
5239
|
refusals: [
|
|
5193
5240
|
...refusals,
|
|
@@ -5196,9 +5243,9 @@ function renderLocked(db, candidates, o) {
|
|
|
5196
5243
|
};
|
|
5197
5244
|
}
|
|
5198
5245
|
audit("memory_file_render_refused", { reason: "write_failed", error: String(err) });
|
|
5199
|
-
return { ...EMPTY("write_failed"), enabled: true, refusals };
|
|
5246
|
+
return { ...EMPTY("write_failed", candidates.length), enabled: true, refusals, unchanged, capped };
|
|
5200
5247
|
}
|
|
5201
|
-
return { enabled: true, dryRun: false, written, refusals, indexLines, bytesWritten };
|
|
5248
|
+
return { enabled: true, dryRun: false, written, refusals, indexLines, bytesWritten, ...books };
|
|
5202
5249
|
}
|
|
5203
5250
|
function sha256(s) {
|
|
5204
5251
|
return createHash5("sha256").update(s, "utf8").digest("hex");
|
|
@@ -5267,7 +5314,7 @@ function buildIndexLines(db, memoryDir, planned, config) {
|
|
|
5267
5314
|
function oneLine(s) {
|
|
5268
5315
|
return s.replace(/[\r\n]+/g, " ").slice(0, 120);
|
|
5269
5316
|
}
|
|
5270
|
-
var EMPTY;
|
|
5317
|
+
var RenderAccountingLeak, EMPTY;
|
|
5271
5318
|
var init_memory_renderer = __esm({
|
|
5272
5319
|
"src/memory-renderer.ts"() {
|
|
5273
5320
|
"use strict";
|
|
@@ -5282,14 +5329,22 @@ var init_memory_renderer = __esm({
|
|
|
5282
5329
|
init_memory_index_region();
|
|
5283
5330
|
init_memory_files_config();
|
|
5284
5331
|
init_memory_file_ingest();
|
|
5285
|
-
|
|
5332
|
+
RenderAccountingLeak = class extends Error {
|
|
5333
|
+
};
|
|
5334
|
+
EMPTY = (reason, considered = 0) => ({
|
|
5286
5335
|
enabled: false,
|
|
5287
5336
|
dryRun: false,
|
|
5288
5337
|
written: [],
|
|
5289
5338
|
refusals: [],
|
|
5290
5339
|
indexLines: [],
|
|
5291
5340
|
bytesWritten: 0,
|
|
5292
|
-
skippedReason: reason
|
|
5341
|
+
skippedReason: reason,
|
|
5342
|
+
// An early gate refused, so every candidate was dropped — by that ONE named reason.
|
|
5343
|
+
// Reporting `considered` here is what distinguishes "nothing to do" from "walked away
|
|
5344
|
+
// from 59 rows because the lock was busy".
|
|
5345
|
+
considered,
|
|
5346
|
+
unchanged: 0,
|
|
5347
|
+
capped: 0
|
|
5293
5348
|
});
|
|
5294
5349
|
}
|
|
5295
5350
|
});
|
|
@@ -5297,31 +5352,54 @@ var init_memory_renderer = __esm({
|
|
|
5297
5352
|
// src/memory-render-candidates.ts
|
|
5298
5353
|
var memory_render_candidates_exports = {};
|
|
5299
5354
|
__export(memory_render_candidates_exports, {
|
|
5355
|
+
CandidateAccountingLeak: () => CandidateAccountingLeak,
|
|
5356
|
+
EXCLUSION_MEMORY_FILE_REINGEST: () => EXCLUSION_MEMORY_FILE_REINGEST,
|
|
5300
5357
|
RENDERABLE_MEMORY_TYPES: () => RENDERABLE_MEMORY_TYPES,
|
|
5301
5358
|
loadRenderCandidates: () => loadRenderCandidates
|
|
5302
5359
|
});
|
|
5303
5360
|
function loadRenderCandidates(db) {
|
|
5304
5361
|
const cfg = resolveMemoryFilesConfig();
|
|
5305
5362
|
const typePlaceholders = RENDERABLE_MEMORY_TYPES.map(() => "?").join(", ");
|
|
5363
|
+
const WHERE = `WHERE importance >= ?
|
|
5364
|
+
AND COALESCE(expired_at_epoch, 0) = 0
|
|
5365
|
+
AND type IN (${typePlaceholders})`;
|
|
5366
|
+
const { population } = db.prepare(`SELECT COUNT(*) AS population FROM observations ${WHERE}`).get(cfg.renderMinImportance, ...RENDERABLE_MEMORY_TYPES);
|
|
5306
5367
|
const rows = db.prepare(
|
|
5307
5368
|
`SELECT id, title, detail, importance, COALESCE(origin, 'local') AS origin
|
|
5308
5369
|
FROM observations
|
|
5309
|
-
|
|
5310
|
-
AND COALESCE(expired_at_epoch, 0) = 0
|
|
5311
|
-
AND type IN (${typePlaceholders})
|
|
5370
|
+
${WHERE}
|
|
5312
5371
|
ORDER BY importance DESC, created_at_epoch DESC
|
|
5313
|
-
LIMIT
|
|
5372
|
+
LIMIT ${CANDIDATE_WINDOW}`
|
|
5314
5373
|
).all(cfg.renderMinImportance, ...RENDERABLE_MEMORY_TYPES);
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5374
|
+
const reingest = rows.filter((r) => r.title.startsWith("[memory-file]"));
|
|
5375
|
+
const kept = rows.filter((r) => !r.title.startsWith("[memory-file]"));
|
|
5376
|
+
const excluded = reingest.length ? [{ reason: EXCLUSION_MEMORY_FILE_REINGEST, count: reingest.length }] : [];
|
|
5377
|
+
const ledger = {
|
|
5378
|
+
population,
|
|
5379
|
+
windowed: rows.length,
|
|
5380
|
+
truncatedByWindow: Math.max(0, population - rows.length),
|
|
5381
|
+
excluded,
|
|
5382
|
+
returned: kept.length
|
|
5383
|
+
};
|
|
5384
|
+
const accounted = ledger.returned + ledger.truncatedByWindow + excluded.reduce((n, e) => n + e.count, 0);
|
|
5385
|
+
if (accounted !== population) {
|
|
5386
|
+
throw new CandidateAccountingLeak(
|
|
5387
|
+
`candidate ledger does not balance: population=${population} but accounted=${accounted} (returned=${ledger.returned} truncated=${ledger.truncatedByWindow} excluded=${JSON.stringify(excluded)}). A row was dropped without a bucket.`
|
|
5388
|
+
);
|
|
5389
|
+
}
|
|
5390
|
+
return {
|
|
5391
|
+
ledger,
|
|
5392
|
+
candidates: kept.map((r) => ({
|
|
5393
|
+
observationId: r.id,
|
|
5394
|
+
name: r.title,
|
|
5395
|
+
title: r.title,
|
|
5396
|
+
body: r.detail ?? "",
|
|
5397
|
+
importance: r.importance,
|
|
5398
|
+
origin: r.origin
|
|
5399
|
+
}))
|
|
5400
|
+
};
|
|
5323
5401
|
}
|
|
5324
|
-
var RENDERABLE_MEMORY_TYPES;
|
|
5402
|
+
var RENDERABLE_MEMORY_TYPES, CANDIDATE_WINDOW, EXCLUSION_MEMORY_FILE_REINGEST, CandidateAccountingLeak;
|
|
5325
5403
|
var init_memory_render_candidates = __esm({
|
|
5326
5404
|
"src/memory-render-candidates.ts"() {
|
|
5327
5405
|
"use strict";
|
|
@@ -5332,6 +5410,10 @@ var init_memory_render_candidates = __esm({
|
|
|
5332
5410
|
"incident_near_miss",
|
|
5333
5411
|
"cr_violation"
|
|
5334
5412
|
];
|
|
5413
|
+
CANDIDATE_WINDOW = 50;
|
|
5414
|
+
EXCLUSION_MEMORY_FILE_REINGEST = "memory_file_reingest";
|
|
5415
|
+
CandidateAccountingLeak = class extends Error {
|
|
5416
|
+
};
|
|
5335
5417
|
}
|
|
5336
5418
|
});
|
|
5337
5419
|
|
|
@@ -14149,7 +14231,8 @@ Session memory, code intelligence, and governance are now active.
|
|
|
14149
14231
|
if (memoryDir) {
|
|
14150
14232
|
const { renderMemoryFiles: renderMemoryFiles2 } = await Promise.resolve().then(() => (init_memory_renderer(), memory_renderer_exports));
|
|
14151
14233
|
const { loadRenderCandidates: loadRenderCandidates2 } = await Promise.resolve().then(() => (init_memory_render_candidates(), memory_render_candidates_exports));
|
|
14152
|
-
|
|
14234
|
+
const { candidates } = loadRenderCandidates2(db);
|
|
14235
|
+
renderMemoryFiles2(db, candidates, { memoryDir });
|
|
14153
14236
|
}
|
|
14154
14237
|
} catch (_renderErr) {
|
|
14155
14238
|
}
|
|
@@ -1339,6 +1339,16 @@ var init_memory_vector = __esm({
|
|
|
1339
1339
|
}
|
|
1340
1340
|
});
|
|
1341
1341
|
|
|
1342
|
+
// src/lib/timestamps.ts
|
|
1343
|
+
function nowIso() {
|
|
1344
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1345
|
+
}
|
|
1346
|
+
var init_timestamps = __esm({
|
|
1347
|
+
"src/lib/timestamps.ts"() {
|
|
1348
|
+
"use strict";
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1351
|
+
|
|
1342
1352
|
// src/db-backup.ts
|
|
1343
1353
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readdirSync, statSync, unlinkSync, copyFileSync, rmSync as rmSync4 } from "fs";
|
|
1344
1354
|
import { resolve as resolve3, join as join3, basename, dirname as dirname4 } from "path";
|
|
@@ -3695,8 +3705,8 @@ function linkSessionToTask(db, sessionId, taskId) {
|
|
|
3695
3705
|
}
|
|
3696
3706
|
function addConversationTurn(db, sessionId, turnNumber, userPrompt, assistantResponse, toolCallsJson, toolCallCount, promptTokens, responseTokens) {
|
|
3697
3707
|
const result = db.prepare(`
|
|
3698
|
-
INSERT INTO conversation_turns (session_id, turn_number, user_prompt, assistant_response, tool_calls_json, tool_call_count, prompt_tokens, response_tokens)
|
|
3699
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
3708
|
+
INSERT INTO conversation_turns (session_id, turn_number, user_prompt, assistant_response, tool_calls_json, tool_call_count, prompt_tokens, response_tokens, created_at)
|
|
3709
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
3700
3710
|
`).run(
|
|
3701
3711
|
sessionId,
|
|
3702
3712
|
turnNumber,
|
|
@@ -3705,14 +3715,15 @@ function addConversationTurn(db, sessionId, turnNumber, userPrompt, assistantRes
|
|
|
3705
3715
|
toolCallsJson,
|
|
3706
3716
|
toolCallCount,
|
|
3707
3717
|
promptTokens,
|
|
3708
|
-
responseTokens
|
|
3718
|
+
responseTokens,
|
|
3719
|
+
nowIso()
|
|
3709
3720
|
);
|
|
3710
3721
|
return Number(result.lastInsertRowid);
|
|
3711
3722
|
}
|
|
3712
3723
|
function addToolCallDetail(db, sessionId, turnNumber, toolName, inputSummary, inputSize, outputSize, success, filesInvolved) {
|
|
3713
3724
|
db.prepare(`
|
|
3714
|
-
INSERT INTO tool_call_details (session_id, turn_number, tool_name, tool_input_summary, tool_input_size, tool_output_size, tool_success, files_involved)
|
|
3715
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
3725
|
+
INSERT INTO tool_call_details (session_id, turn_number, tool_name, tool_input_summary, tool_input_size, tool_output_size, tool_success, files_involved, created_at)
|
|
3726
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
3716
3727
|
`).run(
|
|
3717
3728
|
sessionId,
|
|
3718
3729
|
turnNumber,
|
|
@@ -3721,7 +3732,8 @@ function addToolCallDetail(db, sessionId, turnNumber, toolName, inputSummary, in
|
|
|
3721
3732
|
inputSize,
|
|
3722
3733
|
outputSize,
|
|
3723
3734
|
success ? 1 : 0,
|
|
3724
|
-
filesInvolved ? JSON.stringify(filesInvolved) : null
|
|
3735
|
+
filesInvolved ? JSON.stringify(filesInvolved) : null,
|
|
3736
|
+
nowIso()
|
|
3725
3737
|
);
|
|
3726
3738
|
}
|
|
3727
3739
|
function getLastProcessedLine(db, sessionId) {
|
|
@@ -3980,6 +3992,7 @@ var init_memory_db = __esm({
|
|
|
3980
3992
|
init_db_driver();
|
|
3981
3993
|
init_config();
|
|
3982
3994
|
init_memory_vector();
|
|
3995
|
+
init_timestamps();
|
|
3983
3996
|
init_db_backup();
|
|
3984
3997
|
init_rule_delivery();
|
|
3985
3998
|
init_rule_candidate_store();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@massu/core",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI Engineering Governance MCP Server - Session memory, knowledge system, feature registry, code intelligence, rule enforcement, tiered tooling (12 free / 73 total), 56 workflow commands, 11 agents, 20+ patterns",
|
|
6
6
|
"main": "./dist/cli.js",
|