@massu/core 2.5.1 → 2.5.3
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 +240 -0
- package/agents/massu-output-scorer.md +2 -2
- package/agents/massu-plan-auditor.md +1 -1
- package/commands/_shared-references/test-first-protocol.md +4 -4
- package/commands/_shared-references/verification-table.md +5 -5
- package/commands/massu-audit-deps.md +2 -2
- package/commands/massu-batch.md +3 -3
- package/commands/massu-checkpoint.md +7 -7
- package/commands/massu-ci-fix.md +1 -1
- package/commands/massu-cleanup.md +16 -16
- package/commands/massu-commit.md +7 -7
- package/commands/massu-create-plan.md +7 -7
- package/commands/massu-dead-code.md +3 -3
- package/commands/massu-debug/references/common-shortcuts.md +1 -1
- package/commands/massu-debug/references/investigation-phases.md +4 -4
- package/commands/massu-debug/references/report-format.md +2 -2
- package/commands/massu-deploy.md +1 -1
- package/commands/massu-deps.md +5 -5
- package/commands/massu-doc-gen.md +3 -3
- package/commands/massu-docs.md +6 -6
- package/commands/massu-estimate.md +3 -3
- package/commands/massu-golden-path/references/competitive-mode.md +2 -2
- package/commands/massu-golden-path/references/phase-1-plan-creation.md +1 -1
- package/commands/massu-golden-path/references/phase-2-implementation.md +2 -2
- package/commands/massu-golden-path/references/phase-4-commit.md +3 -3
- package/commands/massu-golden-path/references/phase-5-push.md +5 -5
- package/commands/massu-guide.md +3 -3
- package/commands/massu-hotfix.md +14 -14
- package/commands/massu-loop/references/checkpoint-audit.md +3 -3
- package/commands/massu-loop/references/iteration-structure.md +3 -3
- package/commands/massu-loop/references/loop-controller.md +5 -5
- package/commands/massu-loop/references/plan-extraction.md +4 -4
- package/commands/massu-loop/references/vr-plan-spec.md +3 -3
- package/commands/massu-loop-playwright.md +5 -5
- package/commands/massu-loop.md +1 -1
- package/commands/massu-new-feature.md +6 -24
- package/commands/massu-perf.md +1 -1
- package/commands/massu-plan.md +21 -21
- package/commands/massu-push-light.md +9 -9
- package/commands/massu-recap.md +1 -1
- package/commands/massu-refactor.md +8 -8
- package/commands/massu-release.md +3 -3
- package/commands/massu-review.md +1 -1
- package/commands/massu-rollback.md +6 -6
- package/commands/massu-scaffold-page.md +1 -1
- package/commands/massu-scaffold-router.md +1 -1
- package/commands/massu-status.md +9 -9
- package/commands/massu-tdd.md +2 -2
- package/commands/massu-test.md +13 -13
- package/commands/massu-verify-playwright.md +1 -1
- package/commands/massu-verify.md +20 -20
- package/dist/cli.js +1731 -976
- package/dist/hooks/auto-learning-pipeline.js +745 -87
- package/dist/hooks/classify-failure.js +747 -45
- package/dist/hooks/cost-tracker.js +89 -28
- package/dist/hooks/fix-detector.js +536 -48
- package/dist/hooks/incident-pipeline.js +96 -29
- package/dist/hooks/intent-suggester.js +89 -28
- package/dist/hooks/memory-recall.js +89 -28
- package/dist/hooks/post-edit-context.js +137 -29
- package/dist/hooks/post-tool-use.js +95 -30
- package/dist/hooks/pre-compact.js +89 -28
- package/dist/hooks/pre-delete-check.js +137 -31
- package/dist/hooks/pre-tool-use-gate.js +271 -43
- package/dist/hooks/quality-event.js +89 -28
- package/dist/hooks/rule-enforcement-pipeline.js +89 -28
- package/dist/hooks/security-gate.js +219 -39
- package/dist/hooks/session-end.js +92 -28
- package/dist/hooks/session-start.js +140 -62
- package/dist/hooks/user-prompt.js +89 -28
- package/fragments/feature-components.md +15 -0
- package/fragments/feature-components.python.md +15 -0
- package/fragments/feature-components.typescript.md +15 -0
- package/package.json +6 -5
- package/patterns/testing-patterns.md +8 -8
- package/protocols/plan-implementation.md +2 -2
- package/protocols/verification.md +4 -4
- package/reference/lessons-learned.md +4 -4
- package/reference/vr-verification-reference.md +9 -9
- package/templates/aspnet/massu.config.yaml +2 -0
- package/templates/go-chi/massu.config.yaml +2 -0
- package/templates/multi-runtime/massu.config.yaml +4 -2
- package/templates/phoenix/massu.config.yaml +2 -0
- package/templates/python-django/massu.config.yaml +3 -1
- package/templates/python-fastapi/massu.config.yaml +3 -1
- package/templates/python-flask/massu.config.yaml +3 -1
- package/templates/rails/massu.config.yaml +4 -2
- package/templates/rust-actix/massu.config.yaml +2 -0
- package/templates/spring/massu.config.yaml +2 -0
- package/templates/swift-ios/massu.config.yaml +3 -1
- package/templates/ts-nestjs/massu.config.yaml +2 -0
- package/templates/ts-nextjs/massu.config.yaml +2 -0
|
@@ -36,6 +36,15 @@ var init_memory_path = __esm({
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
+
// src/lib/corrections-md.ts
|
|
40
|
+
var CORRECTIONS_FILENAME;
|
|
41
|
+
var init_corrections_md = __esm({
|
|
42
|
+
"src/lib/corrections-md.ts"() {
|
|
43
|
+
"use strict";
|
|
44
|
+
CORRECTIONS_FILENAME = "corrections.md";
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
39
48
|
// src/credentials.ts
|
|
40
49
|
import { homedir } from "os";
|
|
41
50
|
import { resolve } from "path";
|
|
@@ -137,7 +146,7 @@ var init_config_memory_schema = __esm({
|
|
|
137
146
|
message: "memory.recall.embedEndpoint must be an http(s) URL"
|
|
138
147
|
}).optional(),
|
|
139
148
|
embedModel: z.string().min(1).optional()
|
|
140
|
-
}).
|
|
149
|
+
}).prefault({}),
|
|
141
150
|
// --- Contradiction / supersede gate (plan-living-memory-slice-2-temporal-model, P5-001) ---
|
|
142
151
|
// When a new high-value memory (decision/correction) is written, find
|
|
143
152
|
// semantically-related existing records and, if the new one contradicts an
|
|
@@ -166,7 +175,7 @@ var init_config_memory_schema = __esm({
|
|
|
166
175
|
annotateSuperseded: z.boolean().default(false),
|
|
167
176
|
// Time budget (ms) for the contradiction check; exceeded → fail-open (ADD).
|
|
168
177
|
budgetMs: z.number().int().positive().default(800)
|
|
169
|
-
}).
|
|
178
|
+
}).prefault({}),
|
|
170
179
|
// --- Background consolidation, the "sleep-time" pass
|
|
171
180
|
// (plan-living-memory-slice-3-consolidation) ---
|
|
172
181
|
// Keeps memory sharp over years: dedupes, distills dying sessions into
|
|
@@ -212,7 +221,7 @@ var init_config_memory_schema = __esm({
|
|
|
212
221
|
// Surface optional upgrades (e.g. "a local model was detected") in chat.
|
|
213
222
|
suggestUpgrades: z.boolean().default(true),
|
|
214
223
|
suggestIntervalDays: z.number().int().positive().default(30)
|
|
215
|
-
}).
|
|
224
|
+
}).prefault({}),
|
|
216
225
|
// A-20 (Slice 4) — memory FILES: the mirror, and the one switch that decides whether
|
|
217
226
|
// Massu may ever WRITE into the user's memory directory.
|
|
218
227
|
//
|
|
@@ -237,7 +246,7 @@ var init_config_memory_schema = __esm({
|
|
|
237
246
|
// turn of EVERY session, so an unbounded index is a permanent context tax — and the
|
|
238
247
|
// per-session cap bounds only the RATE, never the total.
|
|
239
248
|
indexMaxLines: z.number().int().min(1).default(50)
|
|
240
|
-
}).
|
|
249
|
+
}).prefault({}),
|
|
241
250
|
// --- Cross-repo memory surfacing (plan-living-memory-slice-5-cross-repo-surfacing) ---
|
|
242
251
|
// A decision made in one of your repos can surface in another — opt-in per
|
|
243
252
|
// decision AND opt-in per repo, signed, verified, and materialized ONLY on
|
|
@@ -262,8 +271,8 @@ var init_config_memory_schema = __esm({
|
|
|
262
271
|
enabled: z.boolean().default(true),
|
|
263
272
|
maxCrossRepoItems: z.number().int().min(0).default(1),
|
|
264
273
|
minScore: z.number().optional()
|
|
265
|
-
}).
|
|
266
|
-
}).
|
|
274
|
+
}).prefault({})
|
|
275
|
+
}).prefault({})
|
|
267
276
|
}).optional();
|
|
268
277
|
}
|
|
269
278
|
});
|
|
@@ -443,13 +452,19 @@ function getResolvedPaths() {
|
|
|
443
452
|
settingsLocalPath: resolve2(root, claudeDirName, "settings.local.json")
|
|
444
453
|
};
|
|
445
454
|
}
|
|
446
|
-
var DomainConfigSchema, PatternRuleConfigSchema, CostModelSchema, AnalyticsConfigSchema, CustomPatternSchema, GovernanceConfigSchema, SecurityPatternSchema, SecurityConfigSchema, TeamConfigSchema, RegressionConfigSchema, AutoLearningConfigSchema, CloudConfigSchema, ConventionsConfigSchema, PythonDomainConfigSchema, PythonConfigSchema, PathsConfigSchema, LanguageFrameworkEntrySchema, FrameworkConfigSchema, DetectedConfigSchema, VerificationEntrySchema, VerificationConfigSchema, CanonicalPathsSchema, VerificationTypesSchema, DetectionRuleEntrySchema, DetectionConfigSchema, WatchConfigSchema, AdapterLocalPathSchema, AdaptersConfigSchema, TelemetryConfigSchema, LSPConfigSchema, RawConfigSchema, _config, _resolvedApiKeySource, _projectRoot;
|
|
455
|
+
var DEFAULT_KNOWLEDGE_SOURCE_FILES, DomainConfigSchema, PatternRuleConfigSchema, CostModelSchema, AnalyticsConfigSchema, CustomPatternSchema, GovernanceConfigSchema, SecurityPatternSchema, SecurityConfigSchema, TeamConfigSchema, RegressionConfigSchema, AutoLearningConfigSchema, CloudConfigSchema, ConventionsConfigSchema, PythonDomainConfigSchema, PythonConfigSchema, PathsConfigSchema, LanguageFrameworkEntrySchema, FrameworkConfigSchema, DetectedConfigSchema, VerificationEntrySchema, VerificationConfigSchema, CanonicalPathsSchema, VerificationTypesSchema, DetectionRuleEntrySchema, DetectionConfigSchema, WatchConfigSchema, AdapterLocalPathSchema, AdaptersConfigSchema, TelemetryConfigSchema, LSPConfigSchema, RawConfigSchema, _config, _resolvedApiKeySource, _projectRoot;
|
|
447
456
|
var init_config = __esm({
|
|
448
457
|
"src/config.ts"() {
|
|
449
458
|
"use strict";
|
|
450
459
|
init_memory_path();
|
|
460
|
+
init_corrections_md();
|
|
451
461
|
init_credentials();
|
|
452
462
|
init_config_memory_schema();
|
|
463
|
+
DEFAULT_KNOWLEDGE_SOURCE_FILES = [
|
|
464
|
+
"CLAUDE.md",
|
|
465
|
+
"MEMORY.md",
|
|
466
|
+
CORRECTIONS_FILENAME
|
|
467
|
+
];
|
|
453
468
|
DomainConfigSchema = z2.object({
|
|
454
469
|
name: z2.string().default("Unknown"),
|
|
455
470
|
routers: z2.array(z2.string()).default([]),
|
|
@@ -578,34 +593,40 @@ var init_config = __esm({
|
|
|
578
593
|
fixDetection: z2.object({
|
|
579
594
|
enabled: z2.boolean().default(true),
|
|
580
595
|
lookbackDays: z2.number().default(7),
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
596
|
+
// ⛔ NO DEFAULT LIST HERE, DELIBERATELY — the heuristics are the SSOT.
|
|
597
|
+
//
|
|
598
|
+
// This carried a hand-typed copy of all eight signal names while
|
|
599
|
+
// `fix-detector.ts` already read `config…signals ?? FIX_HEURISTICS.map(h => h.name)`.
|
|
600
|
+
// Because zod ALWAYS materialised the default, that fallback — the correct expression
|
|
601
|
+
// — was unreachable, and the duplicate was the only thing in effect. Two authoring
|
|
602
|
+
// sites for one vocabulary, and the drift is SILENT: a name listed here that no longer
|
|
603
|
+
// exists simply never matches `enabledSignals.has(...)`, so a retired heuristic lingers
|
|
604
|
+
// as a dead entry with no error. Retiring `method_name_correction` would have landed at
|
|
605
|
+
// one site of two (CR-74).
|
|
606
|
+
//
|
|
607
|
+
// Optional, so an ABSENT value reaches the `??` and the heuristic list defines itself
|
|
608
|
+
// (Rule 25). An explicit list in massu.config.yaml still overrides, which is the only
|
|
609
|
+
// behaviour anyone actually configured — measured: `fix-detector.ts:267` is the sole
|
|
610
|
+
// consumer and no config file in the repo sets it.
|
|
611
|
+
signals: z2.array(z2.string()).optional()
|
|
612
|
+
}).prefault({}),
|
|
592
613
|
failureClassification: z2.object({
|
|
593
614
|
enabled: z2.boolean().default(true),
|
|
594
615
|
thresholds: z2.object({
|
|
595
616
|
known: z2.number().default(5),
|
|
596
617
|
similar: z2.number().default(3)
|
|
597
|
-
}).
|
|
618
|
+
}).prefault({}),
|
|
598
619
|
scoring: z2.object({
|
|
599
620
|
diffPatternWeight: z2.number().default(3),
|
|
600
621
|
filePatternWeight: z2.number().default(2),
|
|
601
622
|
promptKeywordWeight: z2.number().default(2)
|
|
602
|
-
}).
|
|
603
|
-
}).
|
|
623
|
+
}).prefault({})
|
|
624
|
+
}).prefault({}),
|
|
604
625
|
pipeline: z2.object({
|
|
605
626
|
requireIncidentReport: z2.boolean().default(true),
|
|
606
627
|
requirePreventionRule: z2.boolean().default(true),
|
|
607
628
|
requireEnforcement: z2.boolean().default(true)
|
|
608
|
-
}).
|
|
629
|
+
}).prefault({}),
|
|
609
630
|
// plan-v0.2-interactive-rule-approval P-D-008 / P-D-009: project-configured
|
|
610
631
|
// custom destinations for the rule-candidate funnel. The classifier matches
|
|
611
632
|
// a candidate to one of these entries when none of the framework
|
|
@@ -638,7 +659,7 @@ var init_config = __esm({
|
|
|
638
659
|
memory: z2.boolean().default(true),
|
|
639
660
|
analytics: z2.boolean().default(true),
|
|
640
661
|
audit: z2.boolean().default(true)
|
|
641
|
-
}).
|
|
662
|
+
}).prefault({ memory: true, analytics: true, audit: true })
|
|
642
663
|
}).optional();
|
|
643
664
|
ConventionsConfigSchema = z2.object({
|
|
644
665
|
claudeDirName: z2.string().default(".claude").refine(
|
|
@@ -669,7 +690,7 @@ var init_config = __esm({
|
|
|
669
690
|
"session-state",
|
|
670
691
|
"agents"
|
|
671
692
|
]),
|
|
672
|
-
knowledgeSourceFiles: z2.array(z2.string()).default([
|
|
693
|
+
knowledgeSourceFiles: z2.array(z2.string()).default([...DEFAULT_KNOWLEDGE_SOURCE_FILES]),
|
|
673
694
|
excludePatterns: z2.array(z2.string()).default(["/ARCHIVE/", "/SESSION-HISTORY/"])
|
|
674
695
|
}).optional();
|
|
675
696
|
PythonDomainConfigSchema = z2.object({
|
|
@@ -685,6 +706,23 @@ var init_config = __esm({
|
|
|
685
706
|
}).optional();
|
|
686
707
|
PathsConfigSchema = z2.object({
|
|
687
708
|
source: z2.string().default("src"),
|
|
709
|
+
/**
|
|
710
|
+
* Where this stack's tests live, relative to the project root.
|
|
711
|
+
*
|
|
712
|
+
* Added 2026-09-20 for P4.3 of docs/plans/2026-09-20-stack-conformant-asset-rendering.md.
|
|
713
|
+
* ~25 shipped assets told every customer their tests belong in
|
|
714
|
+
* `packages/core/src/__tests__/` — massu's OWN layout — and no vocabulary could express
|
|
715
|
+
* the alternative because none existed. A test directory is a first-class property of
|
|
716
|
+
* every stack (`tests/` on FastAPI, `test/` on Rails, `src/test/java` on Spring,
|
|
717
|
+
* `Tests/` on SwiftPM, and Go keeps `_test.go` beside the source), so it belongs here
|
|
718
|
+
* rather than in prose.
|
|
719
|
+
*
|
|
720
|
+
* OPTIONAL, so every config written before this key existed keeps loading unchanged; an
|
|
721
|
+
* asset that needs it uses `{{paths.tests | default("...")}}`. All 13 shipped templates
|
|
722
|
+
* declare it, each with the convention it follows recorded at the site (G32 option 2),
|
|
723
|
+
* and `stack-template-conformance.test.ts` asserts that.
|
|
724
|
+
*/
|
|
725
|
+
tests: z2.string().optional(),
|
|
688
726
|
aliases: z2.record(z2.string(), z2.string()).default({ "@": "src" }),
|
|
689
727
|
monorepo_roots: z2.array(z2.string()).optional(),
|
|
690
728
|
routers: z2.string().optional(),
|
|
@@ -697,6 +735,13 @@ var init_config = __esm({
|
|
|
697
735
|
});
|
|
698
736
|
LanguageFrameworkEntrySchema = z2.object({
|
|
699
737
|
framework: z2.string().optional(),
|
|
738
|
+
// `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
|
|
739
|
+
// by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
|
|
740
|
+
// `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
|
|
741
|
+
// derives the index builders' candidate set from it, so it is typed here rather than
|
|
742
|
+
// read as an unknown: a consumer that has to shape-check its own SoT is one branch away
|
|
743
|
+
// from silently contributing `undefined` to a path predicate.
|
|
744
|
+
source_dirs: z2.array(z2.string()).optional(),
|
|
700
745
|
test_framework: z2.string().optional(),
|
|
701
746
|
test: z2.string().optional(),
|
|
702
747
|
runtime: z2.string().optional(),
|
|
@@ -787,14 +832,14 @@ var init_config = __esm({
|
|
|
787
832
|
project: z2.object({
|
|
788
833
|
name: z2.string().default("my-project"),
|
|
789
834
|
root: z2.string().default("auto")
|
|
790
|
-
}).
|
|
791
|
-
framework: FrameworkConfigSchema.
|
|
835
|
+
}).prefault({ name: "my-project", root: "auto" }),
|
|
836
|
+
framework: FrameworkConfigSchema.prefault({
|
|
792
837
|
type: "typescript",
|
|
793
838
|
router: "none",
|
|
794
839
|
orm: "none",
|
|
795
840
|
ui: "none"
|
|
796
841
|
}),
|
|
797
|
-
paths: PathsConfigSchema.
|
|
842
|
+
paths: PathsConfigSchema.prefault({ source: "src", aliases: { "@": "src" } }),
|
|
798
843
|
toolPrefix: z2.string().default("massu"),
|
|
799
844
|
dbAccessPattern: z2.string().optional(),
|
|
800
845
|
knownMismatches: z2.record(z2.string(), z2.record(z2.string(), z2.string())).optional(),
|
|
@@ -4028,7 +4073,24 @@ function writeHookContext(hookEventName, message) {
|
|
|
4028
4073
|
|
|
4029
4074
|
// src/hooks/incident-pipeline.ts
|
|
4030
4075
|
init_hook_failure_signal();
|
|
4076
|
+
|
|
4077
|
+
// src/hooks/lib/is-direct-invocation.ts
|
|
4078
|
+
import { pathToFileURL } from "url";
|
|
4079
|
+
function isDirectInvocation(moduleUrl) {
|
|
4080
|
+
const entry = process.argv[1];
|
|
4081
|
+
if (!entry) return false;
|
|
4082
|
+
try {
|
|
4083
|
+
return moduleUrl === pathToFileURL(entry).href;
|
|
4084
|
+
} catch {
|
|
4085
|
+
return false;
|
|
4086
|
+
}
|
|
4087
|
+
}
|
|
4088
|
+
|
|
4089
|
+
// src/hooks/incident-pipeline.ts
|
|
4031
4090
|
var HOOK_EVENT = "PostToolUse";
|
|
4091
|
+
function hasPreventionSection(content) {
|
|
4092
|
+
return /^##\s*(?:\d+[.)]?\s*)?(?:Prevention Rules|Prevention|Rules)\b/im.test(content);
|
|
4093
|
+
}
|
|
4032
4094
|
async function main() {
|
|
4033
4095
|
try {
|
|
4034
4096
|
const input = await readStdin();
|
|
@@ -4074,7 +4136,7 @@ async function main() {
|
|
|
4074
4136
|
process.exit(0);
|
|
4075
4137
|
return;
|
|
4076
4138
|
}
|
|
4077
|
-
const hasPrevention =
|
|
4139
|
+
const hasPrevention = hasPreventionSection(content);
|
|
4078
4140
|
if (config.autoLearning?.pipeline?.requirePreventionRule === false) {
|
|
4079
4141
|
process.exit(0);
|
|
4080
4142
|
return;
|
|
@@ -4155,4 +4217,9 @@ function readStdin() {
|
|
|
4155
4217
|
setTimeout(() => resolve6(data), 3e3);
|
|
4156
4218
|
});
|
|
4157
4219
|
}
|
|
4158
|
-
|
|
4220
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4221
|
+
main();
|
|
4222
|
+
}
|
|
4223
|
+
export {
|
|
4224
|
+
hasPreventionSection
|
|
4225
|
+
};
|
|
@@ -574,6 +574,15 @@ var init_memory_path = __esm({
|
|
|
574
574
|
}
|
|
575
575
|
});
|
|
576
576
|
|
|
577
|
+
// src/lib/corrections-md.ts
|
|
578
|
+
var CORRECTIONS_FILENAME;
|
|
579
|
+
var init_corrections_md = __esm({
|
|
580
|
+
"src/lib/corrections-md.ts"() {
|
|
581
|
+
"use strict";
|
|
582
|
+
CORRECTIONS_FILENAME = "corrections.md";
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
|
|
577
586
|
// src/config-memory-schema.ts
|
|
578
587
|
import { z } from "zod";
|
|
579
588
|
var MemoryConfigSchema;
|
|
@@ -607,7 +616,7 @@ var init_config_memory_schema = __esm({
|
|
|
607
616
|
message: "memory.recall.embedEndpoint must be an http(s) URL"
|
|
608
617
|
}).optional(),
|
|
609
618
|
embedModel: z.string().min(1).optional()
|
|
610
|
-
}).
|
|
619
|
+
}).prefault({}),
|
|
611
620
|
// --- Contradiction / supersede gate (plan-living-memory-slice-2-temporal-model, P5-001) ---
|
|
612
621
|
// When a new high-value memory (decision/correction) is written, find
|
|
613
622
|
// semantically-related existing records and, if the new one contradicts an
|
|
@@ -636,7 +645,7 @@ var init_config_memory_schema = __esm({
|
|
|
636
645
|
annotateSuperseded: z.boolean().default(false),
|
|
637
646
|
// Time budget (ms) for the contradiction check; exceeded → fail-open (ADD).
|
|
638
647
|
budgetMs: z.number().int().positive().default(800)
|
|
639
|
-
}).
|
|
648
|
+
}).prefault({}),
|
|
640
649
|
// --- Background consolidation, the "sleep-time" pass
|
|
641
650
|
// (plan-living-memory-slice-3-consolidation) ---
|
|
642
651
|
// Keeps memory sharp over years: dedupes, distills dying sessions into
|
|
@@ -682,7 +691,7 @@ var init_config_memory_schema = __esm({
|
|
|
682
691
|
// Surface optional upgrades (e.g. "a local model was detected") in chat.
|
|
683
692
|
suggestUpgrades: z.boolean().default(true),
|
|
684
693
|
suggestIntervalDays: z.number().int().positive().default(30)
|
|
685
|
-
}).
|
|
694
|
+
}).prefault({}),
|
|
686
695
|
// A-20 (Slice 4) — memory FILES: the mirror, and the one switch that decides whether
|
|
687
696
|
// Massu may ever WRITE into the user's memory directory.
|
|
688
697
|
//
|
|
@@ -707,7 +716,7 @@ var init_config_memory_schema = __esm({
|
|
|
707
716
|
// turn of EVERY session, so an unbounded index is a permanent context tax — and the
|
|
708
717
|
// per-session cap bounds only the RATE, never the total.
|
|
709
718
|
indexMaxLines: z.number().int().min(1).default(50)
|
|
710
|
-
}).
|
|
719
|
+
}).prefault({}),
|
|
711
720
|
// --- Cross-repo memory surfacing (plan-living-memory-slice-5-cross-repo-surfacing) ---
|
|
712
721
|
// A decision made in one of your repos can surface in another — opt-in per
|
|
713
722
|
// decision AND opt-in per repo, signed, verified, and materialized ONLY on
|
|
@@ -732,8 +741,8 @@ var init_config_memory_schema = __esm({
|
|
|
732
741
|
enabled: z.boolean().default(true),
|
|
733
742
|
maxCrossRepoItems: z.number().int().min(0).default(1),
|
|
734
743
|
minScore: z.number().optional()
|
|
735
|
-
}).
|
|
736
|
-
}).
|
|
744
|
+
}).prefault({})
|
|
745
|
+
}).prefault({})
|
|
737
746
|
}).optional();
|
|
738
747
|
}
|
|
739
748
|
});
|
|
@@ -913,13 +922,19 @@ function getResolvedPaths() {
|
|
|
913
922
|
settingsLocalPath: resolve2(root, claudeDirName, "settings.local.json")
|
|
914
923
|
};
|
|
915
924
|
}
|
|
916
|
-
var DomainConfigSchema, PatternRuleConfigSchema, CostModelSchema, AnalyticsConfigSchema, CustomPatternSchema, GovernanceConfigSchema, SecurityPatternSchema, SecurityConfigSchema, TeamConfigSchema, RegressionConfigSchema, AutoLearningConfigSchema, CloudConfigSchema, ConventionsConfigSchema, PythonDomainConfigSchema, PythonConfigSchema, PathsConfigSchema, LanguageFrameworkEntrySchema, FrameworkConfigSchema, DetectedConfigSchema, VerificationEntrySchema, VerificationConfigSchema, CanonicalPathsSchema, VerificationTypesSchema, DetectionRuleEntrySchema, DetectionConfigSchema, WatchConfigSchema, AdapterLocalPathSchema, AdaptersConfigSchema, TelemetryConfigSchema, LSPConfigSchema, RawConfigSchema, _config, _resolvedApiKeySource, _projectRoot;
|
|
925
|
+
var DEFAULT_KNOWLEDGE_SOURCE_FILES, DomainConfigSchema, PatternRuleConfigSchema, CostModelSchema, AnalyticsConfigSchema, CustomPatternSchema, GovernanceConfigSchema, SecurityPatternSchema, SecurityConfigSchema, TeamConfigSchema, RegressionConfigSchema, AutoLearningConfigSchema, CloudConfigSchema, ConventionsConfigSchema, PythonDomainConfigSchema, PythonConfigSchema, PathsConfigSchema, LanguageFrameworkEntrySchema, FrameworkConfigSchema, DetectedConfigSchema, VerificationEntrySchema, VerificationConfigSchema, CanonicalPathsSchema, VerificationTypesSchema, DetectionRuleEntrySchema, DetectionConfigSchema, WatchConfigSchema, AdapterLocalPathSchema, AdaptersConfigSchema, TelemetryConfigSchema, LSPConfigSchema, RawConfigSchema, _config, _resolvedApiKeySource, _projectRoot;
|
|
917
926
|
var init_config = __esm({
|
|
918
927
|
"src/config.ts"() {
|
|
919
928
|
"use strict";
|
|
920
929
|
init_memory_path();
|
|
930
|
+
init_corrections_md();
|
|
921
931
|
init_credentials();
|
|
922
932
|
init_config_memory_schema();
|
|
933
|
+
DEFAULT_KNOWLEDGE_SOURCE_FILES = [
|
|
934
|
+
"CLAUDE.md",
|
|
935
|
+
"MEMORY.md",
|
|
936
|
+
CORRECTIONS_FILENAME
|
|
937
|
+
];
|
|
923
938
|
DomainConfigSchema = z2.object({
|
|
924
939
|
name: z2.string().default("Unknown"),
|
|
925
940
|
routers: z2.array(z2.string()).default([]),
|
|
@@ -1048,34 +1063,40 @@ var init_config = __esm({
|
|
|
1048
1063
|
fixDetection: z2.object({
|
|
1049
1064
|
enabled: z2.boolean().default(true),
|
|
1050
1065
|
lookbackDays: z2.number().default(7),
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1066
|
+
// ⛔ NO DEFAULT LIST HERE, DELIBERATELY — the heuristics are the SSOT.
|
|
1067
|
+
//
|
|
1068
|
+
// This carried a hand-typed copy of all eight signal names while
|
|
1069
|
+
// `fix-detector.ts` already read `config…signals ?? FIX_HEURISTICS.map(h => h.name)`.
|
|
1070
|
+
// Because zod ALWAYS materialised the default, that fallback — the correct expression
|
|
1071
|
+
// — was unreachable, and the duplicate was the only thing in effect. Two authoring
|
|
1072
|
+
// sites for one vocabulary, and the drift is SILENT: a name listed here that no longer
|
|
1073
|
+
// exists simply never matches `enabledSignals.has(...)`, so a retired heuristic lingers
|
|
1074
|
+
// as a dead entry with no error. Retiring `method_name_correction` would have landed at
|
|
1075
|
+
// one site of two (CR-74).
|
|
1076
|
+
//
|
|
1077
|
+
// Optional, so an ABSENT value reaches the `??` and the heuristic list defines itself
|
|
1078
|
+
// (Rule 25). An explicit list in massu.config.yaml still overrides, which is the only
|
|
1079
|
+
// behaviour anyone actually configured — measured: `fix-detector.ts:267` is the sole
|
|
1080
|
+
// consumer and no config file in the repo sets it.
|
|
1081
|
+
signals: z2.array(z2.string()).optional()
|
|
1082
|
+
}).prefault({}),
|
|
1062
1083
|
failureClassification: z2.object({
|
|
1063
1084
|
enabled: z2.boolean().default(true),
|
|
1064
1085
|
thresholds: z2.object({
|
|
1065
1086
|
known: z2.number().default(5),
|
|
1066
1087
|
similar: z2.number().default(3)
|
|
1067
|
-
}).
|
|
1088
|
+
}).prefault({}),
|
|
1068
1089
|
scoring: z2.object({
|
|
1069
1090
|
diffPatternWeight: z2.number().default(3),
|
|
1070
1091
|
filePatternWeight: z2.number().default(2),
|
|
1071
1092
|
promptKeywordWeight: z2.number().default(2)
|
|
1072
|
-
}).
|
|
1073
|
-
}).
|
|
1093
|
+
}).prefault({})
|
|
1094
|
+
}).prefault({}),
|
|
1074
1095
|
pipeline: z2.object({
|
|
1075
1096
|
requireIncidentReport: z2.boolean().default(true),
|
|
1076
1097
|
requirePreventionRule: z2.boolean().default(true),
|
|
1077
1098
|
requireEnforcement: z2.boolean().default(true)
|
|
1078
|
-
}).
|
|
1099
|
+
}).prefault({}),
|
|
1079
1100
|
// plan-v0.2-interactive-rule-approval P-D-008 / P-D-009: project-configured
|
|
1080
1101
|
// custom destinations for the rule-candidate funnel. The classifier matches
|
|
1081
1102
|
// a candidate to one of these entries when none of the framework
|
|
@@ -1108,7 +1129,7 @@ var init_config = __esm({
|
|
|
1108
1129
|
memory: z2.boolean().default(true),
|
|
1109
1130
|
analytics: z2.boolean().default(true),
|
|
1110
1131
|
audit: z2.boolean().default(true)
|
|
1111
|
-
}).
|
|
1132
|
+
}).prefault({ memory: true, analytics: true, audit: true })
|
|
1112
1133
|
}).optional();
|
|
1113
1134
|
ConventionsConfigSchema = z2.object({
|
|
1114
1135
|
claudeDirName: z2.string().default(".claude").refine(
|
|
@@ -1139,7 +1160,7 @@ var init_config = __esm({
|
|
|
1139
1160
|
"session-state",
|
|
1140
1161
|
"agents"
|
|
1141
1162
|
]),
|
|
1142
|
-
knowledgeSourceFiles: z2.array(z2.string()).default([
|
|
1163
|
+
knowledgeSourceFiles: z2.array(z2.string()).default([...DEFAULT_KNOWLEDGE_SOURCE_FILES]),
|
|
1143
1164
|
excludePatterns: z2.array(z2.string()).default(["/ARCHIVE/", "/SESSION-HISTORY/"])
|
|
1144
1165
|
}).optional();
|
|
1145
1166
|
PythonDomainConfigSchema = z2.object({
|
|
@@ -1155,6 +1176,23 @@ var init_config = __esm({
|
|
|
1155
1176
|
}).optional();
|
|
1156
1177
|
PathsConfigSchema = z2.object({
|
|
1157
1178
|
source: z2.string().default("src"),
|
|
1179
|
+
/**
|
|
1180
|
+
* Where this stack's tests live, relative to the project root.
|
|
1181
|
+
*
|
|
1182
|
+
* Added 2026-09-20 for P4.3 of docs/plans/2026-09-20-stack-conformant-asset-rendering.md.
|
|
1183
|
+
* ~25 shipped assets told every customer their tests belong in
|
|
1184
|
+
* `packages/core/src/__tests__/` — massu's OWN layout — and no vocabulary could express
|
|
1185
|
+
* the alternative because none existed. A test directory is a first-class property of
|
|
1186
|
+
* every stack (`tests/` on FastAPI, `test/` on Rails, `src/test/java` on Spring,
|
|
1187
|
+
* `Tests/` on SwiftPM, and Go keeps `_test.go` beside the source), so it belongs here
|
|
1188
|
+
* rather than in prose.
|
|
1189
|
+
*
|
|
1190
|
+
* OPTIONAL, so every config written before this key existed keeps loading unchanged; an
|
|
1191
|
+
* asset that needs it uses `{{paths.tests | default("...")}}`. All 13 shipped templates
|
|
1192
|
+
* declare it, each with the convention it follows recorded at the site (G32 option 2),
|
|
1193
|
+
* and `stack-template-conformance.test.ts` asserts that.
|
|
1194
|
+
*/
|
|
1195
|
+
tests: z2.string().optional(),
|
|
1158
1196
|
aliases: z2.record(z2.string(), z2.string()).default({ "@": "src" }),
|
|
1159
1197
|
monorepo_roots: z2.array(z2.string()).optional(),
|
|
1160
1198
|
routers: z2.string().optional(),
|
|
@@ -1167,6 +1205,13 @@ var init_config = __esm({
|
|
|
1167
1205
|
});
|
|
1168
1206
|
LanguageFrameworkEntrySchema = z2.object({
|
|
1169
1207
|
framework: z2.string().optional(),
|
|
1208
|
+
// `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
|
|
1209
|
+
// by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
|
|
1210
|
+
// `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
|
|
1211
|
+
// derives the index builders' candidate set from it, so it is typed here rather than
|
|
1212
|
+
// read as an unknown: a consumer that has to shape-check its own SoT is one branch away
|
|
1213
|
+
// from silently contributing `undefined` to a path predicate.
|
|
1214
|
+
source_dirs: z2.array(z2.string()).optional(),
|
|
1170
1215
|
test_framework: z2.string().optional(),
|
|
1171
1216
|
test: z2.string().optional(),
|
|
1172
1217
|
runtime: z2.string().optional(),
|
|
@@ -1257,14 +1302,14 @@ var init_config = __esm({
|
|
|
1257
1302
|
project: z2.object({
|
|
1258
1303
|
name: z2.string().default("my-project"),
|
|
1259
1304
|
root: z2.string().default("auto")
|
|
1260
|
-
}).
|
|
1261
|
-
framework: FrameworkConfigSchema.
|
|
1305
|
+
}).prefault({ name: "my-project", root: "auto" }),
|
|
1306
|
+
framework: FrameworkConfigSchema.prefault({
|
|
1262
1307
|
type: "typescript",
|
|
1263
1308
|
router: "none",
|
|
1264
1309
|
orm: "none",
|
|
1265
1310
|
ui: "none"
|
|
1266
1311
|
}),
|
|
1267
|
-
paths: PathsConfigSchema.
|
|
1312
|
+
paths: PathsConfigSchema.prefault({ source: "src", aliases: { "@": "src" } }),
|
|
1268
1313
|
toolPrefix: z2.string().default("massu"),
|
|
1269
1314
|
dbAccessPattern: z2.string().optional(),
|
|
1270
1315
|
knownMismatches: z2.record(z2.string(), z2.record(z2.string(), z2.string())).optional(),
|
|
@@ -4022,6 +4067,20 @@ function writeHookContext(hookEventName, message) {
|
|
|
4022
4067
|
|
|
4023
4068
|
// src/hooks/intent-suggester.ts
|
|
4024
4069
|
init_hook_failure_signal();
|
|
4070
|
+
|
|
4071
|
+
// src/hooks/lib/is-direct-invocation.ts
|
|
4072
|
+
import { pathToFileURL } from "url";
|
|
4073
|
+
function isDirectInvocation(moduleUrl) {
|
|
4074
|
+
const entry = process.argv[1];
|
|
4075
|
+
if (!entry) return false;
|
|
4076
|
+
try {
|
|
4077
|
+
return moduleUrl === pathToFileURL(entry).href;
|
|
4078
|
+
} catch {
|
|
4079
|
+
return false;
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
|
|
4083
|
+
// src/hooks/intent-suggester.ts
|
|
4025
4084
|
var HOOK_EVENT = "UserPromptSubmit";
|
|
4026
4085
|
var COMMAND_MAPPINGS = [
|
|
4027
4086
|
{
|
|
@@ -4117,4 +4176,6 @@ function readStdin() {
|
|
|
4117
4176
|
setTimeout(() => resolve5(data), 3e3);
|
|
4118
4177
|
});
|
|
4119
4178
|
}
|
|
4120
|
-
|
|
4179
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4180
|
+
main();
|
|
4181
|
+
}
|