@massu/core 2.5.5 → 2.5.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 +63 -0
- package/dist/cli.js +167 -46
- package/dist/hooks/auto-learning-pipeline.js +81 -16
- package/dist/hooks/classify-failure.js +90 -652
- package/dist/hooks/cost-tracker.js +69 -4
- package/dist/hooks/fix-detector.js +79 -12
- package/dist/hooks/incident-pipeline.js +72 -7
- package/dist/hooks/intent-suggester.js +69 -4
- package/dist/hooks/memory-recall.js +89 -6
- package/dist/hooks/post-edit-context.js +69 -4
- package/dist/hooks/post-tool-use.js +76 -11
- package/dist/hooks/pre-compact.js +69 -4
- package/dist/hooks/pre-delete-check.js +446 -71
- package/dist/hooks/pre-tool-use-gate.js +237 -223
- package/dist/hooks/quality-event.js +69 -4
- package/dist/hooks/rule-enforcement-pipeline.js +72 -7
- package/dist/hooks/security-gate.js +611 -181
- package/dist/hooks/session-end.js +607 -73
- package/dist/hooks/session-start.js +112 -8
- package/dist/hooks/user-prompt.js +83 -18
- package/package.json +1 -1
|
@@ -2205,6 +2205,8 @@ __export(memory_db_exports, {
|
|
|
2205
2205
|
MEMORY_FILE_TITLE_LIKE: () => MEMORY_FILE_TITLE_LIKE,
|
|
2206
2206
|
MEMORY_FILE_TITLE_PREFIX: () => MEMORY_FILE_TITLE_PREFIX,
|
|
2207
2207
|
MEMORY_SCHEMA_VERSION: () => MEMORY_SCHEMA_VERSION,
|
|
2208
|
+
PENDING_SYNC_MAX_AGE_DAYS: () => PENDING_SYNC_MAX_AGE_DAYS,
|
|
2209
|
+
PENDING_SYNC_MAX_ITEMS: () => PENDING_SYNC_MAX_ITEMS,
|
|
2208
2210
|
TOOL_COST_EVENTS_RETENTION_DAYS: () => TOOL_COST_EVENTS_RETENTION_DAYS,
|
|
2209
2211
|
USAGE_COUNTER_ARMED_KEY: () => USAGE_COUNTER_ARMED_KEY,
|
|
2210
2212
|
addConversationTurn: () => addConversationTurn,
|
|
@@ -2213,6 +2215,7 @@ __export(memory_db_exports, {
|
|
|
2213
2215
|
addSummary: () => addSummary,
|
|
2214
2216
|
addToolCallDetail: () => addToolCallDetail,
|
|
2215
2217
|
addUserPrompt: () => addUserPrompt,
|
|
2218
|
+
allPendingSync: () => allPendingSync,
|
|
2216
2219
|
appendIncidentToFailureClass: () => appendIncidentToFailureClass,
|
|
2217
2220
|
armUsageCounter: () => armUsageCounter,
|
|
2218
2221
|
assignImportance: () => assignImportance,
|
|
@@ -2220,6 +2223,7 @@ __export(memory_db_exports, {
|
|
|
2220
2223
|
createSession: () => createSession,
|
|
2221
2224
|
deduplicateFailedAttempt: () => deduplicateFailedAttempt,
|
|
2222
2225
|
dequeuePendingSync: () => dequeuePendingSync,
|
|
2226
|
+
discardPendingSync: () => discardPendingSync,
|
|
2223
2227
|
embedMissingObservations: () => embedMissingObservations,
|
|
2224
2228
|
endSession: () => endSession,
|
|
2225
2229
|
enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
|
|
@@ -3202,6 +3206,35 @@ function initMemorySchema(db) {
|
|
|
3202
3206
|
}
|
|
3203
3207
|
function enqueueSyncPayload(db, payload) {
|
|
3204
3208
|
db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
|
|
3209
|
+
const overflow = db.prepare(
|
|
3210
|
+
`SELECT id, retry_count, last_error, payload FROM pending_sync
|
|
3211
|
+
WHERE created_at < datetime('now', ?)
|
|
3212
|
+
OR id NOT IN (SELECT id FROM pending_sync ORDER BY created_at DESC, id DESC LIMIT ?)
|
|
3213
|
+
LIMIT 10000`
|
|
3214
|
+
).all(`-${PENDING_SYNC_MAX_AGE_DAYS} days`, PENDING_SYNC_MAX_ITEMS);
|
|
3215
|
+
if (overflow.length > 0) {
|
|
3216
|
+
discardPendingSync(db, overflow, `over the queue limit (${PENDING_SYNC_MAX_ITEMS} items / ${PENDING_SYNC_MAX_AGE_DAYS} days)`);
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
function discardPendingSync(db, rows, why) {
|
|
3220
|
+
if (rows.length === 0) return 0;
|
|
3221
|
+
const rescued = rescueLearningFromStalePayloads(db, rows);
|
|
3222
|
+
for (let i = 0; i < rows.length; i += 500) {
|
|
3223
|
+
const ids = rows.slice(i, i + 500).map((r) => r.id);
|
|
3224
|
+
db.prepare(`DELETE FROM pending_sync WHERE id IN (${ids.map(() => "?").join(",")})`).run(...ids);
|
|
3225
|
+
}
|
|
3226
|
+
if (rescued > 0) {
|
|
3227
|
+
process.stderr.write(
|
|
3228
|
+
`[massu] RESCUED ${rescued} learned rule(s) from ${rows.length} discarded payload(s) \u2014 they were re-queued for delivery, NOT discarded.
|
|
3229
|
+
`
|
|
3230
|
+
);
|
|
3231
|
+
}
|
|
3232
|
+
process.stderr.write(`[massu] cloud sync: discarded ${rows.length} queued upload(s): ${why}.
|
|
3233
|
+
`);
|
|
3234
|
+
return rows.length;
|
|
3235
|
+
}
|
|
3236
|
+
function allPendingSync(db) {
|
|
3237
|
+
return db.prepare("SELECT id, retry_count, last_error, payload FROM pending_sync").all();
|
|
3205
3238
|
}
|
|
3206
3239
|
function getMemoryMeta(db, key) {
|
|
3207
3240
|
const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
|
|
@@ -3404,7 +3437,9 @@ function dequeuePendingSync(db, limit = 10) {
|
|
|
3404
3437
|
}
|
|
3405
3438
|
}
|
|
3406
3439
|
return db.prepare(
|
|
3407
|
-
|
|
3440
|
+
// Least-retried first: oldest-first retried the same 10 items until they were discarded
|
|
3441
|
+
// while every newer item waited at retry 0 (2026-11-09: 43,492 never attempted).
|
|
3442
|
+
"SELECT id, payload, retry_count FROM pending_sync ORDER BY retry_count ASC, created_at ASC LIMIT ?"
|
|
3408
3443
|
).all(limit);
|
|
3409
3444
|
}
|
|
3410
3445
|
function removePendingSync(db, id) {
|
|
@@ -4077,7 +4112,7 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
|
|
|
4077
4112
|
}
|
|
4078
4113
|
return bestMatch;
|
|
4079
4114
|
}
|
|
4080
|
-
var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
|
|
4115
|
+
var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, PENDING_SYNC_MAX_ITEMS, PENDING_SYNC_MAX_AGE_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
|
|
4081
4116
|
var init_memory_db = __esm({
|
|
4082
4117
|
"src/memory-db.ts"() {
|
|
4083
4118
|
"use strict";
|
|
@@ -4092,6 +4127,8 @@ var init_memory_db = __esm({
|
|
|
4092
4127
|
init_memory_embed_sweep();
|
|
4093
4128
|
MEMORY_SCHEMA_VERSION = 2;
|
|
4094
4129
|
TOOL_COST_EVENTS_RETENTION_DAYS = 90;
|
|
4130
|
+
PENDING_SYNC_MAX_ITEMS = 500;
|
|
4131
|
+
PENDING_SYNC_MAX_AGE_DAYS = 30;
|
|
4095
4132
|
MAX_DRAFT_TEXT_LEN = 16384;
|
|
4096
4133
|
FUNNEL_EVENT_OUTBOX_CAP = 2e4;
|
|
4097
4134
|
_temporalColCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -4219,6 +4256,13 @@ function assertContainedIn(rootDir, candidate, opts = {}) {
|
|
|
4219
4256
|
}
|
|
4220
4257
|
return abs;
|
|
4221
4258
|
}
|
|
4259
|
+
function isSameRealPath(a, b) {
|
|
4260
|
+
try {
|
|
4261
|
+
return realpathSync(a) === realpathSync(b);
|
|
4262
|
+
} catch {
|
|
4263
|
+
return false;
|
|
4264
|
+
}
|
|
4265
|
+
}
|
|
4222
4266
|
function isContainedIn(rootDir, candidate, opts = {}) {
|
|
4223
4267
|
if (candidate.includes("\0")) return false;
|
|
4224
4268
|
const root = resolve6(rootDir);
|
|
@@ -13984,7 +14028,7 @@ init_config();
|
|
|
13984
14028
|
init_corrections_md();
|
|
13985
14029
|
init_db_driver();
|
|
13986
14030
|
import { readFileSync as readFileSync19, existsSync as existsSync24 } from "fs";
|
|
13987
|
-
import { resolve as resolve9 } from "path";
|
|
14031
|
+
import { dirname as dirname13, join as join18, resolve as resolve9 } from "path";
|
|
13988
14032
|
import { parse as parseYaml4 } from "yaml";
|
|
13989
14033
|
|
|
13990
14034
|
// src/capability-advisor.ts
|
|
@@ -14276,18 +14320,69 @@ function checkWindows(pid) {
|
|
|
14276
14320
|
init_hook_failure_signal();
|
|
14277
14321
|
|
|
14278
14322
|
// src/hooks/lib/is-direct-invocation.ts
|
|
14279
|
-
|
|
14323
|
+
init_safe_write();
|
|
14324
|
+
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
14280
14325
|
function isDirectInvocation(moduleUrl) {
|
|
14281
14326
|
const entry = process.argv[1];
|
|
14282
14327
|
if (!entry) return false;
|
|
14283
14328
|
try {
|
|
14284
|
-
|
|
14329
|
+
if (moduleUrl === pathToFileURL(entry).href) return true;
|
|
14285
14330
|
} catch {
|
|
14286
14331
|
return false;
|
|
14287
14332
|
}
|
|
14333
|
+
try {
|
|
14334
|
+
return isSameRealPath(fileURLToPath2(moduleUrl), entry);
|
|
14335
|
+
} catch {
|
|
14336
|
+
return false;
|
|
14337
|
+
}
|
|
14338
|
+
}
|
|
14339
|
+
|
|
14340
|
+
// src/cloud-sync.ts
|
|
14341
|
+
init_config();
|
|
14342
|
+
init_memory_db();
|
|
14343
|
+
init_rule_delivery();
|
|
14344
|
+
|
|
14345
|
+
// src/observation-extractor.ts
|
|
14346
|
+
init_memory_db();
|
|
14347
|
+
init_config();
|
|
14348
|
+
|
|
14349
|
+
// src/cloud-sync.ts
|
|
14350
|
+
var CLOUD_SYNC_REFUSAL_KEY = "cloud_sync_refused";
|
|
14351
|
+
var CLOUD_SYNC_RECHECK_MS = 24 * 60 * 60 * 1e3;
|
|
14352
|
+
function readCloudSyncRefusal(db) {
|
|
14353
|
+
try {
|
|
14354
|
+
const raw = getMemoryMeta(db, CLOUD_SYNC_REFUSAL_KEY);
|
|
14355
|
+
if (!raw) return null;
|
|
14356
|
+
const v = JSON.parse(raw);
|
|
14357
|
+
return v && typeof v.status === "number" ? v : null;
|
|
14358
|
+
} catch {
|
|
14359
|
+
return null;
|
|
14360
|
+
}
|
|
14361
|
+
}
|
|
14362
|
+
function cloudSyncRefusalBanner(db) {
|
|
14363
|
+
const r = readCloudSyncRefusal(db);
|
|
14364
|
+
if (!r) return null;
|
|
14365
|
+
return `=== MASSU CLOUD SYNC PAUSED ===
|
|
14366
|
+
The massu cloud refused uploads from this project (HTTP ${r.status}: ${r.reason || "no reason given"}) on ${r.at}. Nothing is being uploaded or queued; local memory is unaffected. It re-checks once a day and resumes on its own when the account allows it.
|
|
14367
|
+
=== END ===
|
|
14368
|
+
|
|
14369
|
+
`;
|
|
14288
14370
|
}
|
|
14289
14371
|
|
|
14290
14372
|
// src/hooks/session-start.ts
|
|
14373
|
+
import { spawn } from "child_process";
|
|
14374
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
14375
|
+
function startRecallWarmUp() {
|
|
14376
|
+
if (process.env.MASSU_RECALL_WARMUP === "0") return false;
|
|
14377
|
+
try {
|
|
14378
|
+
const recall = join18(dirname13(fileURLToPath3(import.meta.url)), "memory-recall.js");
|
|
14379
|
+
if (!existsSync24(recall)) return false;
|
|
14380
|
+
spawn(process.execPath, [recall, "--warm-cache"], { detached: true, stdio: "ignore" }).unref();
|
|
14381
|
+
return true;
|
|
14382
|
+
} catch {
|
|
14383
|
+
return false;
|
|
14384
|
+
}
|
|
14385
|
+
}
|
|
14291
14386
|
async function main() {
|
|
14292
14387
|
try {
|
|
14293
14388
|
const input = await readStdin();
|
|
@@ -14347,6 +14442,12 @@ Session memory, code intelligence, and governance are now active.
|
|
|
14347
14442
|
const watcherBanner = buildWatcherBanner();
|
|
14348
14443
|
if (watcherBanner) process.stdout.write(watcherBanner);
|
|
14349
14444
|
}
|
|
14445
|
+
try {
|
|
14446
|
+
const syncBanner = cloudSyncRefusalBanner(db);
|
|
14447
|
+
if (syncBanner) process.stdout.write(syncBanner);
|
|
14448
|
+
} catch {
|
|
14449
|
+
}
|
|
14450
|
+
startRecallWarmUp();
|
|
14350
14451
|
try {
|
|
14351
14452
|
const consolidationCfg = resolveConsolidationConfig();
|
|
14352
14453
|
const advisorBlock = await runAdvisors([localModelAdvisor, crossRepoShareAdvisor], {
|
|
@@ -14499,11 +14600,11 @@ Index has ${stats.doc_count} documents, last indexed ${ageHours}h ago. Consider
|
|
|
14499
14600
|
}
|
|
14500
14601
|
sections.sort((a, b) => b.importance - a.importance);
|
|
14501
14602
|
let usedTokens = 0;
|
|
14502
|
-
const headerTokens =
|
|
14603
|
+
const headerTokens = estimateTokens2("=== Massu Memory: Previous Session Context ===\n\n=== END Massu Memory ===\n");
|
|
14503
14604
|
usedTokens += headerTokens;
|
|
14504
14605
|
const includedSections = [];
|
|
14505
14606
|
for (const section of sections) {
|
|
14506
|
-
const sectionTokens =
|
|
14607
|
+
const sectionTokens = estimateTokens2(section.text);
|
|
14507
14608
|
if (usedTokens + sectionTokens <= tokenBudget) {
|
|
14508
14609
|
includedSections.push(section.text);
|
|
14509
14610
|
usedTokens += sectionTokens;
|
|
@@ -14516,7 +14617,7 @@ ${includedSections.join("\n")}
|
|
|
14516
14617
|
=== END Massu Memory ===
|
|
14517
14618
|
`;
|
|
14518
14619
|
}
|
|
14519
|
-
function
|
|
14620
|
+
function estimateTokens2(text) {
|
|
14520
14621
|
return Math.ceil(text.length / 4);
|
|
14521
14622
|
}
|
|
14522
14623
|
async function getGitBranch() {
|
|
@@ -14649,6 +14750,9 @@ function formatAge(ms) {
|
|
|
14649
14750
|
if (isDirectInvocation(import.meta.url)) {
|
|
14650
14751
|
main();
|
|
14651
14752
|
}
|
|
14753
|
+
export {
|
|
14754
|
+
startRecallWarmUp
|
|
14755
|
+
};
|
|
14652
14756
|
/*! Bundled license information:
|
|
14653
14757
|
|
|
14654
14758
|
is-extglob/index.js:
|
|
@@ -2182,6 +2182,8 @@ __export(memory_db_exports, {
|
|
|
2182
2182
|
MEMORY_FILE_TITLE_LIKE: () => MEMORY_FILE_TITLE_LIKE,
|
|
2183
2183
|
MEMORY_FILE_TITLE_PREFIX: () => MEMORY_FILE_TITLE_PREFIX,
|
|
2184
2184
|
MEMORY_SCHEMA_VERSION: () => MEMORY_SCHEMA_VERSION,
|
|
2185
|
+
PENDING_SYNC_MAX_AGE_DAYS: () => PENDING_SYNC_MAX_AGE_DAYS,
|
|
2186
|
+
PENDING_SYNC_MAX_ITEMS: () => PENDING_SYNC_MAX_ITEMS,
|
|
2185
2187
|
TOOL_COST_EVENTS_RETENTION_DAYS: () => TOOL_COST_EVENTS_RETENTION_DAYS,
|
|
2186
2188
|
USAGE_COUNTER_ARMED_KEY: () => USAGE_COUNTER_ARMED_KEY,
|
|
2187
2189
|
addConversationTurn: () => addConversationTurn,
|
|
@@ -2190,6 +2192,7 @@ __export(memory_db_exports, {
|
|
|
2190
2192
|
addSummary: () => addSummary,
|
|
2191
2193
|
addToolCallDetail: () => addToolCallDetail,
|
|
2192
2194
|
addUserPrompt: () => addUserPrompt,
|
|
2195
|
+
allPendingSync: () => allPendingSync,
|
|
2193
2196
|
appendIncidentToFailureClass: () => appendIncidentToFailureClass,
|
|
2194
2197
|
armUsageCounter: () => armUsageCounter,
|
|
2195
2198
|
assignImportance: () => assignImportance,
|
|
@@ -2197,6 +2200,7 @@ __export(memory_db_exports, {
|
|
|
2197
2200
|
createSession: () => createSession,
|
|
2198
2201
|
deduplicateFailedAttempt: () => deduplicateFailedAttempt,
|
|
2199
2202
|
dequeuePendingSync: () => dequeuePendingSync,
|
|
2203
|
+
discardPendingSync: () => discardPendingSync,
|
|
2200
2204
|
embedMissingObservations: () => embedMissingObservations,
|
|
2201
2205
|
endSession: () => endSession,
|
|
2202
2206
|
enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
|
|
@@ -3179,6 +3183,35 @@ function initMemorySchema(db) {
|
|
|
3179
3183
|
}
|
|
3180
3184
|
function enqueueSyncPayload(db, payload) {
|
|
3181
3185
|
db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
|
|
3186
|
+
const overflow = db.prepare(
|
|
3187
|
+
`SELECT id, retry_count, last_error, payload FROM pending_sync
|
|
3188
|
+
WHERE created_at < datetime('now', ?)
|
|
3189
|
+
OR id NOT IN (SELECT id FROM pending_sync ORDER BY created_at DESC, id DESC LIMIT ?)
|
|
3190
|
+
LIMIT 10000`
|
|
3191
|
+
).all(`-${PENDING_SYNC_MAX_AGE_DAYS} days`, PENDING_SYNC_MAX_ITEMS);
|
|
3192
|
+
if (overflow.length > 0) {
|
|
3193
|
+
discardPendingSync(db, overflow, `over the queue limit (${PENDING_SYNC_MAX_ITEMS} items / ${PENDING_SYNC_MAX_AGE_DAYS} days)`);
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
function discardPendingSync(db, rows, why) {
|
|
3197
|
+
if (rows.length === 0) return 0;
|
|
3198
|
+
const rescued = rescueLearningFromStalePayloads(db, rows);
|
|
3199
|
+
for (let i = 0; i < rows.length; i += 500) {
|
|
3200
|
+
const ids = rows.slice(i, i + 500).map((r) => r.id);
|
|
3201
|
+
db.prepare(`DELETE FROM pending_sync WHERE id IN (${ids.map(() => "?").join(",")})`).run(...ids);
|
|
3202
|
+
}
|
|
3203
|
+
if (rescued > 0) {
|
|
3204
|
+
process.stderr.write(
|
|
3205
|
+
`[massu] RESCUED ${rescued} learned rule(s) from ${rows.length} discarded payload(s) \u2014 they were re-queued for delivery, NOT discarded.
|
|
3206
|
+
`
|
|
3207
|
+
);
|
|
3208
|
+
}
|
|
3209
|
+
process.stderr.write(`[massu] cloud sync: discarded ${rows.length} queued upload(s): ${why}.
|
|
3210
|
+
`);
|
|
3211
|
+
return rows.length;
|
|
3212
|
+
}
|
|
3213
|
+
function allPendingSync(db) {
|
|
3214
|
+
return db.prepare("SELECT id, retry_count, last_error, payload FROM pending_sync").all();
|
|
3182
3215
|
}
|
|
3183
3216
|
function getMemoryMeta(db, key) {
|
|
3184
3217
|
const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
|
|
@@ -3381,7 +3414,9 @@ function dequeuePendingSync(db, limit = 10) {
|
|
|
3381
3414
|
}
|
|
3382
3415
|
}
|
|
3383
3416
|
return db.prepare(
|
|
3384
|
-
|
|
3417
|
+
// Least-retried first: oldest-first retried the same 10 items until they were discarded
|
|
3418
|
+
// while every newer item waited at retry 0 (2026-11-09: 43,492 never attempted).
|
|
3419
|
+
"SELECT id, payload, retry_count FROM pending_sync ORDER BY retry_count ASC, created_at ASC LIMIT ?"
|
|
3385
3420
|
).all(limit);
|
|
3386
3421
|
}
|
|
3387
3422
|
function removePendingSync(db, id) {
|
|
@@ -4054,7 +4089,7 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
|
|
|
4054
4089
|
}
|
|
4055
4090
|
return bestMatch;
|
|
4056
4091
|
}
|
|
4057
|
-
var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
|
|
4092
|
+
var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, PENDING_SYNC_MAX_ITEMS, PENDING_SYNC_MAX_AGE_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
|
|
4058
4093
|
var init_memory_db = __esm({
|
|
4059
4094
|
"src/memory-db.ts"() {
|
|
4060
4095
|
"use strict";
|
|
@@ -4069,6 +4104,8 @@ var init_memory_db = __esm({
|
|
|
4069
4104
|
init_memory_embed_sweep();
|
|
4070
4105
|
MEMORY_SCHEMA_VERSION = 2;
|
|
4071
4106
|
TOOL_COST_EVENTS_RETENTION_DAYS = 90;
|
|
4107
|
+
PENDING_SYNC_MAX_ITEMS = 500;
|
|
4108
|
+
PENDING_SYNC_MAX_AGE_DAYS = 30;
|
|
4072
4109
|
MAX_DRAFT_TEXT_LEN = 16384;
|
|
4073
4110
|
FUNNEL_EVENT_OUTBOX_CAP = 2e4;
|
|
4074
4111
|
_temporalColCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -4083,7 +4120,7 @@ var init_memory_db = __esm({
|
|
|
4083
4120
|
init_memory_db();
|
|
4084
4121
|
init_db_driver();
|
|
4085
4122
|
init_config();
|
|
4086
|
-
import { existsSync as
|
|
4123
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, writeFileSync as writeFileSync5, readFileSync as readFileSync7, readdirSync as readdirSync3, openSync as openSync3, fstatSync, readSync, closeSync as closeSync3 } from "fs";
|
|
4087
4124
|
import { join as join7 } from "path";
|
|
4088
4125
|
|
|
4089
4126
|
// src/rule-candidate-detector.ts
|
|
@@ -4395,13 +4432,41 @@ function entitledForTeamSharedPromotion(tier) {
|
|
|
4395
4432
|
init_rule_candidate_store();
|
|
4396
4433
|
init_hook_failure_signal();
|
|
4397
4434
|
|
|
4435
|
+
// src/lib/safe-write.ts
|
|
4436
|
+
import {
|
|
4437
|
+
writeFileSync as writeFileSync4,
|
|
4438
|
+
renameSync,
|
|
4439
|
+
openSync as openSync2,
|
|
4440
|
+
fsyncSync as fsyncSync2,
|
|
4441
|
+
closeSync as closeSync2,
|
|
4442
|
+
existsSync as existsSync10,
|
|
4443
|
+
realpathSync,
|
|
4444
|
+
unlinkSync as unlinkSync2,
|
|
4445
|
+
accessSync as accessSync2,
|
|
4446
|
+
statSync as statSync2,
|
|
4447
|
+
chmodSync as chmodSync3,
|
|
4448
|
+
constants
|
|
4449
|
+
} from "fs";
|
|
4450
|
+
function isSameRealPath(a, b) {
|
|
4451
|
+
try {
|
|
4452
|
+
return realpathSync(a) === realpathSync(b);
|
|
4453
|
+
} catch {
|
|
4454
|
+
return false;
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
|
|
4398
4458
|
// src/hooks/lib/is-direct-invocation.ts
|
|
4399
|
-
import { pathToFileURL } from "url";
|
|
4459
|
+
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
4400
4460
|
function isDirectInvocation(moduleUrl) {
|
|
4401
4461
|
const entry = process.argv[1];
|
|
4402
4462
|
if (!entry) return false;
|
|
4403
4463
|
try {
|
|
4404
|
-
|
|
4464
|
+
if (moduleUrl === pathToFileURL(entry).href) return true;
|
|
4465
|
+
} catch {
|
|
4466
|
+
return false;
|
|
4467
|
+
}
|
|
4468
|
+
try {
|
|
4469
|
+
return isSameRealPath(fileURLToPath2(moduleUrl), entry);
|
|
4405
4470
|
} catch {
|
|
4406
4471
|
return false;
|
|
4407
4472
|
}
|
|
@@ -4439,7 +4504,7 @@ async function main() {
|
|
|
4439
4504
|
const fileRefs = extractFileReferences(prompt);
|
|
4440
4505
|
if (fileRefs.length > 0) {
|
|
4441
4506
|
const knowledgeDbPath = getResolvedPaths().knowledgeDbPath;
|
|
4442
|
-
if (knowledgeDbPath &&
|
|
4507
|
+
if (knowledgeDbPath && existsSync11(knowledgeDbPath)) {
|
|
4443
4508
|
const kdb = openDatabase2(knowledgeDbPath, { readonly: true, selfHeal: false });
|
|
4444
4509
|
try {
|
|
4445
4510
|
const placeholders = fileRefs.map(() => "?").join(",");
|
|
@@ -4499,7 +4564,7 @@ async function main() {
|
|
|
4499
4564
|
mkdirSync8(candidateDir, { recursive: true });
|
|
4500
4565
|
const promptHash = hashPrompt(prompt);
|
|
4501
4566
|
const candidatePath = join7(candidateDir, `${promptHash}.json`);
|
|
4502
|
-
if (!
|
|
4567
|
+
if (!existsSync11(candidatePath)) {
|
|
4503
4568
|
upsertCandidate(db, hookInput.cwd, {
|
|
4504
4569
|
prompt,
|
|
4505
4570
|
prompt_hash: promptHash,
|
|
@@ -4524,7 +4589,7 @@ async function main() {
|
|
|
4524
4589
|
}
|
|
4525
4590
|
} else {
|
|
4526
4591
|
const nudgePath = join7(candidateDir, ".last-tier-nudge");
|
|
4527
|
-
if (!
|
|
4592
|
+
if (!existsSync11(nudgePath)) {
|
|
4528
4593
|
mkdirSync8(candidateDir, { recursive: true });
|
|
4529
4594
|
process.stderr.write(
|
|
4530
4595
|
`
|
|
@@ -4532,18 +4597,18 @@ async function main() {
|
|
|
4532
4597
|
|
|
4533
4598
|
`
|
|
4534
4599
|
);
|
|
4535
|
-
|
|
4600
|
+
writeFileSync5(nudgePath, (/* @__PURE__ */ new Date()).toISOString());
|
|
4536
4601
|
}
|
|
4537
4602
|
}
|
|
4538
4603
|
}
|
|
4539
|
-
if (
|
|
4604
|
+
if (existsSync11(candidateDir)) {
|
|
4540
4605
|
const candidates = readdirSync3(candidateDir).filter(
|
|
4541
4606
|
(f) => f.endsWith(".json") && !f.startsWith(".")
|
|
4542
4607
|
);
|
|
4543
4608
|
const candidateCount = candidates.length;
|
|
4544
4609
|
const surfacedPath = join7(candidateDir, ".last-surfaced");
|
|
4545
4610
|
let lastSurfaced = 0;
|
|
4546
|
-
if (
|
|
4611
|
+
if (existsSync11(surfacedPath)) {
|
|
4547
4612
|
const raw = readFileSync7(surfacedPath, "utf-8").trim();
|
|
4548
4613
|
const parsed = parseInt(raw, 10);
|
|
4549
4614
|
if (!Number.isNaN(parsed)) lastSurfaced = parsed;
|
|
@@ -4555,17 +4620,17 @@ async function main() {
|
|
|
4555
4620
|
|
|
4556
4621
|
`
|
|
4557
4622
|
);
|
|
4558
|
-
|
|
4623
|
+
writeFileSync5(surfacedPath, String(candidateCount));
|
|
4559
4624
|
}
|
|
4560
4625
|
}
|
|
4561
4626
|
} catch (candidateErr) {
|
|
4562
4627
|
try {
|
|
4563
4628
|
const dir = join7(hookInput.cwd, ".massu", "rule-candidates");
|
|
4564
|
-
if (!
|
|
4629
|
+
if (!existsSync11(dir)) mkdirSync8(dir, { recursive: true });
|
|
4565
4630
|
const logPath = join7(dir, ".detector-failures.jsonl");
|
|
4566
|
-
const pre =
|
|
4631
|
+
const pre = existsSync11(logPath) ? readFileSync7(logPath, "utf-8") : "";
|
|
4567
4632
|
const sep = pre && !pre.endsWith("\n") ? "\n" : "";
|
|
4568
|
-
|
|
4633
|
+
writeFileSync5(logPath, pre + sep + JSON.stringify({
|
|
4569
4634
|
session_id,
|
|
4570
4635
|
// Security review (plan-2026-05-27): log the prompt HASH, never a
|
|
4571
4636
|
// raw prompt excerpt — the failure log must not persist PII/secrets.
|
|
@@ -4586,13 +4651,13 @@ async function main() {
|
|
|
4586
4651
|
}
|
|
4587
4652
|
function detectPriorAssistantTurn(transcriptPath) {
|
|
4588
4653
|
try {
|
|
4589
|
-
if (!transcriptPath || !
|
|
4654
|
+
if (!transcriptPath || !existsSync11(transcriptPath)) {
|
|
4590
4655
|
return { hadEditOrWrite: false, files: [] };
|
|
4591
4656
|
}
|
|
4592
4657
|
if (!transcriptPath.includes("/.claude/projects/")) {
|
|
4593
4658
|
return { hadEditOrWrite: false, files: [] };
|
|
4594
4659
|
}
|
|
4595
|
-
const fd =
|
|
4660
|
+
const fd = openSync3(transcriptPath, "r");
|
|
4596
4661
|
let buf;
|
|
4597
4662
|
try {
|
|
4598
4663
|
const stats = fstatSync(fd);
|
|
@@ -4601,7 +4666,7 @@ function detectPriorAssistantTurn(transcriptPath) {
|
|
|
4601
4666
|
buf = Buffer.alloc(readLen);
|
|
4602
4667
|
readSync(fd, buf, 0, readLen, offset);
|
|
4603
4668
|
} finally {
|
|
4604
|
-
|
|
4669
|
+
closeSync3(fd);
|
|
4605
4670
|
}
|
|
4606
4671
|
const lines = buf.toString("utf-8").split("\n").filter(Boolean);
|
|
4607
4672
|
const files = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@massu/core",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.7",
|
|
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",
|