mustflow 2.103.16 → 2.103.21

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.
Files changed (39) hide show
  1. package/README.md +2 -0
  2. package/dist/cli/commands/run/args.js +83 -0
  3. package/dist/cli/commands/run/execution.js +334 -0
  4. package/dist/cli/commands/run/preview.js +29 -0
  5. package/dist/cli/commands/run/profile.js +6 -0
  6. package/dist/cli/commands/run.js +19 -425
  7. package/dist/cli/commands/script-pack.js +1 -0
  8. package/dist/cli/commands/verify.js +15 -18
  9. package/dist/cli/i18n/en.js +27 -0
  10. package/dist/cli/i18n/es.js +27 -0
  11. package/dist/cli/i18n/fr.js +27 -0
  12. package/dist/cli/i18n/hi.js +27 -0
  13. package/dist/cli/i18n/ko.js +27 -0
  14. package/dist/cli/i18n/zh.js +27 -0
  15. package/dist/cli/lib/command-registry.js +92 -0
  16. package/dist/cli/lib/option-parser.js +26 -0
  17. package/dist/cli/lib/script-pack-registry.js +39 -0
  18. package/dist/cli/script-packs/code-module-boundary.js +210 -0
  19. package/dist/cli/script-packs/repo-env-contract.js +4 -17
  20. package/dist/cli/script-packs/repo-secret-risk-scan.js +4 -17
  21. package/dist/cli/script-packs/repo-security-pattern-scan.js +4 -17
  22. package/dist/core/module-boundary.js +523 -0
  23. package/dist/core/public-json-contracts.js +50 -0
  24. package/dist/core/script-pack-suggestions.js +5 -0
  25. package/package.json +1 -1
  26. package/schemas/README.md +12 -0
  27. package/schemas/check-report.schema.json +52 -0
  28. package/schemas/index-report.schema.json +103 -0
  29. package/schemas/module-boundary-report.schema.json +210 -0
  30. package/schemas/search-report.schema.json +102 -0
  31. package/schemas/status-report.schema.json +50 -0
  32. package/templates/default/i18n.toml +10 -4
  33. package/templates/default/locales/en/.mustflow/skills/INDEX.md +7 -1
  34. package/templates/default/locales/en/.mustflow/skills/database-migration-change/SKILL.md +16 -2
  35. package/templates/default/locales/en/.mustflow/skills/http-api-semantics-review/SKILL.md +286 -0
  36. package/templates/default/locales/en/.mustflow/skills/module-boundary-review/SKILL.md +12 -1
  37. package/templates/default/locales/en/.mustflow/skills/payment-integrity-review/SKILL.md +17 -10
  38. package/templates/default/locales/en/.mustflow/skills/routes.toml +6 -0
  39. package/templates/default/manifest.toml +8 -1
@@ -777,6 +777,7 @@ Lisez ces fichiers avant de travailler :
777
777
  "scriptPack.script.codeOutline.summary": "Scan TypeScript and JavaScript files for symbol headers and line ranges",
778
778
  "scriptPack.script.codeDependencyGraph.summary": "Trace relative TypeScript and JavaScript dependency graph edges",
779
779
  "scriptPack.script.codeImportCycle.summary": "Detect relative TypeScript and JavaScript import cycles with line evidence",
780
+ "scriptPack.script.codeModuleBoundary.summary": "Check configured module boundary import rules and shared budgets",
780
781
  "scriptPack.script.codeChangeImpact.summary": "Analyze changed files for impact, script-pack, and verification hints",
781
782
  "scriptPack.script.codeSymbolRead.summary": "Read a bounded source snippet by source anchor, symbol line, or explicit line range",
782
783
  "scriptPack.script.codeRouteOutline.summary": "Scan Hono, Elysia, Axum, and NestJS route methods, paths, handlers, and lifecycle chains",
@@ -978,6 +979,32 @@ Lisez ces fichiers avant de travailler :
978
979
  "importCycle.error.unknownAction": "Unknown import-cycle action: {action}",
979
980
  "importCycle.error.missingPath": "Provide at least one path to check",
980
981
  "importCycle.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
982
+ "moduleBoundary.help.summary": "Check configured module boundary rules against TypeScript and JavaScript import graph evidence.",
983
+ "moduleBoundary.help.option.config": "Module boundary TOML config path. Default: .mustflow/config/module-boundaries.toml",
984
+ "moduleBoundary.help.option.maxDepth": "Maximum dependency depth from target files. Default: 20",
985
+ "moduleBoundary.help.option.maxFiles": "Maximum number of source files to scan. Default: 1000",
986
+ "moduleBoundary.help.option.maxFileBytes": "Maximum bytes to read from each source file. Default: 262144",
987
+ "moduleBoundary.help.option.maxNodes": "Maximum number of graph nodes to inspect. Default: 300",
988
+ "moduleBoundary.help.option.maxEdges": "Maximum number of graph edges to inspect. Default: 800",
989
+ "moduleBoundary.help.option.maxCycles": "Maximum number of import cycles to report. Default: 50",
990
+ "moduleBoundary.help.option.maxSharedFiles": "Maximum number of shared-budget source files to count. Default: 1000",
991
+ "moduleBoundary.help.exit.ok": "No blocking module boundary findings were detected",
992
+ "moduleBoundary.help.exit.fail": "A module boundary rule, cycle, invalid input, unreadable path, or scan limit failed",
993
+ "moduleBoundary.title": "mustflow module boundary",
994
+ "moduleBoundary.label.config": "Config",
995
+ "moduleBoundary.label.targets": "Targets",
996
+ "moduleBoundary.label.edges": "Edges",
997
+ "moduleBoundary.label.rules": "Rules",
998
+ "moduleBoundary.label.findings": "Findings",
999
+ "moduleBoundary.label.truncated": "Truncated",
1000
+ "moduleBoundary.label.findingList": "Module boundary findings",
1001
+ "moduleBoundary.label.sharedMetrics": "Shared budget metrics",
1002
+ "moduleBoundary.label.issues": "Issues",
1003
+ "moduleBoundary.clean": "No module boundary findings were found.",
1004
+ "moduleBoundary.error.missingAction": "Specify a module-boundary action: check",
1005
+ "moduleBoundary.error.unknownAction": "Unknown module-boundary action: {action}",
1006
+ "moduleBoundary.error.missingPath": "Provide at least one path to check",
1007
+ "moduleBoundary.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
981
1008
  "changeImpact.help.summary": "Analyze git changes and return bounded file-impact, script-pack, and verification hints.",
982
1009
  "changeImpact.help.option.base": "Git base ref to compare from. Default: HEAD",
983
1010
  "changeImpact.help.option.head": "Git head ref to compare to. Omit to compare the base with the working tree.",
@@ -777,6 +777,7 @@ export const hiMessages = {
777
777
  "scriptPack.script.codeOutline.summary": "Scan TypeScript and JavaScript files for symbol headers and line ranges",
778
778
  "scriptPack.script.codeDependencyGraph.summary": "Trace relative TypeScript and JavaScript dependency graph edges",
779
779
  "scriptPack.script.codeImportCycle.summary": "Detect relative TypeScript and JavaScript import cycles with line evidence",
780
+ "scriptPack.script.codeModuleBoundary.summary": "Check configured module boundary import rules and shared budgets",
780
781
  "scriptPack.script.codeChangeImpact.summary": "Analyze changed files for impact, script-pack, and verification hints",
781
782
  "scriptPack.script.codeSymbolRead.summary": "Read a bounded source snippet by source anchor, symbol line, or explicit line range",
782
783
  "scriptPack.script.codeRouteOutline.summary": "Scan Hono, Elysia, Axum, and NestJS route methods, paths, handlers, and lifecycle chains",
@@ -978,6 +979,32 @@ export const hiMessages = {
978
979
  "importCycle.error.unknownAction": "Unknown import-cycle action: {action}",
979
980
  "importCycle.error.missingPath": "Provide at least one path to check",
980
981
  "importCycle.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
982
+ "moduleBoundary.help.summary": "Check configured module boundary rules against TypeScript and JavaScript import graph evidence.",
983
+ "moduleBoundary.help.option.config": "Module boundary TOML config path. Default: .mustflow/config/module-boundaries.toml",
984
+ "moduleBoundary.help.option.maxDepth": "Maximum dependency depth from target files. Default: 20",
985
+ "moduleBoundary.help.option.maxFiles": "Maximum number of source files to scan. Default: 1000",
986
+ "moduleBoundary.help.option.maxFileBytes": "Maximum bytes to read from each source file. Default: 262144",
987
+ "moduleBoundary.help.option.maxNodes": "Maximum number of graph nodes to inspect. Default: 300",
988
+ "moduleBoundary.help.option.maxEdges": "Maximum number of graph edges to inspect. Default: 800",
989
+ "moduleBoundary.help.option.maxCycles": "Maximum number of import cycles to report. Default: 50",
990
+ "moduleBoundary.help.option.maxSharedFiles": "Maximum number of shared-budget source files to count. Default: 1000",
991
+ "moduleBoundary.help.exit.ok": "No blocking module boundary findings were detected",
992
+ "moduleBoundary.help.exit.fail": "A module boundary rule, cycle, invalid input, unreadable path, or scan limit failed",
993
+ "moduleBoundary.title": "mustflow module boundary",
994
+ "moduleBoundary.label.config": "Config",
995
+ "moduleBoundary.label.targets": "Targets",
996
+ "moduleBoundary.label.edges": "Edges",
997
+ "moduleBoundary.label.rules": "Rules",
998
+ "moduleBoundary.label.findings": "Findings",
999
+ "moduleBoundary.label.truncated": "Truncated",
1000
+ "moduleBoundary.label.findingList": "Module boundary findings",
1001
+ "moduleBoundary.label.sharedMetrics": "Shared budget metrics",
1002
+ "moduleBoundary.label.issues": "Issues",
1003
+ "moduleBoundary.clean": "No module boundary findings were found.",
1004
+ "moduleBoundary.error.missingAction": "Specify a module-boundary action: check",
1005
+ "moduleBoundary.error.unknownAction": "Unknown module-boundary action: {action}",
1006
+ "moduleBoundary.error.missingPath": "Provide at least one path to check",
1007
+ "moduleBoundary.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
981
1008
  "changeImpact.help.summary": "Analyze git changes and return bounded file-impact, script-pack, and verification hints.",
982
1009
  "changeImpact.help.option.base": "Git base ref to compare from. Default: HEAD",
983
1010
  "changeImpact.help.option.head": "Git head ref to compare to. Omit to compare the base with the working tree.",
@@ -777,6 +777,7 @@ export const koMessages = {
777
777
  "scriptPack.script.codeOutline.summary": "TypeScript와 JavaScript 파일에서 symbol header와 라인 범위를 스캔합니다",
778
778
  "scriptPack.script.codeDependencyGraph.summary": "Trace relative TypeScript and JavaScript dependency graph edges",
779
779
  "scriptPack.script.codeImportCycle.summary": "Detect relative TypeScript and JavaScript import cycles with line evidence",
780
+ "scriptPack.script.codeModuleBoundary.summary": "Check configured module boundary import rules and shared budgets",
780
781
  "scriptPack.script.codeChangeImpact.summary": "Analyze changed files for impact, script-pack, and verification hints",
781
782
  "scriptPack.script.codeSymbolRead.summary": "source anchor, symbol 라인, 또는 명시 라인 범위로 제한된 소스 snippet을 읽습니다",
782
783
  "scriptPack.script.codeRouteOutline.summary": "Hono, Elysia, Axum, NestJS route method, path, handler, lifecycle chain을 스캔합니다",
@@ -978,6 +979,32 @@ export const koMessages = {
978
979
  "importCycle.error.unknownAction": "Unknown import-cycle action: {action}",
979
980
  "importCycle.error.missingPath": "Provide at least one path to check",
980
981
  "importCycle.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
982
+ "moduleBoundary.help.summary": "Check configured module boundary rules against TypeScript and JavaScript import graph evidence.",
983
+ "moduleBoundary.help.option.config": "Module boundary TOML config path. Default: .mustflow/config/module-boundaries.toml",
984
+ "moduleBoundary.help.option.maxDepth": "Maximum dependency depth from target files. Default: 20",
985
+ "moduleBoundary.help.option.maxFiles": "Maximum number of source files to scan. Default: 1000",
986
+ "moduleBoundary.help.option.maxFileBytes": "Maximum bytes to read from each source file. Default: 262144",
987
+ "moduleBoundary.help.option.maxNodes": "Maximum number of graph nodes to inspect. Default: 300",
988
+ "moduleBoundary.help.option.maxEdges": "Maximum number of graph edges to inspect. Default: 800",
989
+ "moduleBoundary.help.option.maxCycles": "Maximum number of import cycles to report. Default: 50",
990
+ "moduleBoundary.help.option.maxSharedFiles": "Maximum number of shared-budget source files to count. Default: 1000",
991
+ "moduleBoundary.help.exit.ok": "No blocking module boundary findings were detected",
992
+ "moduleBoundary.help.exit.fail": "A module boundary rule, cycle, invalid input, unreadable path, or scan limit failed",
993
+ "moduleBoundary.title": "mustflow module boundary",
994
+ "moduleBoundary.label.config": "Config",
995
+ "moduleBoundary.label.targets": "Targets",
996
+ "moduleBoundary.label.edges": "Edges",
997
+ "moduleBoundary.label.rules": "Rules",
998
+ "moduleBoundary.label.findings": "Findings",
999
+ "moduleBoundary.label.truncated": "Truncated",
1000
+ "moduleBoundary.label.findingList": "Module boundary findings",
1001
+ "moduleBoundary.label.sharedMetrics": "Shared budget metrics",
1002
+ "moduleBoundary.label.issues": "Issues",
1003
+ "moduleBoundary.clean": "No module boundary findings were found.",
1004
+ "moduleBoundary.error.missingAction": "Specify a module-boundary action: check",
1005
+ "moduleBoundary.error.unknownAction": "Unknown module-boundary action: {action}",
1006
+ "moduleBoundary.error.missingPath": "Provide at least one path to check",
1007
+ "moduleBoundary.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
981
1008
  "changeImpact.help.summary": "Analyze git changes and return bounded file-impact, script-pack, and verification hints.",
982
1009
  "changeImpact.help.option.base": "Git base ref to compare from. Default: HEAD",
983
1010
  "changeImpact.help.option.head": "Git head ref to compare to. Omit to compare the base with the working tree.",
@@ -777,6 +777,7 @@ export const zhMessages = {
777
777
  "scriptPack.script.codeOutline.summary": "Scan TypeScript and JavaScript files for symbol headers and line ranges",
778
778
  "scriptPack.script.codeDependencyGraph.summary": "Trace relative TypeScript and JavaScript dependency graph edges",
779
779
  "scriptPack.script.codeImportCycle.summary": "Detect relative TypeScript and JavaScript import cycles with line evidence",
780
+ "scriptPack.script.codeModuleBoundary.summary": "Check configured module boundary import rules and shared budgets",
780
781
  "scriptPack.script.codeChangeImpact.summary": "Analyze changed files for impact, script-pack, and verification hints",
781
782
  "scriptPack.script.codeSymbolRead.summary": "Read a bounded source snippet by source anchor, symbol line, or explicit line range",
782
783
  "scriptPack.script.codeRouteOutline.summary": "Scan Hono, Elysia, Axum, and NestJS route methods, paths, handlers, and lifecycle chains",
@@ -978,6 +979,32 @@ export const zhMessages = {
978
979
  "importCycle.error.unknownAction": "Unknown import-cycle action: {action}",
979
980
  "importCycle.error.missingPath": "Provide at least one path to check",
980
981
  "importCycle.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
982
+ "moduleBoundary.help.summary": "Check configured module boundary rules against TypeScript and JavaScript import graph evidence.",
983
+ "moduleBoundary.help.option.config": "Module boundary TOML config path. Default: .mustflow/config/module-boundaries.toml",
984
+ "moduleBoundary.help.option.maxDepth": "Maximum dependency depth from target files. Default: 20",
985
+ "moduleBoundary.help.option.maxFiles": "Maximum number of source files to scan. Default: 1000",
986
+ "moduleBoundary.help.option.maxFileBytes": "Maximum bytes to read from each source file. Default: 262144",
987
+ "moduleBoundary.help.option.maxNodes": "Maximum number of graph nodes to inspect. Default: 300",
988
+ "moduleBoundary.help.option.maxEdges": "Maximum number of graph edges to inspect. Default: 800",
989
+ "moduleBoundary.help.option.maxCycles": "Maximum number of import cycles to report. Default: 50",
990
+ "moduleBoundary.help.option.maxSharedFiles": "Maximum number of shared-budget source files to count. Default: 1000",
991
+ "moduleBoundary.help.exit.ok": "No blocking module boundary findings were detected",
992
+ "moduleBoundary.help.exit.fail": "A module boundary rule, cycle, invalid input, unreadable path, or scan limit failed",
993
+ "moduleBoundary.title": "mustflow module boundary",
994
+ "moduleBoundary.label.config": "Config",
995
+ "moduleBoundary.label.targets": "Targets",
996
+ "moduleBoundary.label.edges": "Edges",
997
+ "moduleBoundary.label.rules": "Rules",
998
+ "moduleBoundary.label.findings": "Findings",
999
+ "moduleBoundary.label.truncated": "Truncated",
1000
+ "moduleBoundary.label.findingList": "Module boundary findings",
1001
+ "moduleBoundary.label.sharedMetrics": "Shared budget metrics",
1002
+ "moduleBoundary.label.issues": "Issues",
1003
+ "moduleBoundary.clean": "No module boundary findings were found.",
1004
+ "moduleBoundary.error.missingAction": "Specify a module-boundary action: check",
1005
+ "moduleBoundary.error.unknownAction": "Unknown module-boundary action: {action}",
1006
+ "moduleBoundary.error.missingPath": "Provide at least one path to check",
1007
+ "moduleBoundary.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
981
1008
  "changeImpact.help.summary": "Analyze git changes and return bounded file-impact, script-pack, and verification hints.",
982
1009
  "changeImpact.help.option.base": "Git base ref to compare from. Default: HEAD",
983
1010
  "changeImpact.help.option.head": "Git head ref to compare to. Omit to compare the base with the working tree.",
@@ -1,200 +1,292 @@
1
+ const TEXT_OUTPUT = ['text'];
2
+ const TEXT_JSON_OUTPUT = ['text', 'json'];
3
+ const TEXT_JSONL_OUTPUT = ['text', 'json', 'jsonl'];
4
+ const TEXT_JSON_FILE_OUTPUT = ['text', 'json', 'file'];
5
+ const DEFAULT_EXIT_CODES = [0, 1];
6
+ function commandContract(outputModes, publicJsonSchemaIds = [], exitCodes = DEFAULT_EXIT_CODES) {
7
+ return {
8
+ outputModes,
9
+ exitCodes,
10
+ publicJsonSchemaIds,
11
+ };
12
+ }
1
13
  export const COMMAND_DEFINITIONS = [
2
14
  {
3
15
  id: 'api',
4
16
  usage: 'mf api',
5
17
  summaryKey: 'command.api.summary',
18
+ contract: commandContract(TEXT_JSONL_OUTPUT, [
19
+ 'workspace-summary',
20
+ 'command-catalog',
21
+ 'verification-plan',
22
+ 'latest-evidence',
23
+ 'diff-risk',
24
+ 'health',
25
+ 'locks',
26
+ 'api-serve-response',
27
+ ]),
6
28
  loadRunner: async () => (await import('../commands/api.js')).runApi,
7
29
  },
8
30
  {
9
31
  id: 'adapters',
10
32
  usage: 'mf adapters',
11
33
  summaryKey: 'command.adapters.summary',
34
+ contract: commandContract(TEXT_JSON_OUTPUT, ['adapter-compatibility-report']),
12
35
  loadRunner: async () => (await import('../commands/adapters.js')).runAdapters,
13
36
  },
14
37
  {
15
38
  id: 'init',
16
39
  usage: 'mf init',
17
40
  summaryKey: 'command.init.summary',
41
+ contract: commandContract(TEXT_OUTPUT),
18
42
  loadRunner: async () => (await import('../commands/init.js')).runInit,
19
43
  },
20
44
  {
21
45
  id: 'check',
22
46
  usage: 'mf check',
23
47
  summaryKey: 'command.check.summary',
48
+ contract: commandContract(TEXT_JSON_OUTPUT, ['check-report']),
24
49
  loadRunner: async () => (await import('../commands/check.js')).runCheck,
25
50
  },
26
51
  {
27
52
  id: 'classify',
28
53
  usage: 'mf classify',
29
54
  summaryKey: 'command.classify.summary',
55
+ contract: commandContract(TEXT_JSON_OUTPUT, ['classify-report']),
30
56
  loadRunner: async () => (await import('../commands/classify.js')).runClassify,
31
57
  },
32
58
  {
33
59
  id: 'contract-lint',
34
60
  usage: 'mf contract-lint',
35
61
  summaryKey: 'command.contractLint.summary',
62
+ contract: commandContract(TEXT_JSON_OUTPUT, ['contract-lint-report']),
36
63
  loadRunner: async () => (await import('../commands/contract-lint.js')).runContractLint,
37
64
  },
38
65
  {
39
66
  id: 'onboard',
40
67
  usage: 'mf onboard',
41
68
  summaryKey: 'command.onboard.summary',
69
+ contract: commandContract(TEXT_JSON_OUTPUT, ['onboard-commands-report']),
42
70
  loadRunner: async () => (await import('../commands/onboard.js')).runOnboard,
43
71
  },
44
72
  {
45
73
  id: 'next',
46
74
  usage: 'mf next',
47
75
  summaryKey: 'command.next.summary',
76
+ contract: commandContract(TEXT_JSON_OUTPUT, ['next-report']),
48
77
  loadRunner: async () => (await import('../commands/next.js')).runNext,
49
78
  },
50
79
  {
51
80
  id: 'evidence',
52
81
  usage: 'mf evidence',
53
82
  summaryKey: 'command.evidence.summary',
83
+ contract: commandContract(TEXT_JSON_OUTPUT, ['evidence-report']),
54
84
  loadRunner: async () => (await import('../commands/evidence.js')).runEvidence,
55
85
  },
56
86
  {
57
87
  id: 'workspace',
58
88
  usage: 'mf workspace',
59
89
  summaryKey: 'command.workspace.summary',
90
+ contract: commandContract(TEXT_JSON_OUTPUT, [
91
+ 'workspace-status',
92
+ 'workspace-command-catalog',
93
+ 'workspace-verification-plan',
94
+ ]),
60
95
  loadRunner: async () => (await import('../commands/workspace.js')).runWorkspace,
61
96
  },
62
97
  {
63
98
  id: 'status',
64
99
  usage: 'mf status',
65
100
  summaryKey: 'command.status.summary',
101
+ contract: commandContract(TEXT_JSON_OUTPUT, ['status-report']),
66
102
  loadRunner: async () => (await import('../commands/status.js')).runStatus,
67
103
  },
68
104
  {
69
105
  id: 'update',
70
106
  usage: 'mf update',
71
107
  summaryKey: 'command.update.summary',
108
+ contract: commandContract(TEXT_JSON_OUTPUT),
72
109
  loadRunner: async () => (await import('../commands/update.js')).runUpdate,
73
110
  },
74
111
  {
75
112
  id: 'upgrade',
76
113
  usage: 'mf upgrade',
77
114
  summaryKey: 'command.upgrade.summary',
115
+ contract: commandContract(TEXT_OUTPUT),
78
116
  loadRunner: async () => (await import('../commands/upgrade.js')).runUpgrade,
79
117
  },
80
118
  {
81
119
  id: 'map',
82
120
  usage: 'mf map',
83
121
  summaryKey: 'command.map.summary',
122
+ contract: commandContract(TEXT_OUTPUT),
84
123
  loadRunner: async () => (await import('../commands/map.js')).runMap,
85
124
  },
86
125
  {
87
126
  id: 'line-endings',
88
127
  usage: 'mf line-endings',
89
128
  summaryKey: 'command.lineEndings.summary',
129
+ contract: commandContract(TEXT_JSON_OUTPUT, ['line-endings-report']),
90
130
  loadRunner: async () => (await import('../commands/line-endings.js')).runLineEndings,
91
131
  },
92
132
  {
93
133
  id: 'quality',
94
134
  usage: 'mf quality',
95
135
  summaryKey: 'command.quality.summary',
136
+ contract: commandContract(TEXT_JSON_OUTPUT, ['quality-gaming-report']),
96
137
  loadRunner: async () => (await import('../commands/quality.js')).runQuality,
97
138
  },
98
139
  {
99
140
  id: 'script-pack',
100
141
  usage: 'mf script-pack',
101
142
  summaryKey: 'command.scriptPack.summary',
143
+ contract: commandContract(TEXT_JSON_OUTPUT, [
144
+ 'script-pack-catalog',
145
+ 'script-pack-suggestion-report',
146
+ 'code-outline-report',
147
+ 'dependency-graph-report',
148
+ 'import-cycle-report',
149
+ 'module-boundary-report',
150
+ 'change-impact-report',
151
+ 'code-symbol-read-report',
152
+ 'route-outline-report',
153
+ 'export-diff-report',
154
+ 'reference-drift-report',
155
+ 'link-integrity-report',
156
+ 'test-performance-report',
157
+ 'test-regression-selector-report',
158
+ 'text-budget-report',
159
+ 'generated-boundary-report',
160
+ 'repo-merge-conflict-scan-report',
161
+ 'repo-git-ignore-audit-report',
162
+ 'repo-manifest-lock-drift-report',
163
+ 'skill-route-audit-report',
164
+ 'repo-version-source-report',
165
+ 'repo-approval-gate-report',
166
+ 'repo-deploy-surface-report',
167
+ 'config-chain-report',
168
+ 'env-contract-report',
169
+ 'secret-risk-scan-report',
170
+ 'security-pattern-scan-report',
171
+ 'related-files-report',
172
+ ]),
102
173
  loadRunner: async () => (await import('../commands/script-pack.js')).runScriptPack,
103
174
  },
104
175
  {
105
176
  id: 'run',
106
177
  usage: 'mf run',
107
178
  summaryKey: 'command.run.summary',
179
+ contract: commandContract(TEXT_JSON_OUTPUT, ['run-receipt']),
108
180
  loadRunner: async () => (await import('../commands/run.js')).runRun,
109
181
  },
110
182
  {
111
183
  id: 'context',
112
184
  usage: 'mf context',
113
185
  summaryKey: 'command.context.summary',
186
+ contract: commandContract(TEXT_JSON_OUTPUT, ['context-report']),
114
187
  loadRunner: async () => (await import('../commands/context.js')).runContext,
115
188
  },
116
189
  {
117
190
  id: 'tech',
118
191
  usage: 'mf tech',
119
192
  summaryKey: 'command.tech.summary',
193
+ contract: commandContract(TEXT_JSON_OUTPUT),
120
194
  loadRunner: async () => (await import('../commands/tech.js')).runTech,
121
195
  },
122
196
  {
123
197
  id: 'doctor',
124
198
  usage: 'mf doctor',
125
199
  summaryKey: 'command.doctor.summary',
200
+ contract: commandContract(TEXT_JSON_OUTPUT, ['doctor-report']),
126
201
  loadRunner: async () => (await import('../commands/doctor.js')).runDoctor,
127
202
  },
128
203
  {
129
204
  id: 'docs',
130
205
  usage: 'mf docs',
131
206
  summaryKey: 'command.docs.summary',
207
+ contract: commandContract(TEXT_JSON_OUTPUT, ['docs-review-list']),
132
208
  loadRunner: async () => (await import('../commands/docs.js')).runDocs,
133
209
  },
134
210
  {
135
211
  id: 'handoff',
136
212
  usage: 'mf handoff',
137
213
  summaryKey: 'command.handoff.summary',
214
+ contract: commandContract(TEXT_JSON_OUTPUT, ['handoff-validation-report']),
138
215
  loadRunner: async () => (await import('../commands/handoff.js')).runHandoff,
139
216
  },
140
217
  {
141
218
  id: 'index',
142
219
  usage: 'mf index',
143
220
  summaryKey: 'command.index.summary',
221
+ contract: commandContract(TEXT_JSON_OUTPUT, ['index-report']),
144
222
  loadRunner: async () => (await import('../commands/index.js')).runIndex,
145
223
  },
146
224
  {
147
225
  id: 'search',
148
226
  usage: 'mf search',
149
227
  summaryKey: 'command.search.summary',
228
+ contract: commandContract(TEXT_JSON_OUTPUT, ['search-report']),
150
229
  loadRunner: async () => (await import('../commands/search.js')).runSearch,
151
230
  },
152
231
  {
153
232
  id: 'skill',
154
233
  usage: 'mf skill',
155
234
  summaryKey: 'command.skill.summary',
235
+ contract: commandContract(TEXT_JSON_OUTPUT, ['skill-route-report', 'skill-import-report']),
156
236
  loadRunner: async () => (await import('../commands/skill.js')).runSkill,
157
237
  },
158
238
  {
159
239
  id: 'dashboard',
160
240
  usage: 'mf dashboard',
161
241
  summaryKey: 'command.dashboard.summary',
242
+ contract: commandContract(TEXT_JSON_FILE_OUTPUT, ['dashboard-export']),
162
243
  loadRunner: async () => (await import('../commands/dashboard.js')).runDashboard,
163
244
  },
164
245
  {
165
246
  id: 'version',
166
247
  usage: 'mf version',
167
248
  summaryKey: 'command.version.summary',
249
+ contract: commandContract(TEXT_OUTPUT),
168
250
  loadRunner: async () => (await import('../commands/version.js')).runVersion,
169
251
  },
170
252
  {
171
253
  id: 'version-sources',
172
254
  usage: 'mf version-sources',
173
255
  summaryKey: 'command.versionSources.summary',
256
+ contract: commandContract(TEXT_JSON_OUTPUT, ['version-sources-report']),
174
257
  loadRunner: async () => (await import('../commands/version-sources.js')).runVersionSources,
175
258
  },
176
259
  {
177
260
  id: 'verify',
178
261
  usage: 'mf verify',
179
262
  summaryKey: 'command.verify.summary',
263
+ contract: commandContract(TEXT_JSON_OUTPUT, [
264
+ 'verify-report',
265
+ 'change-verification-report',
266
+ 'verify-run-manifest',
267
+ 'latest-run-pointer',
268
+ ]),
180
269
  loadRunner: async () => (await import('../commands/verify.js')).runVerify,
181
270
  },
182
271
  {
183
272
  id: 'explain',
184
273
  usage: 'mf explain',
185
274
  summaryKey: 'command.explain.summary',
275
+ contract: commandContract(TEXT_JSON_OUTPUT, ['explain-report']),
186
276
  loadRunner: async () => (await import('../commands/explain.js')).runExplain,
187
277
  },
188
278
  {
189
279
  id: 'impact',
190
280
  usage: 'mf impact',
191
281
  summaryKey: 'command.impact.summary',
282
+ contract: commandContract(TEXT_JSON_OUTPUT, ['impact-report']),
192
283
  loadRunner: async () => (await import('../commands/impact.js')).runImpact,
193
284
  },
194
285
  {
195
286
  id: 'help',
196
287
  usage: 'mf help',
197
288
  summaryKey: 'command.help.summary',
289
+ contract: commandContract(TEXT_OUTPUT),
198
290
  loadRunner: async () => (await import('../commands/help.js')).runHelp,
199
291
  },
200
292
  ];
@@ -85,6 +85,32 @@ export function getParsedCliStringOption(parsed, name) {
85
85
  const value = parsed.values.get(name);
86
86
  return typeof value === 'string' ? value : null;
87
87
  }
88
+ export function parsePositiveIntegerCliOption(value, option, invalidMessageKey, lang) {
89
+ if (value === null) {
90
+ return { value: null };
91
+ }
92
+ if (!/^[1-9]\d*$/u.test(value)) {
93
+ return { value: null, error: t(lang, invalidMessageKey, { option, value }) };
94
+ }
95
+ const parsed = Number(value);
96
+ if (!Number.isSafeInteger(parsed)) {
97
+ return { value: null, error: t(lang, invalidMessageKey, { option, value }) };
98
+ }
99
+ return { value: parsed };
100
+ }
101
+ export function parseNonNegativeIntegerCliOption(value, option, invalidMessageKey, lang) {
102
+ if (value === null) {
103
+ return { value: null };
104
+ }
105
+ if (!/^(?:0|[1-9]\d*)$/u.test(value)) {
106
+ return { value: null, error: t(lang, invalidMessageKey, { option, value }) };
107
+ }
108
+ const parsed = Number(value);
109
+ if (!Number.isSafeInteger(parsed)) {
110
+ return { value: null, error: t(lang, invalidMessageKey, { option, value }) };
111
+ }
112
+ return { value: parsed };
113
+ }
88
114
  export function formatCliOptionParseError(error, lang) {
89
115
  if (error.kind === 'missing_value') {
90
116
  return t(lang, 'cli.error.missingValue', { option: error.option });
@@ -94,6 +94,45 @@ export const SCRIPT_PACKS = [
94
94
  reportSchemaFile: 'import-cycle-report.schema.json',
95
95
  loadRunner: async () => (await import('../script-packs/code-import-cycle.js')).runCodeImportCycleScript,
96
96
  },
97
+ {
98
+ packId: 'code',
99
+ id: 'module-boundary',
100
+ ref: scriptRef('code', 'module-boundary'),
101
+ usage: 'mf script-pack run code/module-boundary check <path...> [options]',
102
+ summaryKey: 'scriptPack.script.codeModuleBoundary.summary',
103
+ actions: ['check'],
104
+ useWhen: [
105
+ 'Check configured module boundary rules for relative TypeScript and JavaScript import edges before or after boundary-sensitive changes.',
106
+ 'Review layer deny rules, public entrypoint access, feature-to-feature imports, ' +
107
+ 'shared/common budgets, and cycle evidence using .mustflow/config/module-boundaries.toml.',
108
+ ],
109
+ phases: ['before_change', 'after_change', 'review'],
110
+ readOnly: true,
111
+ mutates: false,
112
+ network: false,
113
+ inputs: [
114
+ 'path',
115
+ 'config_path',
116
+ 'max_files',
117
+ 'max_file_bytes',
118
+ 'max_depth',
119
+ 'max_nodes',
120
+ 'max_edges',
121
+ 'max_cycles',
122
+ ],
123
+ outputs: ['human_summary', 'json_report', 'module_boundary_findings', 'shared_budget_metrics'],
124
+ relatedSkills: [
125
+ 'change-blast-radius-review',
126
+ 'codebase-orientation',
127
+ 'javascript-code-change',
128
+ 'module-boundary-review',
129
+ 'typescript-code-change',
130
+ ],
131
+ riskLevel: 'low',
132
+ cost: 'low',
133
+ reportSchemaFile: 'module-boundary-report.schema.json',
134
+ loadRunner: async () => (await import('../script-packs/code-module-boundary.js')).runCodeModuleBoundaryScript,
135
+ },
97
136
  {
98
137
  packId: 'code',
99
138
  id: 'change-impact',