@massu/core 1.13.0 → 1.14.0
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 +44 -2
- package/commands/_shared-preamble.md +15 -10
- package/commands/_shared-references/verification-table.md +9 -5
- package/commands/massu-checkpoint.md +31 -15
- package/commands/massu-data.md +24 -10
- package/commands/massu-golden-path/references/phase-5.5-production-verify.md +1 -1
- package/commands/massu-production-verify.md +7 -2
- package/commands/massu-rollback.md +26 -8
- package/commands/massu-security.md +29 -10
- package/dist/cli.js +983 -224
- package/dist/hooks/classify-failure.js +46 -0
- package/dist/hooks/cost-tracker.js +46 -0
- package/dist/hooks/incident-pipeline.js +46 -0
- package/dist/hooks/post-tool-use.js +46 -0
- package/dist/hooks/pre-compact.js +46 -0
- package/dist/hooks/quality-event.js +46 -0
- package/dist/hooks/session-end.js +702 -5
- package/dist/hooks/session-start.js +612 -56
- package/dist/hooks/user-prompt.js +296 -14
- package/package.json +3 -3
- package/commands/massu-autoresearch/references/eval-runner.md +0 -84
- package/commands/massu-autoresearch/references/safety-rails.md +0 -125
- package/commands/massu-autoresearch/references/scoring-protocol.md +0 -151
- package/commands/massu-autoresearch.md +0 -258
- package/commands/massu-command-health.md +0 -132
- package/commands/massu-command-improve.md +0 -232
- package/commands/massu-infra-audit.md +0 -187
package/dist/cli.js
CHANGED
|
@@ -622,8 +622,14 @@ __export(memory_db_exports, {
|
|
|
622
622
|
createSession: () => createSession,
|
|
623
623
|
deduplicateFailedAttempt: () => deduplicateFailedAttempt,
|
|
624
624
|
dequeuePendingSync: () => dequeuePendingSync,
|
|
625
|
+
drainRulePromotionEvents: () => drainRulePromotionEvents,
|
|
626
|
+
drainTeamPromotions: () => drainTeamPromotions,
|
|
627
|
+
drainTeamRevocations: () => drainTeamRevocations,
|
|
625
628
|
endSession: () => endSession,
|
|
629
|
+
enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
|
|
626
630
|
enqueueSyncPayload: () => enqueueSyncPayload,
|
|
631
|
+
enqueueTeamPromotion: () => enqueueTeamPromotion,
|
|
632
|
+
enqueueTeamRevocation: () => enqueueTeamRevocation,
|
|
627
633
|
getConversationTurns: () => getConversationTurns,
|
|
628
634
|
getCrossTaskProgress: () => getCrossTaskProgress,
|
|
629
635
|
getDecisionsAbout: () => getDecisionsAbout,
|
|
@@ -631,8 +637,10 @@ __export(memory_db_exports, {
|
|
|
631
637
|
getFailureClasses: () => getFailureClasses,
|
|
632
638
|
getLastProcessedLine: () => getLastProcessedLine,
|
|
633
639
|
getMemoryDb: () => getMemoryDb,
|
|
640
|
+
getMemoryMeta: () => getMemoryMeta,
|
|
634
641
|
getObservabilityDbSize: () => getObservabilityDbSize,
|
|
635
642
|
getRecentObservations: () => getRecentObservations,
|
|
643
|
+
getRecurrenceCountForPromptHash: () => getRecurrenceCountForPromptHash,
|
|
636
644
|
getSessionStats: () => getSessionStats,
|
|
637
645
|
getSessionSummaries: () => getSessionSummaries,
|
|
638
646
|
getSessionTimeline: () => getSessionTimeline,
|
|
@@ -645,12 +653,14 @@ __export(memory_db_exports, {
|
|
|
645
653
|
pruneOldConversationTurns: () => pruneOldConversationTurns,
|
|
646
654
|
pruneOldObservations: () => pruneOldObservations,
|
|
647
655
|
pruneToolCostEvents: () => pruneToolCostEvents,
|
|
656
|
+
recordTelemetry: () => recordTelemetry,
|
|
648
657
|
removePendingSync: () => removePendingSync,
|
|
649
658
|
sanitizeFts5Query: () => sanitizeFts5Query,
|
|
650
659
|
scoreFailureClasses: () => scoreFailureClasses,
|
|
651
660
|
searchConversationTurns: () => searchConversationTurns,
|
|
652
661
|
searchObservations: () => searchObservations,
|
|
653
|
-
setLastProcessedLine: () => setLastProcessedLine
|
|
662
|
+
setLastProcessedLine: () => setLastProcessedLine,
|
|
663
|
+
setMemoryMeta: () => setMemoryMeta
|
|
654
664
|
});
|
|
655
665
|
import Database from "better-sqlite3";
|
|
656
666
|
import { dirname as dirname2, basename } from "path";
|
|
@@ -1156,6 +1166,45 @@ function initMemorySchema(db) {
|
|
|
1156
1166
|
CREATE INDEX IF NOT EXISTS idx_so_file ON shared_observations(file_path);
|
|
1157
1167
|
CREATE INDEX IF NOT EXISTS idx_so_module ON shared_observations(module);
|
|
1158
1168
|
`);
|
|
1169
|
+
db.exec(`
|
|
1170
|
+
CREATE TABLE IF NOT EXISTS team_promotion_outbound (
|
|
1171
|
+
prompt_hash TEXT PRIMARY KEY,
|
|
1172
|
+
destination TEXT NOT NULL,
|
|
1173
|
+
draft_text TEXT NOT NULL,
|
|
1174
|
+
score REAL,
|
|
1175
|
+
signals_json TEXT NOT NULL DEFAULT '[]',
|
|
1176
|
+
content_hash TEXT NOT NULL,
|
|
1177
|
+
-- PA3-004 (Phase 3 Stream A): hardened-destination publish carries the
|
|
1178
|
+
-- publisher's review attestation so the server CHECK (hardened rows need a
|
|
1179
|
+
-- review_attestation) is satisfiable. hardened=0 for the Phase-2 rows.
|
|
1180
|
+
hardened INTEGER NOT NULL DEFAULT 0,
|
|
1181
|
+
review_attestation_json TEXT,
|
|
1182
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
1183
|
+
);
|
|
1184
|
+
CREATE TABLE IF NOT EXISTS team_revocation_outbound (
|
|
1185
|
+
prompt_hash TEXT PRIMARY KEY,
|
|
1186
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
1187
|
+
);
|
|
1188
|
+
`);
|
|
1189
|
+
db.exec(`
|
|
1190
|
+
CREATE TABLE IF NOT EXISTS rule_promotion_events_outbound (
|
|
1191
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1192
|
+
prompt_hash TEXT NOT NULL,
|
|
1193
|
+
event_type TEXT NOT NULL,
|
|
1194
|
+
metadata_json TEXT NOT NULL DEFAULT '{}',
|
|
1195
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1196
|
+
);
|
|
1197
|
+
CREATE INDEX IF NOT EXISTS idx_rpe_outbound_created ON rule_promotion_events_outbound(created_at);
|
|
1198
|
+
`);
|
|
1199
|
+
db.exec(`
|
|
1200
|
+
CREATE TABLE IF NOT EXISTS analytics_events (
|
|
1201
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1202
|
+
event_type TEXT NOT NULL,
|
|
1203
|
+
event_data TEXT NOT NULL DEFAULT '{}',
|
|
1204
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
1205
|
+
);
|
|
1206
|
+
CREATE INDEX IF NOT EXISTS idx_analytics_events_type ON analytics_events(event_type);
|
|
1207
|
+
`);
|
|
1159
1208
|
db.exec(`
|
|
1160
1209
|
CREATE TABLE IF NOT EXISTS knowledge_conflicts (
|
|
1161
1210
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -1236,6 +1285,13 @@ function initMemorySchema(db) {
|
|
|
1236
1285
|
`ALTER TABLE license_cache ADD COLUMN signed_payload_json TEXT NOT NULL DEFAULT ''`
|
|
1237
1286
|
);
|
|
1238
1287
|
}
|
|
1288
|
+
const outboundCols = db.prepare(`PRAGMA table_info(team_promotion_outbound)`).all();
|
|
1289
|
+
if (!outboundCols.some((c2) => c2.name === "hardened")) {
|
|
1290
|
+
db.exec(`ALTER TABLE team_promotion_outbound ADD COLUMN hardened INTEGER NOT NULL DEFAULT 0`);
|
|
1291
|
+
}
|
|
1292
|
+
if (!outboundCols.some((c2) => c2.name === "review_attestation_json")) {
|
|
1293
|
+
db.exec(`ALTER TABLE team_promotion_outbound ADD COLUMN review_attestation_json TEXT`);
|
|
1294
|
+
}
|
|
1239
1295
|
db.exec(`
|
|
1240
1296
|
CREATE TABLE IF NOT EXISTS failure_classes (
|
|
1241
1297
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -1259,6 +1315,136 @@ function initMemorySchema(db) {
|
|
|
1259
1315
|
function enqueueSyncPayload(db, payload) {
|
|
1260
1316
|
db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
|
|
1261
1317
|
}
|
|
1318
|
+
function getMemoryMeta(db, key) {
|
|
1319
|
+
const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
|
|
1320
|
+
return row ? row.value : null;
|
|
1321
|
+
}
|
|
1322
|
+
function setMemoryMeta(db, key, value) {
|
|
1323
|
+
db.prepare("INSERT OR REPLACE INTO memory_meta (key, value) VALUES (?, ?)").run(key, value);
|
|
1324
|
+
}
|
|
1325
|
+
function enqueueTeamPromotion(db, promo) {
|
|
1326
|
+
db.prepare(`
|
|
1327
|
+
INSERT OR REPLACE INTO team_promotion_outbound
|
|
1328
|
+
(prompt_hash, destination, draft_text, score, signals_json, content_hash, hardened, review_attestation_json, created_at)
|
|
1329
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
1330
|
+
`).run(
|
|
1331
|
+
promo.prompt_hash,
|
|
1332
|
+
promo.destination,
|
|
1333
|
+
promo.draft_text.slice(0, MAX_DRAFT_TEXT_LEN),
|
|
1334
|
+
promo.score ?? null,
|
|
1335
|
+
JSON.stringify(promo.signals ?? []),
|
|
1336
|
+
promo.content_hash,
|
|
1337
|
+
promo.hardened ? 1 : 0,
|
|
1338
|
+
promo.review_attestation !== void 0 ? JSON.stringify(promo.review_attestation) : null
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
function drainTeamPromotions(db) {
|
|
1342
|
+
const rows = db.prepare(`
|
|
1343
|
+
SELECT prompt_hash, destination, draft_text, score, signals_json, content_hash, hardened, review_attestation_json
|
|
1344
|
+
FROM team_promotion_outbound ORDER BY created_at ASC LIMIT 1000
|
|
1345
|
+
`).all();
|
|
1346
|
+
if (rows.length === 0) return [];
|
|
1347
|
+
db.prepare("DELETE FROM team_promotion_outbound").run();
|
|
1348
|
+
return rows.map((r2) => ({
|
|
1349
|
+
prompt_hash: r2.prompt_hash,
|
|
1350
|
+
destination: r2.destination,
|
|
1351
|
+
draft_text: r2.draft_text,
|
|
1352
|
+
score: r2.score ?? void 0,
|
|
1353
|
+
signals: safeJsonArray(r2.signals_json),
|
|
1354
|
+
content_hash: r2.content_hash,
|
|
1355
|
+
hardened: r2.hardened === 1,
|
|
1356
|
+
review_attestation: r2.review_attestation_json ? safeJsonParse(r2.review_attestation_json) : void 0
|
|
1357
|
+
}));
|
|
1358
|
+
}
|
|
1359
|
+
function enqueueTeamRevocation(db, promptHash) {
|
|
1360
|
+
db.prepare(`
|
|
1361
|
+
INSERT OR REPLACE INTO team_revocation_outbound (prompt_hash, created_at)
|
|
1362
|
+
VALUES (?, datetime('now'))
|
|
1363
|
+
`).run(promptHash);
|
|
1364
|
+
}
|
|
1365
|
+
function drainTeamRevocations(db) {
|
|
1366
|
+
const rows = db.prepare(
|
|
1367
|
+
`SELECT prompt_hash FROM team_revocation_outbound ORDER BY created_at ASC LIMIT 1000`
|
|
1368
|
+
).all();
|
|
1369
|
+
if (rows.length === 0) return [];
|
|
1370
|
+
db.prepare("DELETE FROM team_revocation_outbound").run();
|
|
1371
|
+
return rows.map((r2) => r2.prompt_hash);
|
|
1372
|
+
}
|
|
1373
|
+
function getRecurrenceCountForPromptHash(db, promptHash) {
|
|
1374
|
+
try {
|
|
1375
|
+
const row = db.prepare(`
|
|
1376
|
+
SELECT json_extract(metadata, '$.recurrence_count') AS rc
|
|
1377
|
+
FROM audit_log
|
|
1378
|
+
WHERE event_type = 'rule_promoted'
|
|
1379
|
+
AND json_extract(metadata, '$.prompt_hash') = ?
|
|
1380
|
+
LIMIT 1
|
|
1381
|
+
`).get(promptHash);
|
|
1382
|
+
if (!row || row.rc === null || row.rc === void 0) return null;
|
|
1383
|
+
return Number(row.rc);
|
|
1384
|
+
} catch {
|
|
1385
|
+
return null;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
function enqueueRulePromotionEvent(db, ev) {
|
|
1389
|
+
try {
|
|
1390
|
+
db.prepare(`
|
|
1391
|
+
INSERT INTO rule_promotion_events_outbound
|
|
1392
|
+
(prompt_hash, event_type, metadata_json, created_at)
|
|
1393
|
+
VALUES (?, ?, ?, ?)
|
|
1394
|
+
`).run(
|
|
1395
|
+
ev.prompt_hash,
|
|
1396
|
+
ev.event_type,
|
|
1397
|
+
JSON.stringify(ev.metadata ?? {}),
|
|
1398
|
+
ev.created_at
|
|
1399
|
+
);
|
|
1400
|
+
db.prepare(`
|
|
1401
|
+
DELETE FROM rule_promotion_events_outbound
|
|
1402
|
+
WHERE id NOT IN (
|
|
1403
|
+
SELECT id FROM rule_promotion_events_outbound ORDER BY id DESC LIMIT ?
|
|
1404
|
+
)
|
|
1405
|
+
`).run(FUNNEL_EVENT_OUTBOX_CAP);
|
|
1406
|
+
} catch {
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
function drainRulePromotionEvents(db) {
|
|
1410
|
+
const rows = db.prepare(`
|
|
1411
|
+
SELECT id, prompt_hash, event_type, metadata_json, created_at
|
|
1412
|
+
FROM rule_promotion_events_outbound ORDER BY id ASC LIMIT ?
|
|
1413
|
+
`).all(FUNNEL_EVENT_DRAIN_LIMIT);
|
|
1414
|
+
if (rows.length === 0) return [];
|
|
1415
|
+
const maxId = rows[rows.length - 1].id;
|
|
1416
|
+
db.prepare("DELETE FROM rule_promotion_events_outbound WHERE id <= ?").run(maxId);
|
|
1417
|
+
return rows.map((r2) => ({
|
|
1418
|
+
prompt_hash: r2.prompt_hash,
|
|
1419
|
+
event_type: r2.event_type,
|
|
1420
|
+
created_at: r2.created_at,
|
|
1421
|
+
metadata: safeJsonParse(r2.metadata_json) ?? {}
|
|
1422
|
+
}));
|
|
1423
|
+
}
|
|
1424
|
+
function recordTelemetry(db, eventType, data) {
|
|
1425
|
+
try {
|
|
1426
|
+
db.prepare(`
|
|
1427
|
+
INSERT INTO analytics_events (event_type, event_data, created_at)
|
|
1428
|
+
VALUES (?, ?, datetime('now'))
|
|
1429
|
+
`).run(eventType, JSON.stringify(data));
|
|
1430
|
+
} catch {
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
function safeJsonArray(json) {
|
|
1434
|
+
try {
|
|
1435
|
+
const v3 = JSON.parse(json);
|
|
1436
|
+
return Array.isArray(v3) ? v3 : [];
|
|
1437
|
+
} catch {
|
|
1438
|
+
return [];
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
function safeJsonParse(json) {
|
|
1442
|
+
try {
|
|
1443
|
+
return JSON.parse(json);
|
|
1444
|
+
} catch {
|
|
1445
|
+
return void 0;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1262
1448
|
function dequeuePendingSync(db, limit = 10) {
|
|
1263
1449
|
const stale = db.prepare(
|
|
1264
1450
|
"SELECT id, retry_count, last_error FROM pending_sync WHERE retry_count >= 10 LIMIT 10000"
|
|
@@ -1809,12 +1995,15 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
|
|
|
1809
1995
|
}
|
|
1810
1996
|
return bestMatch;
|
|
1811
1997
|
}
|
|
1812
|
-
var TOOL_COST_EVENTS_RETENTION_DAYS;
|
|
1998
|
+
var TOOL_COST_EVENTS_RETENTION_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_DRAIN_LIMIT, FUNNEL_EVENT_OUTBOX_CAP;
|
|
1813
1999
|
var init_memory_db = __esm({
|
|
1814
2000
|
"src/memory-db.ts"() {
|
|
1815
2001
|
"use strict";
|
|
1816
2002
|
init_config();
|
|
1817
2003
|
TOOL_COST_EVENTS_RETENTION_DAYS = 90;
|
|
2004
|
+
MAX_DRAFT_TEXT_LEN = 16384;
|
|
2005
|
+
FUNNEL_EVENT_DRAIN_LIMIT = 5e3;
|
|
2006
|
+
FUNNEL_EVENT_OUTBOX_CAP = 2e4;
|
|
1818
2007
|
}
|
|
1819
2008
|
});
|
|
1820
2009
|
|
|
@@ -14344,26 +14533,13 @@ var init_init = __esm({
|
|
|
14344
14533
|
}
|
|
14345
14534
|
});
|
|
14346
14535
|
|
|
14347
|
-
// src/security/
|
|
14348
|
-
var LICENSE_PUBKEY_ED25519, LICENSE_PUBKEY_FINGERPRINT_HEX, KNOWN_LICENSE_PUBKEY_FINGERPRINTS;
|
|
14349
|
-
var init_license_pubkey_generated = __esm({
|
|
14350
|
-
"src/security/license-pubkey.generated.ts"() {
|
|
14351
|
-
"use strict";
|
|
14352
|
-
LICENSE_PUBKEY_ED25519 = new Uint8Array([39, 136, 108, 146, 85, 233, 119, 252, 223, 226, 123, 155, 234, 168, 200, 150, 36, 249, 174, 6, 130, 146, 125, 196, 136, 224, 202, 150, 53, 228, 114, 15]);
|
|
14353
|
-
LICENSE_PUBKEY_FINGERPRINT_HEX = "18a63d64fdec9e5a368fc45feaa49bed6ced815967e582bc7b8af534f22a9475";
|
|
14354
|
-
KNOWN_LICENSE_PUBKEY_FINGERPRINTS = /* @__PURE__ */ new Set([
|
|
14355
|
-
"18a63d64fdec9e5a368fc45feaa49bed6ced815967e582bc7b8af534f22a9475"
|
|
14356
|
-
]);
|
|
14357
|
-
}
|
|
14358
|
-
});
|
|
14359
|
-
|
|
14360
|
-
// src/security/license-response-verifier.ts
|
|
14536
|
+
// src/security/ed25519-envelope-verifier.ts
|
|
14361
14537
|
import { createPublicKey, verify as cryptoVerify } from "crypto";
|
|
14362
|
-
function
|
|
14363
|
-
if (!
|
|
14538
|
+
function verifyEd25519SignedEnvelope(key, payload) {
|
|
14539
|
+
if (!key.knownFingerprints.has(key.fingerprintHex)) {
|
|
14364
14540
|
return {
|
|
14365
14541
|
kind: "error",
|
|
14366
|
-
reason: `Bundled
|
|
14542
|
+
reason: `Bundled ${key.keyLabel} pubkey fingerprint ${key.fingerprintHex} is not in the trusted allowlist. Possible build-time tamper.`
|
|
14367
14543
|
};
|
|
14368
14544
|
}
|
|
14369
14545
|
const sig = payload._signature;
|
|
@@ -14379,7 +14555,7 @@ function verifyLicenseResponse(payload) {
|
|
|
14379
14555
|
if (!Array.isArray(payloadKeys) || payloadKeys.length === 0) {
|
|
14380
14556
|
return { kind: "error", reason: "Missing _signature_payload_keys" };
|
|
14381
14557
|
}
|
|
14382
|
-
if (typeof sigPubkey === "string" && sigPubkey !==
|
|
14558
|
+
if (typeof sigPubkey === "string" && sigPubkey !== key.fingerprintHex) {
|
|
14383
14559
|
return { kind: "unknown_pubkey", got: sigPubkey };
|
|
14384
14560
|
}
|
|
14385
14561
|
const canonicalObj = {};
|
|
@@ -14389,21 +14565,7 @@ function verifyLicenseResponse(payload) {
|
|
|
14389
14565
|
}
|
|
14390
14566
|
const canonical = JSON.stringify(canonicalObj, [...payloadKeys].sort());
|
|
14391
14567
|
try {
|
|
14392
|
-
const
|
|
14393
|
-
48,
|
|
14394
|
-
42,
|
|
14395
|
-
48,
|
|
14396
|
-
5,
|
|
14397
|
-
6,
|
|
14398
|
-
3,
|
|
14399
|
-
43,
|
|
14400
|
-
101,
|
|
14401
|
-
112,
|
|
14402
|
-
3,
|
|
14403
|
-
33,
|
|
14404
|
-
0
|
|
14405
|
-
]);
|
|
14406
|
-
const der = Buffer.concat([spkiPrefix, Buffer.from(LICENSE_PUBKEY_ED25519)]);
|
|
14568
|
+
const der = Buffer.concat([SPKI_ED25519_PREFIX, Buffer.from(key.pubkeyBytes)]);
|
|
14407
14569
|
const pubkey = createPublicKey({ key: der, format: "der", type: "spki" });
|
|
14408
14570
|
const ok = cryptoVerify(
|
|
14409
14571
|
null,
|
|
@@ -14419,12 +14581,59 @@ function verifyLicenseResponse(payload) {
|
|
|
14419
14581
|
};
|
|
14420
14582
|
}
|
|
14421
14583
|
}
|
|
14584
|
+
var SPKI_ED25519_PREFIX;
|
|
14585
|
+
var init_ed25519_envelope_verifier = __esm({
|
|
14586
|
+
"src/security/ed25519-envelope-verifier.ts"() {
|
|
14587
|
+
"use strict";
|
|
14588
|
+
SPKI_ED25519_PREFIX = Buffer.from([
|
|
14589
|
+
48,
|
|
14590
|
+
42,
|
|
14591
|
+
48,
|
|
14592
|
+
5,
|
|
14593
|
+
6,
|
|
14594
|
+
3,
|
|
14595
|
+
43,
|
|
14596
|
+
101,
|
|
14597
|
+
112,
|
|
14598
|
+
3,
|
|
14599
|
+
33,
|
|
14600
|
+
0
|
|
14601
|
+
]);
|
|
14602
|
+
}
|
|
14603
|
+
});
|
|
14604
|
+
|
|
14605
|
+
// src/security/license-pubkey.generated.ts
|
|
14606
|
+
var LICENSE_PUBKEY_ED25519, LICENSE_PUBKEY_FINGERPRINT_HEX, KNOWN_LICENSE_PUBKEY_FINGERPRINTS;
|
|
14607
|
+
var init_license_pubkey_generated = __esm({
|
|
14608
|
+
"src/security/license-pubkey.generated.ts"() {
|
|
14609
|
+
"use strict";
|
|
14610
|
+
LICENSE_PUBKEY_ED25519 = new Uint8Array([39, 136, 108, 146, 85, 233, 119, 252, 223, 226, 123, 155, 234, 168, 200, 150, 36, 249, 174, 6, 130, 146, 125, 196, 136, 224, 202, 150, 53, 228, 114, 15]);
|
|
14611
|
+
LICENSE_PUBKEY_FINGERPRINT_HEX = "18a63d64fdec9e5a368fc45feaa49bed6ced815967e582bc7b8af534f22a9475";
|
|
14612
|
+
KNOWN_LICENSE_PUBKEY_FINGERPRINTS = /* @__PURE__ */ new Set([
|
|
14613
|
+
"18a63d64fdec9e5a368fc45feaa49bed6ced815967e582bc7b8af534f22a9475"
|
|
14614
|
+
]);
|
|
14615
|
+
}
|
|
14616
|
+
});
|
|
14617
|
+
|
|
14618
|
+
// src/security/license-response-verifier.ts
|
|
14619
|
+
function verifyLicenseResponse(payload) {
|
|
14620
|
+
return verifyEd25519SignedEnvelope(
|
|
14621
|
+
{
|
|
14622
|
+
pubkeyBytes: LICENSE_PUBKEY_ED25519,
|
|
14623
|
+
fingerprintHex: LICENSE_PUBKEY_FINGERPRINT_HEX,
|
|
14624
|
+
knownFingerprints: KNOWN_LICENSE_PUBKEY_FINGERPRINTS,
|
|
14625
|
+
keyLabel: "license"
|
|
14626
|
+
},
|
|
14627
|
+
payload
|
|
14628
|
+
);
|
|
14629
|
+
}
|
|
14422
14630
|
function isLicenseSignatureRequired() {
|
|
14423
14631
|
return process.env.MASSU_REQUIRE_SIGNED_LICENSE === "true";
|
|
14424
14632
|
}
|
|
14425
14633
|
var init_license_response_verifier = __esm({
|
|
14426
14634
|
"src/security/license-response-verifier.ts"() {
|
|
14427
14635
|
"use strict";
|
|
14636
|
+
init_ed25519_envelope_verifier();
|
|
14428
14637
|
init_license_pubkey_generated();
|
|
14429
14638
|
}
|
|
14430
14639
|
});
|
|
@@ -14540,7 +14749,7 @@ async function validateLicense(apiKey) {
|
|
|
14540
14749
|
}
|
|
14541
14750
|
if (cached && trusted) {
|
|
14542
14751
|
const lastValidated = new Date(cached.last_validated);
|
|
14543
|
-
const sevenDaysAgo = new Date(Date.now() -
|
|
14752
|
+
const sevenDaysAgo = new Date(Date.now() - GRACE_PERIOD_MS);
|
|
14544
14753
|
if (lastValidated > sevenDaysAgo) {
|
|
14545
14754
|
return trusted;
|
|
14546
14755
|
}
|
|
@@ -14591,7 +14800,8 @@ function readTrustedCache(cached) {
|
|
|
14591
14800
|
const tier = verifiedPlan ? PLAN_TO_TIER_MAP[verifiedPlan] ?? "free" : verifiedTierField ?? "free";
|
|
14592
14801
|
const validUntil = typeof parsed.validUntil === "string" ? parsed.validUntil : "";
|
|
14593
14802
|
const features = Array.isArray(parsed.features) ? parsed.features : [];
|
|
14594
|
-
|
|
14803
|
+
const orgId = typeof parsed.orgId === "string" && parsed.orgId.length > 0 ? parsed.orgId : void 0;
|
|
14804
|
+
return { tier, validUntil, features, orgId };
|
|
14595
14805
|
}
|
|
14596
14806
|
async function getCurrentTier() {
|
|
14597
14807
|
if (cachedTier && Date.now() - cachedTierTimestamp < IN_MEMORY_CACHE_TTL_MS) {
|
|
@@ -14609,6 +14819,64 @@ async function getCurrentTier() {
|
|
|
14609
14819
|
cachedTierTimestamp = Date.now();
|
|
14610
14820
|
return info.tier;
|
|
14611
14821
|
}
|
|
14822
|
+
function getCachedTierReadOnly(memDb) {
|
|
14823
|
+
const config = getConfig();
|
|
14824
|
+
const apiKey = config.cloud?.apiKey;
|
|
14825
|
+
if (!apiKey) return "free";
|
|
14826
|
+
const ownsDb = !memDb;
|
|
14827
|
+
const db = memDb ?? getMemoryDb();
|
|
14828
|
+
try {
|
|
14829
|
+
const keyHash = createHash5("sha256").update(apiKey).digest("hex");
|
|
14830
|
+
const cached = db.prepare(
|
|
14831
|
+
"SELECT tier, valid_until, last_validated, features, signed_payload_json FROM license_cache WHERE api_key_hash = ?"
|
|
14832
|
+
).get(keyHash);
|
|
14833
|
+
if (!cached) return "free";
|
|
14834
|
+
const trusted = readTrustedCache(cached);
|
|
14835
|
+
if (!trusted) return "free";
|
|
14836
|
+
const lastValidated = new Date(cached.last_validated);
|
|
14837
|
+
const sevenDaysAgo = new Date(Date.now() - GRACE_PERIOD_MS);
|
|
14838
|
+
if (!(lastValidated > sevenDaysAgo)) return "free";
|
|
14839
|
+
return trusted.tier;
|
|
14840
|
+
} catch {
|
|
14841
|
+
return "free";
|
|
14842
|
+
} finally {
|
|
14843
|
+
if (ownsDb) {
|
|
14844
|
+
try {
|
|
14845
|
+
db.close();
|
|
14846
|
+
} catch {
|
|
14847
|
+
}
|
|
14848
|
+
}
|
|
14849
|
+
}
|
|
14850
|
+
}
|
|
14851
|
+
function getCachedOrgId(memDb) {
|
|
14852
|
+
const config = getConfig();
|
|
14853
|
+
const apiKey = config.cloud?.apiKey;
|
|
14854
|
+
if (!apiKey) return null;
|
|
14855
|
+
const ownsDb = !memDb;
|
|
14856
|
+
const db = memDb ?? getMemoryDb();
|
|
14857
|
+
try {
|
|
14858
|
+
const keyHash = createHash5("sha256").update(apiKey).digest("hex");
|
|
14859
|
+
const cached = db.prepare(
|
|
14860
|
+
"SELECT tier, valid_until, last_validated, features, signed_payload_json FROM license_cache WHERE api_key_hash = ?"
|
|
14861
|
+
).get(keyHash);
|
|
14862
|
+
if (!cached) return null;
|
|
14863
|
+
const trusted = readTrustedCache(cached);
|
|
14864
|
+
if (!trusted) return null;
|
|
14865
|
+
const lastValidated = new Date(cached.last_validated);
|
|
14866
|
+
const sevenDaysAgo = new Date(Date.now() - GRACE_PERIOD_MS);
|
|
14867
|
+
if (!(lastValidated > sevenDaysAgo)) return null;
|
|
14868
|
+
return trusted.orgId ?? null;
|
|
14869
|
+
} catch {
|
|
14870
|
+
return null;
|
|
14871
|
+
} finally {
|
|
14872
|
+
if (ownsDb) {
|
|
14873
|
+
try {
|
|
14874
|
+
db.close();
|
|
14875
|
+
} catch {
|
|
14876
|
+
}
|
|
14877
|
+
}
|
|
14878
|
+
}
|
|
14879
|
+
}
|
|
14612
14880
|
async function getLicenseInfo() {
|
|
14613
14881
|
if (!cachedTier || Date.now() - cachedTierTimestamp >= IN_MEMORY_CACHE_TTL_MS) {
|
|
14614
14882
|
await getCurrentTier();
|
|
@@ -14675,7 +14943,7 @@ async function handleLicenseToolCall(name, _args, _memDb) {
|
|
|
14675
14943
|
}
|
|
14676
14944
|
return { content: [{ type: "text", text: `Unknown license tool: ${name}` }] };
|
|
14677
14945
|
}
|
|
14678
|
-
var _warnedLicenseSig, TIER_LEVELS, TOOL_TIER_MAP, PLAN_TO_TIER_MAP, TIER_LABELS, cachedTier, cachedTierTimestamp, IN_MEMORY_CACHE_TTL_MS;
|
|
14946
|
+
var _warnedLicenseSig, TIER_LEVELS, TOOL_TIER_MAP, PLAN_TO_TIER_MAP, TIER_LABELS, cachedTier, cachedTierTimestamp, IN_MEMORY_CACHE_TTL_MS, GRACE_PERIOD_MS;
|
|
14679
14947
|
var init_license = __esm({
|
|
14680
14948
|
"src/license.ts"() {
|
|
14681
14949
|
"use strict";
|
|
@@ -14789,6 +15057,7 @@ var init_license = __esm({
|
|
|
14789
15057
|
cachedTier = null;
|
|
14790
15058
|
cachedTierTimestamp = 0;
|
|
14791
15059
|
IN_MEMORY_CACHE_TTL_MS = 15 * 60 * 1e3;
|
|
15060
|
+
GRACE_PERIOD_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
14792
15061
|
}
|
|
14793
15062
|
});
|
|
14794
15063
|
|
|
@@ -15307,26 +15576,12 @@ var __filename4, __dirname4, HOOK_NAME_TO_FILE;
|
|
|
15307
15576
|
var init_hook_runner = __esm({
|
|
15308
15577
|
"src/commands/hook-runner.ts"() {
|
|
15309
15578
|
"use strict";
|
|
15579
|
+
init_hook_registry();
|
|
15310
15580
|
__filename4 = fileURLToPath4(import.meta.url);
|
|
15311
15581
|
__dirname4 = dirname8(__filename4);
|
|
15312
|
-
HOOK_NAME_TO_FILE =
|
|
15313
|
-
|
|
15314
|
-
|
|
15315
|
-
"security-gate": "security-gate.js",
|
|
15316
|
-
"pre-delete-check": "pre-delete-check.js",
|
|
15317
|
-
"post-tool-use": "post-tool-use.js",
|
|
15318
|
-
"post-edit-context": "post-edit-context.js",
|
|
15319
|
-
"quality-event": "quality-event.js",
|
|
15320
|
-
"cost-tracker": "cost-tracker.js",
|
|
15321
|
-
"fix-detector": "fix-detector.js",
|
|
15322
|
-
"classify-failure": "classify-failure.js",
|
|
15323
|
-
"incident-pipeline": "incident-pipeline.js",
|
|
15324
|
-
"rule-enforcement-pipeline": "rule-enforcement-pipeline.js",
|
|
15325
|
-
"auto-learning-pipeline": "auto-learning-pipeline.js",
|
|
15326
|
-
"pre-compact": "pre-compact.js",
|
|
15327
|
-
"user-prompt": "user-prompt.js",
|
|
15328
|
-
"intent-suggester": "intent-suggester.js"
|
|
15329
|
-
};
|
|
15582
|
+
HOOK_NAME_TO_FILE = Object.freeze(
|
|
15583
|
+
Object.fromEntries(REGISTERED_HOOKS.map((name) => [name, `${name}.js`]))
|
|
15584
|
+
);
|
|
15330
15585
|
}
|
|
15331
15586
|
});
|
|
15332
15587
|
|
|
@@ -15457,6 +15712,111 @@ var init_permissions2 = __esm({
|
|
|
15457
15712
|
}
|
|
15458
15713
|
});
|
|
15459
15714
|
|
|
15715
|
+
// src/auto-learning-entitlement.ts
|
|
15716
|
+
function autoLearningUpgradeMessage(currentTier) {
|
|
15717
|
+
return `Auto-learning (rule-candidate detection + /massu-rule promotion) is a Pro feature. Your tier: ${currentTier.toUpperCase()}. Upgrade at https://massu.ai/pricing`;
|
|
15718
|
+
}
|
|
15719
|
+
function entitledForTeamSharedPromotion(tier) {
|
|
15720
|
+
return tierLevel(tier) >= tierLevel(TEAM_SHARED_PROMOTION_MIN_TIER);
|
|
15721
|
+
}
|
|
15722
|
+
var TEAM_SHARED_PROMOTION_MIN_TIER;
|
|
15723
|
+
var init_auto_learning_entitlement = __esm({
|
|
15724
|
+
"src/auto-learning-entitlement.ts"() {
|
|
15725
|
+
"use strict";
|
|
15726
|
+
init_license();
|
|
15727
|
+
TEAM_SHARED_PROMOTION_MIN_TIER = "team";
|
|
15728
|
+
}
|
|
15729
|
+
});
|
|
15730
|
+
|
|
15731
|
+
// src/commands/license.ts
|
|
15732
|
+
var license_exports = {};
|
|
15733
|
+
__export(license_exports, {
|
|
15734
|
+
handleLicenseSubcommand: () => handleLicenseSubcommand,
|
|
15735
|
+
printLicenseHelp: () => printLicenseHelp
|
|
15736
|
+
});
|
|
15737
|
+
function isValidTier(value) {
|
|
15738
|
+
return VALID_TIERS.includes(value);
|
|
15739
|
+
}
|
|
15740
|
+
async function handleLicenseSubcommand(args2) {
|
|
15741
|
+
const sub = args2[0];
|
|
15742
|
+
switch (sub) {
|
|
15743
|
+
case "check": {
|
|
15744
|
+
const minIdx = args2.indexOf("--min");
|
|
15745
|
+
if (minIdx === -1 || minIdx === args2.length - 1) {
|
|
15746
|
+
process.stderr.write(
|
|
15747
|
+
"Usage: massu license check --min <free|pro|team|enterprise>\n"
|
|
15748
|
+
);
|
|
15749
|
+
return { exitCode: 2 };
|
|
15750
|
+
}
|
|
15751
|
+
const minRaw = args2[minIdx + 1];
|
|
15752
|
+
if (!isValidTier(minRaw)) {
|
|
15753
|
+
process.stderr.write(
|
|
15754
|
+
`massu: invalid --min tier "${minRaw}" (expected one of: ${VALID_TIERS.join(", ")})
|
|
15755
|
+
`
|
|
15756
|
+
);
|
|
15757
|
+
return { exitCode: 2 };
|
|
15758
|
+
}
|
|
15759
|
+
const min = minRaw;
|
|
15760
|
+
let current;
|
|
15761
|
+
try {
|
|
15762
|
+
current = await getCurrentTier();
|
|
15763
|
+
} catch (err) {
|
|
15764
|
+
process.stderr.write(
|
|
15765
|
+
`massu: could not resolve license tier (${err instanceof Error ? err.message : String(err)})
|
|
15766
|
+
`
|
|
15767
|
+
);
|
|
15768
|
+
return { exitCode: 3 };
|
|
15769
|
+
}
|
|
15770
|
+
if (tierLevel(current) >= tierLevel(min)) {
|
|
15771
|
+
return { exitCode: 0 };
|
|
15772
|
+
}
|
|
15773
|
+
process.stderr.write(autoLearningUpgradeMessage(current) + "\n");
|
|
15774
|
+
return { exitCode: 3 };
|
|
15775
|
+
}
|
|
15776
|
+
case "--help":
|
|
15777
|
+
case "-h":
|
|
15778
|
+
case void 0: {
|
|
15779
|
+
printLicenseHelp();
|
|
15780
|
+
return { exitCode: 0 };
|
|
15781
|
+
}
|
|
15782
|
+
default: {
|
|
15783
|
+
process.stderr.write(`massu: unknown license subcommand: ${sub}
|
|
15784
|
+
`);
|
|
15785
|
+
printLicenseHelp();
|
|
15786
|
+
return { exitCode: 1 };
|
|
15787
|
+
}
|
|
15788
|
+
}
|
|
15789
|
+
}
|
|
15790
|
+
function printLicenseHelp() {
|
|
15791
|
+
process.stdout.write(`
|
|
15792
|
+
massu license <subcommand>
|
|
15793
|
+
|
|
15794
|
+
Subcommands:
|
|
15795
|
+
check --min <tier> Exit 0 if the current license tier is at or above <tier>,
|
|
15796
|
+
else exit 3 with a generic upgrade message on stderr.
|
|
15797
|
+
<tier> is one of: free | pro | team | enterprise.
|
|
15798
|
+
Fail-closed \u2014 any error resolving the tier exits non-zero.
|
|
15799
|
+
|
|
15800
|
+
Use as the first step of a gated command to hard-fail:
|
|
15801
|
+
npx massu license check --min pro || exit 1
|
|
15802
|
+
|
|
15803
|
+
Examples:
|
|
15804
|
+
npx massu license check --min pro
|
|
15805
|
+
npx massu license check --min team
|
|
15806
|
+
|
|
15807
|
+
Documentation: https://massu.ai/docs/reference/license-tiers
|
|
15808
|
+
`);
|
|
15809
|
+
}
|
|
15810
|
+
var VALID_TIERS;
|
|
15811
|
+
var init_license2 = __esm({
|
|
15812
|
+
"src/commands/license.ts"() {
|
|
15813
|
+
"use strict";
|
|
15814
|
+
init_license();
|
|
15815
|
+
init_auto_learning_entitlement();
|
|
15816
|
+
VALID_TIERS = ["free", "pro", "team", "enterprise"];
|
|
15817
|
+
}
|
|
15818
|
+
});
|
|
15819
|
+
|
|
15460
15820
|
// src/changelog-generator.ts
|
|
15461
15821
|
import { existsSync as existsSync14, readFileSync as readFileSync13, readdirSync as readdirSync12 } from "fs";
|
|
15462
15822
|
import { resolve as resolve11 } from "path";
|
|
@@ -15696,12 +16056,397 @@ var init_changelog = __esm({
|
|
|
15696
16056
|
}
|
|
15697
16057
|
});
|
|
15698
16058
|
|
|
16059
|
+
// src/security/promotion-pubkey.generated.ts
|
|
16060
|
+
var PROMOTION_PUBKEY_ED25519, PROMOTION_PUBKEY_FINGERPRINT_HEX, KNOWN_PROMOTION_PUBKEY_FINGERPRINTS;
|
|
16061
|
+
var init_promotion_pubkey_generated = __esm({
|
|
16062
|
+
"src/security/promotion-pubkey.generated.ts"() {
|
|
16063
|
+
"use strict";
|
|
16064
|
+
PROMOTION_PUBKEY_ED25519 = new Uint8Array([107, 161, 33, 17, 189, 44, 193, 128, 252, 155, 188, 236, 100, 163, 23, 146, 219, 155, 216, 139, 134, 72, 211, 182, 151, 122, 209, 151, 135, 65, 167, 26]);
|
|
16065
|
+
PROMOTION_PUBKEY_FINGERPRINT_HEX = "b14e2a73e23c02891e976ec161d339da6c930266c0202828d3187a3bd6e5d83f";
|
|
16066
|
+
KNOWN_PROMOTION_PUBKEY_FINGERPRINTS = /* @__PURE__ */ new Set([
|
|
16067
|
+
"b14e2a73e23c02891e976ec161d339da6c930266c0202828d3187a3bd6e5d83f"
|
|
16068
|
+
]);
|
|
16069
|
+
}
|
|
16070
|
+
});
|
|
16071
|
+
|
|
16072
|
+
// src/security/promotion-envelope-verifier.ts
|
|
16073
|
+
function verifyPromotionEnvelope(payload) {
|
|
16074
|
+
return verifyEd25519SignedEnvelope(
|
|
16075
|
+
{
|
|
16076
|
+
pubkeyBytes: PROMOTION_PUBKEY_ED25519,
|
|
16077
|
+
fingerprintHex: PROMOTION_PUBKEY_FINGERPRINT_HEX,
|
|
16078
|
+
knownFingerprints: KNOWN_PROMOTION_PUBKEY_FINGERPRINTS,
|
|
16079
|
+
keyLabel: "promotion"
|
|
16080
|
+
},
|
|
16081
|
+
payload
|
|
16082
|
+
);
|
|
16083
|
+
}
|
|
16084
|
+
var init_promotion_envelope_verifier = __esm({
|
|
16085
|
+
"src/security/promotion-envelope-verifier.ts"() {
|
|
16086
|
+
"use strict";
|
|
16087
|
+
init_ed25519_envelope_verifier();
|
|
16088
|
+
init_promotion_pubkey_generated();
|
|
16089
|
+
}
|
|
16090
|
+
});
|
|
16091
|
+
|
|
16092
|
+
// src/rule-candidate-hardened.ts
|
|
16093
|
+
var TEAM_HARDENED_SHAREABLE_DESTINATIONS;
|
|
16094
|
+
var init_rule_candidate_hardened = __esm({
|
|
16095
|
+
"src/rule-candidate-hardened.ts"() {
|
|
16096
|
+
"use strict";
|
|
16097
|
+
TEAM_HARDENED_SHAREABLE_DESTINATIONS = [
|
|
16098
|
+
"pattern-scanner",
|
|
16099
|
+
"custom-destination"
|
|
16100
|
+
];
|
|
16101
|
+
}
|
|
16102
|
+
});
|
|
16103
|
+
|
|
16104
|
+
// src/rule-pack-schema.ts
|
|
16105
|
+
function isRuleDestination(value) {
|
|
16106
|
+
return typeof value === "string" && RULE_DESTINATIONS.includes(value);
|
|
16107
|
+
}
|
|
16108
|
+
function isExecutableDestination(destination) {
|
|
16109
|
+
return TEAM_HARDENED_SHAREABLE_DESTINATIONS.includes(destination);
|
|
16110
|
+
}
|
|
16111
|
+
function isNonEmptyString(value) {
|
|
16112
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
16113
|
+
}
|
|
16114
|
+
function validateRulePackRule(rule) {
|
|
16115
|
+
const errors = [];
|
|
16116
|
+
if (typeof rule !== "object" || rule === null || Array.isArray(rule)) {
|
|
16117
|
+
return { valid: false, errors: ["rule must be a non-null object"], requiresHardened: false };
|
|
16118
|
+
}
|
|
16119
|
+
const r2 = rule;
|
|
16120
|
+
if (!isNonEmptyString(r2.title)) {
|
|
16121
|
+
errors.push("missing required field: title");
|
|
16122
|
+
}
|
|
16123
|
+
if (!isNonEmptyString(r2.description)) {
|
|
16124
|
+
errors.push("missing required field: description");
|
|
16125
|
+
}
|
|
16126
|
+
if (!isNonEmptyString(r2.severity)) {
|
|
16127
|
+
errors.push("missing required field: severity");
|
|
16128
|
+
}
|
|
16129
|
+
const destinationKnown = isRuleDestination(r2.destination);
|
|
16130
|
+
if (!destinationKnown) {
|
|
16131
|
+
errors.push(
|
|
16132
|
+
`invalid destination: ${JSON.stringify(r2.destination)} is not a known RuleDestination (one of ${RULE_DESTINATIONS.join(", ")})`
|
|
16133
|
+
);
|
|
16134
|
+
}
|
|
16135
|
+
if (destinationKnown) {
|
|
16136
|
+
const destination = r2.destination;
|
|
16137
|
+
const hasPattern = isNonEmptyString(r2.pattern);
|
|
16138
|
+
const hasCheck = isNonEmptyString(r2.check);
|
|
16139
|
+
const hasTextBody = isNonEmptyString(r2.description);
|
|
16140
|
+
switch (destination) {
|
|
16141
|
+
case "pattern-scanner":
|
|
16142
|
+
if (!hasPattern && !hasCheck) {
|
|
16143
|
+
errors.push(
|
|
16144
|
+
"inert rule: pattern-scanner destination requires a non-empty `pattern` (or a `check` command)"
|
|
16145
|
+
);
|
|
16146
|
+
}
|
|
16147
|
+
break;
|
|
16148
|
+
case "custom-destination":
|
|
16149
|
+
if (!hasPattern && !hasCheck) {
|
|
16150
|
+
errors.push(
|
|
16151
|
+
"inert rule: custom-destination requires a deterministic enforcement body (`pattern` or `check`)"
|
|
16152
|
+
);
|
|
16153
|
+
}
|
|
16154
|
+
break;
|
|
16155
|
+
case "corrections-md":
|
|
16156
|
+
case "claude-md-cr":
|
|
16157
|
+
if (!hasTextBody && !hasPattern && !hasCheck) {
|
|
16158
|
+
errors.push(
|
|
16159
|
+
`inert rule: ${destination} requires a non-empty text body (description)`
|
|
16160
|
+
);
|
|
16161
|
+
}
|
|
16162
|
+
break;
|
|
16163
|
+
}
|
|
16164
|
+
}
|
|
16165
|
+
const requiresHardened = destinationKnown && isExecutableDestination(r2.destination);
|
|
16166
|
+
return { valid: errors.length === 0, errors, requiresHardened };
|
|
16167
|
+
}
|
|
16168
|
+
var RULE_DESTINATIONS;
|
|
16169
|
+
var init_rule_pack_schema = __esm({
|
|
16170
|
+
"src/rule-pack-schema.ts"() {
|
|
16171
|
+
"use strict";
|
|
16172
|
+
init_rule_candidate_hardened();
|
|
16173
|
+
RULE_DESTINATIONS = [
|
|
16174
|
+
"corrections-md",
|
|
16175
|
+
"pattern-scanner",
|
|
16176
|
+
"claude-md-cr",
|
|
16177
|
+
"custom-destination"
|
|
16178
|
+
];
|
|
16179
|
+
}
|
|
16180
|
+
});
|
|
16181
|
+
|
|
16182
|
+
// src/rule-pack-sync.ts
|
|
16183
|
+
import { existsSync as existsSync16, writeFileSync as writeFileSync3, mkdirSync as mkdirSync6 } from "fs";
|
|
16184
|
+
import { join as join11, dirname as dirname9 } from "path";
|
|
16185
|
+
async function pullInstalledPackRules(db, opts = {}) {
|
|
16186
|
+
const config = getConfig();
|
|
16187
|
+
const cloud = config.cloud;
|
|
16188
|
+
const projectRoot = opts.projectRoot ?? getProjectRoot();
|
|
16189
|
+
const tier = opts.tier ?? getCachedTierReadOnly(db);
|
|
16190
|
+
if (!entitledForTeamSharedPromotion(tier)) return { ...ZERO };
|
|
16191
|
+
const endpoint = opts.endpoint ?? cloud?.endpoint;
|
|
16192
|
+
const apiKey = opts.apiKey ?? cloud?.apiKey;
|
|
16193
|
+
if (!endpoint || !apiKey) return { ...ZERO };
|
|
16194
|
+
const ownOrgId = opts.orgId !== void 0 ? opts.orgId : getCachedOrgId(db);
|
|
16195
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
16196
|
+
const timeoutMs = opts.timeoutMs ?? cloud?.requestTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
16197
|
+
const url = `${endpoint}/installed-rules${opts.updatesOnly ? "?updates_only=1" : ""}`;
|
|
16198
|
+
let envelope;
|
|
16199
|
+
try {
|
|
16200
|
+
const res = await fetchImpl(url, {
|
|
16201
|
+
method: "GET",
|
|
16202
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
16203
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
16204
|
+
});
|
|
16205
|
+
if (!res.ok) return { ...ZERO };
|
|
16206
|
+
envelope = await res.json();
|
|
16207
|
+
} catch {
|
|
16208
|
+
return { ...ZERO };
|
|
16209
|
+
}
|
|
16210
|
+
const verdict = verifyPromotionEnvelope(envelope);
|
|
16211
|
+
if (verdict.kind !== "valid") {
|
|
16212
|
+
emitDropTelemetry(db, "pack_rules_envelope_dropped", { reason: verdict.kind });
|
|
16213
|
+
return { ...ZERO, dropped_unverified: countUntrusted(envelope) };
|
|
16214
|
+
}
|
|
16215
|
+
const signedKeys = Array.isArray(envelope._signature_payload_keys) ? envelope._signature_payload_keys : [];
|
|
16216
|
+
if (!signedKeys.includes("orgId") || !signedKeys.includes("packs_json")) {
|
|
16217
|
+
emitDropTelemetry(db, "pack_rules_unsigned_field", {
|
|
16218
|
+
orgId_signed: signedKeys.includes("orgId"),
|
|
16219
|
+
packs_json_signed: signedKeys.includes("packs_json")
|
|
16220
|
+
});
|
|
16221
|
+
return { ...ZERO, dropped_unverified: countUntrusted(envelope) };
|
|
16222
|
+
}
|
|
16223
|
+
const signedOrgId = typeof envelope.orgId === "string" ? envelope.orgId : null;
|
|
16224
|
+
if (!signedOrgId || !ownOrgId || signedOrgId !== ownOrgId) {
|
|
16225
|
+
emitDropTelemetry(db, "pack_rules_org_mismatch", {
|
|
16226
|
+
signed_org_present: !!signedOrgId,
|
|
16227
|
+
own_org_present: !!ownOrgId
|
|
16228
|
+
});
|
|
16229
|
+
return { ...ZERO, dropped_unverified: countUntrusted(envelope) };
|
|
16230
|
+
}
|
|
16231
|
+
const packs = parsePacks(envelope.packs_json);
|
|
16232
|
+
const result = { ...ZERO };
|
|
16233
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
16234
|
+
for (const pack of packs) {
|
|
16235
|
+
if (!isValidInstalledPack(pack)) continue;
|
|
16236
|
+
for (const rawRule of pack.rules) {
|
|
16237
|
+
const validation = validateRulePackRule(rawRule);
|
|
16238
|
+
if (!validation.valid) {
|
|
16239
|
+
result.skipped += 1;
|
|
16240
|
+
continue;
|
|
16241
|
+
}
|
|
16242
|
+
const rule = rawRule;
|
|
16243
|
+
result.pulled += 1;
|
|
16244
|
+
const promptHash = packRulePromptHash(pack.slug, rule);
|
|
16245
|
+
const candidatePath = sidecarPath(projectRoot, promptHash);
|
|
16246
|
+
if (existsSync16(candidatePath) || alreadyApplied(db, promptHash)) {
|
|
16247
|
+
result.skipped += 1;
|
|
16248
|
+
continue;
|
|
16249
|
+
}
|
|
16250
|
+
materializeCandidate(projectRoot, candidatePath, promptHash, rule, pack, signedOrgId, nowIso);
|
|
16251
|
+
result.materialized += 1;
|
|
16252
|
+
}
|
|
16253
|
+
}
|
|
16254
|
+
return result;
|
|
16255
|
+
}
|
|
16256
|
+
function parsePacks(json) {
|
|
16257
|
+
if (typeof json !== "string") return [];
|
|
16258
|
+
try {
|
|
16259
|
+
const v3 = JSON.parse(json);
|
|
16260
|
+
return Array.isArray(v3) ? v3 : [];
|
|
16261
|
+
} catch {
|
|
16262
|
+
return [];
|
|
16263
|
+
}
|
|
16264
|
+
}
|
|
16265
|
+
function countUntrusted(envelope) {
|
|
16266
|
+
const packs = parsePacks(envelope.packs_json);
|
|
16267
|
+
let n = 0;
|
|
16268
|
+
for (const p19 of packs) {
|
|
16269
|
+
if (p19 && Array.isArray(p19.rules)) n += p19.rules.length;
|
|
16270
|
+
}
|
|
16271
|
+
return n > 0 ? n : 1;
|
|
16272
|
+
}
|
|
16273
|
+
function isValidInstalledPack(p19) {
|
|
16274
|
+
if (!p19 || typeof p19 !== "object") return false;
|
|
16275
|
+
const r2 = p19;
|
|
16276
|
+
return typeof r2.slug === "string" && r2.slug.length > 0 && Array.isArray(r2.rules);
|
|
16277
|
+
}
|
|
16278
|
+
function packRulePromptHash(slug, rule) {
|
|
16279
|
+
const { createHash: createHash10 } = __require("node:crypto");
|
|
16280
|
+
const body = `${slug}\0${rule.destination}\0${rule.title}\0${rule.pattern ?? rule.check ?? rule.description}`;
|
|
16281
|
+
return createHash10("sha256").update(body, "utf-8").digest("hex").slice(0, 16);
|
|
16282
|
+
}
|
|
16283
|
+
function sidecarPath(projectRoot, promptHash) {
|
|
16284
|
+
return join11(projectRoot, ".massu", "rule-candidates", `${promptHash}.json`);
|
|
16285
|
+
}
|
|
16286
|
+
function alreadyApplied(db, promptHash) {
|
|
16287
|
+
try {
|
|
16288
|
+
const row = db.prepare(
|
|
16289
|
+
`SELECT 1 FROM audit_log WHERE event_type = 'rule_promoted'
|
|
16290
|
+
AND json_extract(metadata, '$.prompt_hash') = ? LIMIT 1`
|
|
16291
|
+
).get(promptHash);
|
|
16292
|
+
return !!row;
|
|
16293
|
+
} catch {
|
|
16294
|
+
return false;
|
|
16295
|
+
}
|
|
16296
|
+
}
|
|
16297
|
+
function materializeCandidate(projectRoot, candidatePath, promptHash, rule, pack, orgId, nowIso) {
|
|
16298
|
+
const promptText = `${rule.title}: ${rule.description}`.replace(/\n+/g, " ").slice(0, 200) || `pack rule ${promptHash}`;
|
|
16299
|
+
const draftText = rule.pattern ?? rule.check ?? rule.description;
|
|
16300
|
+
const hardened = isExecutableDestination(rule.destination);
|
|
16301
|
+
const sidecar = {
|
|
16302
|
+
// Standard RuleCandidatePayload fields (so `/massu-rule approve` → readCandidate
|
|
16303
|
+
// → validateCandidatePayload passes), synthesized from the pack rule.
|
|
16304
|
+
prompt: promptText,
|
|
16305
|
+
prompt_hash: promptHash,
|
|
16306
|
+
score: 0,
|
|
16307
|
+
signals: [],
|
|
16308
|
+
prior_turn_files: [],
|
|
16309
|
+
timestamp: nowIso,
|
|
16310
|
+
session_id: `pack:${pack.slug}`,
|
|
16311
|
+
// Provenance (P2-002/P2-003): the applier's team-origin / hardened apply-gate
|
|
16312
|
+
// keys on this. `origin:'pack'` rides the SAME gate as a team origin
|
|
16313
|
+
// (tier≥Team + signature_verified + shareable/hardened destination). A
|
|
16314
|
+
// hardened (executable-destination) materialization sets `hardened:true` so
|
|
16315
|
+
// the operator's `/massu-rule review` (render-only preview + a distinct
|
|
16316
|
+
// second-operator attestation) is required before `approve`.
|
|
16317
|
+
provenance: {
|
|
16318
|
+
origin: "pack",
|
|
16319
|
+
org_id: orgId,
|
|
16320
|
+
promoted_by: `pack:${pack.slug}`,
|
|
16321
|
+
promoted_at: nowIso,
|
|
16322
|
+
signature_verified: true,
|
|
16323
|
+
pack_slug: pack.slug,
|
|
16324
|
+
pack_version: pack.current_version,
|
|
16325
|
+
...hardened ? { hardened: true } : {}
|
|
16326
|
+
},
|
|
16327
|
+
// Extra fields the `/massu-rule approve` flow reads to drive the apply (the
|
|
16328
|
+
// pack author already decided destination + body). validateCandidatePayload
|
|
16329
|
+
// ignores unknown keys.
|
|
16330
|
+
destination: rule.destination,
|
|
16331
|
+
draft_text: draftText
|
|
16332
|
+
};
|
|
16333
|
+
const dir = dirname9(candidatePath);
|
|
16334
|
+
if (!existsSync16(dir)) mkdirSync6(dir, { recursive: true });
|
|
16335
|
+
writeFileSync3(candidatePath, JSON.stringify(sidecar, null, 2), "utf-8");
|
|
16336
|
+
}
|
|
16337
|
+
function emitDropTelemetry(db, eventType, data) {
|
|
16338
|
+
recordTelemetry(db, eventType, data);
|
|
16339
|
+
process.stderr.write(
|
|
16340
|
+
`[massu] installed-pack rules pull: dropped envelope (${eventType}). A signed/org-matched response is required \u2014 see massu.ai for details.
|
|
16341
|
+
`
|
|
16342
|
+
);
|
|
16343
|
+
}
|
|
16344
|
+
var DEFAULT_TIMEOUT_MS, ZERO;
|
|
16345
|
+
var init_rule_pack_sync = __esm({
|
|
16346
|
+
"src/rule-pack-sync.ts"() {
|
|
16347
|
+
"use strict";
|
|
16348
|
+
init_config();
|
|
16349
|
+
init_license();
|
|
16350
|
+
init_auto_learning_entitlement();
|
|
16351
|
+
init_promotion_envelope_verifier();
|
|
16352
|
+
init_rule_pack_schema();
|
|
16353
|
+
init_memory_db();
|
|
16354
|
+
DEFAULT_TIMEOUT_MS = 2e3;
|
|
16355
|
+
ZERO = {
|
|
16356
|
+
pulled: 0,
|
|
16357
|
+
materialized: 0,
|
|
16358
|
+
skipped: 0,
|
|
16359
|
+
dropped_unverified: 0
|
|
16360
|
+
};
|
|
16361
|
+
}
|
|
16362
|
+
});
|
|
16363
|
+
|
|
16364
|
+
// src/commands/rule.ts
|
|
16365
|
+
var rule_exports = {};
|
|
16366
|
+
__export(rule_exports, {
|
|
16367
|
+
handleRuleSubcommand: () => handleRuleSubcommand
|
|
16368
|
+
});
|
|
16369
|
+
async function handleRuleSubcommand(args2) {
|
|
16370
|
+
const sub = args2[0];
|
|
16371
|
+
switch (sub) {
|
|
16372
|
+
case "record-shown": {
|
|
16373
|
+
const promptHash = args2[1];
|
|
16374
|
+
if (!promptHash || !PROMPT_HASH_RE.test(promptHash)) {
|
|
16375
|
+
process.stderr.write(
|
|
16376
|
+
"Usage: massu rule record-shown <prompt_hash> (16-hex)\n"
|
|
16377
|
+
);
|
|
16378
|
+
return { exitCode: 2 };
|
|
16379
|
+
}
|
|
16380
|
+
try {
|
|
16381
|
+
const db = getMemoryDb();
|
|
16382
|
+
try {
|
|
16383
|
+
if (entitledForTeamSharedPromotion(getCachedTierReadOnly(db))) {
|
|
16384
|
+
enqueueRulePromotionEvent(db, {
|
|
16385
|
+
prompt_hash: promptHash,
|
|
16386
|
+
event_type: "shown",
|
|
16387
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16388
|
+
metadata: {}
|
|
16389
|
+
});
|
|
16390
|
+
}
|
|
16391
|
+
} finally {
|
|
16392
|
+
db.close();
|
|
16393
|
+
}
|
|
16394
|
+
} catch {
|
|
16395
|
+
}
|
|
16396
|
+
return { exitCode: 0 };
|
|
16397
|
+
}
|
|
16398
|
+
case "packs": {
|
|
16399
|
+
try {
|
|
16400
|
+
const db = getMemoryDb();
|
|
16401
|
+
try {
|
|
16402
|
+
const res = await pullInstalledPackRules(db);
|
|
16403
|
+
process.stdout.write(
|
|
16404
|
+
`pack rules: pulled=${res.pulled} materialized=${res.materialized} skipped=${res.skipped} dropped_unverified=${res.dropped_unverified}
|
|
16405
|
+
`
|
|
16406
|
+
);
|
|
16407
|
+
} finally {
|
|
16408
|
+
db.close();
|
|
16409
|
+
}
|
|
16410
|
+
} catch {
|
|
16411
|
+
process.stdout.write(
|
|
16412
|
+
"pack rules: pulled=0 materialized=0 skipped=0 dropped_unverified=0\n"
|
|
16413
|
+
);
|
|
16414
|
+
}
|
|
16415
|
+
return { exitCode: 0 };
|
|
16416
|
+
}
|
|
16417
|
+
case "--help":
|
|
16418
|
+
case "-h":
|
|
16419
|
+
case void 0: {
|
|
16420
|
+
process.stdout.write(
|
|
16421
|
+
"massu rule <subcommand>\n\nSubcommands:\n record-shown <prompt_hash> Record a `shown` promotion-funnel event (Team-gated, best-effort).\n packs Pull installed rule-pack rules as reviewable candidates (Team-gated).\n"
|
|
16422
|
+
);
|
|
16423
|
+
return { exitCode: 0 };
|
|
16424
|
+
}
|
|
16425
|
+
default: {
|
|
16426
|
+
process.stderr.write(`massu: unknown rule subcommand: ${sub}
|
|
16427
|
+
`);
|
|
16428
|
+
return { exitCode: 2 };
|
|
16429
|
+
}
|
|
16430
|
+
}
|
|
16431
|
+
}
|
|
16432
|
+
var PROMPT_HASH_RE;
|
|
16433
|
+
var init_rule = __esm({
|
|
16434
|
+
"src/commands/rule.ts"() {
|
|
16435
|
+
"use strict";
|
|
16436
|
+
init_memory_db();
|
|
16437
|
+
init_license();
|
|
16438
|
+
init_auto_learning_entitlement();
|
|
16439
|
+
init_rule_pack_sync();
|
|
16440
|
+
PROMPT_HASH_RE = /^[0-9a-f]{16}$/;
|
|
16441
|
+
}
|
|
16442
|
+
});
|
|
16443
|
+
|
|
15699
16444
|
// src/commands/show-template.ts
|
|
15700
16445
|
var show_template_exports = {};
|
|
15701
16446
|
__export(show_template_exports, {
|
|
15702
16447
|
runShowTemplate: () => runShowTemplate
|
|
15703
16448
|
});
|
|
15704
|
-
import { existsSync as
|
|
16449
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
|
|
15705
16450
|
import { resolve as resolve13 } from "path";
|
|
15706
16451
|
function normalizeBaseName(input) {
|
|
15707
16452
|
return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
|
|
@@ -15731,7 +16476,7 @@ async function runShowTemplate(args2) {
|
|
|
15731
16476
|
}
|
|
15732
16477
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
15733
16478
|
const file = suffix === "" ? resolve13(sourceDir, `${baseName}.md`) : resolve13(sourceDir, `${baseName}${suffix}.md`);
|
|
15734
|
-
if (!
|
|
16479
|
+
if (!existsSync17(file)) {
|
|
15735
16480
|
process.stderr.write(`massu: resolved template "${file}" no longer exists
|
|
15736
16481
|
`);
|
|
15737
16482
|
process.exit(1);
|
|
@@ -15790,8 +16535,8 @@ var init_passthrough = __esm({
|
|
|
15790
16535
|
});
|
|
15791
16536
|
|
|
15792
16537
|
// src/lib/fileLock.ts
|
|
15793
|
-
import { mkdirSync as
|
|
15794
|
-
import { dirname as
|
|
16538
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync16, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
16539
|
+
import { dirname as dirname10 } from "path";
|
|
15795
16540
|
import * as lockfile from "proper-lockfile";
|
|
15796
16541
|
function readLockHolderPid(lockPath) {
|
|
15797
16542
|
try {
|
|
@@ -15814,7 +16559,7 @@ function busyWaitSync(ms) {
|
|
|
15814
16559
|
Atomics.wait(view, 0, 0, ms);
|
|
15815
16560
|
}
|
|
15816
16561
|
function withFileLockSync(lockPath, fn, opts = {}) {
|
|
15817
|
-
|
|
16562
|
+
mkdirSync7(dirname10(lockPath), { recursive: true });
|
|
15818
16563
|
const staleMs = opts.staleMs ?? 3e4;
|
|
15819
16564
|
const blockMs = opts.retries === 0 ? 0 : opts.blockMs ?? 3e4;
|
|
15820
16565
|
const pollIntervalMs = opts.pollIntervalMs ?? 100;
|
|
@@ -15831,7 +16576,7 @@ function withFileLockSync(lockPath, fn, opts = {}) {
|
|
|
15831
16576
|
realpath: false
|
|
15832
16577
|
});
|
|
15833
16578
|
try {
|
|
15834
|
-
|
|
16579
|
+
writeFileSync4(`${lockPath}.pid`, String(process.pid), "utf-8");
|
|
15835
16580
|
} catch {
|
|
15836
16581
|
}
|
|
15837
16582
|
break;
|
|
@@ -15920,7 +16665,7 @@ __export(config_refresh_exports, {
|
|
|
15920
16665
|
mergeRefresh: () => mergeRefresh,
|
|
15921
16666
|
runConfigRefresh: () => runConfigRefresh
|
|
15922
16667
|
});
|
|
15923
|
-
import { existsSync as
|
|
16668
|
+
import { existsSync as existsSync18, readFileSync as readFileSync17, rmSync as rmSync4 } from "fs";
|
|
15924
16669
|
import { resolve as resolve15 } from "path";
|
|
15925
16670
|
import { parse as parseYaml5 } from "yaml";
|
|
15926
16671
|
function flatten(obj, prefix3 = "") {
|
|
@@ -16052,7 +16797,7 @@ async function runConfigRefresh(opts = {}) {
|
|
|
16052
16797
|
const configPath = resolve15(cwd, "massu.config.yaml");
|
|
16053
16798
|
const log = opts.silent ? () => {
|
|
16054
16799
|
} : (s) => process.stdout.write(s);
|
|
16055
|
-
if (!
|
|
16800
|
+
if (!existsSync18(configPath)) {
|
|
16056
16801
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
16057
16802
|
if (!opts.silent) process.stderr.write(message + "\n");
|
|
16058
16803
|
return { exitCode: 1, applied: false, dryRun: !!opts.dryRun, diff: [], message };
|
|
@@ -16133,7 +16878,7 @@ async function runConfigRefresh(opts = {}) {
|
|
|
16133
16878
|
const stackResolved = installResult.totalInstalled > 0 || installResult.totalUpdated > 0;
|
|
16134
16879
|
if (stackResolved) {
|
|
16135
16880
|
const placeholderPath = resolve15(installResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
16136
|
-
if (
|
|
16881
|
+
if (existsSync18(placeholderPath)) {
|
|
16137
16882
|
try {
|
|
16138
16883
|
rmSync4(placeholderPath, { force: true });
|
|
16139
16884
|
log("Removed _massu-needs-stack.md (stack now declared).\n");
|
|
@@ -16242,12 +16987,12 @@ var init_gitToplevel = __esm({
|
|
|
16242
16987
|
});
|
|
16243
16988
|
|
|
16244
16989
|
// src/watch/lockfile-detector.ts
|
|
16245
|
-
import { existsSync as
|
|
16990
|
+
import { existsSync as existsSync19, statSync as statSync8 } from "fs";
|
|
16246
16991
|
import { resolve as resolve16 } from "path";
|
|
16247
16992
|
function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WINDOW_MS) {
|
|
16248
16993
|
for (const lf of KNOWN_LOCKFILES) {
|
|
16249
16994
|
const p19 = resolve16(projectRoot, lf);
|
|
16250
|
-
if (!
|
|
16995
|
+
if (!existsSync19(p19)) continue;
|
|
16251
16996
|
try {
|
|
16252
16997
|
const stat = statSync8(p19);
|
|
16253
16998
|
const delta = now - stat.mtimeMs;
|
|
@@ -16260,7 +17005,7 @@ function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WIN
|
|
|
16260
17005
|
function gitMidOperation(projectRoot) {
|
|
16261
17006
|
const sentinels = ["MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD", "rebase-apply", "rebase-merge"];
|
|
16262
17007
|
for (const s of sentinels) {
|
|
16263
|
-
if (
|
|
17008
|
+
if (existsSync19(resolve16(projectRoot, ".git", s))) return true;
|
|
16264
17009
|
}
|
|
16265
17010
|
return false;
|
|
16266
17011
|
}
|
|
@@ -16457,8 +17202,8 @@ var init_paths = __esm({
|
|
|
16457
17202
|
});
|
|
16458
17203
|
|
|
16459
17204
|
// src/watch/state.ts
|
|
16460
|
-
import { closeSync as closeSync3, existsSync as
|
|
16461
|
-
import { dirname as
|
|
17205
|
+
import { closeSync as closeSync3, existsSync as existsSync20, fsyncSync as fsyncSync3, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync18, renameSync as renameSync4, rmSync as rmSync5, writeFileSync as writeFileSync5, writeSync as writeSync3 } from "fs";
|
|
17206
|
+
import { dirname as dirname11, resolve as resolve17 } from "path";
|
|
16462
17207
|
function watchStatePath(projectRoot) {
|
|
16463
17208
|
return resolve17(projectRoot, ".massu", "watch-state.json");
|
|
16464
17209
|
}
|
|
@@ -16467,7 +17212,7 @@ function backupStatePath(projectRoot) {
|
|
|
16467
17212
|
}
|
|
16468
17213
|
function readState(projectRoot) {
|
|
16469
17214
|
const path = watchStatePath(projectRoot);
|
|
16470
|
-
if (!
|
|
17215
|
+
if (!existsSync20(path)) return { ...DEFAULT_STATE };
|
|
16471
17216
|
const content = readFileSync18(path, "utf-8");
|
|
16472
17217
|
let raw;
|
|
16473
17218
|
try {
|
|
@@ -16510,14 +17255,14 @@ function readState(projectRoot) {
|
|
|
16510
17255
|
}
|
|
16511
17256
|
function archiveCorrupt(projectRoot, content) {
|
|
16512
17257
|
const bak = backupStatePath(projectRoot);
|
|
16513
|
-
|
|
16514
|
-
|
|
17258
|
+
mkdirSync8(dirname11(bak), { recursive: true });
|
|
17259
|
+
writeFileSync5(bak, content, "utf-8");
|
|
16515
17260
|
}
|
|
16516
17261
|
function writeStateAtomic(projectRoot, state) {
|
|
16517
17262
|
const path = watchStatePath(projectRoot);
|
|
16518
17263
|
writeStateAtomicCounter = writeStateAtomicCounter + 1 >>> 0;
|
|
16519
17264
|
const tmp = `${path}.${process.pid}.${writeStateAtomicCounter}.tmp`;
|
|
16520
|
-
|
|
17265
|
+
mkdirSync8(dirname11(path), { recursive: true });
|
|
16521
17266
|
let renamed = false;
|
|
16522
17267
|
try {
|
|
16523
17268
|
const fd = openSync3(tmp, "w");
|
|
@@ -16531,7 +17276,7 @@ function writeStateAtomic(projectRoot, state) {
|
|
|
16531
17276
|
renameSync4(tmp, path);
|
|
16532
17277
|
renamed = true;
|
|
16533
17278
|
} finally {
|
|
16534
|
-
if (!renamed &&
|
|
17279
|
+
if (!renamed && existsSync20(tmp)) {
|
|
16535
17280
|
try {
|
|
16536
17281
|
rmSync5(tmp, { force: true });
|
|
16537
17282
|
} catch {
|
|
@@ -16811,8 +17556,8 @@ __export(watch_exports, {
|
|
|
16811
17556
|
runWatch: () => runWatch
|
|
16812
17557
|
});
|
|
16813
17558
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
16814
|
-
import { basename as basename5, dirname as
|
|
16815
|
-
import { appendFileSync, existsSync as
|
|
17559
|
+
import { basename as basename5, dirname as dirname12, resolve as resolve18 } from "path";
|
|
17560
|
+
import { appendFileSync, existsSync as existsSync21, mkdirSync as mkdirSync9, readFileSync as readFileSync19 } from "fs";
|
|
16816
17561
|
function parseFlags(args2) {
|
|
16817
17562
|
const out = {
|
|
16818
17563
|
foreground: false,
|
|
@@ -16838,7 +17583,7 @@ function parseFlags(args2) {
|
|
|
16838
17583
|
function findClaudeBg() {
|
|
16839
17584
|
const home = process.env.HOME ?? "";
|
|
16840
17585
|
const fixed = home ? resolve18(home, ".claude", "bin", "claude-bg") : null;
|
|
16841
|
-
if (fixed &&
|
|
17586
|
+
if (fixed && existsSync21(fixed)) return fixed;
|
|
16842
17587
|
const which = spawnSync3("which", ["claude-bg"], { encoding: "utf-8" });
|
|
16843
17588
|
if (which.status === 0 && which.stdout) {
|
|
16844
17589
|
const p19 = which.stdout.trim();
|
|
@@ -16899,7 +17644,7 @@ async function runWatch(args2) {
|
|
|
16899
17644
|
}
|
|
16900
17645
|
function runStatus(root) {
|
|
16901
17646
|
const path = watchStatePath(root);
|
|
16902
|
-
if (!
|
|
17647
|
+
if (!existsSync21(path)) {
|
|
16903
17648
|
process.stdout.write("massu watch: not running (no state file)\n");
|
|
16904
17649
|
return { exitCode: 0 };
|
|
16905
17650
|
}
|
|
@@ -17057,14 +17802,14 @@ function refreshLogPath(projectRoot) {
|
|
|
17057
17802
|
function appendRefreshLog(projectRoot, event) {
|
|
17058
17803
|
const path = refreshLogPath(projectRoot);
|
|
17059
17804
|
try {
|
|
17060
|
-
|
|
17805
|
+
mkdirSync9(dirname12(path), { recursive: true });
|
|
17061
17806
|
appendFileSync(path, JSON.stringify(event) + "\n", "utf-8");
|
|
17062
17807
|
} catch {
|
|
17063
17808
|
}
|
|
17064
17809
|
}
|
|
17065
17810
|
function readRefreshLog(projectRoot, limit = 10, opts = {}) {
|
|
17066
17811
|
const path = refreshLogPath(projectRoot);
|
|
17067
|
-
if (!
|
|
17812
|
+
if (!existsSync21(path)) return [];
|
|
17068
17813
|
const warn = opts.warn ?? ((s) => {
|
|
17069
17814
|
process.stderr.write(s);
|
|
17070
17815
|
});
|
|
@@ -17141,26 +17886,26 @@ var init_refresh_log = __esm({
|
|
|
17141
17886
|
import {
|
|
17142
17887
|
chmodSync as chmodSync3,
|
|
17143
17888
|
closeSync as closeSync4,
|
|
17144
|
-
existsSync as
|
|
17889
|
+
existsSync as existsSync22,
|
|
17145
17890
|
fsyncSync as fsyncSync4,
|
|
17146
|
-
mkdirSync as
|
|
17891
|
+
mkdirSync as mkdirSync10,
|
|
17147
17892
|
openSync as openSync4,
|
|
17148
17893
|
renameSync as renameSync5,
|
|
17149
17894
|
rmSync as rmSync6,
|
|
17150
17895
|
statSync as statSync9,
|
|
17151
17896
|
writeSync as writeSync4
|
|
17152
17897
|
} from "node:fs";
|
|
17153
|
-
import { dirname as
|
|
17898
|
+
import { dirname as dirname13 } from "node:path";
|
|
17154
17899
|
function atomicWrite(path, content, opts = {}) {
|
|
17155
17900
|
const tmpPath = `${path}.tmp`;
|
|
17156
|
-
const parentDir =
|
|
17901
|
+
const parentDir = dirname13(path);
|
|
17157
17902
|
try {
|
|
17158
|
-
if (!
|
|
17903
|
+
if (!existsSync22(parentDir)) {
|
|
17159
17904
|
const mkdirOpts = { recursive: true };
|
|
17160
17905
|
if (opts.ensureParentDirMode !== void 0) {
|
|
17161
17906
|
mkdirOpts.mode = opts.ensureParentDirMode;
|
|
17162
17907
|
}
|
|
17163
|
-
|
|
17908
|
+
mkdirSync10(parentDir, mkdirOpts);
|
|
17164
17909
|
}
|
|
17165
17910
|
const buf = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
|
|
17166
17911
|
const openMode = opts.mode ?? 420;
|
|
@@ -17177,7 +17922,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
17177
17922
|
renameSync5(tmpPath, path);
|
|
17178
17923
|
return { written: true };
|
|
17179
17924
|
} catch (err) {
|
|
17180
|
-
if (
|
|
17925
|
+
if (existsSync22(tmpPath)) {
|
|
17181
17926
|
try {
|
|
17182
17927
|
rmSync6(tmpPath, { force: true });
|
|
17183
17928
|
} catch {
|
|
@@ -17404,7 +18149,7 @@ var init_adapter_verifier = __esm({
|
|
|
17404
18149
|
// src/security/fetcher.ts
|
|
17405
18150
|
async function fetchUrl(url, opts = {}) {
|
|
17406
18151
|
const allowedHosts = opts.allowedHosts ?? ALLOWED_HOSTS;
|
|
17407
|
-
const timeoutMs = opts.timeoutMs ??
|
|
18152
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
17408
18153
|
const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
17409
18154
|
let parsed;
|
|
17410
18155
|
try {
|
|
@@ -17478,11 +18223,11 @@ async function fetchUrl(url, opts = {}) {
|
|
|
17478
18223
|
clearTimeout(timeoutHandle);
|
|
17479
18224
|
}
|
|
17480
18225
|
}
|
|
17481
|
-
var
|
|
18226
|
+
var DEFAULT_TIMEOUT_MS2, DEFAULT_MAX_BODY_BYTES, ALLOWED_HOSTS, FetchAllowlistError, FetchTimeoutError, FetchBodySizeError;
|
|
17482
18227
|
var init_fetcher = __esm({
|
|
17483
18228
|
"src/security/fetcher.ts"() {
|
|
17484
18229
|
"use strict";
|
|
17485
|
-
|
|
18230
|
+
DEFAULT_TIMEOUT_MS2 = 1e4;
|
|
17486
18231
|
DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;
|
|
17487
18232
|
ALLOWED_HOSTS = [
|
|
17488
18233
|
"registry.massu.ai",
|
|
@@ -17520,7 +18265,7 @@ var init_fetcher = __esm({
|
|
|
17520
18265
|
});
|
|
17521
18266
|
|
|
17522
18267
|
// src/security/manifest-cache.ts
|
|
17523
|
-
import { existsSync as
|
|
18268
|
+
import { existsSync as existsSync23, readFileSync as readFileSync20, statSync as statSync10 } from "node:fs";
|
|
17524
18269
|
import { homedir as homedir5 } from "node:os";
|
|
17525
18270
|
import { resolve as resolve19 } from "node:path";
|
|
17526
18271
|
import { z as z4 } from "zod";
|
|
@@ -17532,7 +18277,7 @@ function defaultCachePaths() {
|
|
|
17532
18277
|
};
|
|
17533
18278
|
}
|
|
17534
18279
|
function loadCachedManifest(paths = defaultCachePaths()) {
|
|
17535
|
-
if (!
|
|
18280
|
+
if (!existsSync23(paths.cachePath)) {
|
|
17536
18281
|
return { kind: "absent" };
|
|
17537
18282
|
}
|
|
17538
18283
|
let raw;
|
|
@@ -17726,7 +18471,7 @@ var init_adapter_origin = __esm({
|
|
|
17726
18471
|
});
|
|
17727
18472
|
|
|
17728
18473
|
// src/security/local-fingerprint.ts
|
|
17729
|
-
import { existsSync as
|
|
18474
|
+
import { existsSync as existsSync24, readFileSync as readFileSync21, lstatSync as lstatSync5 } from "node:fs";
|
|
17730
18475
|
import { homedir as homedir6 } from "node:os";
|
|
17731
18476
|
import { resolve as resolve20, isAbsolute } from "node:path";
|
|
17732
18477
|
import { createHash as createHash7 } from "node:crypto";
|
|
@@ -17755,7 +18500,7 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
17755
18500
|
return createHash7("sha256").update(canonical).digest("hex");
|
|
17756
18501
|
}
|
|
17757
18502
|
function readFingerprintSentinel(path = FINGERPRINT_PATH) {
|
|
17758
|
-
if (!
|
|
18503
|
+
if (!existsSync24(path)) return null;
|
|
17759
18504
|
let raw;
|
|
17760
18505
|
try {
|
|
17761
18506
|
raw = JSON.parse(readFileSync21(path, "utf-8"));
|
|
@@ -17822,15 +18567,15 @@ var init_local_fingerprint = __esm({
|
|
|
17822
18567
|
});
|
|
17823
18568
|
|
|
17824
18569
|
// src/security/install-tracking.ts
|
|
17825
|
-
import { readFileSync as readFileSync22, readdirSync as readdirSync13, lstatSync as lstatSync6, existsSync as
|
|
17826
|
-
import { join as
|
|
18570
|
+
import { readFileSync as readFileSync22, readdirSync as readdirSync13, lstatSync as lstatSync6, existsSync as existsSync25 } from "node:fs";
|
|
18571
|
+
import { join as join12, relative as relative5, sep } from "node:path";
|
|
17827
18572
|
import { homedir as homedir7 } from "node:os";
|
|
17828
18573
|
import { resolve as resolve21 } from "node:path";
|
|
17829
18574
|
import { createHash as createHash8 } from "node:crypto";
|
|
17830
18575
|
import { z as z6 } from "zod";
|
|
17831
18576
|
function containsHiddenDirs(packageDir) {
|
|
17832
18577
|
for (const hidden of EXCLUDED_DIR_NAMES) {
|
|
17833
|
-
if (
|
|
18578
|
+
if (existsSync25(`${packageDir}/${hidden}`)) {
|
|
17834
18579
|
return hidden;
|
|
17835
18580
|
}
|
|
17836
18581
|
}
|
|
@@ -17847,7 +18592,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
17847
18592
|
return;
|
|
17848
18593
|
}
|
|
17849
18594
|
for (const entry of entries.sort()) {
|
|
17850
|
-
const absPath =
|
|
18595
|
+
const absPath = join12(currentDir, entry);
|
|
17851
18596
|
let lst;
|
|
17852
18597
|
try {
|
|
17853
18598
|
lst = lstatSync6(absPath);
|
|
@@ -17885,7 +18630,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
17885
18630
|
return top.digest("hex");
|
|
17886
18631
|
}
|
|
17887
18632
|
function readInstalledManifest(path = INSTALLED_MANIFEST_PATH) {
|
|
17888
|
-
if (!
|
|
18633
|
+
if (!existsSync25(path)) return {};
|
|
17889
18634
|
let raw;
|
|
17890
18635
|
try {
|
|
17891
18636
|
raw = JSON.parse(readFileSync22(path, "utf-8"));
|
|
@@ -17927,8 +18672,8 @@ function removeInstalledManifestEntry(packageName, path = INSTALLED_MANIFEST_PAT
|
|
|
17927
18672
|
}
|
|
17928
18673
|
return { written: true };
|
|
17929
18674
|
}
|
|
17930
|
-
function verifyInstalledIntegrity(packageName, packageDir,
|
|
17931
|
-
const installed = readInstalledManifest(
|
|
18675
|
+
function verifyInstalledIntegrity(packageName, packageDir, sidecarPath2 = INSTALLED_MANIFEST_PATH) {
|
|
18676
|
+
const installed = readInstalledManifest(sidecarPath2);
|
|
17932
18677
|
const entry = installed[packageName];
|
|
17933
18678
|
if (!entry) {
|
|
17934
18679
|
return {
|
|
@@ -17975,12 +18720,12 @@ var init_install_tracking = __esm({
|
|
|
17975
18720
|
});
|
|
17976
18721
|
|
|
17977
18722
|
// src/detect/adapters/discover.ts
|
|
17978
|
-
import { existsSync as
|
|
18723
|
+
import { existsSync as existsSync26, readdirSync as readdirSync14, readFileSync as readFileSync23, lstatSync as lstatSync7 } from "node:fs";
|
|
17979
18724
|
import { resolve as resolve22, isAbsolute as isAbsolute2 } from "node:path";
|
|
17980
18725
|
import { z as z7 } from "zod";
|
|
17981
18726
|
function walkNodeModules(projectRoot, warnings) {
|
|
17982
18727
|
const nodeModulesDir = resolve22(projectRoot, "node_modules");
|
|
17983
|
-
if (!
|
|
18728
|
+
if (!existsSync26(nodeModulesDir)) {
|
|
17984
18729
|
return [];
|
|
17985
18730
|
}
|
|
17986
18731
|
const candidates = [];
|
|
@@ -18035,7 +18780,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
18035
18780
|
}
|
|
18036
18781
|
function tryReadAdapterPackage(packageDir, warnings) {
|
|
18037
18782
|
const pkgJsonPath = resolve22(packageDir, "package.json");
|
|
18038
|
-
if (!
|
|
18783
|
+
if (!existsSync26(pkgJsonPath)) return null;
|
|
18039
18784
|
let raw;
|
|
18040
18785
|
try {
|
|
18041
18786
|
raw = JSON.parse(readFileSync23(pkgJsonPath, "utf-8"));
|
|
@@ -18173,7 +18918,7 @@ function discoverAdapters(opts) {
|
|
|
18173
18918
|
for (const localPath of opts.configLocalPaths) {
|
|
18174
18919
|
if (seenIds.has(localPath)) continue;
|
|
18175
18920
|
const absPath = isAbsolute2(localPath) ? localPath : resolve22(opts.projectRoot, localPath);
|
|
18176
|
-
if (!
|
|
18921
|
+
if (!existsSync26(absPath)) {
|
|
18177
18922
|
warnings.push(
|
|
18178
18923
|
`local adapter file not found: ${localPath} (resolved to ${absPath}). Remove via: massu adapters remove-local ${localPath}`
|
|
18179
18924
|
);
|
|
@@ -18255,7 +19000,7 @@ __export(adapters_exports, {
|
|
|
18255
19000
|
runAdaptersResyncLocalFingerprint: () => runAdaptersResyncLocalFingerprint,
|
|
18256
19001
|
runAdaptersSearch: () => runAdaptersSearch
|
|
18257
19002
|
});
|
|
18258
|
-
import { existsSync as
|
|
19003
|
+
import { existsSync as existsSync27, readFileSync as readFileSync24 } from "node:fs";
|
|
18259
19004
|
import { resolve as resolve23 } from "node:path";
|
|
18260
19005
|
import { parseDocument } from "yaml";
|
|
18261
19006
|
async function handleAdaptersSubcommand(args2) {
|
|
@@ -18524,7 +19269,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
18524
19269
|
return { exitCode: 2 };
|
|
18525
19270
|
}
|
|
18526
19271
|
const yamlPath = resolve23(projectRoot, "massu.config.yaml");
|
|
18527
|
-
if (!
|
|
19272
|
+
if (!existsSync27(yamlPath)) {
|
|
18528
19273
|
process.stderr.write(
|
|
18529
19274
|
`${command}: massu.config.yaml not found at ${yamlPath}. Run \`massu init\` first.
|
|
18530
19275
|
`
|
|
@@ -18624,7 +19369,7 @@ async function runAdaptersInstall(args2) {
|
|
|
18624
19369
|
return { exitCode: 1 };
|
|
18625
19370
|
}
|
|
18626
19371
|
const packageDir = resolve23(projectRoot, "node_modules", ...packageName.split("/"));
|
|
18627
|
-
if (!
|
|
19372
|
+
if (!existsSync27(packageDir)) {
|
|
18628
19373
|
process.stderr.write(
|
|
18629
19374
|
`install: ${packageName} is not installed in node_modules. Run \`npm install ${packageName}\` first.
|
|
18630
19375
|
`
|
|
@@ -18632,7 +19377,7 @@ async function runAdaptersInstall(args2) {
|
|
|
18632
19377
|
return { exitCode: 1 };
|
|
18633
19378
|
}
|
|
18634
19379
|
const pkgJsonPath = resolve23(packageDir, "package.json");
|
|
18635
|
-
if (!
|
|
19380
|
+
if (!existsSync27(pkgJsonPath)) {
|
|
18636
19381
|
process.stderr.write(`install: ${packageName} has no package.json at ${pkgJsonPath}
|
|
18637
19382
|
`);
|
|
18638
19383
|
return { exitCode: 1 };
|
|
@@ -18759,7 +19504,7 @@ async function runAdaptersResign(_args) {
|
|
|
18759
19504
|
continue;
|
|
18760
19505
|
}
|
|
18761
19506
|
const packageDir = resolve23(projectRoot, "node_modules", ...name.split("/"));
|
|
18762
|
-
if (!
|
|
19507
|
+
if (!existsSync27(packageDir)) {
|
|
18763
19508
|
removed++;
|
|
18764
19509
|
warnings.push(`${name}@${entry.version}: not present in node_modules \u2014 REMOVED from sidecar`);
|
|
18765
19510
|
removeInstalledManifestEntry(name);
|
|
@@ -18857,11 +19602,11 @@ var init_sql_table_names = __esm({
|
|
|
18857
19602
|
|
|
18858
19603
|
// src/db.ts
|
|
18859
19604
|
import Database2 from "better-sqlite3";
|
|
18860
|
-
import { dirname as
|
|
18861
|
-
import { existsSync as
|
|
19605
|
+
import { dirname as dirname14, join as join13 } from "path";
|
|
19606
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync11, readdirSync as readdirSync15, statSync as statSync11 } from "fs";
|
|
18862
19607
|
function getCodeGraphDb() {
|
|
18863
19608
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
18864
|
-
if (!
|
|
19609
|
+
if (!existsSync28(dbPath)) {
|
|
18865
19610
|
throw new CodegraphDbNotInitializedError(dbPath);
|
|
18866
19611
|
}
|
|
18867
19612
|
const db = new Database2(dbPath, { readonly: true });
|
|
@@ -18870,9 +19615,9 @@ function getCodeGraphDb() {
|
|
|
18870
19615
|
}
|
|
18871
19616
|
function getDataDb() {
|
|
18872
19617
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
18873
|
-
const dir =
|
|
18874
|
-
if (!
|
|
18875
|
-
|
|
19618
|
+
const dir = dirname14(dbPath);
|
|
19619
|
+
if (!existsSync28(dir)) {
|
|
19620
|
+
mkdirSync11(dir, { recursive: true });
|
|
18876
19621
|
}
|
|
18877
19622
|
const db = new Database2(dbPath);
|
|
18878
19623
|
db.pragma("journal_mode = WAL");
|
|
@@ -19144,7 +19889,7 @@ function isPythonDataStale(dataDb, pythonRoot) {
|
|
|
19144
19889
|
try {
|
|
19145
19890
|
const entries = readdirSync15(dir, { withFileTypes: true });
|
|
19146
19891
|
for (const entry of entries) {
|
|
19147
|
-
const fullPath =
|
|
19892
|
+
const fullPath = join13(dir, entry.name);
|
|
19148
19893
|
if (entry.isDirectory()) {
|
|
19149
19894
|
if (["__pycache__", ".venv", "venv", "node_modules", ".mypy_cache", ".pytest_cache"].includes(entry.name)) continue;
|
|
19150
19895
|
if (checkDir(fullPath)) return true;
|
|
@@ -19180,13 +19925,13 @@ var init_db = __esm({
|
|
|
19180
19925
|
|
|
19181
19926
|
// src/knowledge-db.ts
|
|
19182
19927
|
import Database3 from "better-sqlite3";
|
|
19183
|
-
import { dirname as
|
|
19184
|
-
import { existsSync as
|
|
19928
|
+
import { dirname as dirname15 } from "path";
|
|
19929
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync12 } from "fs";
|
|
19185
19930
|
function getKnowledgeDb() {
|
|
19186
19931
|
const dbPath = getResolvedPaths().knowledgeDbPath;
|
|
19187
|
-
const dir =
|
|
19188
|
-
if (!
|
|
19189
|
-
|
|
19932
|
+
const dir = dirname15(dbPath);
|
|
19933
|
+
if (!existsSync29(dir)) {
|
|
19934
|
+
mkdirSync12(dir, { recursive: true });
|
|
19190
19935
|
}
|
|
19191
19936
|
const db = new Database3(dbPath);
|
|
19192
19937
|
db.pragma("journal_mode = WAL");
|
|
@@ -19433,8 +20178,8 @@ var init_rules = __esm({
|
|
|
19433
20178
|
});
|
|
19434
20179
|
|
|
19435
20180
|
// src/import-resolver.ts
|
|
19436
|
-
import { readFileSync as readFileSync25, existsSync as
|
|
19437
|
-
import { resolve as resolve25, dirname as
|
|
20181
|
+
import { readFileSync as readFileSync25, existsSync as existsSync30, statSync as statSync12 } from "fs";
|
|
20182
|
+
import { resolve as resolve25, dirname as dirname16, join as join14 } from "path";
|
|
19438
20183
|
function parseImports(source) {
|
|
19439
20184
|
const imports = [];
|
|
19440
20185
|
const lines = source.split("\n");
|
|
@@ -19492,21 +20237,21 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
19492
20237
|
const paths = getResolvedPaths();
|
|
19493
20238
|
basePath = resolve25(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
19494
20239
|
} else {
|
|
19495
|
-
basePath = resolve25(
|
|
20240
|
+
basePath = resolve25(dirname16(fromFile), specifier);
|
|
19496
20241
|
}
|
|
19497
|
-
if (
|
|
20242
|
+
if (existsSync30(basePath) && !isDirectory(basePath)) {
|
|
19498
20243
|
return toRelative(basePath);
|
|
19499
20244
|
}
|
|
19500
20245
|
const resolvedPaths = getResolvedPaths();
|
|
19501
20246
|
for (const ext of resolvedPaths.extensions) {
|
|
19502
20247
|
const withExt = basePath + ext;
|
|
19503
|
-
if (
|
|
20248
|
+
if (existsSync30(withExt)) {
|
|
19504
20249
|
return toRelative(withExt);
|
|
19505
20250
|
}
|
|
19506
20251
|
}
|
|
19507
20252
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
19508
|
-
const indexPath =
|
|
19509
|
-
if (
|
|
20253
|
+
const indexPath = join14(basePath, indexFile);
|
|
20254
|
+
if (existsSync30(indexPath)) {
|
|
19510
20255
|
return toRelative(indexPath);
|
|
19511
20256
|
}
|
|
19512
20257
|
}
|
|
@@ -19543,7 +20288,7 @@ function buildImportIndex(dataDb, codegraphDb) {
|
|
|
19543
20288
|
let batch = [];
|
|
19544
20289
|
for (const file of files) {
|
|
19545
20290
|
const absPath = ensureWithinRoot(resolve25(projectRoot, file.path), projectRoot);
|
|
19546
|
-
if (!
|
|
20291
|
+
if (!existsSync30(absPath)) continue;
|
|
19547
20292
|
let source;
|
|
19548
20293
|
try {
|
|
19549
20294
|
source = readFileSync25(absPath, "utf-8");
|
|
@@ -19583,12 +20328,12 @@ var init_import_resolver = __esm({
|
|
|
19583
20328
|
});
|
|
19584
20329
|
|
|
19585
20330
|
// src/trpc-index.ts
|
|
19586
|
-
import { readFileSync as readFileSync26, existsSync as
|
|
19587
|
-
import { resolve as resolve26, join as
|
|
20331
|
+
import { readFileSync as readFileSync26, existsSync as existsSync31, readdirSync as readdirSync16 } from "fs";
|
|
20332
|
+
import { resolve as resolve26, join as join15 } from "path";
|
|
19588
20333
|
function parseRootRouter() {
|
|
19589
20334
|
const paths = getResolvedPaths();
|
|
19590
20335
|
const rootPath = paths.rootRouterPath;
|
|
19591
|
-
if (!
|
|
20336
|
+
if (!existsSync31(rootPath)) {
|
|
19592
20337
|
throw new Error(`Root router not found at ${rootPath}`);
|
|
19593
20338
|
}
|
|
19594
20339
|
const source = readFileSync26(rootPath, "utf-8");
|
|
@@ -19603,12 +20348,12 @@ function parseRootRouter() {
|
|
|
19603
20348
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
19604
20349
|
const candidate = fullPath + ext;
|
|
19605
20350
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
19606
|
-
if (
|
|
20351
|
+
if (existsSync31(candidate)) {
|
|
19607
20352
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
19608
20353
|
break;
|
|
19609
20354
|
}
|
|
19610
|
-
const indexCandidate =
|
|
19611
|
-
if (
|
|
20355
|
+
const indexCandidate = join15(fullPath, "index.ts");
|
|
20356
|
+
if (existsSync31(indexCandidate)) {
|
|
19612
20357
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
19613
20358
|
break;
|
|
19614
20359
|
}
|
|
@@ -19628,7 +20373,7 @@ function parseRootRouter() {
|
|
|
19628
20373
|
}
|
|
19629
20374
|
function extractProcedures(routerFilePath) {
|
|
19630
20375
|
const absPath = resolve26(getProjectRoot(), routerFilePath);
|
|
19631
|
-
if (!
|
|
20376
|
+
if (!existsSync31(absPath)) return [];
|
|
19632
20377
|
const source = readFileSync26(absPath, "utf-8");
|
|
19633
20378
|
const procedures = [];
|
|
19634
20379
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -19658,7 +20403,7 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
19658
20403
|
];
|
|
19659
20404
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
19660
20405
|
for (const dir of searchDirs) {
|
|
19661
|
-
if (!
|
|
20406
|
+
if (!existsSync31(dir)) continue;
|
|
19662
20407
|
searchDirectory(dir, searchPattern, callSites);
|
|
19663
20408
|
}
|
|
19664
20409
|
return callSites;
|
|
@@ -19666,7 +20411,7 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
19666
20411
|
function searchDirectory(dir, pattern, results) {
|
|
19667
20412
|
const entries = readdirSync16(dir, { withFileTypes: true });
|
|
19668
20413
|
for (const entry of entries) {
|
|
19669
|
-
const fullPath =
|
|
20414
|
+
const fullPath = join15(dir, entry.name);
|
|
19670
20415
|
if (entry.isDirectory()) {
|
|
19671
20416
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
19672
20417
|
searchDirectory(fullPath, pattern, results);
|
|
@@ -19736,7 +20481,7 @@ var init_trpc_index = __esm({
|
|
|
19736
20481
|
});
|
|
19737
20482
|
|
|
19738
20483
|
// src/page-deps.ts
|
|
19739
|
-
import { readFileSync as readFileSync27, existsSync as
|
|
20484
|
+
import { readFileSync as readFileSync27, existsSync as existsSync32 } from "fs";
|
|
19740
20485
|
import { resolve as resolve27 } from "path";
|
|
19741
20486
|
function deriveRoute(pageFile) {
|
|
19742
20487
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
@@ -19776,7 +20521,7 @@ function findRouterCalls(files) {
|
|
|
19776
20521
|
const projectRoot = getProjectRoot();
|
|
19777
20522
|
for (const file of files) {
|
|
19778
20523
|
const absPath = ensureWithinRoot(resolve27(projectRoot, file), projectRoot);
|
|
19779
|
-
if (!
|
|
20524
|
+
if (!existsSync32(absPath)) continue;
|
|
19780
20525
|
try {
|
|
19781
20526
|
const source = readFileSync27(absPath, "utf-8");
|
|
19782
20527
|
const apiCallRegex = /api\.(\w+)\.\w+/g;
|
|
@@ -19797,7 +20542,7 @@ function findTablesFromRouters(routerNames, dataDb) {
|
|
|
19797
20542
|
).all(routerName);
|
|
19798
20543
|
for (const proc of procs) {
|
|
19799
20544
|
const absPath = ensureWithinRoot(resolve27(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
19800
|
-
if (!
|
|
20545
|
+
if (!existsSync32(absPath)) continue;
|
|
19801
20546
|
try {
|
|
19802
20547
|
const source = readFileSync27(absPath, "utf-8");
|
|
19803
20548
|
const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
|
|
@@ -20071,11 +20816,11 @@ var init_domains = __esm({
|
|
|
20071
20816
|
});
|
|
20072
20817
|
|
|
20073
20818
|
// src/schema-mapper.ts
|
|
20074
|
-
import { readFileSync as readFileSync28, existsSync as
|
|
20075
|
-
import { join as
|
|
20819
|
+
import { readFileSync as readFileSync28, existsSync as existsSync33, readdirSync as readdirSync17 } from "fs";
|
|
20820
|
+
import { join as join16 } from "path";
|
|
20076
20821
|
function parsePrismaSchema() {
|
|
20077
20822
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
20078
|
-
if (!
|
|
20823
|
+
if (!existsSync33(schemaPath)) {
|
|
20079
20824
|
throw new Error(`Prisma schema not found at ${schemaPath}`);
|
|
20080
20825
|
}
|
|
20081
20826
|
const source = readFileSync28(schemaPath, "utf-8");
|
|
@@ -20136,14 +20881,14 @@ function toSnakeCase(str) {
|
|
|
20136
20881
|
function findColumnUsageInRouters(tableName) {
|
|
20137
20882
|
const usage = /* @__PURE__ */ new Map();
|
|
20138
20883
|
const routersDir = getResolvedPaths().routersDir;
|
|
20139
|
-
if (!
|
|
20884
|
+
if (!existsSync33(routersDir)) return usage;
|
|
20140
20885
|
scanDirectory(routersDir, tableName, usage);
|
|
20141
20886
|
return usage;
|
|
20142
20887
|
}
|
|
20143
20888
|
function scanDirectory(dir, tableName, usage) {
|
|
20144
20889
|
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
20145
20890
|
for (const entry of entries) {
|
|
20146
|
-
const fullPath =
|
|
20891
|
+
const fullPath = join16(dir, entry.name);
|
|
20147
20892
|
if (entry.isDirectory()) {
|
|
20148
20893
|
scanDirectory(fullPath, tableName, usage);
|
|
20149
20894
|
} else if (entry.name.endsWith(".ts")) {
|
|
@@ -20198,10 +20943,10 @@ function detectMismatches(models) {
|
|
|
20198
20943
|
}
|
|
20199
20944
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
20200
20945
|
const result = [];
|
|
20201
|
-
if (!
|
|
20946
|
+
if (!existsSync33(dir)) return result;
|
|
20202
20947
|
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
20203
20948
|
for (const entry of entries) {
|
|
20204
|
-
const fullPath =
|
|
20949
|
+
const fullPath = join16(dir, entry.name);
|
|
20205
20950
|
if (entry.isDirectory()) {
|
|
20206
20951
|
result.push(...findFilesUsingColumn(fullPath, column, tableName));
|
|
20207
20952
|
} else if (entry.name.endsWith(".ts")) {
|
|
@@ -20351,34 +21096,34 @@ var init_import_parser = __esm({
|
|
|
20351
21096
|
});
|
|
20352
21097
|
|
|
20353
21098
|
// src/python/import-resolver.ts
|
|
20354
|
-
import { readFileSync as readFileSync29, existsSync as
|
|
20355
|
-
import { resolve as resolve29, join as
|
|
21099
|
+
import { readFileSync as readFileSync29, existsSync as existsSync34, readdirSync as readdirSync18 } from "fs";
|
|
21100
|
+
import { resolve as resolve29, join as join17, relative as relative6, dirname as dirname17 } from "path";
|
|
20356
21101
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
20357
21102
|
const projectRoot = getProjectRoot();
|
|
20358
21103
|
if (level > 0) {
|
|
20359
|
-
let baseDir =
|
|
21104
|
+
let baseDir = dirname17(resolve29(projectRoot, fromFile));
|
|
20360
21105
|
for (let i = 1; i < level; i++) {
|
|
20361
|
-
baseDir =
|
|
21106
|
+
baseDir = dirname17(baseDir);
|
|
20362
21107
|
}
|
|
20363
21108
|
const modulePart = module.replace(/^\.+/, "");
|
|
20364
21109
|
if (modulePart) {
|
|
20365
21110
|
const parts2 = modulePart.split(".");
|
|
20366
|
-
return tryResolvePythonPath(
|
|
21111
|
+
return tryResolvePythonPath(join17(baseDir, ...parts2), projectRoot);
|
|
20367
21112
|
}
|
|
20368
21113
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
20369
21114
|
}
|
|
20370
21115
|
const parts = module.split(".");
|
|
20371
|
-
const candidate =
|
|
21116
|
+
const candidate = join17(resolve29(projectRoot, pythonRoot), ...parts);
|
|
20372
21117
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
20373
21118
|
}
|
|
20374
21119
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
20375
|
-
if (
|
|
21120
|
+
if (existsSync34(basePath + ".py")) {
|
|
20376
21121
|
return relative6(projectRoot, basePath + ".py");
|
|
20377
21122
|
}
|
|
20378
|
-
if (
|
|
20379
|
-
return relative6(projectRoot,
|
|
21123
|
+
if (existsSync34(join17(basePath, "__init__.py"))) {
|
|
21124
|
+
return relative6(projectRoot, join17(basePath, "__init__.py"));
|
|
20380
21125
|
}
|
|
20381
|
-
if (basePath.endsWith(".py") &&
|
|
21126
|
+
if (basePath.endsWith(".py") && existsSync34(basePath)) {
|
|
20382
21127
|
return relative6(projectRoot, basePath);
|
|
20383
21128
|
}
|
|
20384
21129
|
return null;
|
|
@@ -20390,9 +21135,9 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
20390
21135
|
for (const entry of entries) {
|
|
20391
21136
|
if (entry.isDirectory()) {
|
|
20392
21137
|
if (excludeDirs.includes(entry.name)) continue;
|
|
20393
|
-
files.push(...walkPythonFiles(
|
|
21138
|
+
files.push(...walkPythonFiles(join17(dir, entry.name), excludeDirs));
|
|
20394
21139
|
} else if (entry.name.endsWith(".py")) {
|
|
20395
|
-
files.push(
|
|
21140
|
+
files.push(join17(dir, entry.name));
|
|
20396
21141
|
}
|
|
20397
21142
|
}
|
|
20398
21143
|
} catch {
|
|
@@ -20686,7 +21431,7 @@ var init_route_parser = __esm({
|
|
|
20686
21431
|
|
|
20687
21432
|
// src/python/route-indexer.ts
|
|
20688
21433
|
import { readFileSync as readFileSync30, readdirSync as readdirSync19 } from "fs";
|
|
20689
|
-
import { join as
|
|
21434
|
+
import { join as join18, relative as relative7 } from "path";
|
|
20690
21435
|
function walkPyFiles(dir, excludeDirs) {
|
|
20691
21436
|
const files = [];
|
|
20692
21437
|
try {
|
|
@@ -20694,9 +21439,9 @@ function walkPyFiles(dir, excludeDirs) {
|
|
|
20694
21439
|
for (const entry of entries) {
|
|
20695
21440
|
if (entry.isDirectory()) {
|
|
20696
21441
|
if (excludeDirs.includes(entry.name)) continue;
|
|
20697
|
-
files.push(...walkPyFiles(
|
|
21442
|
+
files.push(...walkPyFiles(join18(dir, entry.name), excludeDirs));
|
|
20698
21443
|
} else if (entry.name.endsWith(".py")) {
|
|
20699
|
-
files.push(
|
|
21444
|
+
files.push(join18(dir, entry.name));
|
|
20700
21445
|
}
|
|
20701
21446
|
}
|
|
20702
21447
|
} catch {
|
|
@@ -20705,7 +21450,7 @@ function walkPyFiles(dir, excludeDirs) {
|
|
|
20705
21450
|
}
|
|
20706
21451
|
function buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
20707
21452
|
const projectRoot = getProjectRoot();
|
|
20708
|
-
const absRoot =
|
|
21453
|
+
const absRoot = join18(projectRoot, pythonRoot);
|
|
20709
21454
|
dataDb.exec(`DELETE FROM ${t("py_routes")}`);
|
|
20710
21455
|
dataDb.exec(`DELETE FROM ${t("py_route_callers")}`);
|
|
20711
21456
|
const insertStmt = dataDb.prepare(
|
|
@@ -20931,7 +21676,7 @@ var init_model_parser = __esm({
|
|
|
20931
21676
|
|
|
20932
21677
|
// src/python/model-indexer.ts
|
|
20933
21678
|
import { readFileSync as readFileSync31, readdirSync as readdirSync20 } from "fs";
|
|
20934
|
-
import { join as
|
|
21679
|
+
import { join as join19, relative as relative8 } from "path";
|
|
20935
21680
|
function walkPyFiles2(dir, excludeDirs) {
|
|
20936
21681
|
const files = [];
|
|
20937
21682
|
try {
|
|
@@ -20939,9 +21684,9 @@ function walkPyFiles2(dir, excludeDirs) {
|
|
|
20939
21684
|
for (const entry of entries) {
|
|
20940
21685
|
if (entry.isDirectory()) {
|
|
20941
21686
|
if (excludeDirs.includes(entry.name)) continue;
|
|
20942
|
-
files.push(...walkPyFiles2(
|
|
21687
|
+
files.push(...walkPyFiles2(join19(dir, entry.name), excludeDirs));
|
|
20943
21688
|
} else if (entry.name.endsWith(".py")) {
|
|
20944
|
-
files.push(
|
|
21689
|
+
files.push(join19(dir, entry.name));
|
|
20945
21690
|
}
|
|
20946
21691
|
}
|
|
20947
21692
|
} catch {
|
|
@@ -20950,7 +21695,7 @@ function walkPyFiles2(dir, excludeDirs) {
|
|
|
20950
21695
|
}
|
|
20951
21696
|
function buildPythonModelIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
20952
21697
|
const projectRoot = getProjectRoot();
|
|
20953
|
-
const absRoot =
|
|
21698
|
+
const absRoot = join19(projectRoot, pythonRoot);
|
|
20954
21699
|
dataDb.exec(`DELETE FROM ${t("py_models")}`);
|
|
20955
21700
|
dataDb.exec(`DELETE FROM ${t("py_fk_edges")}`);
|
|
20956
21701
|
const insertModel = dataDb.prepare(
|
|
@@ -21228,18 +21973,18 @@ var init_migration_parser = __esm({
|
|
|
21228
21973
|
|
|
21229
21974
|
// src/python/migration-indexer.ts
|
|
21230
21975
|
import { readFileSync as readFileSync32, readdirSync as readdirSync21 } from "fs";
|
|
21231
|
-
import { join as
|
|
21976
|
+
import { join as join20, relative as relative9 } from "path";
|
|
21232
21977
|
function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
21233
21978
|
const projectRoot = getProjectRoot();
|
|
21234
|
-
const absDir =
|
|
21979
|
+
const absDir = join20(projectRoot, alembicDir);
|
|
21235
21980
|
dataDb.exec(`DELETE FROM ${t("py_migrations")}`);
|
|
21236
|
-
const versionsDir =
|
|
21981
|
+
const versionsDir = join20(absDir, "versions");
|
|
21237
21982
|
let files = [];
|
|
21238
21983
|
try {
|
|
21239
|
-
files = readdirSync21(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) =>
|
|
21984
|
+
files = readdirSync21(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) => join20(versionsDir, f2));
|
|
21240
21985
|
} catch {
|
|
21241
21986
|
try {
|
|
21242
|
-
files = readdirSync21(absDir).filter((f2) => f2.endsWith(".py") && f2 !== "env.py").map((f2) =>
|
|
21987
|
+
files = readdirSync21(absDir).filter((f2) => f2.endsWith(".py") && f2 !== "env.py").map((f2) => join20(absDir, f2));
|
|
21243
21988
|
} catch {
|
|
21244
21989
|
}
|
|
21245
21990
|
}
|
|
@@ -21289,11 +22034,11 @@ var init_migration_indexer = __esm({
|
|
|
21289
22034
|
|
|
21290
22035
|
// src/python/coupling-detector.ts
|
|
21291
22036
|
import { readFileSync as readFileSync33, readdirSync as readdirSync22 } from "fs";
|
|
21292
|
-
import { join as
|
|
22037
|
+
import { join as join21, relative as relative10 } from "path";
|
|
21293
22038
|
function buildPythonCouplingIndex(dataDb) {
|
|
21294
22039
|
const projectRoot = getProjectRoot();
|
|
21295
22040
|
const config = getConfig();
|
|
21296
|
-
const srcDir =
|
|
22041
|
+
const srcDir = join21(projectRoot, config.paths.source);
|
|
21297
22042
|
const routes = dataDb.prepare(`SELECT id, method, path FROM ${t("py_routes")}`).all();
|
|
21298
22043
|
if (routes.length === 0) return 0;
|
|
21299
22044
|
dataDb.exec(`DELETE FROM ${t("py_route_callers")}`);
|
|
@@ -21357,9 +22102,9 @@ function walkFrontendFiles(dir) {
|
|
|
21357
22102
|
for (const entry of entries) {
|
|
21358
22103
|
if (entry.isDirectory()) {
|
|
21359
22104
|
if (exclude.includes(entry.name)) continue;
|
|
21360
|
-
files.push(...walkFrontendFiles(
|
|
22105
|
+
files.push(...walkFrontendFiles(join21(dir, entry.name)));
|
|
21361
22106
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
21362
|
-
files.push(
|
|
22107
|
+
files.push(join21(dir, entry.name));
|
|
21363
22108
|
}
|
|
21364
22109
|
}
|
|
21365
22110
|
} catch {
|
|
@@ -21731,7 +22476,7 @@ var init_memory_tools = __esm({
|
|
|
21731
22476
|
});
|
|
21732
22477
|
|
|
21733
22478
|
// src/docs-tools.ts
|
|
21734
|
-
import { readFileSync as readFileSync34, existsSync as
|
|
22479
|
+
import { readFileSync as readFileSync34, existsSync as existsSync35 } from "fs";
|
|
21735
22480
|
import { resolve as resolve30, basename as basename6 } from "path";
|
|
21736
22481
|
function p3(baseName) {
|
|
21737
22482
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -21787,7 +22532,7 @@ function handleDocsToolCall(name, args2) {
|
|
|
21787
22532
|
}
|
|
21788
22533
|
function loadDocsMap() {
|
|
21789
22534
|
const mapPath = getResolvedPaths().docsMapPath;
|
|
21790
|
-
if (!
|
|
22535
|
+
if (!existsSync35(mapPath)) {
|
|
21791
22536
|
throw new Error(`docs-map.json not found at ${mapPath}`);
|
|
21792
22537
|
}
|
|
21793
22538
|
return JSON.parse(readFileSync34(mapPath, "utf-8"));
|
|
@@ -21861,9 +22606,9 @@ function extractFrontmatter(content) {
|
|
|
21861
22606
|
function extractProcedureNames(routerPath) {
|
|
21862
22607
|
const root = getProjectRoot();
|
|
21863
22608
|
const absPath = ensureWithinRoot(resolve30(getResolvedPaths().srcDir, "..", routerPath), root);
|
|
21864
|
-
if (!
|
|
22609
|
+
if (!existsSync35(absPath)) {
|
|
21865
22610
|
const altPath = ensureWithinRoot(resolve30(getResolvedPaths().srcDir, "../server/api/routers", basename6(routerPath)), root);
|
|
21866
|
-
if (!
|
|
22611
|
+
if (!existsSync35(altPath)) return [];
|
|
21867
22612
|
return extractProcedureNamesFromContent(readFileSync34(altPath, "utf-8"));
|
|
21868
22613
|
}
|
|
21869
22614
|
return extractProcedureNamesFromContent(readFileSync34(absPath, "utf-8"));
|
|
@@ -21907,7 +22652,7 @@ function handleDocsAudit(args2) {
|
|
|
21907
22652
|
const mapping = docsMap.mappings.find((m3) => m3.id === mappingId);
|
|
21908
22653
|
if (!mapping) continue;
|
|
21909
22654
|
const helpPagePath = ensureWithinRoot(resolve30(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
21910
|
-
if (!
|
|
22655
|
+
if (!existsSync35(helpPagePath)) {
|
|
21911
22656
|
results.push({
|
|
21912
22657
|
helpPage: mapping.helpPage,
|
|
21913
22658
|
mappingId,
|
|
@@ -21960,7 +22705,7 @@ function handleDocsAudit(args2) {
|
|
|
21960
22705
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
21961
22706
|
if (parentId === mappingId) {
|
|
21962
22707
|
const guidePath = ensureWithinRoot(resolve30(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
21963
|
-
if (
|
|
22708
|
+
if (existsSync35(guidePath)) {
|
|
21964
22709
|
const guideContent = readFileSync34(guidePath, "utf-8");
|
|
21965
22710
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
21966
22711
|
if (!guideFrontmatter?.lastVerified || status === "STALE") {
|
|
@@ -21995,7 +22740,7 @@ function handleDocsCoverage(args2) {
|
|
|
21995
22740
|
const mappings = filterDomain ? docsMap.mappings.filter((m3) => m3.id === filterDomain) : docsMap.mappings;
|
|
21996
22741
|
for (const mapping of mappings) {
|
|
21997
22742
|
const helpPagePath = ensureWithinRoot(resolve30(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
21998
|
-
const exists =
|
|
22743
|
+
const exists = existsSync35(helpPagePath);
|
|
21999
22744
|
let hasContent = false;
|
|
22000
22745
|
let lineCount = 0;
|
|
22001
22746
|
let lastVerified = null;
|
|
@@ -22342,7 +23087,7 @@ var init_observability_tools = __esm({
|
|
|
22342
23087
|
});
|
|
22343
23088
|
|
|
22344
23089
|
// src/sentinel-db.ts
|
|
22345
|
-
import { existsSync as
|
|
23090
|
+
import { existsSync as existsSync36 } from "fs";
|
|
22346
23091
|
import { resolve as resolve31 } from "path";
|
|
22347
23092
|
function parsePortalScope(raw) {
|
|
22348
23093
|
if (!raw) return [];
|
|
@@ -22580,22 +23325,22 @@ function validateFeatures(db, domainFilter) {
|
|
|
22580
23325
|
const missingPages = [];
|
|
22581
23326
|
for (const comp of components) {
|
|
22582
23327
|
const absPath = resolve31(PROJECT_ROOT, comp.component_file);
|
|
22583
|
-
if (!
|
|
23328
|
+
if (!existsSync36(absPath)) {
|
|
22584
23329
|
missingComponents.push(comp.component_file);
|
|
22585
23330
|
}
|
|
22586
23331
|
}
|
|
22587
23332
|
for (const proc of procedures) {
|
|
22588
23333
|
const routerPath = resolve31(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
22589
|
-
if (!
|
|
23334
|
+
if (!existsSync36(routerPath)) {
|
|
22590
23335
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
22591
23336
|
}
|
|
22592
23337
|
}
|
|
22593
23338
|
for (const page of pages) {
|
|
22594
23339
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
22595
23340
|
const absPath = resolve31(PROJECT_ROOT, routeToPath);
|
|
22596
|
-
if (page.page_route.startsWith("/") && !
|
|
23341
|
+
if (page.page_route.startsWith("/") && !existsSync36(absPath)) {
|
|
22597
23342
|
const altPath = resolve31(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
|
|
22598
|
-
if (!
|
|
23343
|
+
if (!existsSync36(altPath)) {
|
|
22599
23344
|
missingPages.push(page.page_route);
|
|
22600
23345
|
}
|
|
22601
23346
|
}
|
|
@@ -23121,8 +23866,8 @@ var init_sentinel_tools = __esm({
|
|
|
23121
23866
|
});
|
|
23122
23867
|
|
|
23123
23868
|
// src/sentinel-scanner.ts
|
|
23124
|
-
import { readFileSync as readFileSync35, existsSync as
|
|
23125
|
-
import { resolve as resolve32, join as
|
|
23869
|
+
import { readFileSync as readFileSync35, existsSync as existsSync37, readdirSync as readdirSync23, statSync as statSync13 } from "fs";
|
|
23870
|
+
import { resolve as resolve32, join as join22, basename as basename7, dirname as dirname18, relative as relative11 } from "path";
|
|
23126
23871
|
function inferDomain(filePath) {
|
|
23127
23872
|
const domains = getConfig().domains;
|
|
23128
23873
|
const path = filePath.toLowerCase();
|
|
@@ -23254,7 +23999,7 @@ function scanComponentExports(dataDb) {
|
|
|
23254
23999
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
23255
24000
|
const componentDirs = [];
|
|
23256
24001
|
const basePath = resolve32(projectRoot, componentsBase);
|
|
23257
|
-
if (
|
|
24002
|
+
if (existsSync37(basePath)) {
|
|
23258
24003
|
try {
|
|
23259
24004
|
const entries = readdirSync23(basePath, { withFileTypes: true });
|
|
23260
24005
|
for (const entry of entries) {
|
|
@@ -23267,7 +24012,7 @@ function scanComponentExports(dataDb) {
|
|
|
23267
24012
|
}
|
|
23268
24013
|
for (const dir of componentDirs) {
|
|
23269
24014
|
const absDir = resolve32(projectRoot, dir);
|
|
23270
|
-
if (!
|
|
24015
|
+
if (!existsSync37(absDir)) continue;
|
|
23271
24016
|
const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
23272
24017
|
for (const file of files) {
|
|
23273
24018
|
const relPath = relative11(projectRoot, file);
|
|
@@ -23297,7 +24042,7 @@ function scanComponentExports(dataDb) {
|
|
|
23297
24042
|
if (hasHandlers && exportMatch) {
|
|
23298
24043
|
const componentName = exportMatch[1];
|
|
23299
24044
|
const domain = inferDomain(relPath);
|
|
23300
|
-
const subdomain = basename7(
|
|
24045
|
+
const subdomain = basename7(dirname18(relPath));
|
|
23301
24046
|
const featureKey = `component.${subdomain}.${componentName.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "")}`;
|
|
23302
24047
|
if (!annotations.some((a2) => a2.featureKey === featureKey)) {
|
|
23303
24048
|
features.push({
|
|
@@ -23322,7 +24067,7 @@ function walkDir2(dir) {
|
|
|
23322
24067
|
try {
|
|
23323
24068
|
const entries = readdirSync23(dir);
|
|
23324
24069
|
for (const entry of entries) {
|
|
23325
|
-
const fullPath =
|
|
24070
|
+
const fullPath = join22(dir, entry);
|
|
23326
24071
|
try {
|
|
23327
24072
|
const stat = statSync13(fullPath);
|
|
23328
24073
|
if (stat.isDirectory()) {
|
|
@@ -24314,7 +25059,7 @@ var init_audit_trail = __esm({
|
|
|
24314
25059
|
});
|
|
24315
25060
|
|
|
24316
25061
|
// src/validation-engine.ts
|
|
24317
|
-
import { existsSync as
|
|
25062
|
+
import { existsSync as existsSync38, readFileSync as readFileSync36 } from "fs";
|
|
24318
25063
|
function p10(baseName) {
|
|
24319
25064
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
24320
25065
|
}
|
|
@@ -24345,7 +25090,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
24345
25090
|
});
|
|
24346
25091
|
return checks;
|
|
24347
25092
|
}
|
|
24348
|
-
if (!
|
|
25093
|
+
if (!existsSync38(absPath)) {
|
|
24349
25094
|
checks.push({
|
|
24350
25095
|
name: "file_exists",
|
|
24351
25096
|
severity: "error",
|
|
@@ -24800,7 +25545,7 @@ var init_adr_generator = __esm({
|
|
|
24800
25545
|
});
|
|
24801
25546
|
|
|
24802
25547
|
// src/security-scorer.ts
|
|
24803
|
-
import { existsSync as
|
|
25548
|
+
import { existsSync as existsSync39, readFileSync as readFileSync37 } from "fs";
|
|
24804
25549
|
function p12(baseName) {
|
|
24805
25550
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
24806
25551
|
}
|
|
@@ -24824,7 +25569,7 @@ function scoreFileSecurity(filePath, projectRoot) {
|
|
|
24824
25569
|
}]
|
|
24825
25570
|
};
|
|
24826
25571
|
}
|
|
24827
|
-
if (!
|
|
25572
|
+
if (!existsSync39(absPath)) {
|
|
24828
25573
|
return { riskScore: 0, findings: [] };
|
|
24829
25574
|
}
|
|
24830
25575
|
let source;
|
|
@@ -25119,7 +25864,7 @@ var init_security_scorer = __esm({
|
|
|
25119
25864
|
});
|
|
25120
25865
|
|
|
25121
25866
|
// src/dependency-scorer.ts
|
|
25122
|
-
import { existsSync as
|
|
25867
|
+
import { existsSync as existsSync40, readFileSync as readFileSync38 } from "fs";
|
|
25123
25868
|
import { resolve as resolve33 } from "path";
|
|
25124
25869
|
function p13(baseName) {
|
|
25125
25870
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -25153,7 +25898,7 @@ function calculateDepRisk(factors) {
|
|
|
25153
25898
|
}
|
|
25154
25899
|
function getInstalledPackages(projectRoot) {
|
|
25155
25900
|
const pkgPath = resolve33(projectRoot, "package.json");
|
|
25156
|
-
if (!
|
|
25901
|
+
if (!existsSync40(pkgPath)) return /* @__PURE__ */ new Map();
|
|
25157
25902
|
try {
|
|
25158
25903
|
const pkg = JSON.parse(readFileSync38(pkgPath, "utf-8"));
|
|
25159
25904
|
const packages = /* @__PURE__ */ new Map();
|
|
@@ -25761,7 +26506,7 @@ var init_regression_detector = __esm({
|
|
|
25761
26506
|
|
|
25762
26507
|
// src/knowledge-indexer.ts
|
|
25763
26508
|
import { createHash as createHash9 } from "crypto";
|
|
25764
|
-
import { readFileSync as readFileSync39, readdirSync as readdirSync24, statSync as statSync14, existsSync as
|
|
26509
|
+
import { readFileSync as readFileSync39, readdirSync as readdirSync24, statSync as statSync14, existsSync as existsSync41 } from "fs";
|
|
25765
26510
|
import { resolve as resolve34, relative as relative12, basename as basename8, extname as extname2 } from "path";
|
|
25766
26511
|
function getKnowledgePaths() {
|
|
25767
26512
|
const resolved = getResolvedPaths();
|
|
@@ -26069,11 +26814,11 @@ function indexAllKnowledge(db) {
|
|
|
26069
26814
|
files.push(...memFiles);
|
|
26070
26815
|
} catch {
|
|
26071
26816
|
}
|
|
26072
|
-
if (
|
|
26817
|
+
if (existsSync41(paths.plansDir)) {
|
|
26073
26818
|
const planFiles = discoverMarkdownFiles(paths.plansDir);
|
|
26074
26819
|
files.push(...planFiles);
|
|
26075
26820
|
}
|
|
26076
|
-
if (
|
|
26821
|
+
if (existsSync41(paths.docsDir)) {
|
|
26077
26822
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
26078
26823
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
26079
26824
|
files.push(...docsFiles);
|
|
@@ -26116,7 +26861,7 @@ function indexAllKnowledge(db) {
|
|
|
26116
26861
|
} catch {
|
|
26117
26862
|
}
|
|
26118
26863
|
for (const filePath of files) {
|
|
26119
|
-
if (!
|
|
26864
|
+
if (!existsSync41(filePath)) continue;
|
|
26120
26865
|
const content = readFileSync39(filePath, "utf-8");
|
|
26121
26866
|
const hash = hashContent2(content);
|
|
26122
26867
|
const relPath = filePath.startsWith(paths.claudeDir) ? relative12(paths.claudeDir, filePath) : filePath.startsWith(paths.plansDir) ? "plans/" + relative12(paths.plansDir, filePath) : filePath.startsWith(paths.docsDir) ? "docs/" + relative12(paths.docsDir, filePath) : filePath.startsWith(paths.memoryDir) ? `memory/${relative12(paths.memoryDir, filePath)}` : basename8(filePath);
|
|
@@ -26252,10 +26997,10 @@ function isKnowledgeStale(db) {
|
|
|
26252
26997
|
files.push(...discoverMarkdownFiles(paths.memoryDir));
|
|
26253
26998
|
} catch {
|
|
26254
26999
|
}
|
|
26255
|
-
if (
|
|
27000
|
+
if (existsSync41(paths.plansDir)) {
|
|
26256
27001
|
files.push(...discoverMarkdownFiles(paths.plansDir));
|
|
26257
27002
|
}
|
|
26258
|
-
if (
|
|
27003
|
+
if (existsSync41(paths.docsDir)) {
|
|
26259
27004
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
26260
27005
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
26261
27006
|
files.push(...docsFiles);
|
|
@@ -26284,7 +27029,7 @@ var init_knowledge_indexer = __esm({
|
|
|
26284
27029
|
});
|
|
26285
27030
|
|
|
26286
27031
|
// src/knowledge-tools.ts
|
|
26287
|
-
import { readFileSync as readFileSync40, writeFileSync as
|
|
27032
|
+
import { readFileSync as readFileSync40, writeFileSync as writeFileSync6, appendFileSync as appendFileSync2, readdirSync as readdirSync25 } from "fs";
|
|
26288
27033
|
import { resolve as resolve35, basename as basename9 } from "path";
|
|
26289
27034
|
function p16(baseName) {
|
|
26290
27035
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -27044,7 +27789,7 @@ ${crRule ? `- **CR**: ${crRule}
|
|
|
27044
27789
|
if (archiveIdx > 0) {
|
|
27045
27790
|
const before = existing.slice(0, archiveIdx);
|
|
27046
27791
|
const after = existing.slice(archiveIdx);
|
|
27047
|
-
|
|
27792
|
+
writeFileSync6(correctionsPath, before + entry + after);
|
|
27048
27793
|
} else {
|
|
27049
27794
|
appendFileSync2(correctionsPath, entry);
|
|
27050
27795
|
}
|
|
@@ -27992,7 +28737,7 @@ var init_framework_supports = __esm({
|
|
|
27992
28737
|
});
|
|
27993
28738
|
|
|
27994
28739
|
// src/tools.ts
|
|
27995
|
-
import { readFileSync as readFileSync41, existsSync as
|
|
28740
|
+
import { readFileSync as readFileSync41, existsSync as existsSync43 } from "fs";
|
|
27996
28741
|
import { resolve as resolve36, basename as basename10 } from "path";
|
|
27997
28742
|
function prefix2() {
|
|
27998
28743
|
return getConfig().toolPrefix;
|
|
@@ -28412,7 +29157,7 @@ function handleContext(file, dataDb, codegraphDb) {
|
|
|
28412
29157
|
const resolvedPaths = getResolvedPaths();
|
|
28413
29158
|
const root = getProjectRoot();
|
|
28414
29159
|
const absFilePath = ensureWithinRoot(resolve36(resolvedPaths.srcDir, "..", file), root);
|
|
28415
|
-
if (
|
|
29160
|
+
if (existsSync43(absFilePath)) {
|
|
28416
29161
|
const fileContent = readFileSync41(absFilePath, "utf-8").slice(0, 3e3);
|
|
28417
29162
|
const keywords = [];
|
|
28418
29163
|
if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
|
|
@@ -28851,7 +29596,7 @@ function handleSchema(args2) {
|
|
|
28851
29596
|
lines.push("");
|
|
28852
29597
|
const projectRoot = getProjectRoot();
|
|
28853
29598
|
const absPath = ensureWithinRoot(resolve36(projectRoot, file), projectRoot);
|
|
28854
|
-
if (!
|
|
29599
|
+
if (!existsSync43(absPath)) {
|
|
28855
29600
|
return text17(`File not found: ${file}`);
|
|
28856
29601
|
}
|
|
28857
29602
|
const source = readFileSync41(absPath, "utf-8");
|
|
@@ -29260,7 +30005,7 @@ var init_server_dispatch = __esm({
|
|
|
29260
30005
|
// src/server.ts
|
|
29261
30006
|
var server_exports = {};
|
|
29262
30007
|
import { readFileSync as readFileSync42 } from "fs";
|
|
29263
|
-
import { resolve as resolve37, dirname as
|
|
30008
|
+
import { resolve as resolve37, dirname as dirname19 } from "path";
|
|
29264
30009
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
29265
30010
|
function pruneMemoryOnStartup() {
|
|
29266
30011
|
try {
|
|
@@ -29292,7 +30037,7 @@ var init_server = __esm({
|
|
|
29292
30037
|
init_memory_db();
|
|
29293
30038
|
init_license();
|
|
29294
30039
|
init_server_dispatch();
|
|
29295
|
-
__dirname5 =
|
|
30040
|
+
__dirname5 = dirname19(fileURLToPath5(import.meta.url));
|
|
29296
30041
|
PKG_VERSION = (() => {
|
|
29297
30042
|
try {
|
|
29298
30043
|
const pkg = JSON.parse(readFileSync42(resolve37(__dirname5, "..", "package.json"), "utf-8"));
|
|
@@ -29581,7 +30326,7 @@ var config_upgrade_exports = {};
|
|
|
29581
30326
|
__export(config_upgrade_exports, {
|
|
29582
30327
|
runConfigUpgrade: () => runConfigUpgrade
|
|
29583
30328
|
});
|
|
29584
|
-
import { existsSync as
|
|
30329
|
+
import { existsSync as existsSync44, readFileSync as readFileSync43, writeFileSync as writeFileSync7, copyFileSync, unlinkSync as unlinkSync2 } from "fs";
|
|
29585
30330
|
import { resolve as resolve38 } from "path";
|
|
29586
30331
|
import { parse as parseYaml6 } from "yaml";
|
|
29587
30332
|
async function runConfigUpgrade(opts = {}) {
|
|
@@ -29593,7 +30338,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
29593
30338
|
const err = opts.silent ? () => {
|
|
29594
30339
|
} : (s) => process.stderr.write(s);
|
|
29595
30340
|
if (opts.rollback) {
|
|
29596
|
-
if (!
|
|
30341
|
+
if (!existsSync44(bakPath)) {
|
|
29597
30342
|
const message = `No backup found at ${bakPath}`;
|
|
29598
30343
|
err(message + "\n");
|
|
29599
30344
|
return { exitCode: 1, action: "none", message };
|
|
@@ -29609,7 +30354,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
29609
30354
|
return { exitCode: 2, action: "none", message };
|
|
29610
30355
|
}
|
|
29611
30356
|
}
|
|
29612
|
-
if (!
|
|
30357
|
+
if (!existsSync44(configPath)) {
|
|
29613
30358
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
29614
30359
|
err(message + "\n");
|
|
29615
30360
|
return { exitCode: 1, action: "none", message };
|
|
@@ -29640,7 +30385,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
29640
30385
|
};
|
|
29641
30386
|
try {
|
|
29642
30387
|
const original = readFileSync43(configPath, "utf-8");
|
|
29643
|
-
|
|
30388
|
+
writeFileSync7(bakPath, original, "utf-8");
|
|
29644
30389
|
} catch (e2) {
|
|
29645
30390
|
const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
|
|
29646
30391
|
err(message + "\n");
|
|
@@ -29673,7 +30418,7 @@ var config_check_drift_exports = {};
|
|
|
29673
30418
|
__export(config_check_drift_exports, {
|
|
29674
30419
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
29675
30420
|
});
|
|
29676
|
-
import { existsSync as
|
|
30421
|
+
import { existsSync as existsSync45, readFileSync as readFileSync44 } from "fs";
|
|
29677
30422
|
import { resolve as resolve39 } from "path";
|
|
29678
30423
|
import { parse as parseYaml7 } from "yaml";
|
|
29679
30424
|
function renderChanges(changes) {
|
|
@@ -29687,7 +30432,7 @@ async function runConfigCheckDrift(opts = {}) {
|
|
|
29687
30432
|
} : (s) => process.stdout.write(s);
|
|
29688
30433
|
const err = opts.silent ? () => {
|
|
29689
30434
|
} : (s) => process.stderr.write(s);
|
|
29690
|
-
if (!
|
|
30435
|
+
if (!existsSync45(configPath)) {
|
|
29691
30436
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
29692
30437
|
err(message + "\n");
|
|
29693
30438
|
return {
|
|
@@ -29769,10 +30514,10 @@ var init_config_check_drift = __esm({
|
|
|
29769
30514
|
|
|
29770
30515
|
// src/cli.ts
|
|
29771
30516
|
import { readFileSync as readFileSync45 } from "fs";
|
|
29772
|
-
import { resolve as resolve40, dirname as
|
|
30517
|
+
import { resolve as resolve40, dirname as dirname20 } from "path";
|
|
29773
30518
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
29774
30519
|
var __filename5 = fileURLToPath6(import.meta.url);
|
|
29775
|
-
var __dirname6 =
|
|
30520
|
+
var __dirname6 = dirname20(__filename5);
|
|
29776
30521
|
var args = process.argv.slice(2);
|
|
29777
30522
|
var subcommand = args[0];
|
|
29778
30523
|
async function main() {
|
|
@@ -29809,12 +30554,24 @@ async function main() {
|
|
|
29809
30554
|
process.exit(result.exitCode);
|
|
29810
30555
|
return;
|
|
29811
30556
|
}
|
|
30557
|
+
case "license": {
|
|
30558
|
+
const { handleLicenseSubcommand: handleLicenseSubcommand2 } = await Promise.resolve().then(() => (init_license2(), license_exports));
|
|
30559
|
+
const result = await handleLicenseSubcommand2(args.slice(1));
|
|
30560
|
+
process.exit(result.exitCode);
|
|
30561
|
+
return;
|
|
30562
|
+
}
|
|
29812
30563
|
case "changelog": {
|
|
29813
30564
|
const { handleChangelogSubcommand: handleChangelogSubcommand2 } = await Promise.resolve().then(() => (init_changelog(), changelog_exports));
|
|
29814
30565
|
const result = await handleChangelogSubcommand2(args.slice(1));
|
|
29815
30566
|
process.exit(result.exitCode);
|
|
29816
30567
|
return;
|
|
29817
30568
|
}
|
|
30569
|
+
case "rule": {
|
|
30570
|
+
const { handleRuleSubcommand: handleRuleSubcommand2 } = await Promise.resolve().then(() => (init_rule(), rule_exports));
|
|
30571
|
+
const result = await handleRuleSubcommand2(args.slice(1));
|
|
30572
|
+
process.exit(result.exitCode);
|
|
30573
|
+
return;
|
|
30574
|
+
}
|
|
29818
30575
|
case "show-template": {
|
|
29819
30576
|
const { runShowTemplate: runShowTemplate2 } = await Promise.resolve().then(() => (init_show_template(), show_template_exports));
|
|
29820
30577
|
await runShowTemplate2(args.slice(1));
|
|
@@ -29943,8 +30700,10 @@ Commands:
|
|
|
29943
30700
|
validate-config Validate massu.config.yaml (alias: config validate)
|
|
29944
30701
|
config <sub> Config lifecycle: refresh | validate | upgrade | doctor | check-drift
|
|
29945
30702
|
permissions <sub> MCP permission lifecycle: install | verify | check-drift
|
|
30703
|
+
license <sub> License/tier gate: check --min <free|pro|team|enterprise>
|
|
29946
30704
|
changelog <sub> CHANGELOG generation / verification: generate | verify
|
|
29947
30705
|
adapters <sub> Third-party adapter registry: list | refresh | search | add-local | remove-local | install | resign
|
|
30706
|
+
rule <sub> Auto-learning rule-candidate side-effects: record-shown <prompt_hash>
|
|
29948
30707
|
|
|
29949
30708
|
Options:
|
|
29950
30709
|
--help, -h Show this help message
|