@massu/core 1.10.7 → 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 +559 -400
- 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/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 -1205
- 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,12 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"@massu/core/adapter": "
|
|
2
|
+
"@massu/core/adapter": "37b40614a34247e7ca753f0fdc1db9ab646df7ce8f96684e8555fd4be032881b",
|
|
3
3
|
"query-helpers": "f1372ef965450109258ad5bd300a1b3655660149e0b1b69ad30e1cc4acedcb2e",
|
|
4
4
|
"parse-guard": "1bed6c2298b40c07f0bd9641d975bf00e4d656fb4f52ab42a28666390d47ec6d",
|
|
5
|
-
"tree-sitter-loader": "
|
|
5
|
+
"tree-sitter-loader": "90da8caa618a3fe21d4b8cd6c4e62f39a5cebd4c34b54ee7bd789a2bcee014a9",
|
|
6
6
|
"types": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
|
7
|
-
"rails": "
|
|
8
|
-
"
|
|
9
|
-
"aspnet": "a04de27b4bf31c626375c376b613e2851d420a8c94494d9a222bd01c76f505ad",
|
|
10
|
-
"spring": "101ed8ab391b4769383dec6c1fee7429c2ee1f57efdb7d391f391d69e5dcbe1b",
|
|
11
|
-
"go-chi": "03be4cb66102ae172ec443f154ce18f0d5280e5e32cf408112539f06dad347c9"
|
|
7
|
+
"rails": "c9b1a0c19960d9e78a6ad57fce3fd05bfdd3ea3f862c76dd731c36bf8ef1f34b",
|
|
8
|
+
"spring": "5fb2f16d3aa733693b5090f2a972aab4818c23c850d15f6ef35c8e70a9884290"
|
|
12
9
|
}
|
|
@@ -258,8 +258,9 @@ function evictBeyondRetainCount(retain = getCacheRetainCount()) {
|
|
|
258
258
|
continue;
|
|
259
259
|
}
|
|
260
260
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
261
|
-
|
|
262
|
-
`[tree-sitter-loader] cache eviction skipped non-regular file: ${path} (possible symlink attack \u2014 see Phase 3.5 finding F-008)
|
|
261
|
+
process.stderr.write(
|
|
262
|
+
`[tree-sitter-loader] cache eviction skipped non-regular file: ${path} (possible symlink attack \u2014 see Phase 3.5 finding F-008).
|
|
263
|
+
`
|
|
263
264
|
);
|
|
264
265
|
continue;
|
|
265
266
|
}
|
|
@@ -374,8 +375,9 @@ async function loadGrammar(language, options = {}) {
|
|
|
374
375
|
}
|
|
375
376
|
evictBeyondRetainCount();
|
|
376
377
|
} catch (e) {
|
|
377
|
-
|
|
378
|
-
`[tree-sitter-loader] cache write failed for ${language}: ${e instanceof Error ? e.message : String(e)} \u2014 loading directly from memory
|
|
378
|
+
process.stderr.write(
|
|
379
|
+
`[tree-sitter-loader] cache write failed for ${language}: ${e instanceof Error ? e.message : String(e)} \u2014 loading directly from memory.
|
|
380
|
+
`
|
|
379
381
|
);
|
|
380
382
|
}
|
|
381
383
|
const lang = await Language.load(body);
|
|
@@ -258,8 +258,9 @@ function evictBeyondRetainCount(retain = getCacheRetainCount()) {
|
|
|
258
258
|
continue;
|
|
259
259
|
}
|
|
260
260
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
261
|
-
|
|
262
|
-
`[tree-sitter-loader] cache eviction skipped non-regular file: ${path} (possible symlink attack \u2014 see Phase 3.5 finding F-008)
|
|
261
|
+
process.stderr.write(
|
|
262
|
+
`[tree-sitter-loader] cache eviction skipped non-regular file: ${path} (possible symlink attack \u2014 see Phase 3.5 finding F-008).
|
|
263
|
+
`
|
|
263
264
|
);
|
|
264
265
|
continue;
|
|
265
266
|
}
|
|
@@ -374,8 +375,9 @@ async function loadGrammar(language, options = {}) {
|
|
|
374
375
|
}
|
|
375
376
|
evictBeyondRetainCount();
|
|
376
377
|
} catch (e) {
|
|
377
|
-
|
|
378
|
-
`[tree-sitter-loader] cache write failed for ${language}: ${e instanceof Error ? e.message : String(e)} \u2014 loading directly from memory
|
|
378
|
+
process.stderr.write(
|
|
379
|
+
`[tree-sitter-loader] cache write failed for ${language}: ${e instanceof Error ? e.message : String(e)} \u2014 loading directly from memory.
|
|
380
|
+
`
|
|
379
381
|
);
|
|
380
382
|
}
|
|
381
383
|
const lang = await Language.load(body);
|
|
@@ -174,8 +174,9 @@ function evictBeyondRetainCount(retain = getCacheRetainCount()) {
|
|
|
174
174
|
continue;
|
|
175
175
|
}
|
|
176
176
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
177
|
-
|
|
178
|
-
`[tree-sitter-loader] cache eviction skipped non-regular file: ${path} (possible symlink attack \u2014 see Phase 3.5 finding F-008)
|
|
177
|
+
process.stderr.write(
|
|
178
|
+
`[tree-sitter-loader] cache eviction skipped non-regular file: ${path} (possible symlink attack \u2014 see Phase 3.5 finding F-008).
|
|
179
|
+
`
|
|
179
180
|
);
|
|
180
181
|
continue;
|
|
181
182
|
}
|
|
@@ -293,8 +294,9 @@ async function loadGrammar(language, options = {}) {
|
|
|
293
294
|
}
|
|
294
295
|
evictBeyondRetainCount();
|
|
295
296
|
} catch (e) {
|
|
296
|
-
|
|
297
|
-
`[tree-sitter-loader] cache write failed for ${language}: ${e instanceof Error ? e.message : String(e)} \u2014 loading directly from memory
|
|
297
|
+
process.stderr.write(
|
|
298
|
+
`[tree-sitter-loader] cache write failed for ${language}: ${e instanceof Error ? e.message : String(e)} \u2014 loading directly from memory.
|
|
299
|
+
`
|
|
298
300
|
);
|
|
299
301
|
}
|
|
300
302
|
const lang = await Language.load(body);
|
|
@@ -341,6 +341,22 @@ var RawConfigSchema = z.object({
|
|
|
341
341
|
accessScopes: z.array(z.string()).optional(),
|
|
342
342
|
domains: z.array(DomainConfigSchema).default([]),
|
|
343
343
|
rules: z.array(PatternRuleConfigSchema).default([]),
|
|
344
|
+
// P-M-036 (plan-stage-d-medium-sweep): customer-authored CR-style
|
|
345
|
+
// governance rules. DISTINCT from `rules:` above (path-scoped lint hints
|
|
346
|
+
// used by pattern-scanner). At config-refresh time these entries are
|
|
347
|
+
// loaded into the `knowledge_rules` SQLite table with
|
|
348
|
+
// `source = 'customer-config'` so `massu_knowledge_rule` and the
|
|
349
|
+
// governance docs surface customer-defined rules alongside framework CRs.
|
|
350
|
+
governance_rules: z.array(
|
|
351
|
+
z.object({
|
|
352
|
+
id: z.string().min(1, "governance_rules[].id is required"),
|
|
353
|
+
title: z.string().min(1, "governance_rules[].title is required"),
|
|
354
|
+
description: z.string().min(1, "governance_rules[].description is required"),
|
|
355
|
+
vr_type: z.string().default("VR-CUSTOM"),
|
|
356
|
+
reference_path: z.string().optional(),
|
|
357
|
+
severity: z.enum(["critical", "high", "medium", "low", "info"]).default("medium")
|
|
358
|
+
}).passthrough()
|
|
359
|
+
).default([]),
|
|
344
360
|
analytics: AnalyticsConfigSchema,
|
|
345
361
|
governance: GovernanceConfigSchema,
|
|
346
362
|
security: SecurityConfigSchema,
|
|
@@ -459,6 +475,8 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
459
475
|
accessScopes: parsed.accessScopes,
|
|
460
476
|
domains: parsed.domains,
|
|
461
477
|
rules: parsed.rules,
|
|
478
|
+
// P-M-036: customer-authored CR-style governance rules.
|
|
479
|
+
governance_rules: parsed.governance_rules,
|
|
462
480
|
analytics: parsed.analytics,
|
|
463
481
|
governance: parsed.governance,
|
|
464
482
|
security: parsed.security,
|
|
@@ -489,6 +507,11 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
489
507
|
return _config;
|
|
490
508
|
}
|
|
491
509
|
|
|
510
|
+
// src/hooks/lib/write-hook-message.ts
|
|
511
|
+
function writeHookMessage(message) {
|
|
512
|
+
process.stdout.write(JSON.stringify({ message }) + "\n");
|
|
513
|
+
}
|
|
514
|
+
|
|
492
515
|
// src/hooks/auto-learning-pipeline.ts
|
|
493
516
|
var MAX_FULL_DIFF_BYTES = 2 * 1024 * 1024;
|
|
494
517
|
function getSessionFlagPath(sessionId) {
|
|
@@ -608,7 +631,7 @@ async function main() {
|
|
|
608
631
|
lines.push("");
|
|
609
632
|
lines.push("============================================================================");
|
|
610
633
|
lines.push("");
|
|
611
|
-
|
|
634
|
+
writeHookMessage(lines.join("\n"));
|
|
612
635
|
cleanup(flagPath);
|
|
613
636
|
} catch {
|
|
614
637
|
}
|
|
@@ -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,
|
|
@@ -1021,6 +1039,12 @@ function initMemorySchema(db) {
|
|
|
1021
1039
|
features TEXT DEFAULT '[]'
|
|
1022
1040
|
);
|
|
1023
1041
|
`);
|
|
1042
|
+
const licenseCacheCols = db.prepare(`PRAGMA table_info(license_cache)`).all();
|
|
1043
|
+
if (!licenseCacheCols.some((c) => c.name === "signed_payload_json")) {
|
|
1044
|
+
db.exec(
|
|
1045
|
+
`ALTER TABLE license_cache ADD COLUMN signed_payload_json TEXT NOT NULL DEFAULT ''`
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1024
1048
|
db.exec(`
|
|
1025
1049
|
CREATE TABLE IF NOT EXISTS failure_classes (
|
|
1026
1050
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -1117,6 +1141,11 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
|
|
|
1117
1141
|
return bestMatch;
|
|
1118
1142
|
}
|
|
1119
1143
|
|
|
1144
|
+
// src/hooks/lib/write-hook-message.ts
|
|
1145
|
+
function writeHookMessage(message) {
|
|
1146
|
+
process.stdout.write(JSON.stringify({ message }) + "\n");
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1120
1149
|
// src/hooks/classify-failure.ts
|
|
1121
1150
|
var BUG_FIX_INDICATORS = [
|
|
1122
1151
|
/\b(catch|error|throw|fail|fix|bug|broken|missing|crash|wrong|typo|incorrect)\b/i
|
|
@@ -1258,7 +1287,7 @@ function outputKnownPattern(match) {
|
|
|
1258
1287
|
lines.push(` Covered by: ${match.rules.join(", ")}`);
|
|
1259
1288
|
}
|
|
1260
1289
|
lines.push(" No new rules needed. Reference existing incident if logging.");
|
|
1261
|
-
|
|
1290
|
+
writeHookMessage(lines.join("\n"));
|
|
1262
1291
|
}
|
|
1263
1292
|
function outputSimilarPattern(match) {
|
|
1264
1293
|
const lines = [];
|
|
@@ -1268,7 +1297,7 @@ function outputSimilarPattern(match) {
|
|
|
1268
1297
|
lines.push(` Check if existing rules cover this case: ${match.rules.join(", ")}`);
|
|
1269
1298
|
}
|
|
1270
1299
|
lines.push(" If genuinely new: create incident + prevention rule + enforcement.");
|
|
1271
|
-
|
|
1300
|
+
writeHookMessage(lines.join("\n"));
|
|
1272
1301
|
}
|
|
1273
1302
|
function outputNewPattern(fileName, match) {
|
|
1274
1303
|
const lines = [];
|
|
@@ -1282,7 +1311,7 @@ function outputNewPattern(fileName, match) {
|
|
|
1282
1311
|
lines.push(" 1. INCIDENT REPORT");
|
|
1283
1312
|
lines.push(" 2. PREVENTION RULE (if new failure pattern)");
|
|
1284
1313
|
lines.push(" 3. ENFORCEMENT (hook or static check)");
|
|
1285
|
-
|
|
1314
|
+
writeHookMessage(lines.join("\n"));
|
|
1286
1315
|
}
|
|
1287
1316
|
function readStdin() {
|
|
1288
1317
|
return new Promise((resolve3) => {
|
|
@@ -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,
|
|
@@ -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/hooks/fix-detector.ts
|
|
5
11
|
import { execFileSync } from "child_process";
|
|
@@ -341,6 +347,22 @@ var RawConfigSchema = z.object({
|
|
|
341
347
|
accessScopes: z.array(z.string()).optional(),
|
|
342
348
|
domains: z.array(DomainConfigSchema).default([]),
|
|
343
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([]),
|
|
344
366
|
analytics: AnalyticsConfigSchema,
|
|
345
367
|
governance: GovernanceConfigSchema,
|
|
346
368
|
security: SecurityConfigSchema,
|
|
@@ -459,6 +481,8 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
459
481
|
accessScopes: parsed.accessScopes,
|
|
460
482
|
domains: parsed.domains,
|
|
461
483
|
rules: parsed.rules,
|
|
484
|
+
// P-M-036: customer-authored CR-style governance rules.
|
|
485
|
+
governance_rules: parsed.governance_rules,
|
|
462
486
|
analytics: parsed.analytics,
|
|
463
487
|
governance: parsed.governance,
|
|
464
488
|
security: parsed.security,
|
|
@@ -489,6 +513,11 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
489
513
|
return _config;
|
|
490
514
|
}
|
|
491
515
|
|
|
516
|
+
// src/hooks/lib/write-hook-message.ts
|
|
517
|
+
function writeHookMessage(message) {
|
|
518
|
+
process.stdout.write(JSON.stringify({ message }) + "\n");
|
|
519
|
+
}
|
|
520
|
+
|
|
492
521
|
// src/hooks/fix-detector.ts
|
|
493
522
|
var FIX_HEURISTICS = [
|
|
494
523
|
{
|
|
@@ -538,6 +567,64 @@ function getSessionFlagPath(sessionId) {
|
|
|
538
567
|
}
|
|
539
568
|
return join(dir, `fixes-${sessionId.slice(0, 12)}.jsonl`);
|
|
540
569
|
}
|
|
570
|
+
function _stateDir() {
|
|
571
|
+
const dir = join(tmpdir(), "massu-fix-detector-state");
|
|
572
|
+
if (!existsSync2(dir)) {
|
|
573
|
+
mkdirSync(dir, { recursive: true });
|
|
574
|
+
}
|
|
575
|
+
return dir;
|
|
576
|
+
}
|
|
577
|
+
function _cwdHash(cwd) {
|
|
578
|
+
let h = 5381;
|
|
579
|
+
for (let i = 0; i < cwd.length; i++) {
|
|
580
|
+
h = (h << 5) + h + cwd.charCodeAt(i) | 0;
|
|
581
|
+
}
|
|
582
|
+
return Math.abs(h).toString(36);
|
|
583
|
+
}
|
|
584
|
+
function isGitWorkTreeFast(cwd) {
|
|
585
|
+
try {
|
|
586
|
+
const cachePath = join(_stateDir(), `worktree-${_cwdHash(cwd)}.json`);
|
|
587
|
+
if (existsSync2(cachePath)) {
|
|
588
|
+
const cached = JSON.parse(readFileSync2(cachePath, "utf-8"));
|
|
589
|
+
const ageMs = Date.now() - cached.ts;
|
|
590
|
+
if (ageMs < 36e5) return cached.isWorkTree;
|
|
591
|
+
}
|
|
592
|
+
let isWorkTree = false;
|
|
593
|
+
try {
|
|
594
|
+
execFileSync("git", ["rev-parse", "--is-inside-work-tree"], { cwd, timeout: 500, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
|
|
595
|
+
isWorkTree = true;
|
|
596
|
+
} catch {
|
|
597
|
+
isWorkTree = false;
|
|
598
|
+
}
|
|
599
|
+
try {
|
|
600
|
+
appendFileSync(cachePath, "");
|
|
601
|
+
const fs = __require("fs");
|
|
602
|
+
fs.writeFileSync(cachePath, JSON.stringify({ isWorkTree, ts: Date.now() }));
|
|
603
|
+
} catch {
|
|
604
|
+
}
|
|
605
|
+
return isWorkTree;
|
|
606
|
+
} catch {
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
function _disabledFlagPath(sessionId) {
|
|
611
|
+
return join(_stateDir(), `disabled-${sessionId.slice(0, 12)}.flag`);
|
|
612
|
+
}
|
|
613
|
+
function isSessionAutoDisabled(sessionId) {
|
|
614
|
+
try {
|
|
615
|
+
return existsSync2(_disabledFlagPath(sessionId));
|
|
616
|
+
} catch {
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
function markSessionAutoDisabled(sessionId, elapsedMs) {
|
|
621
|
+
try {
|
|
622
|
+
const fs = __require("fs");
|
|
623
|
+
fs.writeFileSync(_disabledFlagPath(sessionId), `disabled: previous git diff took ${elapsedMs}ms
|
|
624
|
+
`);
|
|
625
|
+
} catch {
|
|
626
|
+
}
|
|
627
|
+
}
|
|
541
628
|
async function main() {
|
|
542
629
|
try {
|
|
543
630
|
const input = await readStdin();
|
|
@@ -563,12 +650,21 @@ async function main() {
|
|
|
563
650
|
return;
|
|
564
651
|
}
|
|
565
652
|
const root = getProjectRoot();
|
|
653
|
+
if (!isGitWorkTreeFast(root) || isSessionAutoDisabled(hookInput.session_id)) {
|
|
654
|
+
process.exit(0);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
566
657
|
let diff = "";
|
|
567
658
|
try {
|
|
659
|
+
const startMs = Date.now();
|
|
568
660
|
diff = execFileSync("git", ["diff", "--", filePath], { cwd: root, timeout: 3e3, encoding: "utf-8" });
|
|
569
661
|
if (!diff) {
|
|
570
662
|
diff = execFileSync("git", ["diff", "HEAD", "--", filePath], { cwd: root, timeout: 3e3, encoding: "utf-8" });
|
|
571
663
|
}
|
|
664
|
+
const elapsedMs = Date.now() - startMs;
|
|
665
|
+
if (elapsedMs > 2e3) {
|
|
666
|
+
markSessionAutoDisabled(hookInput.session_id, elapsedMs);
|
|
667
|
+
}
|
|
572
668
|
} catch {
|
|
573
669
|
process.exit(0);
|
|
574
670
|
return;
|
|
@@ -597,7 +693,7 @@ async function main() {
|
|
|
597
693
|
appendFileSync(flagPath, JSON.stringify(signal) + "\n");
|
|
598
694
|
const lines = readFileSync2(flagPath, "utf-8").split("\n").filter(Boolean);
|
|
599
695
|
if (lines.length === 1) {
|
|
600
|
-
|
|
696
|
+
writeHookMessage(
|
|
601
697
|
`[Massu Auto-Learning] Bug fix detected in ${filePath} (signals: ${detected.join(", ")}). The auto-learning pipeline will prompt you at session end to create an incident report, derive a prevention rule, and add enforcement.`
|
|
602
698
|
);
|
|
603
699
|
}
|
|
@@ -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,
|
|
@@ -1020,6 +1038,12 @@ function initMemorySchema(db) {
|
|
|
1020
1038
|
features TEXT DEFAULT '[]'
|
|
1021
1039
|
);
|
|
1022
1040
|
`);
|
|
1041
|
+
const licenseCacheCols = db.prepare(`PRAGMA table_info(license_cache)`).all();
|
|
1042
|
+
if (!licenseCacheCols.some((c) => c.name === "signed_payload_json")) {
|
|
1043
|
+
db.exec(
|
|
1044
|
+
`ALTER TABLE license_cache ADD COLUMN signed_payload_json TEXT NOT NULL DEFAULT ''`
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1023
1047
|
db.exec(`
|
|
1024
1048
|
CREATE TABLE IF NOT EXISTS failure_classes (
|
|
1025
1049
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -1143,6 +1167,11 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
|
|
|
1143
1167
|
return bestMatch;
|
|
1144
1168
|
}
|
|
1145
1169
|
|
|
1170
|
+
// src/hooks/lib/write-hook-message.ts
|
|
1171
|
+
function writeHookMessage(message) {
|
|
1172
|
+
process.stdout.write(JSON.stringify({ message }) + "\n");
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1146
1175
|
// src/hooks/incident-pipeline.ts
|
|
1147
1176
|
async function main() {
|
|
1148
1177
|
try {
|
|
@@ -1226,7 +1255,7 @@ async function main() {
|
|
|
1226
1255
|
lines.push(" This step is MANDATORY per the auto-learning pipeline.");
|
|
1227
1256
|
lines.push("============================================================================");
|
|
1228
1257
|
lines.push("");
|
|
1229
|
-
|
|
1258
|
+
writeHookMessage(lines.join("\n"));
|
|
1230
1259
|
try {
|
|
1231
1260
|
const taxonomyConfig = config.autoLearning?.failureClassification;
|
|
1232
1261
|
if (taxonomyConfig?.enabled !== false) {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import{createRequire as __cr}from"module";const require=__cr(import.meta.url);
|
|
3
3
|
|
|
4
|
+
// src/hooks/lib/write-hook-message.ts
|
|
5
|
+
function writeHookMessage(message) {
|
|
6
|
+
process.stdout.write(JSON.stringify({ message }) + "\n");
|
|
7
|
+
}
|
|
8
|
+
|
|
4
9
|
// src/hooks/intent-suggester.ts
|
|
5
10
|
var COMMAND_MAPPINGS = [
|
|
6
11
|
{
|
|
@@ -79,9 +84,7 @@ async function main() {
|
|
|
79
84
|
process.exit(0);
|
|
80
85
|
return;
|
|
81
86
|
}
|
|
82
|
-
|
|
83
|
-
`Tip: Use ${match.command} to ${match.description}.`
|
|
84
|
-
);
|
|
87
|
+
writeHookMessage(`Tip: Use ${match.command} to ${match.description}.`);
|
|
85
88
|
} catch (_e) {
|
|
86
89
|
}
|
|
87
90
|
process.exit(0);
|
|
@@ -346,6 +346,22 @@ var RawConfigSchema = z.object({
|
|
|
346
346
|
accessScopes: z.array(z.string()).optional(),
|
|
347
347
|
domains: z.array(DomainConfigSchema).default([]),
|
|
348
348
|
rules: z.array(PatternRuleConfigSchema).default([]),
|
|
349
|
+
// P-M-036 (plan-stage-d-medium-sweep): customer-authored CR-style
|
|
350
|
+
// governance rules. DISTINCT from `rules:` above (path-scoped lint hints
|
|
351
|
+
// used by pattern-scanner). At config-refresh time these entries are
|
|
352
|
+
// loaded into the `knowledge_rules` SQLite table with
|
|
353
|
+
// `source = 'customer-config'` so `massu_knowledge_rule` and the
|
|
354
|
+
// governance docs surface customer-defined rules alongside framework CRs.
|
|
355
|
+
governance_rules: z.array(
|
|
356
|
+
z.object({
|
|
357
|
+
id: z.string().min(1, "governance_rules[].id is required"),
|
|
358
|
+
title: z.string().min(1, "governance_rules[].title is required"),
|
|
359
|
+
description: z.string().min(1, "governance_rules[].description is required"),
|
|
360
|
+
vr_type: z.string().default("VR-CUSTOM"),
|
|
361
|
+
reference_path: z.string().optional(),
|
|
362
|
+
severity: z.enum(["critical", "high", "medium", "low", "info"]).default("medium")
|
|
363
|
+
}).passthrough()
|
|
364
|
+
).default([]),
|
|
349
365
|
analytics: AnalyticsConfigSchema,
|
|
350
366
|
governance: GovernanceConfigSchema,
|
|
351
367
|
security: SecurityConfigSchema,
|
|
@@ -464,6 +480,8 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
464
480
|
accessScopes: parsed.accessScopes,
|
|
465
481
|
domains: parsed.domains,
|
|
466
482
|
rules: parsed.rules,
|
|
483
|
+
// P-M-036: customer-authored CR-style governance rules.
|
|
484
|
+
governance_rules: parsed.governance_rules,
|
|
467
485
|
analytics: parsed.analytics,
|
|
468
486
|
governance: parsed.governance,
|
|
469
487
|
security: parsed.security,
|
|
@@ -558,6 +576,11 @@ function isInMiddlewareTree(dataDb, file) {
|
|
|
558
576
|
return result !== void 0;
|
|
559
577
|
}
|
|
560
578
|
|
|
579
|
+
// src/hooks/lib/write-hook-message.ts
|
|
580
|
+
function writeHookMessage(message) {
|
|
581
|
+
process.stdout.write(JSON.stringify({ message }) + "\n");
|
|
582
|
+
}
|
|
583
|
+
|
|
561
584
|
// src/hooks/post-edit-context.ts
|
|
562
585
|
async function main() {
|
|
563
586
|
try {
|
|
@@ -595,7 +618,7 @@ async function main() {
|
|
|
595
618
|
} catch (_e) {
|
|
596
619
|
}
|
|
597
620
|
if (warnings.length > 0) {
|
|
598
|
-
|
|
621
|
+
writeHookMessage(`[Massu] ${warnings.join(" | ")}`);
|
|
599
622
|
}
|
|
600
623
|
} catch (_e) {
|
|
601
624
|
}
|