@massu/core 2.5.2 → 2.5.4
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 +93 -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 +1265 -876
- package/dist/hooks/auto-learning-pipeline.js +517 -56
- package/dist/hooks/classify-failure.js +495 -47
- package/dist/hooks/cost-tracker.js +65 -27
- package/dist/hooks/fix-detector.js +496 -47
- package/dist/hooks/incident-pipeline.js +72 -28
- package/dist/hooks/intent-suggester.js +65 -27
- package/dist/hooks/memory-recall.js +65 -27
- package/dist/hooks/post-edit-context.js +65 -27
- package/dist/hooks/post-tool-use.js +70 -29
- package/dist/hooks/pre-compact.js +65 -27
- package/dist/hooks/pre-delete-check.js +65 -27
- package/dist/hooks/pre-tool-use-gate.js +193 -37
- package/dist/hooks/quality-event.js +65 -27
- package/dist/hooks/rule-enforcement-pipeline.js +65 -27
- package/dist/hooks/security-gate.js +197 -38
- package/dist/hooks/session-end.js +68 -27
- package/dist/hooks/session-start.js +116 -61
- package/dist/hooks/user-prompt.js +65 -27
- package/docs/SECURITY.md +1 -1
- 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
|
@@ -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(),
|
|
@@ -1264,14 +1302,14 @@ var init_config = __esm({
|
|
|
1264
1302
|
project: z2.object({
|
|
1265
1303
|
name: z2.string().default("my-project"),
|
|
1266
1304
|
root: z2.string().default("auto")
|
|
1267
|
-
}).
|
|
1268
|
-
framework: FrameworkConfigSchema.
|
|
1305
|
+
}).prefault({ name: "my-project", root: "auto" }),
|
|
1306
|
+
framework: FrameworkConfigSchema.prefault({
|
|
1269
1307
|
type: "typescript",
|
|
1270
1308
|
router: "none",
|
|
1271
1309
|
orm: "none",
|
|
1272
1310
|
ui: "none"
|
|
1273
1311
|
}),
|
|
1274
|
-
paths: PathsConfigSchema.
|
|
1312
|
+
paths: PathsConfigSchema.prefault({ source: "src", aliases: { "@": "src" } }),
|
|
1275
1313
|
toolPrefix: z2.string().default("massu"),
|
|
1276
1314
|
dbAccessPattern: z2.string().optional(),
|
|
1277
1315
|
knownMismatches: z2.record(z2.string(), z2.record(z2.string(), z2.string())).optional(),
|
|
@@ -580,6 +580,15 @@ var init_memory_path = __esm({
|
|
|
580
580
|
}
|
|
581
581
|
});
|
|
582
582
|
|
|
583
|
+
// src/lib/corrections-md.ts
|
|
584
|
+
var CORRECTIONS_FILENAME;
|
|
585
|
+
var init_corrections_md = __esm({
|
|
586
|
+
"src/lib/corrections-md.ts"() {
|
|
587
|
+
"use strict";
|
|
588
|
+
CORRECTIONS_FILENAME = "corrections.md";
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
|
|
583
592
|
// src/config-memory-schema.ts
|
|
584
593
|
import { z } from "zod";
|
|
585
594
|
var MemoryConfigSchema;
|
|
@@ -613,7 +622,7 @@ var init_config_memory_schema = __esm({
|
|
|
613
622
|
message: "memory.recall.embedEndpoint must be an http(s) URL"
|
|
614
623
|
}).optional(),
|
|
615
624
|
embedModel: z.string().min(1).optional()
|
|
616
|
-
}).
|
|
625
|
+
}).prefault({}),
|
|
617
626
|
// --- Contradiction / supersede gate (plan-living-memory-slice-2-temporal-model, P5-001) ---
|
|
618
627
|
// When a new high-value memory (decision/correction) is written, find
|
|
619
628
|
// semantically-related existing records and, if the new one contradicts an
|
|
@@ -642,7 +651,7 @@ var init_config_memory_schema = __esm({
|
|
|
642
651
|
annotateSuperseded: z.boolean().default(false),
|
|
643
652
|
// Time budget (ms) for the contradiction check; exceeded → fail-open (ADD).
|
|
644
653
|
budgetMs: z.number().int().positive().default(800)
|
|
645
|
-
}).
|
|
654
|
+
}).prefault({}),
|
|
646
655
|
// --- Background consolidation, the "sleep-time" pass
|
|
647
656
|
// (plan-living-memory-slice-3-consolidation) ---
|
|
648
657
|
// Keeps memory sharp over years: dedupes, distills dying sessions into
|
|
@@ -688,7 +697,7 @@ var init_config_memory_schema = __esm({
|
|
|
688
697
|
// Surface optional upgrades (e.g. "a local model was detected") in chat.
|
|
689
698
|
suggestUpgrades: z.boolean().default(true),
|
|
690
699
|
suggestIntervalDays: z.number().int().positive().default(30)
|
|
691
|
-
}).
|
|
700
|
+
}).prefault({}),
|
|
692
701
|
// A-20 (Slice 4) — memory FILES: the mirror, and the one switch that decides whether
|
|
693
702
|
// Massu may ever WRITE into the user's memory directory.
|
|
694
703
|
//
|
|
@@ -713,7 +722,7 @@ var init_config_memory_schema = __esm({
|
|
|
713
722
|
// turn of EVERY session, so an unbounded index is a permanent context tax — and the
|
|
714
723
|
// per-session cap bounds only the RATE, never the total.
|
|
715
724
|
indexMaxLines: z.number().int().min(1).default(50)
|
|
716
|
-
}).
|
|
725
|
+
}).prefault({}),
|
|
717
726
|
// --- Cross-repo memory surfacing (plan-living-memory-slice-5-cross-repo-surfacing) ---
|
|
718
727
|
// A decision made in one of your repos can surface in another — opt-in per
|
|
719
728
|
// decision AND opt-in per repo, signed, verified, and materialized ONLY on
|
|
@@ -738,8 +747,8 @@ var init_config_memory_schema = __esm({
|
|
|
738
747
|
enabled: z.boolean().default(true),
|
|
739
748
|
maxCrossRepoItems: z.number().int().min(0).default(1),
|
|
740
749
|
minScore: z.number().optional()
|
|
741
|
-
}).
|
|
742
|
-
}).
|
|
750
|
+
}).prefault({})
|
|
751
|
+
}).prefault({})
|
|
743
752
|
}).optional();
|
|
744
753
|
}
|
|
745
754
|
});
|
|
@@ -919,13 +928,19 @@ function getResolvedPaths() {
|
|
|
919
928
|
settingsLocalPath: resolve2(root, claudeDirName, "settings.local.json")
|
|
920
929
|
};
|
|
921
930
|
}
|
|
922
|
-
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;
|
|
931
|
+
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;
|
|
923
932
|
var init_config = __esm({
|
|
924
933
|
"src/config.ts"() {
|
|
925
934
|
"use strict";
|
|
926
935
|
init_memory_path();
|
|
936
|
+
init_corrections_md();
|
|
927
937
|
init_credentials();
|
|
928
938
|
init_config_memory_schema();
|
|
939
|
+
DEFAULT_KNOWLEDGE_SOURCE_FILES = [
|
|
940
|
+
"CLAUDE.md",
|
|
941
|
+
"MEMORY.md",
|
|
942
|
+
CORRECTIONS_FILENAME
|
|
943
|
+
];
|
|
929
944
|
DomainConfigSchema = z2.object({
|
|
930
945
|
name: z2.string().default("Unknown"),
|
|
931
946
|
routers: z2.array(z2.string()).default([]),
|
|
@@ -1054,34 +1069,40 @@ var init_config = __esm({
|
|
|
1054
1069
|
fixDetection: z2.object({
|
|
1055
1070
|
enabled: z2.boolean().default(true),
|
|
1056
1071
|
lookbackDays: z2.number().default(7),
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1072
|
+
// ⛔ NO DEFAULT LIST HERE, DELIBERATELY — the heuristics are the SSOT.
|
|
1073
|
+
//
|
|
1074
|
+
// This carried a hand-typed copy of all eight signal names while
|
|
1075
|
+
// `fix-detector.ts` already read `config…signals ?? FIX_HEURISTICS.map(h => h.name)`.
|
|
1076
|
+
// Because zod ALWAYS materialised the default, that fallback — the correct expression
|
|
1077
|
+
// — was unreachable, and the duplicate was the only thing in effect. Two authoring
|
|
1078
|
+
// sites for one vocabulary, and the drift is SILENT: a name listed here that no longer
|
|
1079
|
+
// exists simply never matches `enabledSignals.has(...)`, so a retired heuristic lingers
|
|
1080
|
+
// as a dead entry with no error. Retiring `method_name_correction` would have landed at
|
|
1081
|
+
// one site of two (CR-74).
|
|
1082
|
+
//
|
|
1083
|
+
// Optional, so an ABSENT value reaches the `??` and the heuristic list defines itself
|
|
1084
|
+
// (Rule 25). An explicit list in massu.config.yaml still overrides, which is the only
|
|
1085
|
+
// behaviour anyone actually configured — measured: `fix-detector.ts:267` is the sole
|
|
1086
|
+
// consumer and no config file in the repo sets it.
|
|
1087
|
+
signals: z2.array(z2.string()).optional()
|
|
1088
|
+
}).prefault({}),
|
|
1068
1089
|
failureClassification: z2.object({
|
|
1069
1090
|
enabled: z2.boolean().default(true),
|
|
1070
1091
|
thresholds: z2.object({
|
|
1071
1092
|
known: z2.number().default(5),
|
|
1072
1093
|
similar: z2.number().default(3)
|
|
1073
|
-
}).
|
|
1094
|
+
}).prefault({}),
|
|
1074
1095
|
scoring: z2.object({
|
|
1075
1096
|
diffPatternWeight: z2.number().default(3),
|
|
1076
1097
|
filePatternWeight: z2.number().default(2),
|
|
1077
1098
|
promptKeywordWeight: z2.number().default(2)
|
|
1078
|
-
}).
|
|
1079
|
-
}).
|
|
1099
|
+
}).prefault({})
|
|
1100
|
+
}).prefault({}),
|
|
1080
1101
|
pipeline: z2.object({
|
|
1081
1102
|
requireIncidentReport: z2.boolean().default(true),
|
|
1082
1103
|
requirePreventionRule: z2.boolean().default(true),
|
|
1083
1104
|
requireEnforcement: z2.boolean().default(true)
|
|
1084
|
-
}).
|
|
1105
|
+
}).prefault({}),
|
|
1085
1106
|
// plan-v0.2-interactive-rule-approval P-D-008 / P-D-009: project-configured
|
|
1086
1107
|
// custom destinations for the rule-candidate funnel. The classifier matches
|
|
1087
1108
|
// a candidate to one of these entries when none of the framework
|
|
@@ -1114,7 +1135,7 @@ var init_config = __esm({
|
|
|
1114
1135
|
memory: z2.boolean().default(true),
|
|
1115
1136
|
analytics: z2.boolean().default(true),
|
|
1116
1137
|
audit: z2.boolean().default(true)
|
|
1117
|
-
}).
|
|
1138
|
+
}).prefault({ memory: true, analytics: true, audit: true })
|
|
1118
1139
|
}).optional();
|
|
1119
1140
|
ConventionsConfigSchema = z2.object({
|
|
1120
1141
|
claudeDirName: z2.string().default(".claude").refine(
|
|
@@ -1145,7 +1166,7 @@ var init_config = __esm({
|
|
|
1145
1166
|
"session-state",
|
|
1146
1167
|
"agents"
|
|
1147
1168
|
]),
|
|
1148
|
-
knowledgeSourceFiles: z2.array(z2.string()).default([
|
|
1169
|
+
knowledgeSourceFiles: z2.array(z2.string()).default([...DEFAULT_KNOWLEDGE_SOURCE_FILES]),
|
|
1149
1170
|
excludePatterns: z2.array(z2.string()).default(["/ARCHIVE/", "/SESSION-HISTORY/"])
|
|
1150
1171
|
}).optional();
|
|
1151
1172
|
PythonDomainConfigSchema = z2.object({
|
|
@@ -1161,6 +1182,23 @@ var init_config = __esm({
|
|
|
1161
1182
|
}).optional();
|
|
1162
1183
|
PathsConfigSchema = z2.object({
|
|
1163
1184
|
source: z2.string().default("src"),
|
|
1185
|
+
/**
|
|
1186
|
+
* Where this stack's tests live, relative to the project root.
|
|
1187
|
+
*
|
|
1188
|
+
* Added 2026-09-20 for P4.3 of docs/plans/2026-09-20-stack-conformant-asset-rendering.md.
|
|
1189
|
+
* ~25 shipped assets told every customer their tests belong in
|
|
1190
|
+
* `packages/core/src/__tests__/` — massu's OWN layout — and no vocabulary could express
|
|
1191
|
+
* the alternative because none existed. A test directory is a first-class property of
|
|
1192
|
+
* every stack (`tests/` on FastAPI, `test/` on Rails, `src/test/java` on Spring,
|
|
1193
|
+
* `Tests/` on SwiftPM, and Go keeps `_test.go` beside the source), so it belongs here
|
|
1194
|
+
* rather than in prose.
|
|
1195
|
+
*
|
|
1196
|
+
* OPTIONAL, so every config written before this key existed keeps loading unchanged; an
|
|
1197
|
+
* asset that needs it uses `{{paths.tests | default("...")}}`. All 13 shipped templates
|
|
1198
|
+
* declare it, each with the convention it follows recorded at the site (G32 option 2),
|
|
1199
|
+
* and `stack-template-conformance.test.ts` asserts that.
|
|
1200
|
+
*/
|
|
1201
|
+
tests: z2.string().optional(),
|
|
1164
1202
|
aliases: z2.record(z2.string(), z2.string()).default({ "@": "src" }),
|
|
1165
1203
|
monorepo_roots: z2.array(z2.string()).optional(),
|
|
1166
1204
|
routers: z2.string().optional(),
|
|
@@ -1270,14 +1308,14 @@ var init_config = __esm({
|
|
|
1270
1308
|
project: z2.object({
|
|
1271
1309
|
name: z2.string().default("my-project"),
|
|
1272
1310
|
root: z2.string().default("auto")
|
|
1273
|
-
}).
|
|
1274
|
-
framework: FrameworkConfigSchema.
|
|
1311
|
+
}).prefault({ name: "my-project", root: "auto" }),
|
|
1312
|
+
framework: FrameworkConfigSchema.prefault({
|
|
1275
1313
|
type: "typescript",
|
|
1276
1314
|
router: "none",
|
|
1277
1315
|
orm: "none",
|
|
1278
1316
|
ui: "none"
|
|
1279
1317
|
}),
|
|
1280
|
-
paths: PathsConfigSchema.
|
|
1318
|
+
paths: PathsConfigSchema.prefault({ source: "src", aliases: { "@": "src" } }),
|
|
1281
1319
|
toolPrefix: z2.string().default("massu"),
|
|
1282
1320
|
dbAccessPattern: z2.string().optional(),
|
|
1283
1321
|
knownMismatches: z2.record(z2.string(), z2.record(z2.string(), z2.string())).optional(),
|
|
@@ -4182,7 +4220,7 @@ function classifyToolCall(tc) {
|
|
|
4182
4220
|
}
|
|
4183
4221
|
case "Read": {
|
|
4184
4222
|
const filePath = tc.input.file_path ?? "unknown";
|
|
4185
|
-
const knowledgeSourceFiles = getConfig().conventions?.knowledgeSourceFiles ??
|
|
4223
|
+
const knowledgeSourceFiles = getConfig().conventions?.knowledgeSourceFiles ?? DEFAULT_KNOWLEDGE_SOURCE_FILES;
|
|
4186
4224
|
const plansDir = getResolvedPaths().plansDir;
|
|
4187
4225
|
if (filePath.includes(plansDir) || knowledgeSourceFiles.some((f) => filePath.includes(f))) {
|
|
4188
4226
|
const title = `Read: ${shortenPath(filePath)}`;
|
|
@@ -4323,6 +4361,9 @@ function detectPlanProgress(rawToolResponse) {
|
|
|
4323
4361
|
return results;
|
|
4324
4362
|
}
|
|
4325
4363
|
|
|
4364
|
+
// src/hooks/post-tool-use.ts
|
|
4365
|
+
init_config();
|
|
4366
|
+
|
|
4326
4367
|
// src/audit-trail.ts
|
|
4327
4368
|
init_config();
|
|
4328
4369
|
function logAuditEntry(db, entry) {
|
|
@@ -5341,7 +5382,7 @@ var _cachedConventions = null;
|
|
|
5341
5382
|
var _cachedConventionsPath = null;
|
|
5342
5383
|
var _cachedConventionsMtimeMs = 0;
|
|
5343
5384
|
var _conventionDefaults = {
|
|
5344
|
-
knowledgeSourceFiles: [
|
|
5385
|
+
knowledgeSourceFiles: [...DEFAULT_KNOWLEDGE_SOURCE_FILES],
|
|
5345
5386
|
claudeDirName: ".claude"
|
|
5346
5387
|
};
|
|
5347
5388
|
function readConventions(cwd) {
|
|
@@ -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(),
|
|
@@ -1264,14 +1302,14 @@ var init_config = __esm({
|
|
|
1264
1302
|
project: z2.object({
|
|
1265
1303
|
name: z2.string().default("my-project"),
|
|
1266
1304
|
root: z2.string().default("auto")
|
|
1267
|
-
}).
|
|
1268
|
-
framework: FrameworkConfigSchema.
|
|
1305
|
+
}).prefault({ name: "my-project", root: "auto" }),
|
|
1306
|
+
framework: FrameworkConfigSchema.prefault({
|
|
1269
1307
|
type: "typescript",
|
|
1270
1308
|
router: "none",
|
|
1271
1309
|
orm: "none",
|
|
1272
1310
|
ui: "none"
|
|
1273
1311
|
}),
|
|
1274
|
-
paths: PathsConfigSchema.
|
|
1312
|
+
paths: PathsConfigSchema.prefault({ source: "src", aliases: { "@": "src" } }),
|
|
1275
1313
|
toolPrefix: z2.string().default("massu"),
|
|
1276
1314
|
dbAccessPattern: z2.string().optional(),
|
|
1277
1315
|
knownMismatches: z2.record(z2.string(), z2.record(z2.string(), z2.string())).optional(),
|