@massu/core 1.10.8 → 1.12.1
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 +1334 -0
- package/dist/adapter.js +6 -4
- package/dist/cli.js +581 -448
- 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 +67 -19
- package/dist/hooks/pre-compact.js +28 -3
- package/dist/hooks/pre-delete-check.js +53 -27
- 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 +31 -6
- package/dist/hooks/session-start.js +8709 -8459
- package/dist/hooks/user-prompt.js +25 -1
- 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() {
|
|
@@ -1992,7 +2028,7 @@ async function main() {
|
|
|
1992
2028
|
const counts = parseTestRunOutput(tool_response ?? "");
|
|
1993
2029
|
if (counts) {
|
|
1994
2030
|
const modifiedFeatures = db.prepare(
|
|
1995
|
-
"SELECT feature_key FROM feature_health WHERE modifications_since_test > 0"
|
|
2031
|
+
"SELECT feature_key FROM feature_health WHERE modifications_since_test > 0 LIMIT 10000"
|
|
1996
2032
|
).all();
|
|
1997
2033
|
for (const row of modifiedFeatures) {
|
|
1998
2034
|
recordTestResult(db, row.feature_key, counts.passing, counts.failing);
|
|
@@ -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,11 +1172,12 @@ 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
|
-
"SELECT prompt_text FROM user_prompts WHERE session_id = ? ORDER BY prompt_number ASC"
|
|
1180
|
+
"SELECT prompt_text FROM user_prompts WHERE session_id = ? ORDER BY prompt_number ASC LIMIT 10000"
|
|
1156
1181
|
).all(session_id);
|
|
1157
1182
|
const summary = buildSnapshotSummary(observations, prompts);
|
|
1158
1183
|
addSummary(db, session_id, summary);
|
|
@@ -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,
|
|
@@ -574,7 +592,7 @@ function getFeatureImpact(db, filePaths) {
|
|
|
574
592
|
const affectedFeatureIds = /* @__PURE__ */ new Set();
|
|
575
593
|
for (const filePath of filePaths) {
|
|
576
594
|
const links = db.prepare(
|
|
577
|
-
`SELECT feature_id FROM ${t("sentinel_components")} WHERE component_file =
|
|
595
|
+
`SELECT feature_id FROM ${t("sentinel_components")} WHERE component_file = ? LIMIT 10000`
|
|
578
596
|
).all(filePath);
|
|
579
597
|
for (const link of links) {
|
|
580
598
|
affectedFeatureIds.add(link.feature_id);
|
|
@@ -587,7 +605,7 @@ function getFeatureImpact(db, filePaths) {
|
|
|
587
605
|
const feature = getFeatureById(db, featureId);
|
|
588
606
|
if (!feature || feature.status !== "active") continue;
|
|
589
607
|
const allComponents = db.prepare(
|
|
590
|
-
`SELECT component_file, is_primary FROM ${t("sentinel_components")} WHERE feature_id =
|
|
608
|
+
`SELECT component_file, is_primary FROM ${t("sentinel_components")} WHERE feature_id = ? LIMIT 10000`
|
|
591
609
|
).all(featureId);
|
|
592
610
|
const affected = allComponents.filter((c) => fileSet.has(c.component_file));
|
|
593
611
|
const remaining = allComponents.filter((c) => !fileSet.has(c.component_file));
|
|
@@ -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,28 +749,27 @@ 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) {
|
|
744
756
|
try {
|
|
745
757
|
for (const pyFile of pyFiles) {
|
|
746
758
|
const importers = db.prepare(
|
|
747
|
-
`SELECT source_file FROM ${t("py_imports")} WHERE target_file =
|
|
759
|
+
`SELECT source_file FROM ${t("py_imports")} WHERE target_file = ? LIMIT 10000`
|
|
748
760
|
).all(pyFile);
|
|
749
761
|
const routes = db.prepare(
|
|
750
|
-
`SELECT method, path FROM ${t("py_routes")} WHERE file =
|
|
762
|
+
`SELECT method, path FROM ${t("py_routes")} WHERE file = ? LIMIT 10000`
|
|
751
763
|
).all(pyFile);
|
|
752
764
|
const models = db.prepare(
|
|
753
|
-
`SELECT class_name FROM ${t("py_models")} WHERE file =
|
|
765
|
+
`SELECT class_name FROM ${t("py_models")} WHERE file = ? LIMIT 10000`
|
|
754
766
|
).all(pyFile);
|
|
755
767
|
if (importers.length > 0 || routes.length > 0 || models.length > 0) {
|
|
756
768
|
const parts = [];
|
|
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
|
+
};
|