@massu/core 1.10.8 → 1.12.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 +1303 -0
- package/dist/adapter.js +6 -4
- package/dist/cli.js +517 -397
- package/dist/detect/adapters/.bundle-shasums.json +4 -7
- package/dist/detect/adapters/rails.js +6 -4
- package/dist/detect/adapters/spring.js +6 -4
- package/dist/detect/adapters/tree-sitter-loader.js +6 -4
- package/dist/hooks/auto-learning-pipeline.js +24 -1
- package/dist/hooks/classify-failure.js +32 -3
- package/dist/hooks/cost-tracker.js +24 -0
- package/dist/hooks/fix-detector.js +97 -1
- package/dist/hooks/incident-pipeline.js +30 -1
- package/dist/hooks/intent-suggester.js +6 -3
- package/dist/hooks/post-edit-context.js +24 -1
- package/dist/hooks/post-tool-use.js +66 -18
- package/dist/hooks/pre-compact.js +27 -2
- package/dist/hooks/pre-delete-check.js +48 -22
- package/dist/hooks/pre-tool-use-gate.js +962 -0
- package/dist/hooks/quality-event.js +24 -0
- package/dist/hooks/rule-enforcement-pipeline.js +24 -1
- package/dist/hooks/security-gate.js +29 -16
- package/dist/hooks/session-end.js +24 -0
- package/dist/hooks/session-start.js +8710 -8460
- package/dist/hooks/user-prompt.js +24 -0
- package/package.json +15 -18
- package/commands/README.md +0 -134
- package/src/adapter.ts +0 -121
- package/src/adr-generator.ts +0 -292
- package/src/analytics.ts +0 -373
- package/src/audit-trail.ts +0 -450
- package/src/backfill-sessions.ts +0 -182
- package/src/changelog-generator.ts +0 -178
- package/src/cli.ts +0 -246
- package/src/cloud-sync.ts +0 -234
- package/src/commands/adapters.ts +0 -824
- package/src/commands/changelog.ts +0 -165
- package/src/commands/config-check-drift.ts +0 -133
- package/src/commands/config-refresh.ts +0 -396
- package/src/commands/config-upgrade.ts +0 -127
- package/src/commands/doctor.ts +0 -485
- package/src/commands/hook-runner.ts +0 -145
- package/src/commands/init.ts +0 -1823
- package/src/commands/install-commands.ts +0 -692
- package/src/commands/install-hooks.ts +0 -27
- package/src/commands/permissions.ts +0 -150
- package/src/commands/refresh-log.ts +0 -37
- package/src/commands/show-template.ts +0 -65
- package/src/commands/template-engine.ts +0 -301
- package/src/commands/watch.ts +0 -430
- package/src/config.ts +0 -765
- package/src/cost-tracker.ts +0 -355
- package/src/db.ts +0 -370
- package/src/dependency-scorer.ts +0 -337
- package/src/detect/adapters/aspnet.ts +0 -4
- package/src/detect/adapters/discover.ts +0 -469
- package/src/detect/adapters/file-sampler.ts +0 -225
- package/src/detect/adapters/go-chi.ts +0 -4
- package/src/detect/adapters/index.ts +0 -51
- package/src/detect/adapters/nextjs-trpc.ts +0 -166
- package/src/detect/adapters/parse-guard.ts +0 -133
- package/src/detect/adapters/phoenix.ts +0 -4
- package/src/detect/adapters/python-django.ts +0 -208
- package/src/detect/adapters/python-fastapi.ts +0 -223
- package/src/detect/adapters/python-flask.ts +0 -235
- package/src/detect/adapters/query-helpers.ts +0 -170
- package/src/detect/adapters/rails.ts +0 -4
- package/src/detect/adapters/runner.ts +0 -284
- package/src/detect/adapters/spring.ts +0 -4
- package/src/detect/adapters/swift-swiftui.ts +0 -171
- package/src/detect/adapters/tree-sitter-loader.ts +0 -517
- package/src/detect/adapters/types.ts +0 -191
- package/src/detect/codebase-introspector.ts +0 -210
- package/src/detect/domain-inferrer.ts +0 -197
- package/src/detect/drift.ts +0 -199
- package/src/detect/framework-detector.ts +0 -307
- package/src/detect/index.ts +0 -209
- package/src/detect/manifest-registry.ts +0 -261
- package/src/detect/migrate.ts +0 -362
- package/src/detect/monorepo-detector.ts +0 -348
- package/src/detect/package-detector.ts +0 -828
- package/src/detect/passthrough.ts +0 -108
- package/src/detect/regex-fallback.ts +0 -449
- package/src/detect/source-dir-detector.ts +0 -297
- package/src/detect/vr-command-map.ts +0 -167
- package/src/docs-map.json +0 -100
- package/src/docs-tools.ts +0 -519
- package/src/domains.ts +0 -182
- package/src/hooks/auto-learning-pipeline.ts +0 -228
- package/src/hooks/classify-failure.ts +0 -259
- package/src/hooks/cost-tracker.ts +0 -66
- package/src/hooks/fix-detector.ts +0 -186
- package/src/hooks/incident-pipeline.ts +0 -190
- package/src/hooks/intent-suggester.ts +0 -131
- package/src/hooks/post-edit-context.ts +0 -91
- package/src/hooks/post-tool-use.ts +0 -413
- package/src/hooks/pre-compact.ts +0 -168
- package/src/hooks/pre-delete-check.ts +0 -243
- package/src/hooks/quality-event.ts +0 -127
- package/src/hooks/rule-enforcement-pipeline.ts +0 -159
- package/src/hooks/security-gate.ts +0 -153
- package/src/hooks/session-end.ts +0 -467
- package/src/hooks/session-start.ts +0 -436
- package/src/hooks/user-prompt.ts +0 -157
- package/src/import-resolver.ts +0 -226
- package/src/knowledge-db.ts +0 -176
- package/src/knowledge-indexer.ts +0 -708
- package/src/knowledge-tools.ts +0 -1414
- package/src/lib/fileLock.ts +0 -203
- package/src/lib/framework-supports.ts +0 -85
- package/src/lib/gitToplevel.ts +0 -22
- package/src/lib/hook-registry.ts +0 -43
- package/src/lib/installLock.ts +0 -66
- package/src/lib/memory-path.ts +0 -49
- package/src/lib/pidLiveness.ts +0 -67
- package/src/lib/settings-local.ts +0 -110
- package/src/lib/sql-table-names.ts +0 -71
- package/src/license.ts +0 -547
- package/src/lsp/auto-detect.ts +0 -98
- package/src/lsp/client.ts +0 -776
- package/src/lsp/enrich.ts +0 -127
- package/src/lsp/types.ts +0 -221
- package/src/memory-db.ts +0 -1614
- package/src/memory-file-ingest.ts +0 -128
- package/src/memory-tools.ts +0 -424
- package/src/middleware-tree.ts +0 -71
- package/src/observability-tools.ts +0 -343
- package/src/observation-extractor.ts +0 -418
- package/src/page-deps.ts +0 -285
- package/src/permissions.ts +0 -422
- package/src/prompt-analyzer.ts +0 -332
- package/src/python/coupling-detector.ts +0 -125
- package/src/python/domain-enforcer.ts +0 -84
- package/src/python/impact-analyzer.ts +0 -96
- package/src/python/import-parser.ts +0 -244
- package/src/python/import-resolver.ts +0 -136
- package/src/python/migration-indexer.ts +0 -116
- package/src/python/migration-parser.ts +0 -332
- package/src/python/model-indexer.ts +0 -71
- package/src/python/model-parser.ts +0 -279
- package/src/python/route-indexer.ts +0 -59
- package/src/python/route-parser.ts +0 -317
- package/src/python-tools.ts +0 -630
- package/src/regression-detector.ts +0 -319
- package/src/rules.ts +0 -57
- package/src/schema-mapper.ts +0 -232
- package/src/security/adapter-origin.ts +0 -130
- package/src/security/adapter-verifier.ts +0 -319
- package/src/security/atomic-write.ts +0 -164
- package/src/security/fetcher.ts +0 -200
- package/src/security/install-tracking.ts +0 -319
- package/src/security/license-pubkey.generated.ts +0 -30
- package/src/security/license-response-verifier.ts +0 -149
- package/src/security/local-fingerprint.ts +0 -225
- package/src/security/manifest-cache.ts +0 -333
- package/src/security/manifest-schema.ts +0 -129
- package/src/security/registry-pubkey.generated.ts +0 -35
- package/src/security/telemetry.ts +0 -320
- package/src/security-scorer.ts +0 -405
- package/src/security-utils.ts +0 -133
- package/src/sentinel-db.ts +0 -580
- package/src/sentinel-scanner.ts +0 -406
- package/src/sentinel-tools.ts +0 -513
- package/src/sentinel-types.ts +0 -140
- package/src/server-dispatch.ts +0 -225
- package/src/server.ts +0 -107
- package/src/session-archiver.ts +0 -111
- package/src/session-state-generator.ts +0 -174
- package/src/team-knowledge.ts +0 -407
- package/src/tool-db-needs.ts +0 -232
- package/src/tools.ts +0 -1206
- package/src/transcript-parser.ts +0 -458
- package/src/trpc-index.ts +0 -215
- package/src/validate-features-runner.ts +0 -107
- package/src/validation-engine.ts +0 -358
- package/src/watch/daemon.ts +0 -385
- package/src/watch/lockfile-detector.ts +0 -65
- package/src/watch/paths.ts +0 -279
- package/src/watch/state.ts +0 -178
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import{createRequire as __cr}from"module";const require=__cr(import.meta.url);
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
+
}) : x)(function(x) {
|
|
6
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
3
9
|
|
|
4
10
|
// src/memory-db.ts
|
|
5
11
|
import Database from "better-sqlite3";
|
|
@@ -348,6 +354,22 @@ var RawConfigSchema = z.object({
|
|
|
348
354
|
accessScopes: z.array(z.string()).optional(),
|
|
349
355
|
domains: z.array(DomainConfigSchema).default([]),
|
|
350
356
|
rules: z.array(PatternRuleConfigSchema).default([]),
|
|
357
|
+
// P-M-036 (plan-stage-d-medium-sweep): customer-authored CR-style
|
|
358
|
+
// governance rules. DISTINCT from `rules:` above (path-scoped lint hints
|
|
359
|
+
// used by pattern-scanner). At config-refresh time these entries are
|
|
360
|
+
// loaded into the `knowledge_rules` SQLite table with
|
|
361
|
+
// `source = 'customer-config'` so `massu_knowledge_rule` and the
|
|
362
|
+
// governance docs surface customer-defined rules alongside framework CRs.
|
|
363
|
+
governance_rules: z.array(
|
|
364
|
+
z.object({
|
|
365
|
+
id: z.string().min(1, "governance_rules[].id is required"),
|
|
366
|
+
title: z.string().min(1, "governance_rules[].title is required"),
|
|
367
|
+
description: z.string().min(1, "governance_rules[].description is required"),
|
|
368
|
+
vr_type: z.string().default("VR-CUSTOM"),
|
|
369
|
+
reference_path: z.string().optional(),
|
|
370
|
+
severity: z.enum(["critical", "high", "medium", "low", "info"]).default("medium")
|
|
371
|
+
}).passthrough()
|
|
372
|
+
).default([]),
|
|
351
373
|
analytics: AnalyticsConfigSchema,
|
|
352
374
|
governance: GovernanceConfigSchema,
|
|
353
375
|
security: SecurityConfigSchema,
|
|
@@ -466,6 +488,8 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
466
488
|
accessScopes: parsed.accessScopes,
|
|
467
489
|
domains: parsed.domains,
|
|
468
490
|
rules: parsed.rules,
|
|
491
|
+
// P-M-036: customer-authored CR-style governance rules.
|
|
492
|
+
governance_rules: parsed.governance_rules,
|
|
469
493
|
analytics: parsed.analytics,
|
|
470
494
|
governance: parsed.governance,
|
|
471
495
|
security: parsed.security,
|
|
@@ -1018,6 +1042,12 @@ function initMemorySchema(db) {
|
|
|
1018
1042
|
features TEXT DEFAULT '[]'
|
|
1019
1043
|
);
|
|
1020
1044
|
`);
|
|
1045
|
+
const licenseCacheCols = db.prepare(`PRAGMA table_info(license_cache)`).all();
|
|
1046
|
+
if (!licenseCacheCols.some((c) => c.name === "signed_payload_json")) {
|
|
1047
|
+
db.exec(
|
|
1048
|
+
`ALTER TABLE license_cache ADD COLUMN signed_payload_json TEXT NOT NULL DEFAULT ''`
|
|
1049
|
+
);
|
|
1050
|
+
}
|
|
1021
1051
|
db.exec(`
|
|
1022
1052
|
CREATE TABLE IF NOT EXISTS failure_classes (
|
|
1023
1053
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -1848,9 +1878,8 @@ function storeSecurityScore(db, sessionId, filePath, riskScore, findings) {
|
|
|
1848
1878
|
}
|
|
1849
1879
|
|
|
1850
1880
|
// src/hooks/post-tool-use.ts
|
|
1851
|
-
import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
|
|
1881
|
+
import { readFileSync as readFileSync6, existsSync as existsSync7, statSync as statSync2 } from "fs";
|
|
1852
1882
|
import { join as join2 } from "path";
|
|
1853
|
-
import { parse as parseYaml3 } from "yaml";
|
|
1854
1883
|
|
|
1855
1884
|
// src/memory-file-ingest.ts
|
|
1856
1885
|
import { readFileSync as readFileSync5, existsSync as existsSync6, readdirSync } from "fs";
|
|
@@ -1908,6 +1937,13 @@ function mapMemoryTypeToObservationType(memoryType) {
|
|
|
1908
1937
|
}
|
|
1909
1938
|
|
|
1910
1939
|
// src/hooks/post-tool-use.ts
|
|
1940
|
+
var _yamlParser = null;
|
|
1941
|
+
var parseYaml3 = (content) => {
|
|
1942
|
+
if (!_yamlParser) {
|
|
1943
|
+
_yamlParser = __require("yaml").parse;
|
|
1944
|
+
}
|
|
1945
|
+
return _yamlParser(content);
|
|
1946
|
+
};
|
|
1911
1947
|
var seenReads = /* @__PURE__ */ new Set();
|
|
1912
1948
|
var currentSessionId = null;
|
|
1913
1949
|
async function main() {
|
|
@@ -2135,26 +2171,37 @@ function readStdin() {
|
|
|
2135
2171
|
setTimeout(() => resolve5(data), 3e3);
|
|
2136
2172
|
});
|
|
2137
2173
|
}
|
|
2174
|
+
var _cachedConventions = null;
|
|
2175
|
+
var _cachedConventionsPath = null;
|
|
2176
|
+
var _cachedConventionsMtimeMs = 0;
|
|
2177
|
+
var _conventionDefaults = {
|
|
2178
|
+
knowledgeSourceFiles: ["CLAUDE.md", "MEMORY.md", "corrections.md"],
|
|
2179
|
+
claudeDirName: ".claude"
|
|
2180
|
+
};
|
|
2138
2181
|
function readConventions(cwd) {
|
|
2139
|
-
const defaults = {
|
|
2140
|
-
knowledgeSourceFiles: ["CLAUDE.md", "MEMORY.md", "corrections.md"],
|
|
2141
|
-
claudeDirName: ".claude"
|
|
2142
|
-
};
|
|
2143
2182
|
try {
|
|
2144
2183
|
const projectRoot = cwd ?? process.cwd();
|
|
2145
2184
|
const configPath = join2(projectRoot, "massu.config.yaml");
|
|
2146
|
-
if (!existsSync7(configPath)) return
|
|
2185
|
+
if (!existsSync7(configPath)) return _conventionDefaults;
|
|
2186
|
+
const mtimeMs = statSync2(configPath).mtimeMs;
|
|
2187
|
+
if (_cachedConventions !== null && _cachedConventionsPath === configPath && _cachedConventionsMtimeMs === mtimeMs) {
|
|
2188
|
+
return _cachedConventions;
|
|
2189
|
+
}
|
|
2147
2190
|
const content = readFileSync6(configPath, "utf-8");
|
|
2148
2191
|
const parsed = parseYaml3(content);
|
|
2149
|
-
if (!parsed || typeof parsed !== "object") return
|
|
2192
|
+
if (!parsed || typeof parsed !== "object") return _conventionDefaults;
|
|
2150
2193
|
const conventions = parsed.conventions;
|
|
2151
|
-
if (!conventions || typeof conventions !== "object") return
|
|
2152
|
-
|
|
2153
|
-
knowledgeSourceFiles: Array.isArray(conventions.knowledgeSourceFiles) ? conventions.knowledgeSourceFiles :
|
|
2154
|
-
claudeDirName: typeof conventions.claudeDirName === "string" ? conventions.claudeDirName :
|
|
2194
|
+
if (!conventions || typeof conventions !== "object") return _conventionDefaults;
|
|
2195
|
+
const resolved = {
|
|
2196
|
+
knowledgeSourceFiles: Array.isArray(conventions.knowledgeSourceFiles) ? conventions.knowledgeSourceFiles : _conventionDefaults.knowledgeSourceFiles,
|
|
2197
|
+
claudeDirName: typeof conventions.claudeDirName === "string" ? conventions.claudeDirName : _conventionDefaults.claudeDirName
|
|
2155
2198
|
};
|
|
2199
|
+
_cachedConventions = resolved;
|
|
2200
|
+
_cachedConventionsPath = configPath;
|
|
2201
|
+
_cachedConventionsMtimeMs = mtimeMs;
|
|
2202
|
+
return resolved;
|
|
2156
2203
|
} catch {
|
|
2157
|
-
return
|
|
2204
|
+
return _conventionDefaults;
|
|
2158
2205
|
}
|
|
2159
2206
|
}
|
|
2160
2207
|
function isKnowledgeSourceFile(filePath) {
|
|
@@ -2182,11 +2229,12 @@ function checkMemoryFileIntegrity(filePath) {
|
|
|
2182
2229
|
if (lines.length > MAX_LINES) {
|
|
2183
2230
|
issues.push(`MEMORY.md exceeds ${MAX_LINES} lines (currently ${lines.length}). Consider archiving old entries.`);
|
|
2184
2231
|
}
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2232
|
+
if (!/^#\s+Memory(\s+Index)?\s*$/m.test(content)) {
|
|
2233
|
+
issues.push("MEMORY.md missing top-level `# Memory Index` heading");
|
|
2234
|
+
}
|
|
2235
|
+
const linkLineCount = (content.match(/^- \[[^\]]+\]\([^)]+\.md\)/mg) ?? []).length;
|
|
2236
|
+
if (linkLineCount === 0) {
|
|
2237
|
+
issues.push("MEMORY.md has no `- [Title](file.md) \u2014 hook` index lines");
|
|
2190
2238
|
}
|
|
2191
2239
|
} catch (_e) {
|
|
2192
2240
|
}
|
|
@@ -348,6 +348,22 @@ var RawConfigSchema = z.object({
|
|
|
348
348
|
accessScopes: z.array(z.string()).optional(),
|
|
349
349
|
domains: z.array(DomainConfigSchema).default([]),
|
|
350
350
|
rules: z.array(PatternRuleConfigSchema).default([]),
|
|
351
|
+
// P-M-036 (plan-stage-d-medium-sweep): customer-authored CR-style
|
|
352
|
+
// governance rules. DISTINCT from `rules:` above (path-scoped lint hints
|
|
353
|
+
// used by pattern-scanner). At config-refresh time these entries are
|
|
354
|
+
// loaded into the `knowledge_rules` SQLite table with
|
|
355
|
+
// `source = 'customer-config'` so `massu_knowledge_rule` and the
|
|
356
|
+
// governance docs surface customer-defined rules alongside framework CRs.
|
|
357
|
+
governance_rules: z.array(
|
|
358
|
+
z.object({
|
|
359
|
+
id: z.string().min(1, "governance_rules[].id is required"),
|
|
360
|
+
title: z.string().min(1, "governance_rules[].title is required"),
|
|
361
|
+
description: z.string().min(1, "governance_rules[].description is required"),
|
|
362
|
+
vr_type: z.string().default("VR-CUSTOM"),
|
|
363
|
+
reference_path: z.string().optional(),
|
|
364
|
+
severity: z.enum(["critical", "high", "medium", "low", "info"]).default("medium")
|
|
365
|
+
}).passthrough()
|
|
366
|
+
).default([]),
|
|
351
367
|
analytics: AnalyticsConfigSchema,
|
|
352
368
|
governance: GovernanceConfigSchema,
|
|
353
369
|
security: SecurityConfigSchema,
|
|
@@ -466,6 +482,8 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
466
482
|
accessScopes: parsed.accessScopes,
|
|
467
483
|
domains: parsed.domains,
|
|
468
484
|
rules: parsed.rules,
|
|
485
|
+
// P-M-036: customer-authored CR-style governance rules.
|
|
486
|
+
governance_rules: parsed.governance_rules,
|
|
469
487
|
analytics: parsed.analytics,
|
|
470
488
|
governance: parsed.governance,
|
|
471
489
|
security: parsed.security,
|
|
@@ -1018,6 +1036,12 @@ function initMemorySchema(db) {
|
|
|
1018
1036
|
features TEXT DEFAULT '[]'
|
|
1019
1037
|
);
|
|
1020
1038
|
`);
|
|
1039
|
+
const licenseCacheCols = db.prepare(`PRAGMA table_info(license_cache)`).all();
|
|
1040
|
+
if (!licenseCacheCols.some((c) => c.name === "signed_payload_json")) {
|
|
1041
|
+
db.exec(
|
|
1042
|
+
`ALTER TABLE license_cache ADD COLUMN signed_payload_json TEXT NOT NULL DEFAULT ''`
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1021
1045
|
db.exec(`
|
|
1022
1046
|
CREATE TABLE IF NOT EXISTS failure_classes (
|
|
1023
1047
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -1148,9 +1172,10 @@ async function main() {
|
|
|
1148
1172
|
const db = getMemoryDb();
|
|
1149
1173
|
try {
|
|
1150
1174
|
createSession(db, session_id);
|
|
1151
|
-
const
|
|
1152
|
-
"SELECT * FROM observations WHERE session_id = ? ORDER BY created_at_epoch
|
|
1175
|
+
const observationsDesc = db.prepare(
|
|
1176
|
+
"SELECT * FROM observations WHERE session_id = ? ORDER BY created_at_epoch DESC LIMIT 1000"
|
|
1153
1177
|
).all(session_id);
|
|
1178
|
+
const observations = observationsDesc.reverse();
|
|
1154
1179
|
const prompts = db.prepare(
|
|
1155
1180
|
"SELECT prompt_text FROM user_prompts WHERE session_id = ? ORDER BY prompt_number ASC"
|
|
1156
1181
|
).all(session_id);
|
|
@@ -347,6 +347,22 @@ var RawConfigSchema = z.object({
|
|
|
347
347
|
accessScopes: z.array(z.string()).optional(),
|
|
348
348
|
domains: z.array(DomainConfigSchema).default([]),
|
|
349
349
|
rules: z.array(PatternRuleConfigSchema).default([]),
|
|
350
|
+
// P-M-036 (plan-stage-d-medium-sweep): customer-authored CR-style
|
|
351
|
+
// governance rules. DISTINCT from `rules:` above (path-scoped lint hints
|
|
352
|
+
// used by pattern-scanner). At config-refresh time these entries are
|
|
353
|
+
// loaded into the `knowledge_rules` SQLite table with
|
|
354
|
+
// `source = 'customer-config'` so `massu_knowledge_rule` and the
|
|
355
|
+
// governance docs surface customer-defined rules alongside framework CRs.
|
|
356
|
+
governance_rules: z.array(
|
|
357
|
+
z.object({
|
|
358
|
+
id: z.string().min(1, "governance_rules[].id is required"),
|
|
359
|
+
title: z.string().min(1, "governance_rules[].title is required"),
|
|
360
|
+
description: z.string().min(1, "governance_rules[].description is required"),
|
|
361
|
+
vr_type: z.string().default("VR-CUSTOM"),
|
|
362
|
+
reference_path: z.string().optional(),
|
|
363
|
+
severity: z.enum(["critical", "high", "medium", "low", "info"]).default("medium")
|
|
364
|
+
}).passthrough()
|
|
365
|
+
).default([]),
|
|
350
366
|
analytics: AnalyticsConfigSchema,
|
|
351
367
|
governance: GovernanceConfigSchema,
|
|
352
368
|
security: SecurityConfigSchema,
|
|
@@ -465,6 +481,8 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
465
481
|
accessScopes: parsed.accessScopes,
|
|
466
482
|
domains: parsed.domains,
|
|
467
483
|
rules: parsed.rules,
|
|
484
|
+
// P-M-036: customer-authored CR-style governance rules.
|
|
485
|
+
governance_rules: parsed.governance_rules,
|
|
468
486
|
analytics: parsed.analytics,
|
|
469
487
|
governance: parsed.governance,
|
|
470
488
|
security: parsed.security,
|
|
@@ -620,6 +638,11 @@ function getFeatureImpact(db, filePaths) {
|
|
|
620
638
|
};
|
|
621
639
|
}
|
|
622
640
|
|
|
641
|
+
// src/hooks/lib/write-hook-message.ts
|
|
642
|
+
function writeHookMessage(message) {
|
|
643
|
+
process.stdout.write(JSON.stringify({ message }) + "\n");
|
|
644
|
+
}
|
|
645
|
+
|
|
623
646
|
// src/hooks/pre-delete-check.ts
|
|
624
647
|
var PROJECT_ROOT2 = getProjectRoot();
|
|
625
648
|
var KNOWLEDGE_PROTECTED_FILES = [
|
|
@@ -688,35 +711,24 @@ function extractDeletedFiles(input) {
|
|
|
688
711
|
}
|
|
689
712
|
return files;
|
|
690
713
|
}
|
|
691
|
-
|
|
714
|
+
function runPreDeleteChecks(hookInput) {
|
|
715
|
+
const messages = [];
|
|
692
716
|
try {
|
|
693
|
-
const input = await readStdin();
|
|
694
|
-
const hookInput = JSON.parse(input);
|
|
695
717
|
const knowledgeWarning = checkKnowledgeFileProtection(hookInput);
|
|
696
718
|
if (knowledgeWarning) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
return;
|
|
719
|
+
messages.push(knowledgeWarning);
|
|
720
|
+
return messages;
|
|
700
721
|
}
|
|
701
722
|
const deletedFiles = extractDeletedFiles(hookInput);
|
|
702
|
-
if (deletedFiles.length === 0)
|
|
703
|
-
process.exit(0);
|
|
704
|
-
return;
|
|
705
|
-
}
|
|
723
|
+
if (deletedFiles.length === 0) return messages;
|
|
706
724
|
const db = getDataDb();
|
|
707
|
-
if (!db)
|
|
708
|
-
process.exit(0);
|
|
709
|
-
return;
|
|
710
|
-
}
|
|
725
|
+
if (!db) return messages;
|
|
711
726
|
const SENTINEL_TABLE = t("sentinel");
|
|
712
727
|
try {
|
|
713
728
|
const tableExists = db.prepare(
|
|
714
729
|
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`
|
|
715
730
|
).get(SENTINEL_TABLE);
|
|
716
|
-
if (!tableExists)
|
|
717
|
-
process.exit(0);
|
|
718
|
-
return;
|
|
719
|
-
}
|
|
731
|
+
if (!tableExists) return messages;
|
|
720
732
|
const impact = getFeatureImpact(db, deletedFiles);
|
|
721
733
|
if (impact.blocked) {
|
|
722
734
|
const msg = [
|
|
@@ -737,7 +749,7 @@ async function main() {
|
|
|
737
749
|
}
|
|
738
750
|
msg.push("");
|
|
739
751
|
msg.push("Create a migration plan before deleting these files.");
|
|
740
|
-
|
|
752
|
+
messages.push(msg.join("\n"));
|
|
741
753
|
}
|
|
742
754
|
const pyFiles = deletedFiles.filter((f) => f.endsWith(".py"));
|
|
743
755
|
if (pyFiles.length > 0) {
|
|
@@ -757,8 +769,7 @@ async function main() {
|
|
|
757
769
|
if (importers.length > 0) parts.push(`imported by ${importers.length} files`);
|
|
758
770
|
if (routes.length > 0) parts.push(`defines ${routes.length} routes`);
|
|
759
771
|
if (models.length > 0) parts.push(`defines ${models.length} models`);
|
|
760
|
-
|
|
761
|
-
process.stdout.write(JSON.stringify({ message: msg }));
|
|
772
|
+
messages.push(`PYTHON IMPACT: "${pyFile}" ${parts.join(", ")}. Check dependents before deleting.`);
|
|
762
773
|
}
|
|
763
774
|
}
|
|
764
775
|
} catch {
|
|
@@ -769,6 +780,16 @@ async function main() {
|
|
|
769
780
|
}
|
|
770
781
|
} catch {
|
|
771
782
|
}
|
|
783
|
+
return messages;
|
|
784
|
+
}
|
|
785
|
+
async function main() {
|
|
786
|
+
try {
|
|
787
|
+
const input = await readStdin();
|
|
788
|
+
const hookInput = JSON.parse(input);
|
|
789
|
+
const messages = runPreDeleteChecks(hookInput);
|
|
790
|
+
for (const msg of messages) writeHookMessage(msg);
|
|
791
|
+
} catch {
|
|
792
|
+
}
|
|
772
793
|
process.exit(0);
|
|
773
794
|
}
|
|
774
795
|
function readStdin() {
|
|
@@ -782,4 +803,9 @@ function readStdin() {
|
|
|
782
803
|
setTimeout(() => resolve2(data), 400);
|
|
783
804
|
});
|
|
784
805
|
}
|
|
785
|
-
|
|
806
|
+
if (process.argv[1]?.endsWith("pre-delete-check.js") || process.argv[1]?.endsWith("pre-delete-check")) {
|
|
807
|
+
main();
|
|
808
|
+
}
|
|
809
|
+
export {
|
|
810
|
+
runPreDeleteChecks
|
|
811
|
+
};
|