@massu/core 1.13.1 → 1.15.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 +61 -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 +979 -206
- 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
|
|
|
@@ -15443,6 +15712,111 @@ var init_permissions2 = __esm({
|
|
|
15443
15712
|
}
|
|
15444
15713
|
});
|
|
15445
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
|
+
|
|
15446
15820
|
// src/changelog-generator.ts
|
|
15447
15821
|
import { existsSync as existsSync14, readFileSync as readFileSync13, readdirSync as readdirSync12 } from "fs";
|
|
15448
15822
|
import { resolve as resolve11 } from "path";
|
|
@@ -15682,12 +16056,397 @@ var init_changelog = __esm({
|
|
|
15682
16056
|
}
|
|
15683
16057
|
});
|
|
15684
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
|
+
|
|
15685
16444
|
// src/commands/show-template.ts
|
|
15686
16445
|
var show_template_exports = {};
|
|
15687
16446
|
__export(show_template_exports, {
|
|
15688
16447
|
runShowTemplate: () => runShowTemplate
|
|
15689
16448
|
});
|
|
15690
|
-
import { existsSync as
|
|
16449
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
|
|
15691
16450
|
import { resolve as resolve13 } from "path";
|
|
15692
16451
|
function normalizeBaseName(input) {
|
|
15693
16452
|
return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
|
|
@@ -15717,7 +16476,7 @@ async function runShowTemplate(args2) {
|
|
|
15717
16476
|
}
|
|
15718
16477
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
15719
16478
|
const file = suffix === "" ? resolve13(sourceDir, `${baseName}.md`) : resolve13(sourceDir, `${baseName}${suffix}.md`);
|
|
15720
|
-
if (!
|
|
16479
|
+
if (!existsSync17(file)) {
|
|
15721
16480
|
process.stderr.write(`massu: resolved template "${file}" no longer exists
|
|
15722
16481
|
`);
|
|
15723
16482
|
process.exit(1);
|
|
@@ -15776,8 +16535,8 @@ var init_passthrough = __esm({
|
|
|
15776
16535
|
});
|
|
15777
16536
|
|
|
15778
16537
|
// src/lib/fileLock.ts
|
|
15779
|
-
import { mkdirSync as
|
|
15780
|
-
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";
|
|
15781
16540
|
import * as lockfile from "proper-lockfile";
|
|
15782
16541
|
function readLockHolderPid(lockPath) {
|
|
15783
16542
|
try {
|
|
@@ -15800,7 +16559,7 @@ function busyWaitSync(ms) {
|
|
|
15800
16559
|
Atomics.wait(view, 0, 0, ms);
|
|
15801
16560
|
}
|
|
15802
16561
|
function withFileLockSync(lockPath, fn, opts = {}) {
|
|
15803
|
-
|
|
16562
|
+
mkdirSync7(dirname10(lockPath), { recursive: true });
|
|
15804
16563
|
const staleMs = opts.staleMs ?? 3e4;
|
|
15805
16564
|
const blockMs = opts.retries === 0 ? 0 : opts.blockMs ?? 3e4;
|
|
15806
16565
|
const pollIntervalMs = opts.pollIntervalMs ?? 100;
|
|
@@ -15817,7 +16576,7 @@ function withFileLockSync(lockPath, fn, opts = {}) {
|
|
|
15817
16576
|
realpath: false
|
|
15818
16577
|
});
|
|
15819
16578
|
try {
|
|
15820
|
-
|
|
16579
|
+
writeFileSync4(`${lockPath}.pid`, String(process.pid), "utf-8");
|
|
15821
16580
|
} catch {
|
|
15822
16581
|
}
|
|
15823
16582
|
break;
|
|
@@ -15906,7 +16665,7 @@ __export(config_refresh_exports, {
|
|
|
15906
16665
|
mergeRefresh: () => mergeRefresh,
|
|
15907
16666
|
runConfigRefresh: () => runConfigRefresh
|
|
15908
16667
|
});
|
|
15909
|
-
import { existsSync as
|
|
16668
|
+
import { existsSync as existsSync18, readFileSync as readFileSync17, rmSync as rmSync4 } from "fs";
|
|
15910
16669
|
import { resolve as resolve15 } from "path";
|
|
15911
16670
|
import { parse as parseYaml5 } from "yaml";
|
|
15912
16671
|
function flatten(obj, prefix3 = "") {
|
|
@@ -16038,7 +16797,7 @@ async function runConfigRefresh(opts = {}) {
|
|
|
16038
16797
|
const configPath = resolve15(cwd, "massu.config.yaml");
|
|
16039
16798
|
const log = opts.silent ? () => {
|
|
16040
16799
|
} : (s) => process.stdout.write(s);
|
|
16041
|
-
if (!
|
|
16800
|
+
if (!existsSync18(configPath)) {
|
|
16042
16801
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
16043
16802
|
if (!opts.silent) process.stderr.write(message + "\n");
|
|
16044
16803
|
return { exitCode: 1, applied: false, dryRun: !!opts.dryRun, diff: [], message };
|
|
@@ -16119,7 +16878,7 @@ async function runConfigRefresh(opts = {}) {
|
|
|
16119
16878
|
const stackResolved = installResult.totalInstalled > 0 || installResult.totalUpdated > 0;
|
|
16120
16879
|
if (stackResolved) {
|
|
16121
16880
|
const placeholderPath = resolve15(installResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
16122
|
-
if (
|
|
16881
|
+
if (existsSync18(placeholderPath)) {
|
|
16123
16882
|
try {
|
|
16124
16883
|
rmSync4(placeholderPath, { force: true });
|
|
16125
16884
|
log("Removed _massu-needs-stack.md (stack now declared).\n");
|
|
@@ -16228,12 +16987,12 @@ var init_gitToplevel = __esm({
|
|
|
16228
16987
|
});
|
|
16229
16988
|
|
|
16230
16989
|
// src/watch/lockfile-detector.ts
|
|
16231
|
-
import { existsSync as
|
|
16990
|
+
import { existsSync as existsSync19, statSync as statSync8 } from "fs";
|
|
16232
16991
|
import { resolve as resolve16 } from "path";
|
|
16233
16992
|
function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WINDOW_MS) {
|
|
16234
16993
|
for (const lf of KNOWN_LOCKFILES) {
|
|
16235
16994
|
const p19 = resolve16(projectRoot, lf);
|
|
16236
|
-
if (!
|
|
16995
|
+
if (!existsSync19(p19)) continue;
|
|
16237
16996
|
try {
|
|
16238
16997
|
const stat = statSync8(p19);
|
|
16239
16998
|
const delta = now - stat.mtimeMs;
|
|
@@ -16246,7 +17005,7 @@ function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WIN
|
|
|
16246
17005
|
function gitMidOperation(projectRoot) {
|
|
16247
17006
|
const sentinels = ["MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD", "rebase-apply", "rebase-merge"];
|
|
16248
17007
|
for (const s of sentinels) {
|
|
16249
|
-
if (
|
|
17008
|
+
if (existsSync19(resolve16(projectRoot, ".git", s))) return true;
|
|
16250
17009
|
}
|
|
16251
17010
|
return false;
|
|
16252
17011
|
}
|
|
@@ -16443,8 +17202,8 @@ var init_paths = __esm({
|
|
|
16443
17202
|
});
|
|
16444
17203
|
|
|
16445
17204
|
// src/watch/state.ts
|
|
16446
|
-
import { closeSync as closeSync3, existsSync as
|
|
16447
|
-
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";
|
|
16448
17207
|
function watchStatePath(projectRoot) {
|
|
16449
17208
|
return resolve17(projectRoot, ".massu", "watch-state.json");
|
|
16450
17209
|
}
|
|
@@ -16453,7 +17212,7 @@ function backupStatePath(projectRoot) {
|
|
|
16453
17212
|
}
|
|
16454
17213
|
function readState(projectRoot) {
|
|
16455
17214
|
const path = watchStatePath(projectRoot);
|
|
16456
|
-
if (!
|
|
17215
|
+
if (!existsSync20(path)) return { ...DEFAULT_STATE };
|
|
16457
17216
|
const content = readFileSync18(path, "utf-8");
|
|
16458
17217
|
let raw;
|
|
16459
17218
|
try {
|
|
@@ -16496,14 +17255,14 @@ function readState(projectRoot) {
|
|
|
16496
17255
|
}
|
|
16497
17256
|
function archiveCorrupt(projectRoot, content) {
|
|
16498
17257
|
const bak = backupStatePath(projectRoot);
|
|
16499
|
-
|
|
16500
|
-
|
|
17258
|
+
mkdirSync8(dirname11(bak), { recursive: true });
|
|
17259
|
+
writeFileSync5(bak, content, "utf-8");
|
|
16501
17260
|
}
|
|
16502
17261
|
function writeStateAtomic(projectRoot, state) {
|
|
16503
17262
|
const path = watchStatePath(projectRoot);
|
|
16504
17263
|
writeStateAtomicCounter = writeStateAtomicCounter + 1 >>> 0;
|
|
16505
17264
|
const tmp = `${path}.${process.pid}.${writeStateAtomicCounter}.tmp`;
|
|
16506
|
-
|
|
17265
|
+
mkdirSync8(dirname11(path), { recursive: true });
|
|
16507
17266
|
let renamed = false;
|
|
16508
17267
|
try {
|
|
16509
17268
|
const fd = openSync3(tmp, "w");
|
|
@@ -16517,7 +17276,7 @@ function writeStateAtomic(projectRoot, state) {
|
|
|
16517
17276
|
renameSync4(tmp, path);
|
|
16518
17277
|
renamed = true;
|
|
16519
17278
|
} finally {
|
|
16520
|
-
if (!renamed &&
|
|
17279
|
+
if (!renamed && existsSync20(tmp)) {
|
|
16521
17280
|
try {
|
|
16522
17281
|
rmSync5(tmp, { force: true });
|
|
16523
17282
|
} catch {
|
|
@@ -16797,8 +17556,8 @@ __export(watch_exports, {
|
|
|
16797
17556
|
runWatch: () => runWatch
|
|
16798
17557
|
});
|
|
16799
17558
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
16800
|
-
import { basename as basename5, dirname as
|
|
16801
|
-
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";
|
|
16802
17561
|
function parseFlags(args2) {
|
|
16803
17562
|
const out = {
|
|
16804
17563
|
foreground: false,
|
|
@@ -16824,7 +17583,7 @@ function parseFlags(args2) {
|
|
|
16824
17583
|
function findClaudeBg() {
|
|
16825
17584
|
const home = process.env.HOME ?? "";
|
|
16826
17585
|
const fixed = home ? resolve18(home, ".claude", "bin", "claude-bg") : null;
|
|
16827
|
-
if (fixed &&
|
|
17586
|
+
if (fixed && existsSync21(fixed)) return fixed;
|
|
16828
17587
|
const which = spawnSync3("which", ["claude-bg"], { encoding: "utf-8" });
|
|
16829
17588
|
if (which.status === 0 && which.stdout) {
|
|
16830
17589
|
const p19 = which.stdout.trim();
|
|
@@ -16885,7 +17644,7 @@ async function runWatch(args2) {
|
|
|
16885
17644
|
}
|
|
16886
17645
|
function runStatus(root) {
|
|
16887
17646
|
const path = watchStatePath(root);
|
|
16888
|
-
if (!
|
|
17647
|
+
if (!existsSync21(path)) {
|
|
16889
17648
|
process.stdout.write("massu watch: not running (no state file)\n");
|
|
16890
17649
|
return { exitCode: 0 };
|
|
16891
17650
|
}
|
|
@@ -17043,14 +17802,14 @@ function refreshLogPath(projectRoot) {
|
|
|
17043
17802
|
function appendRefreshLog(projectRoot, event) {
|
|
17044
17803
|
const path = refreshLogPath(projectRoot);
|
|
17045
17804
|
try {
|
|
17046
|
-
|
|
17805
|
+
mkdirSync9(dirname12(path), { recursive: true });
|
|
17047
17806
|
appendFileSync(path, JSON.stringify(event) + "\n", "utf-8");
|
|
17048
17807
|
} catch {
|
|
17049
17808
|
}
|
|
17050
17809
|
}
|
|
17051
17810
|
function readRefreshLog(projectRoot, limit = 10, opts = {}) {
|
|
17052
17811
|
const path = refreshLogPath(projectRoot);
|
|
17053
|
-
if (!
|
|
17812
|
+
if (!existsSync21(path)) return [];
|
|
17054
17813
|
const warn = opts.warn ?? ((s) => {
|
|
17055
17814
|
process.stderr.write(s);
|
|
17056
17815
|
});
|
|
@@ -17127,26 +17886,26 @@ var init_refresh_log = __esm({
|
|
|
17127
17886
|
import {
|
|
17128
17887
|
chmodSync as chmodSync3,
|
|
17129
17888
|
closeSync as closeSync4,
|
|
17130
|
-
existsSync as
|
|
17889
|
+
existsSync as existsSync22,
|
|
17131
17890
|
fsyncSync as fsyncSync4,
|
|
17132
|
-
mkdirSync as
|
|
17891
|
+
mkdirSync as mkdirSync10,
|
|
17133
17892
|
openSync as openSync4,
|
|
17134
17893
|
renameSync as renameSync5,
|
|
17135
17894
|
rmSync as rmSync6,
|
|
17136
17895
|
statSync as statSync9,
|
|
17137
17896
|
writeSync as writeSync4
|
|
17138
17897
|
} from "node:fs";
|
|
17139
|
-
import { dirname as
|
|
17898
|
+
import { dirname as dirname13 } from "node:path";
|
|
17140
17899
|
function atomicWrite(path, content, opts = {}) {
|
|
17141
17900
|
const tmpPath = `${path}.tmp`;
|
|
17142
|
-
const parentDir =
|
|
17901
|
+
const parentDir = dirname13(path);
|
|
17143
17902
|
try {
|
|
17144
|
-
if (!
|
|
17903
|
+
if (!existsSync22(parentDir)) {
|
|
17145
17904
|
const mkdirOpts = { recursive: true };
|
|
17146
17905
|
if (opts.ensureParentDirMode !== void 0) {
|
|
17147
17906
|
mkdirOpts.mode = opts.ensureParentDirMode;
|
|
17148
17907
|
}
|
|
17149
|
-
|
|
17908
|
+
mkdirSync10(parentDir, mkdirOpts);
|
|
17150
17909
|
}
|
|
17151
17910
|
const buf = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
|
|
17152
17911
|
const openMode = opts.mode ?? 420;
|
|
@@ -17163,7 +17922,7 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
17163
17922
|
renameSync5(tmpPath, path);
|
|
17164
17923
|
return { written: true };
|
|
17165
17924
|
} catch (err) {
|
|
17166
|
-
if (
|
|
17925
|
+
if (existsSync22(tmpPath)) {
|
|
17167
17926
|
try {
|
|
17168
17927
|
rmSync6(tmpPath, { force: true });
|
|
17169
17928
|
} catch {
|
|
@@ -17390,7 +18149,7 @@ var init_adapter_verifier = __esm({
|
|
|
17390
18149
|
// src/security/fetcher.ts
|
|
17391
18150
|
async function fetchUrl(url, opts = {}) {
|
|
17392
18151
|
const allowedHosts = opts.allowedHosts ?? ALLOWED_HOSTS;
|
|
17393
|
-
const timeoutMs = opts.timeoutMs ??
|
|
18152
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
17394
18153
|
const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
17395
18154
|
let parsed;
|
|
17396
18155
|
try {
|
|
@@ -17464,11 +18223,11 @@ async function fetchUrl(url, opts = {}) {
|
|
|
17464
18223
|
clearTimeout(timeoutHandle);
|
|
17465
18224
|
}
|
|
17466
18225
|
}
|
|
17467
|
-
var
|
|
18226
|
+
var DEFAULT_TIMEOUT_MS2, DEFAULT_MAX_BODY_BYTES, ALLOWED_HOSTS, FetchAllowlistError, FetchTimeoutError, FetchBodySizeError;
|
|
17468
18227
|
var init_fetcher = __esm({
|
|
17469
18228
|
"src/security/fetcher.ts"() {
|
|
17470
18229
|
"use strict";
|
|
17471
|
-
|
|
18230
|
+
DEFAULT_TIMEOUT_MS2 = 1e4;
|
|
17472
18231
|
DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;
|
|
17473
18232
|
ALLOWED_HOSTS = [
|
|
17474
18233
|
"registry.massu.ai",
|
|
@@ -17506,7 +18265,7 @@ var init_fetcher = __esm({
|
|
|
17506
18265
|
});
|
|
17507
18266
|
|
|
17508
18267
|
// src/security/manifest-cache.ts
|
|
17509
|
-
import { existsSync as
|
|
18268
|
+
import { existsSync as existsSync23, readFileSync as readFileSync20, statSync as statSync10 } from "node:fs";
|
|
17510
18269
|
import { homedir as homedir5 } from "node:os";
|
|
17511
18270
|
import { resolve as resolve19 } from "node:path";
|
|
17512
18271
|
import { z as z4 } from "zod";
|
|
@@ -17518,7 +18277,7 @@ function defaultCachePaths() {
|
|
|
17518
18277
|
};
|
|
17519
18278
|
}
|
|
17520
18279
|
function loadCachedManifest(paths = defaultCachePaths()) {
|
|
17521
|
-
if (!
|
|
18280
|
+
if (!existsSync23(paths.cachePath)) {
|
|
17522
18281
|
return { kind: "absent" };
|
|
17523
18282
|
}
|
|
17524
18283
|
let raw;
|
|
@@ -17712,7 +18471,7 @@ var init_adapter_origin = __esm({
|
|
|
17712
18471
|
});
|
|
17713
18472
|
|
|
17714
18473
|
// src/security/local-fingerprint.ts
|
|
17715
|
-
import { existsSync as
|
|
18474
|
+
import { existsSync as existsSync24, readFileSync as readFileSync21, lstatSync as lstatSync5 } from "node:fs";
|
|
17716
18475
|
import { homedir as homedir6 } from "node:os";
|
|
17717
18476
|
import { resolve as resolve20, isAbsolute } from "node:path";
|
|
17718
18477
|
import { createHash as createHash7 } from "node:crypto";
|
|
@@ -17741,7 +18500,7 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
17741
18500
|
return createHash7("sha256").update(canonical).digest("hex");
|
|
17742
18501
|
}
|
|
17743
18502
|
function readFingerprintSentinel(path = FINGERPRINT_PATH) {
|
|
17744
|
-
if (!
|
|
18503
|
+
if (!existsSync24(path)) return null;
|
|
17745
18504
|
let raw;
|
|
17746
18505
|
try {
|
|
17747
18506
|
raw = JSON.parse(readFileSync21(path, "utf-8"));
|
|
@@ -17808,15 +18567,15 @@ var init_local_fingerprint = __esm({
|
|
|
17808
18567
|
});
|
|
17809
18568
|
|
|
17810
18569
|
// src/security/install-tracking.ts
|
|
17811
|
-
import { readFileSync as readFileSync22, readdirSync as readdirSync13, lstatSync as lstatSync6, existsSync as
|
|
17812
|
-
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";
|
|
17813
18572
|
import { homedir as homedir7 } from "node:os";
|
|
17814
18573
|
import { resolve as resolve21 } from "node:path";
|
|
17815
18574
|
import { createHash as createHash8 } from "node:crypto";
|
|
17816
18575
|
import { z as z6 } from "zod";
|
|
17817
18576
|
function containsHiddenDirs(packageDir) {
|
|
17818
18577
|
for (const hidden of EXCLUDED_DIR_NAMES) {
|
|
17819
|
-
if (
|
|
18578
|
+
if (existsSync25(`${packageDir}/${hidden}`)) {
|
|
17820
18579
|
return hidden;
|
|
17821
18580
|
}
|
|
17822
18581
|
}
|
|
@@ -17833,7 +18592,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
17833
18592
|
return;
|
|
17834
18593
|
}
|
|
17835
18594
|
for (const entry of entries.sort()) {
|
|
17836
|
-
const absPath =
|
|
18595
|
+
const absPath = join12(currentDir, entry);
|
|
17837
18596
|
let lst;
|
|
17838
18597
|
try {
|
|
17839
18598
|
lst = lstatSync6(absPath);
|
|
@@ -17871,7 +18630,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
17871
18630
|
return top.digest("hex");
|
|
17872
18631
|
}
|
|
17873
18632
|
function readInstalledManifest(path = INSTALLED_MANIFEST_PATH) {
|
|
17874
|
-
if (!
|
|
18633
|
+
if (!existsSync25(path)) return {};
|
|
17875
18634
|
let raw;
|
|
17876
18635
|
try {
|
|
17877
18636
|
raw = JSON.parse(readFileSync22(path, "utf-8"));
|
|
@@ -17913,8 +18672,8 @@ function removeInstalledManifestEntry(packageName, path = INSTALLED_MANIFEST_PAT
|
|
|
17913
18672
|
}
|
|
17914
18673
|
return { written: true };
|
|
17915
18674
|
}
|
|
17916
|
-
function verifyInstalledIntegrity(packageName, packageDir,
|
|
17917
|
-
const installed = readInstalledManifest(
|
|
18675
|
+
function verifyInstalledIntegrity(packageName, packageDir, sidecarPath2 = INSTALLED_MANIFEST_PATH) {
|
|
18676
|
+
const installed = readInstalledManifest(sidecarPath2);
|
|
17918
18677
|
const entry = installed[packageName];
|
|
17919
18678
|
if (!entry) {
|
|
17920
18679
|
return {
|
|
@@ -17961,12 +18720,12 @@ var init_install_tracking = __esm({
|
|
|
17961
18720
|
});
|
|
17962
18721
|
|
|
17963
18722
|
// src/detect/adapters/discover.ts
|
|
17964
|
-
import { existsSync as
|
|
18723
|
+
import { existsSync as existsSync26, readdirSync as readdirSync14, readFileSync as readFileSync23, lstatSync as lstatSync7 } from "node:fs";
|
|
17965
18724
|
import { resolve as resolve22, isAbsolute as isAbsolute2 } from "node:path";
|
|
17966
18725
|
import { z as z7 } from "zod";
|
|
17967
18726
|
function walkNodeModules(projectRoot, warnings) {
|
|
17968
18727
|
const nodeModulesDir = resolve22(projectRoot, "node_modules");
|
|
17969
|
-
if (!
|
|
18728
|
+
if (!existsSync26(nodeModulesDir)) {
|
|
17970
18729
|
return [];
|
|
17971
18730
|
}
|
|
17972
18731
|
const candidates = [];
|
|
@@ -18021,7 +18780,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
18021
18780
|
}
|
|
18022
18781
|
function tryReadAdapterPackage(packageDir, warnings) {
|
|
18023
18782
|
const pkgJsonPath = resolve22(packageDir, "package.json");
|
|
18024
|
-
if (!
|
|
18783
|
+
if (!existsSync26(pkgJsonPath)) return null;
|
|
18025
18784
|
let raw;
|
|
18026
18785
|
try {
|
|
18027
18786
|
raw = JSON.parse(readFileSync23(pkgJsonPath, "utf-8"));
|
|
@@ -18159,7 +18918,7 @@ function discoverAdapters(opts) {
|
|
|
18159
18918
|
for (const localPath of opts.configLocalPaths) {
|
|
18160
18919
|
if (seenIds.has(localPath)) continue;
|
|
18161
18920
|
const absPath = isAbsolute2(localPath) ? localPath : resolve22(opts.projectRoot, localPath);
|
|
18162
|
-
if (!
|
|
18921
|
+
if (!existsSync26(absPath)) {
|
|
18163
18922
|
warnings.push(
|
|
18164
18923
|
`local adapter file not found: ${localPath} (resolved to ${absPath}). Remove via: massu adapters remove-local ${localPath}`
|
|
18165
18924
|
);
|
|
@@ -18241,7 +19000,7 @@ __export(adapters_exports, {
|
|
|
18241
19000
|
runAdaptersResyncLocalFingerprint: () => runAdaptersResyncLocalFingerprint,
|
|
18242
19001
|
runAdaptersSearch: () => runAdaptersSearch
|
|
18243
19002
|
});
|
|
18244
|
-
import { existsSync as
|
|
19003
|
+
import { existsSync as existsSync27, readFileSync as readFileSync24 } from "node:fs";
|
|
18245
19004
|
import { resolve as resolve23 } from "node:path";
|
|
18246
19005
|
import { parseDocument } from "yaml";
|
|
18247
19006
|
async function handleAdaptersSubcommand(args2) {
|
|
@@ -18510,7 +19269,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
18510
19269
|
return { exitCode: 2 };
|
|
18511
19270
|
}
|
|
18512
19271
|
const yamlPath = resolve23(projectRoot, "massu.config.yaml");
|
|
18513
|
-
if (!
|
|
19272
|
+
if (!existsSync27(yamlPath)) {
|
|
18514
19273
|
process.stderr.write(
|
|
18515
19274
|
`${command}: massu.config.yaml not found at ${yamlPath}. Run \`massu init\` first.
|
|
18516
19275
|
`
|
|
@@ -18610,7 +19369,7 @@ async function runAdaptersInstall(args2) {
|
|
|
18610
19369
|
return { exitCode: 1 };
|
|
18611
19370
|
}
|
|
18612
19371
|
const packageDir = resolve23(projectRoot, "node_modules", ...packageName.split("/"));
|
|
18613
|
-
if (!
|
|
19372
|
+
if (!existsSync27(packageDir)) {
|
|
18614
19373
|
process.stderr.write(
|
|
18615
19374
|
`install: ${packageName} is not installed in node_modules. Run \`npm install ${packageName}\` first.
|
|
18616
19375
|
`
|
|
@@ -18618,7 +19377,7 @@ async function runAdaptersInstall(args2) {
|
|
|
18618
19377
|
return { exitCode: 1 };
|
|
18619
19378
|
}
|
|
18620
19379
|
const pkgJsonPath = resolve23(packageDir, "package.json");
|
|
18621
|
-
if (!
|
|
19380
|
+
if (!existsSync27(pkgJsonPath)) {
|
|
18622
19381
|
process.stderr.write(`install: ${packageName} has no package.json at ${pkgJsonPath}
|
|
18623
19382
|
`);
|
|
18624
19383
|
return { exitCode: 1 };
|
|
@@ -18745,7 +19504,7 @@ async function runAdaptersResign(_args) {
|
|
|
18745
19504
|
continue;
|
|
18746
19505
|
}
|
|
18747
19506
|
const packageDir = resolve23(projectRoot, "node_modules", ...name.split("/"));
|
|
18748
|
-
if (!
|
|
19507
|
+
if (!existsSync27(packageDir)) {
|
|
18749
19508
|
removed++;
|
|
18750
19509
|
warnings.push(`${name}@${entry.version}: not present in node_modules \u2014 REMOVED from sidecar`);
|
|
18751
19510
|
removeInstalledManifestEntry(name);
|
|
@@ -18843,11 +19602,11 @@ var init_sql_table_names = __esm({
|
|
|
18843
19602
|
|
|
18844
19603
|
// src/db.ts
|
|
18845
19604
|
import Database2 from "better-sqlite3";
|
|
18846
|
-
import { dirname as
|
|
18847
|
-
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";
|
|
18848
19607
|
function getCodeGraphDb() {
|
|
18849
19608
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
18850
|
-
if (!
|
|
19609
|
+
if (!existsSync28(dbPath)) {
|
|
18851
19610
|
throw new CodegraphDbNotInitializedError(dbPath);
|
|
18852
19611
|
}
|
|
18853
19612
|
const db = new Database2(dbPath, { readonly: true });
|
|
@@ -18856,9 +19615,9 @@ function getCodeGraphDb() {
|
|
|
18856
19615
|
}
|
|
18857
19616
|
function getDataDb() {
|
|
18858
19617
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
18859
|
-
const dir =
|
|
18860
|
-
if (!
|
|
18861
|
-
|
|
19618
|
+
const dir = dirname14(dbPath);
|
|
19619
|
+
if (!existsSync28(dir)) {
|
|
19620
|
+
mkdirSync11(dir, { recursive: true });
|
|
18862
19621
|
}
|
|
18863
19622
|
const db = new Database2(dbPath);
|
|
18864
19623
|
db.pragma("journal_mode = WAL");
|
|
@@ -19130,7 +19889,7 @@ function isPythonDataStale(dataDb, pythonRoot) {
|
|
|
19130
19889
|
try {
|
|
19131
19890
|
const entries = readdirSync15(dir, { withFileTypes: true });
|
|
19132
19891
|
for (const entry of entries) {
|
|
19133
|
-
const fullPath =
|
|
19892
|
+
const fullPath = join13(dir, entry.name);
|
|
19134
19893
|
if (entry.isDirectory()) {
|
|
19135
19894
|
if (["__pycache__", ".venv", "venv", "node_modules", ".mypy_cache", ".pytest_cache"].includes(entry.name)) continue;
|
|
19136
19895
|
if (checkDir(fullPath)) return true;
|
|
@@ -19166,13 +19925,13 @@ var init_db = __esm({
|
|
|
19166
19925
|
|
|
19167
19926
|
// src/knowledge-db.ts
|
|
19168
19927
|
import Database3 from "better-sqlite3";
|
|
19169
|
-
import { dirname as
|
|
19170
|
-
import { existsSync as
|
|
19928
|
+
import { dirname as dirname15 } from "path";
|
|
19929
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync12 } from "fs";
|
|
19171
19930
|
function getKnowledgeDb() {
|
|
19172
19931
|
const dbPath = getResolvedPaths().knowledgeDbPath;
|
|
19173
|
-
const dir =
|
|
19174
|
-
if (!
|
|
19175
|
-
|
|
19932
|
+
const dir = dirname15(dbPath);
|
|
19933
|
+
if (!existsSync29(dir)) {
|
|
19934
|
+
mkdirSync12(dir, { recursive: true });
|
|
19176
19935
|
}
|
|
19177
19936
|
const db = new Database3(dbPath);
|
|
19178
19937
|
db.pragma("journal_mode = WAL");
|
|
@@ -19419,8 +20178,8 @@ var init_rules = __esm({
|
|
|
19419
20178
|
});
|
|
19420
20179
|
|
|
19421
20180
|
// src/import-resolver.ts
|
|
19422
|
-
import { readFileSync as readFileSync25, existsSync as
|
|
19423
|
-
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";
|
|
19424
20183
|
function parseImports(source) {
|
|
19425
20184
|
const imports = [];
|
|
19426
20185
|
const lines = source.split("\n");
|
|
@@ -19478,21 +20237,21 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
19478
20237
|
const paths = getResolvedPaths();
|
|
19479
20238
|
basePath = resolve25(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
19480
20239
|
} else {
|
|
19481
|
-
basePath = resolve25(
|
|
20240
|
+
basePath = resolve25(dirname16(fromFile), specifier);
|
|
19482
20241
|
}
|
|
19483
|
-
if (
|
|
20242
|
+
if (existsSync30(basePath) && !isDirectory(basePath)) {
|
|
19484
20243
|
return toRelative(basePath);
|
|
19485
20244
|
}
|
|
19486
20245
|
const resolvedPaths = getResolvedPaths();
|
|
19487
20246
|
for (const ext of resolvedPaths.extensions) {
|
|
19488
20247
|
const withExt = basePath + ext;
|
|
19489
|
-
if (
|
|
20248
|
+
if (existsSync30(withExt)) {
|
|
19490
20249
|
return toRelative(withExt);
|
|
19491
20250
|
}
|
|
19492
20251
|
}
|
|
19493
20252
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
19494
|
-
const indexPath =
|
|
19495
|
-
if (
|
|
20253
|
+
const indexPath = join14(basePath, indexFile);
|
|
20254
|
+
if (existsSync30(indexPath)) {
|
|
19496
20255
|
return toRelative(indexPath);
|
|
19497
20256
|
}
|
|
19498
20257
|
}
|
|
@@ -19529,7 +20288,7 @@ function buildImportIndex(dataDb, codegraphDb) {
|
|
|
19529
20288
|
let batch = [];
|
|
19530
20289
|
for (const file of files) {
|
|
19531
20290
|
const absPath = ensureWithinRoot(resolve25(projectRoot, file.path), projectRoot);
|
|
19532
|
-
if (!
|
|
20291
|
+
if (!existsSync30(absPath)) continue;
|
|
19533
20292
|
let source;
|
|
19534
20293
|
try {
|
|
19535
20294
|
source = readFileSync25(absPath, "utf-8");
|
|
@@ -19569,12 +20328,12 @@ var init_import_resolver = __esm({
|
|
|
19569
20328
|
});
|
|
19570
20329
|
|
|
19571
20330
|
// src/trpc-index.ts
|
|
19572
|
-
import { readFileSync as readFileSync26, existsSync as
|
|
19573
|
-
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";
|
|
19574
20333
|
function parseRootRouter() {
|
|
19575
20334
|
const paths = getResolvedPaths();
|
|
19576
20335
|
const rootPath = paths.rootRouterPath;
|
|
19577
|
-
if (!
|
|
20336
|
+
if (!existsSync31(rootPath)) {
|
|
19578
20337
|
throw new Error(`Root router not found at ${rootPath}`);
|
|
19579
20338
|
}
|
|
19580
20339
|
const source = readFileSync26(rootPath, "utf-8");
|
|
@@ -19589,12 +20348,12 @@ function parseRootRouter() {
|
|
|
19589
20348
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
19590
20349
|
const candidate = fullPath + ext;
|
|
19591
20350
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
19592
|
-
if (
|
|
20351
|
+
if (existsSync31(candidate)) {
|
|
19593
20352
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
19594
20353
|
break;
|
|
19595
20354
|
}
|
|
19596
|
-
const indexCandidate =
|
|
19597
|
-
if (
|
|
20355
|
+
const indexCandidate = join15(fullPath, "index.ts");
|
|
20356
|
+
if (existsSync31(indexCandidate)) {
|
|
19598
20357
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
19599
20358
|
break;
|
|
19600
20359
|
}
|
|
@@ -19614,7 +20373,7 @@ function parseRootRouter() {
|
|
|
19614
20373
|
}
|
|
19615
20374
|
function extractProcedures(routerFilePath) {
|
|
19616
20375
|
const absPath = resolve26(getProjectRoot(), routerFilePath);
|
|
19617
|
-
if (!
|
|
20376
|
+
if (!existsSync31(absPath)) return [];
|
|
19618
20377
|
const source = readFileSync26(absPath, "utf-8");
|
|
19619
20378
|
const procedures = [];
|
|
19620
20379
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -19644,7 +20403,7 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
19644
20403
|
];
|
|
19645
20404
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
19646
20405
|
for (const dir of searchDirs) {
|
|
19647
|
-
if (!
|
|
20406
|
+
if (!existsSync31(dir)) continue;
|
|
19648
20407
|
searchDirectory(dir, searchPattern, callSites);
|
|
19649
20408
|
}
|
|
19650
20409
|
return callSites;
|
|
@@ -19652,7 +20411,7 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
19652
20411
|
function searchDirectory(dir, pattern, results) {
|
|
19653
20412
|
const entries = readdirSync16(dir, { withFileTypes: true });
|
|
19654
20413
|
for (const entry of entries) {
|
|
19655
|
-
const fullPath =
|
|
20414
|
+
const fullPath = join15(dir, entry.name);
|
|
19656
20415
|
if (entry.isDirectory()) {
|
|
19657
20416
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
19658
20417
|
searchDirectory(fullPath, pattern, results);
|
|
@@ -19722,7 +20481,7 @@ var init_trpc_index = __esm({
|
|
|
19722
20481
|
});
|
|
19723
20482
|
|
|
19724
20483
|
// src/page-deps.ts
|
|
19725
|
-
import { readFileSync as readFileSync27, existsSync as
|
|
20484
|
+
import { readFileSync as readFileSync27, existsSync as existsSync32 } from "fs";
|
|
19726
20485
|
import { resolve as resolve27 } from "path";
|
|
19727
20486
|
function deriveRoute(pageFile) {
|
|
19728
20487
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
@@ -19762,7 +20521,7 @@ function findRouterCalls(files) {
|
|
|
19762
20521
|
const projectRoot = getProjectRoot();
|
|
19763
20522
|
for (const file of files) {
|
|
19764
20523
|
const absPath = ensureWithinRoot(resolve27(projectRoot, file), projectRoot);
|
|
19765
|
-
if (!
|
|
20524
|
+
if (!existsSync32(absPath)) continue;
|
|
19766
20525
|
try {
|
|
19767
20526
|
const source = readFileSync27(absPath, "utf-8");
|
|
19768
20527
|
const apiCallRegex = /api\.(\w+)\.\w+/g;
|
|
@@ -19783,7 +20542,7 @@ function findTablesFromRouters(routerNames, dataDb) {
|
|
|
19783
20542
|
).all(routerName);
|
|
19784
20543
|
for (const proc of procs) {
|
|
19785
20544
|
const absPath = ensureWithinRoot(resolve27(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
19786
|
-
if (!
|
|
20545
|
+
if (!existsSync32(absPath)) continue;
|
|
19787
20546
|
try {
|
|
19788
20547
|
const source = readFileSync27(absPath, "utf-8");
|
|
19789
20548
|
const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
|
|
@@ -20057,11 +20816,11 @@ var init_domains = __esm({
|
|
|
20057
20816
|
});
|
|
20058
20817
|
|
|
20059
20818
|
// src/schema-mapper.ts
|
|
20060
|
-
import { readFileSync as readFileSync28, existsSync as
|
|
20061
|
-
import { join as
|
|
20819
|
+
import { readFileSync as readFileSync28, existsSync as existsSync33, readdirSync as readdirSync17 } from "fs";
|
|
20820
|
+
import { join as join16 } from "path";
|
|
20062
20821
|
function parsePrismaSchema() {
|
|
20063
20822
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
20064
|
-
if (!
|
|
20823
|
+
if (!existsSync33(schemaPath)) {
|
|
20065
20824
|
throw new Error(`Prisma schema not found at ${schemaPath}`);
|
|
20066
20825
|
}
|
|
20067
20826
|
const source = readFileSync28(schemaPath, "utf-8");
|
|
@@ -20122,14 +20881,14 @@ function toSnakeCase(str) {
|
|
|
20122
20881
|
function findColumnUsageInRouters(tableName) {
|
|
20123
20882
|
const usage = /* @__PURE__ */ new Map();
|
|
20124
20883
|
const routersDir = getResolvedPaths().routersDir;
|
|
20125
|
-
if (!
|
|
20884
|
+
if (!existsSync33(routersDir)) return usage;
|
|
20126
20885
|
scanDirectory(routersDir, tableName, usage);
|
|
20127
20886
|
return usage;
|
|
20128
20887
|
}
|
|
20129
20888
|
function scanDirectory(dir, tableName, usage) {
|
|
20130
20889
|
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
20131
20890
|
for (const entry of entries) {
|
|
20132
|
-
const fullPath =
|
|
20891
|
+
const fullPath = join16(dir, entry.name);
|
|
20133
20892
|
if (entry.isDirectory()) {
|
|
20134
20893
|
scanDirectory(fullPath, tableName, usage);
|
|
20135
20894
|
} else if (entry.name.endsWith(".ts")) {
|
|
@@ -20184,10 +20943,10 @@ function detectMismatches(models) {
|
|
|
20184
20943
|
}
|
|
20185
20944
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
20186
20945
|
const result = [];
|
|
20187
|
-
if (!
|
|
20946
|
+
if (!existsSync33(dir)) return result;
|
|
20188
20947
|
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
20189
20948
|
for (const entry of entries) {
|
|
20190
|
-
const fullPath =
|
|
20949
|
+
const fullPath = join16(dir, entry.name);
|
|
20191
20950
|
if (entry.isDirectory()) {
|
|
20192
20951
|
result.push(...findFilesUsingColumn(fullPath, column, tableName));
|
|
20193
20952
|
} else if (entry.name.endsWith(".ts")) {
|
|
@@ -20337,34 +21096,34 @@ var init_import_parser = __esm({
|
|
|
20337
21096
|
});
|
|
20338
21097
|
|
|
20339
21098
|
// src/python/import-resolver.ts
|
|
20340
|
-
import { readFileSync as readFileSync29, existsSync as
|
|
20341
|
-
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";
|
|
20342
21101
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
20343
21102
|
const projectRoot = getProjectRoot();
|
|
20344
21103
|
if (level > 0) {
|
|
20345
|
-
let baseDir =
|
|
21104
|
+
let baseDir = dirname17(resolve29(projectRoot, fromFile));
|
|
20346
21105
|
for (let i = 1; i < level; i++) {
|
|
20347
|
-
baseDir =
|
|
21106
|
+
baseDir = dirname17(baseDir);
|
|
20348
21107
|
}
|
|
20349
21108
|
const modulePart = module.replace(/^\.+/, "");
|
|
20350
21109
|
if (modulePart) {
|
|
20351
21110
|
const parts2 = modulePart.split(".");
|
|
20352
|
-
return tryResolvePythonPath(
|
|
21111
|
+
return tryResolvePythonPath(join17(baseDir, ...parts2), projectRoot);
|
|
20353
21112
|
}
|
|
20354
21113
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
20355
21114
|
}
|
|
20356
21115
|
const parts = module.split(".");
|
|
20357
|
-
const candidate =
|
|
21116
|
+
const candidate = join17(resolve29(projectRoot, pythonRoot), ...parts);
|
|
20358
21117
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
20359
21118
|
}
|
|
20360
21119
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
20361
|
-
if (
|
|
21120
|
+
if (existsSync34(basePath + ".py")) {
|
|
20362
21121
|
return relative6(projectRoot, basePath + ".py");
|
|
20363
21122
|
}
|
|
20364
|
-
if (
|
|
20365
|
-
return relative6(projectRoot,
|
|
21123
|
+
if (existsSync34(join17(basePath, "__init__.py"))) {
|
|
21124
|
+
return relative6(projectRoot, join17(basePath, "__init__.py"));
|
|
20366
21125
|
}
|
|
20367
|
-
if (basePath.endsWith(".py") &&
|
|
21126
|
+
if (basePath.endsWith(".py") && existsSync34(basePath)) {
|
|
20368
21127
|
return relative6(projectRoot, basePath);
|
|
20369
21128
|
}
|
|
20370
21129
|
return null;
|
|
@@ -20376,9 +21135,9 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
20376
21135
|
for (const entry of entries) {
|
|
20377
21136
|
if (entry.isDirectory()) {
|
|
20378
21137
|
if (excludeDirs.includes(entry.name)) continue;
|
|
20379
|
-
files.push(...walkPythonFiles(
|
|
21138
|
+
files.push(...walkPythonFiles(join17(dir, entry.name), excludeDirs));
|
|
20380
21139
|
} else if (entry.name.endsWith(".py")) {
|
|
20381
|
-
files.push(
|
|
21140
|
+
files.push(join17(dir, entry.name));
|
|
20382
21141
|
}
|
|
20383
21142
|
}
|
|
20384
21143
|
} catch {
|
|
@@ -20672,7 +21431,7 @@ var init_route_parser = __esm({
|
|
|
20672
21431
|
|
|
20673
21432
|
// src/python/route-indexer.ts
|
|
20674
21433
|
import { readFileSync as readFileSync30, readdirSync as readdirSync19 } from "fs";
|
|
20675
|
-
import { join as
|
|
21434
|
+
import { join as join18, relative as relative7 } from "path";
|
|
20676
21435
|
function walkPyFiles(dir, excludeDirs) {
|
|
20677
21436
|
const files = [];
|
|
20678
21437
|
try {
|
|
@@ -20680,9 +21439,9 @@ function walkPyFiles(dir, excludeDirs) {
|
|
|
20680
21439
|
for (const entry of entries) {
|
|
20681
21440
|
if (entry.isDirectory()) {
|
|
20682
21441
|
if (excludeDirs.includes(entry.name)) continue;
|
|
20683
|
-
files.push(...walkPyFiles(
|
|
21442
|
+
files.push(...walkPyFiles(join18(dir, entry.name), excludeDirs));
|
|
20684
21443
|
} else if (entry.name.endsWith(".py")) {
|
|
20685
|
-
files.push(
|
|
21444
|
+
files.push(join18(dir, entry.name));
|
|
20686
21445
|
}
|
|
20687
21446
|
}
|
|
20688
21447
|
} catch {
|
|
@@ -20691,7 +21450,7 @@ function walkPyFiles(dir, excludeDirs) {
|
|
|
20691
21450
|
}
|
|
20692
21451
|
function buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
20693
21452
|
const projectRoot = getProjectRoot();
|
|
20694
|
-
const absRoot =
|
|
21453
|
+
const absRoot = join18(projectRoot, pythonRoot);
|
|
20695
21454
|
dataDb.exec(`DELETE FROM ${t("py_routes")}`);
|
|
20696
21455
|
dataDb.exec(`DELETE FROM ${t("py_route_callers")}`);
|
|
20697
21456
|
const insertStmt = dataDb.prepare(
|
|
@@ -20917,7 +21676,7 @@ var init_model_parser = __esm({
|
|
|
20917
21676
|
|
|
20918
21677
|
// src/python/model-indexer.ts
|
|
20919
21678
|
import { readFileSync as readFileSync31, readdirSync as readdirSync20 } from "fs";
|
|
20920
|
-
import { join as
|
|
21679
|
+
import { join as join19, relative as relative8 } from "path";
|
|
20921
21680
|
function walkPyFiles2(dir, excludeDirs) {
|
|
20922
21681
|
const files = [];
|
|
20923
21682
|
try {
|
|
@@ -20925,9 +21684,9 @@ function walkPyFiles2(dir, excludeDirs) {
|
|
|
20925
21684
|
for (const entry of entries) {
|
|
20926
21685
|
if (entry.isDirectory()) {
|
|
20927
21686
|
if (excludeDirs.includes(entry.name)) continue;
|
|
20928
|
-
files.push(...walkPyFiles2(
|
|
21687
|
+
files.push(...walkPyFiles2(join19(dir, entry.name), excludeDirs));
|
|
20929
21688
|
} else if (entry.name.endsWith(".py")) {
|
|
20930
|
-
files.push(
|
|
21689
|
+
files.push(join19(dir, entry.name));
|
|
20931
21690
|
}
|
|
20932
21691
|
}
|
|
20933
21692
|
} catch {
|
|
@@ -20936,7 +21695,7 @@ function walkPyFiles2(dir, excludeDirs) {
|
|
|
20936
21695
|
}
|
|
20937
21696
|
function buildPythonModelIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
20938
21697
|
const projectRoot = getProjectRoot();
|
|
20939
|
-
const absRoot =
|
|
21698
|
+
const absRoot = join19(projectRoot, pythonRoot);
|
|
20940
21699
|
dataDb.exec(`DELETE FROM ${t("py_models")}`);
|
|
20941
21700
|
dataDb.exec(`DELETE FROM ${t("py_fk_edges")}`);
|
|
20942
21701
|
const insertModel = dataDb.prepare(
|
|
@@ -21214,18 +21973,18 @@ var init_migration_parser = __esm({
|
|
|
21214
21973
|
|
|
21215
21974
|
// src/python/migration-indexer.ts
|
|
21216
21975
|
import { readFileSync as readFileSync32, readdirSync as readdirSync21 } from "fs";
|
|
21217
|
-
import { join as
|
|
21976
|
+
import { join as join20, relative as relative9 } from "path";
|
|
21218
21977
|
function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
21219
21978
|
const projectRoot = getProjectRoot();
|
|
21220
|
-
const absDir =
|
|
21979
|
+
const absDir = join20(projectRoot, alembicDir);
|
|
21221
21980
|
dataDb.exec(`DELETE FROM ${t("py_migrations")}`);
|
|
21222
|
-
const versionsDir =
|
|
21981
|
+
const versionsDir = join20(absDir, "versions");
|
|
21223
21982
|
let files = [];
|
|
21224
21983
|
try {
|
|
21225
|
-
files = readdirSync21(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) =>
|
|
21984
|
+
files = readdirSync21(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) => join20(versionsDir, f2));
|
|
21226
21985
|
} catch {
|
|
21227
21986
|
try {
|
|
21228
|
-
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));
|
|
21229
21988
|
} catch {
|
|
21230
21989
|
}
|
|
21231
21990
|
}
|
|
@@ -21275,11 +22034,11 @@ var init_migration_indexer = __esm({
|
|
|
21275
22034
|
|
|
21276
22035
|
// src/python/coupling-detector.ts
|
|
21277
22036
|
import { readFileSync as readFileSync33, readdirSync as readdirSync22 } from "fs";
|
|
21278
|
-
import { join as
|
|
22037
|
+
import { join as join21, relative as relative10 } from "path";
|
|
21279
22038
|
function buildPythonCouplingIndex(dataDb) {
|
|
21280
22039
|
const projectRoot = getProjectRoot();
|
|
21281
22040
|
const config = getConfig();
|
|
21282
|
-
const srcDir =
|
|
22041
|
+
const srcDir = join21(projectRoot, config.paths.source);
|
|
21283
22042
|
const routes = dataDb.prepare(`SELECT id, method, path FROM ${t("py_routes")}`).all();
|
|
21284
22043
|
if (routes.length === 0) return 0;
|
|
21285
22044
|
dataDb.exec(`DELETE FROM ${t("py_route_callers")}`);
|
|
@@ -21343,9 +22102,9 @@ function walkFrontendFiles(dir) {
|
|
|
21343
22102
|
for (const entry of entries) {
|
|
21344
22103
|
if (entry.isDirectory()) {
|
|
21345
22104
|
if (exclude.includes(entry.name)) continue;
|
|
21346
|
-
files.push(...walkFrontendFiles(
|
|
22105
|
+
files.push(...walkFrontendFiles(join21(dir, entry.name)));
|
|
21347
22106
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
21348
|
-
files.push(
|
|
22107
|
+
files.push(join21(dir, entry.name));
|
|
21349
22108
|
}
|
|
21350
22109
|
}
|
|
21351
22110
|
} catch {
|
|
@@ -21717,7 +22476,7 @@ var init_memory_tools = __esm({
|
|
|
21717
22476
|
});
|
|
21718
22477
|
|
|
21719
22478
|
// src/docs-tools.ts
|
|
21720
|
-
import { readFileSync as readFileSync34, existsSync as
|
|
22479
|
+
import { readFileSync as readFileSync34, existsSync as existsSync35 } from "fs";
|
|
21721
22480
|
import { resolve as resolve30, basename as basename6 } from "path";
|
|
21722
22481
|
function p3(baseName) {
|
|
21723
22482
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -21773,7 +22532,7 @@ function handleDocsToolCall(name, args2) {
|
|
|
21773
22532
|
}
|
|
21774
22533
|
function loadDocsMap() {
|
|
21775
22534
|
const mapPath = getResolvedPaths().docsMapPath;
|
|
21776
|
-
if (!
|
|
22535
|
+
if (!existsSync35(mapPath)) {
|
|
21777
22536
|
throw new Error(`docs-map.json not found at ${mapPath}`);
|
|
21778
22537
|
}
|
|
21779
22538
|
return JSON.parse(readFileSync34(mapPath, "utf-8"));
|
|
@@ -21847,9 +22606,9 @@ function extractFrontmatter(content) {
|
|
|
21847
22606
|
function extractProcedureNames(routerPath) {
|
|
21848
22607
|
const root = getProjectRoot();
|
|
21849
22608
|
const absPath = ensureWithinRoot(resolve30(getResolvedPaths().srcDir, "..", routerPath), root);
|
|
21850
|
-
if (!
|
|
22609
|
+
if (!existsSync35(absPath)) {
|
|
21851
22610
|
const altPath = ensureWithinRoot(resolve30(getResolvedPaths().srcDir, "../server/api/routers", basename6(routerPath)), root);
|
|
21852
|
-
if (!
|
|
22611
|
+
if (!existsSync35(altPath)) return [];
|
|
21853
22612
|
return extractProcedureNamesFromContent(readFileSync34(altPath, "utf-8"));
|
|
21854
22613
|
}
|
|
21855
22614
|
return extractProcedureNamesFromContent(readFileSync34(absPath, "utf-8"));
|
|
@@ -21893,7 +22652,7 @@ function handleDocsAudit(args2) {
|
|
|
21893
22652
|
const mapping = docsMap.mappings.find((m3) => m3.id === mappingId);
|
|
21894
22653
|
if (!mapping) continue;
|
|
21895
22654
|
const helpPagePath = ensureWithinRoot(resolve30(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
21896
|
-
if (!
|
|
22655
|
+
if (!existsSync35(helpPagePath)) {
|
|
21897
22656
|
results.push({
|
|
21898
22657
|
helpPage: mapping.helpPage,
|
|
21899
22658
|
mappingId,
|
|
@@ -21946,7 +22705,7 @@ function handleDocsAudit(args2) {
|
|
|
21946
22705
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
21947
22706
|
if (parentId === mappingId) {
|
|
21948
22707
|
const guidePath = ensureWithinRoot(resolve30(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
21949
|
-
if (
|
|
22708
|
+
if (existsSync35(guidePath)) {
|
|
21950
22709
|
const guideContent = readFileSync34(guidePath, "utf-8");
|
|
21951
22710
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
21952
22711
|
if (!guideFrontmatter?.lastVerified || status === "STALE") {
|
|
@@ -21981,7 +22740,7 @@ function handleDocsCoverage(args2) {
|
|
|
21981
22740
|
const mappings = filterDomain ? docsMap.mappings.filter((m3) => m3.id === filterDomain) : docsMap.mappings;
|
|
21982
22741
|
for (const mapping of mappings) {
|
|
21983
22742
|
const helpPagePath = ensureWithinRoot(resolve30(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
21984
|
-
const exists =
|
|
22743
|
+
const exists = existsSync35(helpPagePath);
|
|
21985
22744
|
let hasContent = false;
|
|
21986
22745
|
let lineCount = 0;
|
|
21987
22746
|
let lastVerified = null;
|
|
@@ -22328,7 +23087,7 @@ var init_observability_tools = __esm({
|
|
|
22328
23087
|
});
|
|
22329
23088
|
|
|
22330
23089
|
// src/sentinel-db.ts
|
|
22331
|
-
import { existsSync as
|
|
23090
|
+
import { existsSync as existsSync36 } from "fs";
|
|
22332
23091
|
import { resolve as resolve31 } from "path";
|
|
22333
23092
|
function parsePortalScope(raw) {
|
|
22334
23093
|
if (!raw) return [];
|
|
@@ -22566,22 +23325,22 @@ function validateFeatures(db, domainFilter) {
|
|
|
22566
23325
|
const missingPages = [];
|
|
22567
23326
|
for (const comp of components) {
|
|
22568
23327
|
const absPath = resolve31(PROJECT_ROOT, comp.component_file);
|
|
22569
|
-
if (!
|
|
23328
|
+
if (!existsSync36(absPath)) {
|
|
22570
23329
|
missingComponents.push(comp.component_file);
|
|
22571
23330
|
}
|
|
22572
23331
|
}
|
|
22573
23332
|
for (const proc of procedures) {
|
|
22574
23333
|
const routerPath = resolve31(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
22575
|
-
if (!
|
|
23334
|
+
if (!existsSync36(routerPath)) {
|
|
22576
23335
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
22577
23336
|
}
|
|
22578
23337
|
}
|
|
22579
23338
|
for (const page of pages) {
|
|
22580
23339
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
22581
23340
|
const absPath = resolve31(PROJECT_ROOT, routeToPath);
|
|
22582
|
-
if (page.page_route.startsWith("/") && !
|
|
23341
|
+
if (page.page_route.startsWith("/") && !existsSync36(absPath)) {
|
|
22583
23342
|
const altPath = resolve31(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
|
|
22584
|
-
if (!
|
|
23343
|
+
if (!existsSync36(altPath)) {
|
|
22585
23344
|
missingPages.push(page.page_route);
|
|
22586
23345
|
}
|
|
22587
23346
|
}
|
|
@@ -23107,8 +23866,8 @@ var init_sentinel_tools = __esm({
|
|
|
23107
23866
|
});
|
|
23108
23867
|
|
|
23109
23868
|
// src/sentinel-scanner.ts
|
|
23110
|
-
import { readFileSync as readFileSync35, existsSync as
|
|
23111
|
-
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";
|
|
23112
23871
|
function inferDomain(filePath) {
|
|
23113
23872
|
const domains = getConfig().domains;
|
|
23114
23873
|
const path = filePath.toLowerCase();
|
|
@@ -23240,7 +23999,7 @@ function scanComponentExports(dataDb) {
|
|
|
23240
23999
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
23241
24000
|
const componentDirs = [];
|
|
23242
24001
|
const basePath = resolve32(projectRoot, componentsBase);
|
|
23243
|
-
if (
|
|
24002
|
+
if (existsSync37(basePath)) {
|
|
23244
24003
|
try {
|
|
23245
24004
|
const entries = readdirSync23(basePath, { withFileTypes: true });
|
|
23246
24005
|
for (const entry of entries) {
|
|
@@ -23253,7 +24012,7 @@ function scanComponentExports(dataDb) {
|
|
|
23253
24012
|
}
|
|
23254
24013
|
for (const dir of componentDirs) {
|
|
23255
24014
|
const absDir = resolve32(projectRoot, dir);
|
|
23256
|
-
if (!
|
|
24015
|
+
if (!existsSync37(absDir)) continue;
|
|
23257
24016
|
const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
23258
24017
|
for (const file of files) {
|
|
23259
24018
|
const relPath = relative11(projectRoot, file);
|
|
@@ -23283,7 +24042,7 @@ function scanComponentExports(dataDb) {
|
|
|
23283
24042
|
if (hasHandlers && exportMatch) {
|
|
23284
24043
|
const componentName = exportMatch[1];
|
|
23285
24044
|
const domain = inferDomain(relPath);
|
|
23286
|
-
const subdomain = basename7(
|
|
24045
|
+
const subdomain = basename7(dirname18(relPath));
|
|
23287
24046
|
const featureKey = `component.${subdomain}.${componentName.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "")}`;
|
|
23288
24047
|
if (!annotations.some((a2) => a2.featureKey === featureKey)) {
|
|
23289
24048
|
features.push({
|
|
@@ -23308,7 +24067,7 @@ function walkDir2(dir) {
|
|
|
23308
24067
|
try {
|
|
23309
24068
|
const entries = readdirSync23(dir);
|
|
23310
24069
|
for (const entry of entries) {
|
|
23311
|
-
const fullPath =
|
|
24070
|
+
const fullPath = join22(dir, entry);
|
|
23312
24071
|
try {
|
|
23313
24072
|
const stat = statSync13(fullPath);
|
|
23314
24073
|
if (stat.isDirectory()) {
|
|
@@ -24300,7 +25059,7 @@ var init_audit_trail = __esm({
|
|
|
24300
25059
|
});
|
|
24301
25060
|
|
|
24302
25061
|
// src/validation-engine.ts
|
|
24303
|
-
import { existsSync as
|
|
25062
|
+
import { existsSync as existsSync38, readFileSync as readFileSync36 } from "fs";
|
|
24304
25063
|
function p10(baseName) {
|
|
24305
25064
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
24306
25065
|
}
|
|
@@ -24331,7 +25090,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
24331
25090
|
});
|
|
24332
25091
|
return checks;
|
|
24333
25092
|
}
|
|
24334
|
-
if (!
|
|
25093
|
+
if (!existsSync38(absPath)) {
|
|
24335
25094
|
checks.push({
|
|
24336
25095
|
name: "file_exists",
|
|
24337
25096
|
severity: "error",
|
|
@@ -24786,7 +25545,7 @@ var init_adr_generator = __esm({
|
|
|
24786
25545
|
});
|
|
24787
25546
|
|
|
24788
25547
|
// src/security-scorer.ts
|
|
24789
|
-
import { existsSync as
|
|
25548
|
+
import { existsSync as existsSync39, readFileSync as readFileSync37 } from "fs";
|
|
24790
25549
|
function p12(baseName) {
|
|
24791
25550
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
24792
25551
|
}
|
|
@@ -24810,7 +25569,7 @@ function scoreFileSecurity(filePath, projectRoot) {
|
|
|
24810
25569
|
}]
|
|
24811
25570
|
};
|
|
24812
25571
|
}
|
|
24813
|
-
if (!
|
|
25572
|
+
if (!existsSync39(absPath)) {
|
|
24814
25573
|
return { riskScore: 0, findings: [] };
|
|
24815
25574
|
}
|
|
24816
25575
|
let source;
|
|
@@ -25105,7 +25864,7 @@ var init_security_scorer = __esm({
|
|
|
25105
25864
|
});
|
|
25106
25865
|
|
|
25107
25866
|
// src/dependency-scorer.ts
|
|
25108
|
-
import { existsSync as
|
|
25867
|
+
import { existsSync as existsSync40, readFileSync as readFileSync38 } from "fs";
|
|
25109
25868
|
import { resolve as resolve33 } from "path";
|
|
25110
25869
|
function p13(baseName) {
|
|
25111
25870
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -25139,7 +25898,7 @@ function calculateDepRisk(factors) {
|
|
|
25139
25898
|
}
|
|
25140
25899
|
function getInstalledPackages(projectRoot) {
|
|
25141
25900
|
const pkgPath = resolve33(projectRoot, "package.json");
|
|
25142
|
-
if (!
|
|
25901
|
+
if (!existsSync40(pkgPath)) return /* @__PURE__ */ new Map();
|
|
25143
25902
|
try {
|
|
25144
25903
|
const pkg = JSON.parse(readFileSync38(pkgPath, "utf-8"));
|
|
25145
25904
|
const packages = /* @__PURE__ */ new Map();
|
|
@@ -25747,7 +26506,7 @@ var init_regression_detector = __esm({
|
|
|
25747
26506
|
|
|
25748
26507
|
// src/knowledge-indexer.ts
|
|
25749
26508
|
import { createHash as createHash9 } from "crypto";
|
|
25750
|
-
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";
|
|
25751
26510
|
import { resolve as resolve34, relative as relative12, basename as basename8, extname as extname2 } from "path";
|
|
25752
26511
|
function getKnowledgePaths() {
|
|
25753
26512
|
const resolved = getResolvedPaths();
|
|
@@ -26055,11 +26814,11 @@ function indexAllKnowledge(db) {
|
|
|
26055
26814
|
files.push(...memFiles);
|
|
26056
26815
|
} catch {
|
|
26057
26816
|
}
|
|
26058
|
-
if (
|
|
26817
|
+
if (existsSync41(paths.plansDir)) {
|
|
26059
26818
|
const planFiles = discoverMarkdownFiles(paths.plansDir);
|
|
26060
26819
|
files.push(...planFiles);
|
|
26061
26820
|
}
|
|
26062
|
-
if (
|
|
26821
|
+
if (existsSync41(paths.docsDir)) {
|
|
26063
26822
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
26064
26823
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
26065
26824
|
files.push(...docsFiles);
|
|
@@ -26102,7 +26861,7 @@ function indexAllKnowledge(db) {
|
|
|
26102
26861
|
} catch {
|
|
26103
26862
|
}
|
|
26104
26863
|
for (const filePath of files) {
|
|
26105
|
-
if (!
|
|
26864
|
+
if (!existsSync41(filePath)) continue;
|
|
26106
26865
|
const content = readFileSync39(filePath, "utf-8");
|
|
26107
26866
|
const hash = hashContent2(content);
|
|
26108
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);
|
|
@@ -26238,10 +26997,10 @@ function isKnowledgeStale(db) {
|
|
|
26238
26997
|
files.push(...discoverMarkdownFiles(paths.memoryDir));
|
|
26239
26998
|
} catch {
|
|
26240
26999
|
}
|
|
26241
|
-
if (
|
|
27000
|
+
if (existsSync41(paths.plansDir)) {
|
|
26242
27001
|
files.push(...discoverMarkdownFiles(paths.plansDir));
|
|
26243
27002
|
}
|
|
26244
|
-
if (
|
|
27003
|
+
if (existsSync41(paths.docsDir)) {
|
|
26245
27004
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
26246
27005
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
26247
27006
|
files.push(...docsFiles);
|
|
@@ -26270,7 +27029,7 @@ var init_knowledge_indexer = __esm({
|
|
|
26270
27029
|
});
|
|
26271
27030
|
|
|
26272
27031
|
// src/knowledge-tools.ts
|
|
26273
|
-
import { readFileSync as readFileSync40, writeFileSync as
|
|
27032
|
+
import { readFileSync as readFileSync40, writeFileSync as writeFileSync6, appendFileSync as appendFileSync2, readdirSync as readdirSync25 } from "fs";
|
|
26274
27033
|
import { resolve as resolve35, basename as basename9 } from "path";
|
|
26275
27034
|
function p16(baseName) {
|
|
26276
27035
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -27030,7 +27789,7 @@ ${crRule ? `- **CR**: ${crRule}
|
|
|
27030
27789
|
if (archiveIdx > 0) {
|
|
27031
27790
|
const before = existing.slice(0, archiveIdx);
|
|
27032
27791
|
const after = existing.slice(archiveIdx);
|
|
27033
|
-
|
|
27792
|
+
writeFileSync6(correctionsPath, before + entry + after);
|
|
27034
27793
|
} else {
|
|
27035
27794
|
appendFileSync2(correctionsPath, entry);
|
|
27036
27795
|
}
|
|
@@ -27978,7 +28737,7 @@ var init_framework_supports = __esm({
|
|
|
27978
28737
|
});
|
|
27979
28738
|
|
|
27980
28739
|
// src/tools.ts
|
|
27981
|
-
import { readFileSync as readFileSync41, existsSync as
|
|
28740
|
+
import { readFileSync as readFileSync41, existsSync as existsSync43 } from "fs";
|
|
27982
28741
|
import { resolve as resolve36, basename as basename10 } from "path";
|
|
27983
28742
|
function prefix2() {
|
|
27984
28743
|
return getConfig().toolPrefix;
|
|
@@ -28398,7 +29157,7 @@ function handleContext(file, dataDb, codegraphDb) {
|
|
|
28398
29157
|
const resolvedPaths = getResolvedPaths();
|
|
28399
29158
|
const root = getProjectRoot();
|
|
28400
29159
|
const absFilePath = ensureWithinRoot(resolve36(resolvedPaths.srcDir, "..", file), root);
|
|
28401
|
-
if (
|
|
29160
|
+
if (existsSync43(absFilePath)) {
|
|
28402
29161
|
const fileContent = readFileSync41(absFilePath, "utf-8").slice(0, 3e3);
|
|
28403
29162
|
const keywords = [];
|
|
28404
29163
|
if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
|
|
@@ -28837,7 +29596,7 @@ function handleSchema(args2) {
|
|
|
28837
29596
|
lines.push("");
|
|
28838
29597
|
const projectRoot = getProjectRoot();
|
|
28839
29598
|
const absPath = ensureWithinRoot(resolve36(projectRoot, file), projectRoot);
|
|
28840
|
-
if (!
|
|
29599
|
+
if (!existsSync43(absPath)) {
|
|
28841
29600
|
return text17(`File not found: ${file}`);
|
|
28842
29601
|
}
|
|
28843
29602
|
const source = readFileSync41(absPath, "utf-8");
|
|
@@ -29246,7 +30005,7 @@ var init_server_dispatch = __esm({
|
|
|
29246
30005
|
// src/server.ts
|
|
29247
30006
|
var server_exports = {};
|
|
29248
30007
|
import { readFileSync as readFileSync42 } from "fs";
|
|
29249
|
-
import { resolve as resolve37, dirname as
|
|
30008
|
+
import { resolve as resolve37, dirname as dirname19 } from "path";
|
|
29250
30009
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
29251
30010
|
function pruneMemoryOnStartup() {
|
|
29252
30011
|
try {
|
|
@@ -29278,7 +30037,7 @@ var init_server = __esm({
|
|
|
29278
30037
|
init_memory_db();
|
|
29279
30038
|
init_license();
|
|
29280
30039
|
init_server_dispatch();
|
|
29281
|
-
__dirname5 =
|
|
30040
|
+
__dirname5 = dirname19(fileURLToPath5(import.meta.url));
|
|
29282
30041
|
PKG_VERSION = (() => {
|
|
29283
30042
|
try {
|
|
29284
30043
|
const pkg = JSON.parse(readFileSync42(resolve37(__dirname5, "..", "package.json"), "utf-8"));
|
|
@@ -29567,7 +30326,7 @@ var config_upgrade_exports = {};
|
|
|
29567
30326
|
__export(config_upgrade_exports, {
|
|
29568
30327
|
runConfigUpgrade: () => runConfigUpgrade
|
|
29569
30328
|
});
|
|
29570
|
-
import { existsSync as
|
|
30329
|
+
import { existsSync as existsSync44, readFileSync as readFileSync43, writeFileSync as writeFileSync7, copyFileSync, unlinkSync as unlinkSync2 } from "fs";
|
|
29571
30330
|
import { resolve as resolve38 } from "path";
|
|
29572
30331
|
import { parse as parseYaml6 } from "yaml";
|
|
29573
30332
|
async function runConfigUpgrade(opts = {}) {
|
|
@@ -29579,7 +30338,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
29579
30338
|
const err = opts.silent ? () => {
|
|
29580
30339
|
} : (s) => process.stderr.write(s);
|
|
29581
30340
|
if (opts.rollback) {
|
|
29582
|
-
if (!
|
|
30341
|
+
if (!existsSync44(bakPath)) {
|
|
29583
30342
|
const message = `No backup found at ${bakPath}`;
|
|
29584
30343
|
err(message + "\n");
|
|
29585
30344
|
return { exitCode: 1, action: "none", message };
|
|
@@ -29595,7 +30354,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
29595
30354
|
return { exitCode: 2, action: "none", message };
|
|
29596
30355
|
}
|
|
29597
30356
|
}
|
|
29598
|
-
if (!
|
|
30357
|
+
if (!existsSync44(configPath)) {
|
|
29599
30358
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
29600
30359
|
err(message + "\n");
|
|
29601
30360
|
return { exitCode: 1, action: "none", message };
|
|
@@ -29626,7 +30385,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
29626
30385
|
};
|
|
29627
30386
|
try {
|
|
29628
30387
|
const original = readFileSync43(configPath, "utf-8");
|
|
29629
|
-
|
|
30388
|
+
writeFileSync7(bakPath, original, "utf-8");
|
|
29630
30389
|
} catch (e2) {
|
|
29631
30390
|
const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
|
|
29632
30391
|
err(message + "\n");
|
|
@@ -29659,7 +30418,7 @@ var config_check_drift_exports = {};
|
|
|
29659
30418
|
__export(config_check_drift_exports, {
|
|
29660
30419
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
29661
30420
|
});
|
|
29662
|
-
import { existsSync as
|
|
30421
|
+
import { existsSync as existsSync45, readFileSync as readFileSync44 } from "fs";
|
|
29663
30422
|
import { resolve as resolve39 } from "path";
|
|
29664
30423
|
import { parse as parseYaml7 } from "yaml";
|
|
29665
30424
|
function renderChanges(changes) {
|
|
@@ -29673,7 +30432,7 @@ async function runConfigCheckDrift(opts = {}) {
|
|
|
29673
30432
|
} : (s) => process.stdout.write(s);
|
|
29674
30433
|
const err = opts.silent ? () => {
|
|
29675
30434
|
} : (s) => process.stderr.write(s);
|
|
29676
|
-
if (!
|
|
30435
|
+
if (!existsSync45(configPath)) {
|
|
29677
30436
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
29678
30437
|
err(message + "\n");
|
|
29679
30438
|
return {
|
|
@@ -29755,10 +30514,10 @@ var init_config_check_drift = __esm({
|
|
|
29755
30514
|
|
|
29756
30515
|
// src/cli.ts
|
|
29757
30516
|
import { readFileSync as readFileSync45 } from "fs";
|
|
29758
|
-
import { resolve as resolve40, dirname as
|
|
30517
|
+
import { resolve as resolve40, dirname as dirname20 } from "path";
|
|
29759
30518
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
29760
30519
|
var __filename5 = fileURLToPath6(import.meta.url);
|
|
29761
|
-
var __dirname6 =
|
|
30520
|
+
var __dirname6 = dirname20(__filename5);
|
|
29762
30521
|
var args = process.argv.slice(2);
|
|
29763
30522
|
var subcommand = args[0];
|
|
29764
30523
|
async function main() {
|
|
@@ -29795,12 +30554,24 @@ async function main() {
|
|
|
29795
30554
|
process.exit(result.exitCode);
|
|
29796
30555
|
return;
|
|
29797
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
|
+
}
|
|
29798
30563
|
case "changelog": {
|
|
29799
30564
|
const { handleChangelogSubcommand: handleChangelogSubcommand2 } = await Promise.resolve().then(() => (init_changelog(), changelog_exports));
|
|
29800
30565
|
const result = await handleChangelogSubcommand2(args.slice(1));
|
|
29801
30566
|
process.exit(result.exitCode);
|
|
29802
30567
|
return;
|
|
29803
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
|
+
}
|
|
29804
30575
|
case "show-template": {
|
|
29805
30576
|
const { runShowTemplate: runShowTemplate2 } = await Promise.resolve().then(() => (init_show_template(), show_template_exports));
|
|
29806
30577
|
await runShowTemplate2(args.slice(1));
|
|
@@ -29929,8 +30700,10 @@ Commands:
|
|
|
29929
30700
|
validate-config Validate massu.config.yaml (alias: config validate)
|
|
29930
30701
|
config <sub> Config lifecycle: refresh | validate | upgrade | doctor | check-drift
|
|
29931
30702
|
permissions <sub> MCP permission lifecycle: install | verify | check-drift
|
|
30703
|
+
license <sub> License/tier gate: check --min <free|pro|team|enterprise>
|
|
29932
30704
|
changelog <sub> CHANGELOG generation / verification: generate | verify
|
|
29933
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>
|
|
29934
30707
|
|
|
29935
30708
|
Options:
|
|
29936
30709
|
--help, -h Show this help message
|