@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
|
@@ -2157,6 +2157,8 @@ __export(memory_db_exports, {
|
|
|
2157
2157
|
MEMORY_FILE_TITLE_LIKE: () => MEMORY_FILE_TITLE_LIKE,
|
|
2158
2158
|
MEMORY_FILE_TITLE_PREFIX: () => MEMORY_FILE_TITLE_PREFIX,
|
|
2159
2159
|
MEMORY_SCHEMA_VERSION: () => MEMORY_SCHEMA_VERSION,
|
|
2160
|
+
PENDING_SYNC_MAX_AGE_DAYS: () => PENDING_SYNC_MAX_AGE_DAYS,
|
|
2161
|
+
PENDING_SYNC_MAX_ITEMS: () => PENDING_SYNC_MAX_ITEMS,
|
|
2160
2162
|
TOOL_COST_EVENTS_RETENTION_DAYS: () => TOOL_COST_EVENTS_RETENTION_DAYS,
|
|
2161
2163
|
USAGE_COUNTER_ARMED_KEY: () => USAGE_COUNTER_ARMED_KEY,
|
|
2162
2164
|
addConversationTurn: () => addConversationTurn,
|
|
@@ -2165,6 +2167,7 @@ __export(memory_db_exports, {
|
|
|
2165
2167
|
addSummary: () => addSummary,
|
|
2166
2168
|
addToolCallDetail: () => addToolCallDetail,
|
|
2167
2169
|
addUserPrompt: () => addUserPrompt,
|
|
2170
|
+
allPendingSync: () => allPendingSync,
|
|
2168
2171
|
appendIncidentToFailureClass: () => appendIncidentToFailureClass,
|
|
2169
2172
|
armUsageCounter: () => armUsageCounter,
|
|
2170
2173
|
assignImportance: () => assignImportance,
|
|
@@ -2172,6 +2175,7 @@ __export(memory_db_exports, {
|
|
|
2172
2175
|
createSession: () => createSession,
|
|
2173
2176
|
deduplicateFailedAttempt: () => deduplicateFailedAttempt,
|
|
2174
2177
|
dequeuePendingSync: () => dequeuePendingSync,
|
|
2178
|
+
discardPendingSync: () => discardPendingSync,
|
|
2175
2179
|
embedMissingObservations: () => embedMissingObservations,
|
|
2176
2180
|
endSession: () => endSession,
|
|
2177
2181
|
enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
|
|
@@ -3154,6 +3158,35 @@ function initMemorySchema(db) {
|
|
|
3154
3158
|
}
|
|
3155
3159
|
function enqueueSyncPayload(db, payload) {
|
|
3156
3160
|
db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
|
|
3161
|
+
const overflow = db.prepare(
|
|
3162
|
+
`SELECT id, retry_count, last_error, payload FROM pending_sync
|
|
3163
|
+
WHERE created_at < datetime('now', ?)
|
|
3164
|
+
OR id NOT IN (SELECT id FROM pending_sync ORDER BY created_at DESC, id DESC LIMIT ?)
|
|
3165
|
+
LIMIT 10000`
|
|
3166
|
+
).all(`-${PENDING_SYNC_MAX_AGE_DAYS} days`, PENDING_SYNC_MAX_ITEMS);
|
|
3167
|
+
if (overflow.length > 0) {
|
|
3168
|
+
discardPendingSync(db, overflow, `over the queue limit (${PENDING_SYNC_MAX_ITEMS} items / ${PENDING_SYNC_MAX_AGE_DAYS} days)`);
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
function discardPendingSync(db, rows, why) {
|
|
3172
|
+
if (rows.length === 0) return 0;
|
|
3173
|
+
const rescued = rescueLearningFromStalePayloads(db, rows);
|
|
3174
|
+
for (let i = 0; i < rows.length; i += 500) {
|
|
3175
|
+
const ids = rows.slice(i, i + 500).map((r) => r.id);
|
|
3176
|
+
db.prepare(`DELETE FROM pending_sync WHERE id IN (${ids.map(() => "?").join(",")})`).run(...ids);
|
|
3177
|
+
}
|
|
3178
|
+
if (rescued > 0) {
|
|
3179
|
+
process.stderr.write(
|
|
3180
|
+
`[massu] RESCUED ${rescued} learned rule(s) from ${rows.length} discarded payload(s) \u2014 they were re-queued for delivery, NOT discarded.
|
|
3181
|
+
`
|
|
3182
|
+
);
|
|
3183
|
+
}
|
|
3184
|
+
process.stderr.write(`[massu] cloud sync: discarded ${rows.length} queued upload(s): ${why}.
|
|
3185
|
+
`);
|
|
3186
|
+
return rows.length;
|
|
3187
|
+
}
|
|
3188
|
+
function allPendingSync(db) {
|
|
3189
|
+
return db.prepare("SELECT id, retry_count, last_error, payload FROM pending_sync").all();
|
|
3157
3190
|
}
|
|
3158
3191
|
function getMemoryMeta(db, key) {
|
|
3159
3192
|
const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
|
|
@@ -3356,7 +3389,9 @@ function dequeuePendingSync(db, limit = 10) {
|
|
|
3356
3389
|
}
|
|
3357
3390
|
}
|
|
3358
3391
|
return db.prepare(
|
|
3359
|
-
|
|
3392
|
+
// Least-retried first: oldest-first retried the same 10 items until they were discarded
|
|
3393
|
+
// while every newer item waited at retry 0 (2026-11-09: 43,492 never attempted).
|
|
3394
|
+
"SELECT id, payload, retry_count FROM pending_sync ORDER BY retry_count ASC, created_at ASC LIMIT ?"
|
|
3360
3395
|
).all(limit);
|
|
3361
3396
|
}
|
|
3362
3397
|
function removePendingSync(db, id) {
|
|
@@ -4029,7 +4064,7 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
|
|
|
4029
4064
|
}
|
|
4030
4065
|
return bestMatch;
|
|
4031
4066
|
}
|
|
4032
|
-
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;
|
|
4067
|
+
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;
|
|
4033
4068
|
var init_memory_db = __esm({
|
|
4034
4069
|
"src/memory-db.ts"() {
|
|
4035
4070
|
"use strict";
|
|
@@ -4044,6 +4079,8 @@ var init_memory_db = __esm({
|
|
|
4044
4079
|
init_memory_embed_sweep();
|
|
4045
4080
|
MEMORY_SCHEMA_VERSION = 2;
|
|
4046
4081
|
TOOL_COST_EVENTS_RETENTION_DAYS = 90;
|
|
4082
|
+
PENDING_SYNC_MAX_ITEMS = 500;
|
|
4083
|
+
PENDING_SYNC_MAX_AGE_DAYS = 30;
|
|
4047
4084
|
MAX_DRAFT_TEXT_LEN = 16384;
|
|
4048
4085
|
FUNNEL_EVENT_OUTBOX_CAP = 2e4;
|
|
4049
4086
|
_temporalColCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -4156,13 +4193,41 @@ function toolResponseText(raw) {
|
|
|
4156
4193
|
init_hook_failure_signal();
|
|
4157
4194
|
init_timestamps();
|
|
4158
4195
|
|
|
4196
|
+
// src/lib/safe-write.ts
|
|
4197
|
+
import {
|
|
4198
|
+
writeFileSync as writeFileSync3,
|
|
4199
|
+
renameSync,
|
|
4200
|
+
openSync as openSync2,
|
|
4201
|
+
fsyncSync as fsyncSync2,
|
|
4202
|
+
closeSync as closeSync2,
|
|
4203
|
+
existsSync as existsSync9,
|
|
4204
|
+
realpathSync,
|
|
4205
|
+
unlinkSync as unlinkSync2,
|
|
4206
|
+
accessSync as accessSync2,
|
|
4207
|
+
statSync as statSync2,
|
|
4208
|
+
chmodSync as chmodSync3,
|
|
4209
|
+
constants
|
|
4210
|
+
} from "fs";
|
|
4211
|
+
function isSameRealPath(a, b) {
|
|
4212
|
+
try {
|
|
4213
|
+
return realpathSync(a) === realpathSync(b);
|
|
4214
|
+
} catch {
|
|
4215
|
+
return false;
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4218
|
+
|
|
4159
4219
|
// src/hooks/lib/is-direct-invocation.ts
|
|
4160
|
-
import { pathToFileURL } from "url";
|
|
4220
|
+
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
4161
4221
|
function isDirectInvocation(moduleUrl) {
|
|
4162
4222
|
const entry = process.argv[1];
|
|
4163
4223
|
if (!entry) return false;
|
|
4164
4224
|
try {
|
|
4165
|
-
|
|
4225
|
+
if (moduleUrl === pathToFileURL(entry).href) return true;
|
|
4226
|
+
} catch {
|
|
4227
|
+
return false;
|
|
4228
|
+
}
|
|
4229
|
+
try {
|
|
4230
|
+
return isSameRealPath(fileURLToPath2(moduleUrl), entry);
|
|
4166
4231
|
} catch {
|
|
4167
4232
|
return false;
|
|
4168
4233
|
}
|
|
@@ -2092,6 +2092,8 @@ __export(memory_db_exports, {
|
|
|
2092
2092
|
MEMORY_FILE_TITLE_LIKE: () => MEMORY_FILE_TITLE_LIKE,
|
|
2093
2093
|
MEMORY_FILE_TITLE_PREFIX: () => MEMORY_FILE_TITLE_PREFIX,
|
|
2094
2094
|
MEMORY_SCHEMA_VERSION: () => MEMORY_SCHEMA_VERSION,
|
|
2095
|
+
PENDING_SYNC_MAX_AGE_DAYS: () => PENDING_SYNC_MAX_AGE_DAYS,
|
|
2096
|
+
PENDING_SYNC_MAX_ITEMS: () => PENDING_SYNC_MAX_ITEMS,
|
|
2095
2097
|
TOOL_COST_EVENTS_RETENTION_DAYS: () => TOOL_COST_EVENTS_RETENTION_DAYS,
|
|
2096
2098
|
USAGE_COUNTER_ARMED_KEY: () => USAGE_COUNTER_ARMED_KEY,
|
|
2097
2099
|
addConversationTurn: () => addConversationTurn,
|
|
@@ -2100,6 +2102,7 @@ __export(memory_db_exports, {
|
|
|
2100
2102
|
addSummary: () => addSummary,
|
|
2101
2103
|
addToolCallDetail: () => addToolCallDetail,
|
|
2102
2104
|
addUserPrompt: () => addUserPrompt,
|
|
2105
|
+
allPendingSync: () => allPendingSync,
|
|
2103
2106
|
appendIncidentToFailureClass: () => appendIncidentToFailureClass,
|
|
2104
2107
|
armUsageCounter: () => armUsageCounter,
|
|
2105
2108
|
assignImportance: () => assignImportance,
|
|
@@ -2107,6 +2110,7 @@ __export(memory_db_exports, {
|
|
|
2107
2110
|
createSession: () => createSession,
|
|
2108
2111
|
deduplicateFailedAttempt: () => deduplicateFailedAttempt,
|
|
2109
2112
|
dequeuePendingSync: () => dequeuePendingSync,
|
|
2113
|
+
discardPendingSync: () => discardPendingSync,
|
|
2110
2114
|
embedMissingObservations: () => embedMissingObservations,
|
|
2111
2115
|
endSession: () => endSession,
|
|
2112
2116
|
enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
|
|
@@ -3089,6 +3093,35 @@ function initMemorySchema(db) {
|
|
|
3089
3093
|
}
|
|
3090
3094
|
function enqueueSyncPayload(db, payload) {
|
|
3091
3095
|
db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
|
|
3096
|
+
const overflow = db.prepare(
|
|
3097
|
+
`SELECT id, retry_count, last_error, payload FROM pending_sync
|
|
3098
|
+
WHERE created_at < datetime('now', ?)
|
|
3099
|
+
OR id NOT IN (SELECT id FROM pending_sync ORDER BY created_at DESC, id DESC LIMIT ?)
|
|
3100
|
+
LIMIT 10000`
|
|
3101
|
+
).all(`-${PENDING_SYNC_MAX_AGE_DAYS} days`, PENDING_SYNC_MAX_ITEMS);
|
|
3102
|
+
if (overflow.length > 0) {
|
|
3103
|
+
discardPendingSync(db, overflow, `over the queue limit (${PENDING_SYNC_MAX_ITEMS} items / ${PENDING_SYNC_MAX_AGE_DAYS} days)`);
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
function discardPendingSync(db, rows, why) {
|
|
3107
|
+
if (rows.length === 0) return 0;
|
|
3108
|
+
const rescued = rescueLearningFromStalePayloads(db, rows);
|
|
3109
|
+
for (let i = 0; i < rows.length; i += 500) {
|
|
3110
|
+
const ids = rows.slice(i, i + 500).map((r) => r.id);
|
|
3111
|
+
db.prepare(`DELETE FROM pending_sync WHERE id IN (${ids.map(() => "?").join(",")})`).run(...ids);
|
|
3112
|
+
}
|
|
3113
|
+
if (rescued > 0) {
|
|
3114
|
+
process.stderr.write(
|
|
3115
|
+
`[massu] RESCUED ${rescued} learned rule(s) from ${rows.length} discarded payload(s) \u2014 they were re-queued for delivery, NOT discarded.
|
|
3116
|
+
`
|
|
3117
|
+
);
|
|
3118
|
+
}
|
|
3119
|
+
process.stderr.write(`[massu] cloud sync: discarded ${rows.length} queued upload(s): ${why}.
|
|
3120
|
+
`);
|
|
3121
|
+
return rows.length;
|
|
3122
|
+
}
|
|
3123
|
+
function allPendingSync(db) {
|
|
3124
|
+
return db.prepare("SELECT id, retry_count, last_error, payload FROM pending_sync").all();
|
|
3092
3125
|
}
|
|
3093
3126
|
function getMemoryMeta(db, key) {
|
|
3094
3127
|
const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
|
|
@@ -3291,7 +3324,9 @@ function dequeuePendingSync(db, limit = 10) {
|
|
|
3291
3324
|
}
|
|
3292
3325
|
}
|
|
3293
3326
|
return db.prepare(
|
|
3294
|
-
|
|
3327
|
+
// Least-retried first: oldest-first retried the same 10 items until they were discarded
|
|
3328
|
+
// while every newer item waited at retry 0 (2026-11-09: 43,492 never attempted).
|
|
3329
|
+
"SELECT id, payload, retry_count FROM pending_sync ORDER BY retry_count ASC, created_at ASC LIMIT ?"
|
|
3295
3330
|
).all(limit);
|
|
3296
3331
|
}
|
|
3297
3332
|
function removePendingSync(db, id) {
|
|
@@ -3964,7 +3999,7 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
|
|
|
3964
3999
|
}
|
|
3965
4000
|
return bestMatch;
|
|
3966
4001
|
}
|
|
3967
|
-
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;
|
|
4002
|
+
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;
|
|
3968
4003
|
var init_memory_db = __esm({
|
|
3969
4004
|
"src/memory-db.ts"() {
|
|
3970
4005
|
"use strict";
|
|
@@ -3979,6 +4014,8 @@ var init_memory_db = __esm({
|
|
|
3979
4014
|
init_memory_embed_sweep();
|
|
3980
4015
|
MEMORY_SCHEMA_VERSION = 2;
|
|
3981
4016
|
TOOL_COST_EVENTS_RETENTION_DAYS = 90;
|
|
4017
|
+
PENDING_SYNC_MAX_ITEMS = 500;
|
|
4018
|
+
PENDING_SYNC_MAX_AGE_DAYS = 30;
|
|
3982
4019
|
MAX_DRAFT_TEXT_LEN = 16384;
|
|
3983
4020
|
FUNNEL_EVENT_OUTBOX_CAP = 2e4;
|
|
3984
4021
|
_temporalColCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -4063,7 +4100,7 @@ var init_hook_failure_signal = __esm({
|
|
|
4063
4100
|
// src/hooks/fix-detector.ts
|
|
4064
4101
|
init_config();
|
|
4065
4102
|
import { execFileSync } from "child_process";
|
|
4066
|
-
import { existsSync as
|
|
4103
|
+
import { existsSync as existsSync10, appendFileSync as appendFileSync3, mkdirSync as mkdirSync7, readFileSync as readFileSync6 } from "fs";
|
|
4067
4104
|
import { tmpdir as tmpdir2 } from "os";
|
|
4068
4105
|
import { join as join6 } from "path";
|
|
4069
4106
|
|
|
@@ -4441,20 +4478,47 @@ function writeHookContext(hookEventName, message) {
|
|
|
4441
4478
|
// src/hooks/fix-detector.ts
|
|
4442
4479
|
init_hook_failure_signal();
|
|
4443
4480
|
|
|
4481
|
+
// src/lib/safe-write.ts
|
|
4482
|
+
import {
|
|
4483
|
+
writeFileSync as writeFileSync3,
|
|
4484
|
+
renameSync,
|
|
4485
|
+
openSync as openSync2,
|
|
4486
|
+
fsyncSync as fsyncSync2,
|
|
4487
|
+
closeSync as closeSync2,
|
|
4488
|
+
existsSync as existsSync9,
|
|
4489
|
+
realpathSync,
|
|
4490
|
+
unlinkSync as unlinkSync2,
|
|
4491
|
+
accessSync as accessSync2,
|
|
4492
|
+
statSync as statSync2,
|
|
4493
|
+
chmodSync as chmodSync3,
|
|
4494
|
+
constants
|
|
4495
|
+
} from "fs";
|
|
4496
|
+
function isSameRealPath(a, b) {
|
|
4497
|
+
try {
|
|
4498
|
+
return realpathSync(a) === realpathSync(b);
|
|
4499
|
+
} catch {
|
|
4500
|
+
return false;
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
|
|
4444
4504
|
// src/hooks/lib/is-direct-invocation.ts
|
|
4445
|
-
import { pathToFileURL } from "url";
|
|
4505
|
+
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
4446
4506
|
function isDirectInvocation(moduleUrl) {
|
|
4447
4507
|
const entry = process.argv[1];
|
|
4448
4508
|
if (!entry) return false;
|
|
4449
4509
|
try {
|
|
4450
|
-
|
|
4510
|
+
if (moduleUrl === pathToFileURL(entry).href) return true;
|
|
4511
|
+
} catch {
|
|
4512
|
+
return false;
|
|
4513
|
+
}
|
|
4514
|
+
try {
|
|
4515
|
+
return isSameRealPath(fileURLToPath2(moduleUrl), entry);
|
|
4451
4516
|
} catch {
|
|
4452
4517
|
return false;
|
|
4453
4518
|
}
|
|
4454
4519
|
}
|
|
4455
4520
|
|
|
4456
|
-
// src/hooks/
|
|
4457
|
-
var HOOK_EVENT = "PostToolUse";
|
|
4521
|
+
// src/hooks/lib/test-or-fixture-path.ts
|
|
4458
4522
|
var TEST_OR_FIXTURE_PATH_PATTERNS = [
|
|
4459
4523
|
/(^|\/)(__tests__|__fixtures__|tests?|fixtures?|spec)\//,
|
|
4460
4524
|
/\.(test|spec)\.[cm]?[jt]sx?$/,
|
|
@@ -4463,6 +4527,9 @@ var TEST_OR_FIXTURE_PATH_PATTERNS = [
|
|
|
4463
4527
|
function isTestOrFixturePath(filePath) {
|
|
4464
4528
|
return TEST_OR_FIXTURE_PATH_PATTERNS.some((re) => re.test(filePath));
|
|
4465
4529
|
}
|
|
4530
|
+
|
|
4531
|
+
// src/hooks/fix-detector.ts
|
|
4532
|
+
var HOOK_EVENT = "PostToolUse";
|
|
4466
4533
|
var FIX_HEURISTICS = [
|
|
4467
4534
|
{
|
|
4468
4535
|
name: "removed_broken_code",
|
|
@@ -4580,14 +4647,14 @@ var FIX_HEURISTICS = [
|
|
|
4580
4647
|
];
|
|
4581
4648
|
function getSessionFlagPath(sessionId) {
|
|
4582
4649
|
const dir = join6(tmpdir2(), "massu-auto-learning");
|
|
4583
|
-
if (!
|
|
4650
|
+
if (!existsSync10(dir)) {
|
|
4584
4651
|
mkdirSync7(dir, { recursive: true });
|
|
4585
4652
|
}
|
|
4586
4653
|
return join6(dir, `fixes-${sessionId.slice(0, 12)}.jsonl`);
|
|
4587
4654
|
}
|
|
4588
4655
|
function _stateDir() {
|
|
4589
4656
|
const dir = join6(tmpdir2(), "massu-fix-detector-state");
|
|
4590
|
-
if (!
|
|
4657
|
+
if (!existsSync10(dir)) {
|
|
4591
4658
|
mkdirSync7(dir, { recursive: true });
|
|
4592
4659
|
}
|
|
4593
4660
|
return dir;
|
|
@@ -4602,7 +4669,7 @@ function _cwdHash(cwd) {
|
|
|
4602
4669
|
function isGitWorkTreeFast(cwd) {
|
|
4603
4670
|
try {
|
|
4604
4671
|
const cachePath = join6(_stateDir(), `worktree-${_cwdHash(cwd)}.json`);
|
|
4605
|
-
if (
|
|
4672
|
+
if (existsSync10(cachePath)) {
|
|
4606
4673
|
const cached = JSON.parse(readFileSync6(cachePath, "utf-8"));
|
|
4607
4674
|
const ageMs = Date.now() - cached.ts;
|
|
4608
4675
|
if (ageMs < 36e5) return cached.isWorkTree;
|
|
@@ -4630,7 +4697,7 @@ function _disabledFlagPath(sessionId) {
|
|
|
4630
4697
|
}
|
|
4631
4698
|
function isSessionAutoDisabled(sessionId) {
|
|
4632
4699
|
try {
|
|
4633
|
-
return
|
|
4700
|
+
return existsSync10(_disabledFlagPath(sessionId));
|
|
4634
4701
|
} catch {
|
|
4635
4702
|
return false;
|
|
4636
4703
|
}
|
|
@@ -4648,7 +4715,7 @@ async function main() {
|
|
|
4648
4715
|
const input = await readStdin();
|
|
4649
4716
|
const hookInput = JSON.parse(input);
|
|
4650
4717
|
const filePath = hookInput.tool_input?.file_path;
|
|
4651
|
-
if (!filePath || !
|
|
4718
|
+
if (!filePath || !existsSync10(filePath)) {
|
|
4652
4719
|
process.exit(0);
|
|
4653
4720
|
return;
|
|
4654
4721
|
}
|
|
@@ -2157,6 +2157,8 @@ __export(memory_db_exports, {
|
|
|
2157
2157
|
MEMORY_FILE_TITLE_LIKE: () => MEMORY_FILE_TITLE_LIKE,
|
|
2158
2158
|
MEMORY_FILE_TITLE_PREFIX: () => MEMORY_FILE_TITLE_PREFIX,
|
|
2159
2159
|
MEMORY_SCHEMA_VERSION: () => MEMORY_SCHEMA_VERSION,
|
|
2160
|
+
PENDING_SYNC_MAX_AGE_DAYS: () => PENDING_SYNC_MAX_AGE_DAYS,
|
|
2161
|
+
PENDING_SYNC_MAX_ITEMS: () => PENDING_SYNC_MAX_ITEMS,
|
|
2160
2162
|
TOOL_COST_EVENTS_RETENTION_DAYS: () => TOOL_COST_EVENTS_RETENTION_DAYS,
|
|
2161
2163
|
USAGE_COUNTER_ARMED_KEY: () => USAGE_COUNTER_ARMED_KEY,
|
|
2162
2164
|
addConversationTurn: () => addConversationTurn,
|
|
@@ -2165,6 +2167,7 @@ __export(memory_db_exports, {
|
|
|
2165
2167
|
addSummary: () => addSummary,
|
|
2166
2168
|
addToolCallDetail: () => addToolCallDetail,
|
|
2167
2169
|
addUserPrompt: () => addUserPrompt,
|
|
2170
|
+
allPendingSync: () => allPendingSync,
|
|
2168
2171
|
appendIncidentToFailureClass: () => appendIncidentToFailureClass,
|
|
2169
2172
|
armUsageCounter: () => armUsageCounter,
|
|
2170
2173
|
assignImportance: () => assignImportance,
|
|
@@ -2172,6 +2175,7 @@ __export(memory_db_exports, {
|
|
|
2172
2175
|
createSession: () => createSession,
|
|
2173
2176
|
deduplicateFailedAttempt: () => deduplicateFailedAttempt,
|
|
2174
2177
|
dequeuePendingSync: () => dequeuePendingSync,
|
|
2178
|
+
discardPendingSync: () => discardPendingSync,
|
|
2175
2179
|
embedMissingObservations: () => embedMissingObservations,
|
|
2176
2180
|
endSession: () => endSession,
|
|
2177
2181
|
enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
|
|
@@ -3154,6 +3158,35 @@ function initMemorySchema(db) {
|
|
|
3154
3158
|
}
|
|
3155
3159
|
function enqueueSyncPayload(db, payload) {
|
|
3156
3160
|
db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
|
|
3161
|
+
const overflow = db.prepare(
|
|
3162
|
+
`SELECT id, retry_count, last_error, payload FROM pending_sync
|
|
3163
|
+
WHERE created_at < datetime('now', ?)
|
|
3164
|
+
OR id NOT IN (SELECT id FROM pending_sync ORDER BY created_at DESC, id DESC LIMIT ?)
|
|
3165
|
+
LIMIT 10000`
|
|
3166
|
+
).all(`-${PENDING_SYNC_MAX_AGE_DAYS} days`, PENDING_SYNC_MAX_ITEMS);
|
|
3167
|
+
if (overflow.length > 0) {
|
|
3168
|
+
discardPendingSync(db, overflow, `over the queue limit (${PENDING_SYNC_MAX_ITEMS} items / ${PENDING_SYNC_MAX_AGE_DAYS} days)`);
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
function discardPendingSync(db, rows, why) {
|
|
3172
|
+
if (rows.length === 0) return 0;
|
|
3173
|
+
const rescued = rescueLearningFromStalePayloads(db, rows);
|
|
3174
|
+
for (let i = 0; i < rows.length; i += 500) {
|
|
3175
|
+
const ids = rows.slice(i, i + 500).map((r) => r.id);
|
|
3176
|
+
db.prepare(`DELETE FROM pending_sync WHERE id IN (${ids.map(() => "?").join(",")})`).run(...ids);
|
|
3177
|
+
}
|
|
3178
|
+
if (rescued > 0) {
|
|
3179
|
+
process.stderr.write(
|
|
3180
|
+
`[massu] RESCUED ${rescued} learned rule(s) from ${rows.length} discarded payload(s) \u2014 they were re-queued for delivery, NOT discarded.
|
|
3181
|
+
`
|
|
3182
|
+
);
|
|
3183
|
+
}
|
|
3184
|
+
process.stderr.write(`[massu] cloud sync: discarded ${rows.length} queued upload(s): ${why}.
|
|
3185
|
+
`);
|
|
3186
|
+
return rows.length;
|
|
3187
|
+
}
|
|
3188
|
+
function allPendingSync(db) {
|
|
3189
|
+
return db.prepare("SELECT id, retry_count, last_error, payload FROM pending_sync").all();
|
|
3157
3190
|
}
|
|
3158
3191
|
function getMemoryMeta(db, key) {
|
|
3159
3192
|
const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
|
|
@@ -3356,7 +3389,9 @@ function dequeuePendingSync(db, limit = 10) {
|
|
|
3356
3389
|
}
|
|
3357
3390
|
}
|
|
3358
3391
|
return db.prepare(
|
|
3359
|
-
|
|
3392
|
+
// Least-retried first: oldest-first retried the same 10 items until they were discarded
|
|
3393
|
+
// while every newer item waited at retry 0 (2026-11-09: 43,492 never attempted).
|
|
3394
|
+
"SELECT id, payload, retry_count FROM pending_sync ORDER BY retry_count ASC, created_at ASC LIMIT ?"
|
|
3360
3395
|
).all(limit);
|
|
3361
3396
|
}
|
|
3362
3397
|
function removePendingSync(db, id) {
|
|
@@ -4029,7 +4064,7 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
|
|
|
4029
4064
|
}
|
|
4030
4065
|
return bestMatch;
|
|
4031
4066
|
}
|
|
4032
|
-
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;
|
|
4067
|
+
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;
|
|
4033
4068
|
var init_memory_db = __esm({
|
|
4034
4069
|
"src/memory-db.ts"() {
|
|
4035
4070
|
"use strict";
|
|
@@ -4044,6 +4079,8 @@ var init_memory_db = __esm({
|
|
|
4044
4079
|
init_memory_embed_sweep();
|
|
4045
4080
|
MEMORY_SCHEMA_VERSION = 2;
|
|
4046
4081
|
TOOL_COST_EVENTS_RETENTION_DAYS = 90;
|
|
4082
|
+
PENDING_SYNC_MAX_ITEMS = 500;
|
|
4083
|
+
PENDING_SYNC_MAX_AGE_DAYS = 30;
|
|
4047
4084
|
MAX_DRAFT_TEXT_LEN = 16384;
|
|
4048
4085
|
FUNNEL_EVENT_OUTBOX_CAP = 2e4;
|
|
4049
4086
|
_temporalColCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -4057,7 +4094,7 @@ var init_memory_db = __esm({
|
|
|
4057
4094
|
// src/hooks/incident-pipeline.ts
|
|
4058
4095
|
init_config();
|
|
4059
4096
|
init_memory_db();
|
|
4060
|
-
import { existsSync as
|
|
4097
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, readdirSync as readdirSync2 } from "fs";
|
|
4061
4098
|
import { basename as basename3, resolve as resolve5 } from "path";
|
|
4062
4099
|
|
|
4063
4100
|
// src/hooks/lib/write-hook-message.ts
|
|
@@ -4098,13 +4135,41 @@ function writeHookContext(hookEventName, message) {
|
|
|
4098
4135
|
// src/hooks/incident-pipeline.ts
|
|
4099
4136
|
init_hook_failure_signal();
|
|
4100
4137
|
|
|
4138
|
+
// src/lib/safe-write.ts
|
|
4139
|
+
import {
|
|
4140
|
+
writeFileSync as writeFileSync3,
|
|
4141
|
+
renameSync,
|
|
4142
|
+
openSync as openSync2,
|
|
4143
|
+
fsyncSync as fsyncSync2,
|
|
4144
|
+
closeSync as closeSync2,
|
|
4145
|
+
existsSync as existsSync9,
|
|
4146
|
+
realpathSync,
|
|
4147
|
+
unlinkSync as unlinkSync2,
|
|
4148
|
+
accessSync as accessSync2,
|
|
4149
|
+
statSync as statSync2,
|
|
4150
|
+
chmodSync as chmodSync3,
|
|
4151
|
+
constants
|
|
4152
|
+
} from "fs";
|
|
4153
|
+
function isSameRealPath(a, b) {
|
|
4154
|
+
try {
|
|
4155
|
+
return realpathSync(a) === realpathSync(b);
|
|
4156
|
+
} catch {
|
|
4157
|
+
return false;
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4160
|
+
|
|
4101
4161
|
// src/hooks/lib/is-direct-invocation.ts
|
|
4102
|
-
import { pathToFileURL } from "url";
|
|
4162
|
+
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
4103
4163
|
function isDirectInvocation(moduleUrl) {
|
|
4104
4164
|
const entry = process.argv[1];
|
|
4105
4165
|
if (!entry) return false;
|
|
4106
4166
|
try {
|
|
4107
|
-
|
|
4167
|
+
if (moduleUrl === pathToFileURL(entry).href) return true;
|
|
4168
|
+
} catch {
|
|
4169
|
+
return false;
|
|
4170
|
+
}
|
|
4171
|
+
try {
|
|
4172
|
+
return isSameRealPath(fileURLToPath2(moduleUrl), entry);
|
|
4108
4173
|
} catch {
|
|
4109
4174
|
return false;
|
|
4110
4175
|
}
|
|
@@ -4137,7 +4202,7 @@ async function main() {
|
|
|
4137
4202
|
process.exit(0);
|
|
4138
4203
|
return;
|
|
4139
4204
|
}
|
|
4140
|
-
if (!
|
|
4205
|
+
if (!existsSync10(filePath)) {
|
|
4141
4206
|
process.exit(0);
|
|
4142
4207
|
return;
|
|
4143
4208
|
}
|
|
@@ -4147,7 +4212,7 @@ async function main() {
|
|
|
4147
4212
|
const slug = basename3(filePath, ".md").replace(/^\d{4}-\d{2}-\d{2}-?/, "").toLowerCase();
|
|
4148
4213
|
const memoryDirAbs = resolve5(root, memoryDir);
|
|
4149
4214
|
let hasExistingRule = false;
|
|
4150
|
-
if (
|
|
4215
|
+
if (existsSync10(memoryDirAbs)) {
|
|
4151
4216
|
const ruleFiles = readdirSync2(memoryDirAbs).filter((f) => f.startsWith("feedback_"));
|
|
4152
4217
|
for (const ruleFile of ruleFiles) {
|
|
4153
4218
|
if (ruleFile.toLowerCase().includes(slug.slice(0, 20))) {
|
|
@@ -2086,6 +2086,8 @@ __export(memory_db_exports, {
|
|
|
2086
2086
|
MEMORY_FILE_TITLE_LIKE: () => MEMORY_FILE_TITLE_LIKE,
|
|
2087
2087
|
MEMORY_FILE_TITLE_PREFIX: () => MEMORY_FILE_TITLE_PREFIX,
|
|
2088
2088
|
MEMORY_SCHEMA_VERSION: () => MEMORY_SCHEMA_VERSION,
|
|
2089
|
+
PENDING_SYNC_MAX_AGE_DAYS: () => PENDING_SYNC_MAX_AGE_DAYS,
|
|
2090
|
+
PENDING_SYNC_MAX_ITEMS: () => PENDING_SYNC_MAX_ITEMS,
|
|
2089
2091
|
TOOL_COST_EVENTS_RETENTION_DAYS: () => TOOL_COST_EVENTS_RETENTION_DAYS,
|
|
2090
2092
|
USAGE_COUNTER_ARMED_KEY: () => USAGE_COUNTER_ARMED_KEY,
|
|
2091
2093
|
addConversationTurn: () => addConversationTurn,
|
|
@@ -2094,6 +2096,7 @@ __export(memory_db_exports, {
|
|
|
2094
2096
|
addSummary: () => addSummary,
|
|
2095
2097
|
addToolCallDetail: () => addToolCallDetail,
|
|
2096
2098
|
addUserPrompt: () => addUserPrompt,
|
|
2099
|
+
allPendingSync: () => allPendingSync,
|
|
2097
2100
|
appendIncidentToFailureClass: () => appendIncidentToFailureClass,
|
|
2098
2101
|
armUsageCounter: () => armUsageCounter,
|
|
2099
2102
|
assignImportance: () => assignImportance,
|
|
@@ -2101,6 +2104,7 @@ __export(memory_db_exports, {
|
|
|
2101
2104
|
createSession: () => createSession,
|
|
2102
2105
|
deduplicateFailedAttempt: () => deduplicateFailedAttempt,
|
|
2103
2106
|
dequeuePendingSync: () => dequeuePendingSync,
|
|
2107
|
+
discardPendingSync: () => discardPendingSync,
|
|
2104
2108
|
embedMissingObservations: () => embedMissingObservations,
|
|
2105
2109
|
endSession: () => endSession,
|
|
2106
2110
|
enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
|
|
@@ -3083,6 +3087,35 @@ function initMemorySchema(db) {
|
|
|
3083
3087
|
}
|
|
3084
3088
|
function enqueueSyncPayload(db, payload) {
|
|
3085
3089
|
db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
|
|
3090
|
+
const overflow = db.prepare(
|
|
3091
|
+
`SELECT id, retry_count, last_error, payload FROM pending_sync
|
|
3092
|
+
WHERE created_at < datetime('now', ?)
|
|
3093
|
+
OR id NOT IN (SELECT id FROM pending_sync ORDER BY created_at DESC, id DESC LIMIT ?)
|
|
3094
|
+
LIMIT 10000`
|
|
3095
|
+
).all(`-${PENDING_SYNC_MAX_AGE_DAYS} days`, PENDING_SYNC_MAX_ITEMS);
|
|
3096
|
+
if (overflow.length > 0) {
|
|
3097
|
+
discardPendingSync(db, overflow, `over the queue limit (${PENDING_SYNC_MAX_ITEMS} items / ${PENDING_SYNC_MAX_AGE_DAYS} days)`);
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
function discardPendingSync(db, rows, why) {
|
|
3101
|
+
if (rows.length === 0) return 0;
|
|
3102
|
+
const rescued = rescueLearningFromStalePayloads(db, rows);
|
|
3103
|
+
for (let i = 0; i < rows.length; i += 500) {
|
|
3104
|
+
const ids = rows.slice(i, i + 500).map((r) => r.id);
|
|
3105
|
+
db.prepare(`DELETE FROM pending_sync WHERE id IN (${ids.map(() => "?").join(",")})`).run(...ids);
|
|
3106
|
+
}
|
|
3107
|
+
if (rescued > 0) {
|
|
3108
|
+
process.stderr.write(
|
|
3109
|
+
`[massu] RESCUED ${rescued} learned rule(s) from ${rows.length} discarded payload(s) \u2014 they were re-queued for delivery, NOT discarded.
|
|
3110
|
+
`
|
|
3111
|
+
);
|
|
3112
|
+
}
|
|
3113
|
+
process.stderr.write(`[massu] cloud sync: discarded ${rows.length} queued upload(s): ${why}.
|
|
3114
|
+
`);
|
|
3115
|
+
return rows.length;
|
|
3116
|
+
}
|
|
3117
|
+
function allPendingSync(db) {
|
|
3118
|
+
return db.prepare("SELECT id, retry_count, last_error, payload FROM pending_sync").all();
|
|
3086
3119
|
}
|
|
3087
3120
|
function getMemoryMeta(db, key) {
|
|
3088
3121
|
const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
|
|
@@ -3285,7 +3318,9 @@ function dequeuePendingSync(db, limit = 10) {
|
|
|
3285
3318
|
}
|
|
3286
3319
|
}
|
|
3287
3320
|
return db.prepare(
|
|
3288
|
-
|
|
3321
|
+
// Least-retried first: oldest-first retried the same 10 items until they were discarded
|
|
3322
|
+
// while every newer item waited at retry 0 (2026-11-09: 43,492 never attempted).
|
|
3323
|
+
"SELECT id, payload, retry_count FROM pending_sync ORDER BY retry_count ASC, created_at ASC LIMIT ?"
|
|
3289
3324
|
).all(limit);
|
|
3290
3325
|
}
|
|
3291
3326
|
function removePendingSync(db, id) {
|
|
@@ -3958,7 +3993,7 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
|
|
|
3958
3993
|
}
|
|
3959
3994
|
return bestMatch;
|
|
3960
3995
|
}
|
|
3961
|
-
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;
|
|
3996
|
+
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;
|
|
3962
3997
|
var init_memory_db = __esm({
|
|
3963
3998
|
"src/memory-db.ts"() {
|
|
3964
3999
|
"use strict";
|
|
@@ -3973,6 +4008,8 @@ var init_memory_db = __esm({
|
|
|
3973
4008
|
init_memory_embed_sweep();
|
|
3974
4009
|
MEMORY_SCHEMA_VERSION = 2;
|
|
3975
4010
|
TOOL_COST_EVENTS_RETENTION_DAYS = 90;
|
|
4011
|
+
PENDING_SYNC_MAX_ITEMS = 500;
|
|
4012
|
+
PENDING_SYNC_MAX_AGE_DAYS = 30;
|
|
3976
4013
|
MAX_DRAFT_TEXT_LEN = 16384;
|
|
3977
4014
|
FUNNEL_EVENT_OUTBOX_CAP = 2e4;
|
|
3978
4015
|
_temporalColCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -4092,13 +4129,41 @@ function writeHookContext(hookEventName, message) {
|
|
|
4092
4129
|
// src/hooks/intent-suggester.ts
|
|
4093
4130
|
init_hook_failure_signal();
|
|
4094
4131
|
|
|
4132
|
+
// src/lib/safe-write.ts
|
|
4133
|
+
import {
|
|
4134
|
+
writeFileSync as writeFileSync3,
|
|
4135
|
+
renameSync,
|
|
4136
|
+
openSync as openSync2,
|
|
4137
|
+
fsyncSync as fsyncSync2,
|
|
4138
|
+
closeSync as closeSync2,
|
|
4139
|
+
existsSync as existsSync9,
|
|
4140
|
+
realpathSync,
|
|
4141
|
+
unlinkSync as unlinkSync2,
|
|
4142
|
+
accessSync as accessSync2,
|
|
4143
|
+
statSync as statSync2,
|
|
4144
|
+
chmodSync as chmodSync3,
|
|
4145
|
+
constants
|
|
4146
|
+
} from "fs";
|
|
4147
|
+
function isSameRealPath(a, b) {
|
|
4148
|
+
try {
|
|
4149
|
+
return realpathSync(a) === realpathSync(b);
|
|
4150
|
+
} catch {
|
|
4151
|
+
return false;
|
|
4152
|
+
}
|
|
4153
|
+
}
|
|
4154
|
+
|
|
4095
4155
|
// src/hooks/lib/is-direct-invocation.ts
|
|
4096
|
-
import { pathToFileURL } from "url";
|
|
4156
|
+
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
4097
4157
|
function isDirectInvocation(moduleUrl) {
|
|
4098
4158
|
const entry = process.argv[1];
|
|
4099
4159
|
if (!entry) return false;
|
|
4100
4160
|
try {
|
|
4101
|
-
|
|
4161
|
+
if (moduleUrl === pathToFileURL(entry).href) return true;
|
|
4162
|
+
} catch {
|
|
4163
|
+
return false;
|
|
4164
|
+
}
|
|
4165
|
+
try {
|
|
4166
|
+
return isSameRealPath(fileURLToPath2(moduleUrl), entry);
|
|
4102
4167
|
} catch {
|
|
4103
4168
|
return false;
|
|
4104
4169
|
}
|