mustflow 2.84.0 → 2.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +11 -2
  2. package/dist/cli/commands/script-pack.js +14 -0
  3. package/dist/cli/i18n/en.js +262 -0
  4. package/dist/cli/i18n/es.js +262 -0
  5. package/dist/cli/i18n/fr.js +262 -0
  6. package/dist/cli/i18n/hi.js +262 -0
  7. package/dist/cli/i18n/ko.js +262 -0
  8. package/dist/cli/i18n/zh.js +262 -0
  9. package/dist/cli/lib/repo-map.js +27 -6
  10. package/dist/cli/lib/run-root-trust.js +15 -1
  11. package/dist/cli/lib/script-pack-registry.js +397 -0
  12. package/dist/cli/lib/validation/index.js +2 -2
  13. package/dist/cli/lib/validation/primitives.js +4 -1
  14. package/dist/cli/script-packs/code-change-impact.js +178 -0
  15. package/dist/cli/script-packs/code-dependency-graph.js +181 -0
  16. package/dist/cli/script-packs/code-import-cycle.js +193 -0
  17. package/dist/cli/script-packs/docs-link-integrity.js +145 -0
  18. package/dist/cli/script-packs/repo-approval-gate.js +100 -0
  19. package/dist/cli/script-packs/repo-env-contract.js +156 -0
  20. package/dist/cli/script-packs/repo-git-ignore-audit.js +119 -0
  21. package/dist/cli/script-packs/repo-manifest-lock-drift.js +122 -0
  22. package/dist/cli/script-packs/repo-merge-conflict-scan.js +123 -0
  23. package/dist/cli/script-packs/repo-secret-risk-scan.js +147 -0
  24. package/dist/cli/script-packs/repo-skill-route-audit.js +86 -0
  25. package/dist/cli/script-packs/repo-version-source.js +92 -0
  26. package/dist/cli/script-packs/test-performance-report.js +247 -0
  27. package/dist/cli/script-packs/test-regression-selector.js +167 -0
  28. package/dist/core/change-impact.js +355 -0
  29. package/dist/core/change-surface-classification.js +198 -0
  30. package/dist/core/change-verification.js +32 -5
  31. package/dist/core/config-loading.js +121 -4
  32. package/dist/core/dependency-graph.js +490 -0
  33. package/dist/core/docs-link-integrity.js +443 -0
  34. package/dist/core/env-contract.js +450 -0
  35. package/dist/core/import-cycle.js +152 -0
  36. package/dist/core/line-endings.js +26 -13
  37. package/dist/core/public-json-contracts.js +167 -0
  38. package/dist/core/repo-approval-gate.js +116 -0
  39. package/dist/core/repo-git-ignore-audit.js +302 -0
  40. package/dist/core/repo-manifest-lock-drift.js +321 -0
  41. package/dist/core/repo-merge-conflict-scan.js +335 -0
  42. package/dist/core/repo-version-source.js +82 -0
  43. package/dist/core/route-outline.js +57 -5
  44. package/dist/core/script-pack-suggestions.js +97 -1
  45. package/dist/core/secret-risk-scan.js +440 -0
  46. package/dist/core/skill-route-audit.js +354 -0
  47. package/dist/core/test-performance-report.js +697 -0
  48. package/dist/core/test-regression-selector.js +335 -0
  49. package/package.json +1 -1
  50. package/schemas/README.md +54 -0
  51. package/schemas/change-impact-report.schema.json +184 -0
  52. package/schemas/commands.schema.json +12 -0
  53. package/schemas/dependency-graph-report.schema.json +149 -0
  54. package/schemas/env-contract-report.schema.json +203 -0
  55. package/schemas/import-cycle-report.schema.json +157 -0
  56. package/schemas/link-integrity-report.schema.json +176 -0
  57. package/schemas/repo-approval-gate-report.schema.json +115 -0
  58. package/schemas/repo-git-ignore-audit-report.schema.json +201 -0
  59. package/schemas/repo-manifest-lock-drift-report.schema.json +202 -0
  60. package/schemas/repo-merge-conflict-scan-report.schema.json +169 -0
  61. package/schemas/repo-version-source-report.schema.json +127 -0
  62. package/schemas/secret-risk-scan-report.schema.json +152 -0
  63. package/schemas/skill-route-audit-report.schema.json +144 -0
  64. package/schemas/test-performance-report.schema.json +319 -0
  65. package/schemas/test-regression-selector-report.schema.json +187 -0
  66. package/templates/default/i18n.toml +80 -26
  67. package/templates/default/locales/en/.mustflow/skills/INDEX.md +51 -9
  68. package/templates/default/locales/en/.mustflow/skills/api-access-control-review/SKILL.md +48 -27
  69. package/templates/default/locales/en/.mustflow/skills/api-failure-triage/SKILL.md +270 -0
  70. package/templates/default/locales/en/.mustflow/skills/architecture-deepening-review/SKILL.md +28 -11
  71. package/templates/default/locales/en/.mustflow/skills/astro-code-change/SKILL.md +71 -27
  72. package/templates/default/locales/en/.mustflow/skills/auth-flow-triage/SKILL.md +192 -0
  73. package/templates/default/locales/en/.mustflow/skills/auth-permission-change/SKILL.md +59 -13
  74. package/templates/default/locales/en/.mustflow/skills/backend-log-evidence-review/SKILL.md +14 -5
  75. package/templates/default/locales/en/.mustflow/skills/cache-integrity-review/SKILL.md +30 -15
  76. package/templates/default/locales/en/.mustflow/skills/change-blast-radius-review/SKILL.md +45 -32
  77. package/templates/default/locales/en/.mustflow/skills/ci-pipeline-triage/SKILL.md +200 -0
  78. package/templates/default/locales/en/.mustflow/skills/clarifying-question-gate/SKILL.md +87 -13
  79. package/templates/default/locales/en/.mustflow/skills/cross-agent-session-reference/SKILL.md +23 -8
  80. package/templates/default/locales/en/.mustflow/skills/dependency-upgrade-review/SKILL.md +3 -1
  81. package/templates/default/locales/en/.mustflow/skills/docker-runtime-triage/SKILL.md +191 -0
  82. package/templates/default/locales/en/.mustflow/skills/github-contribution-quality-gate/SKILL.md +48 -11
  83. package/templates/default/locales/en/.mustflow/skills/go-code-change/SKILL.md +18 -13
  84. package/templates/default/locales/en/.mustflow/skills/javascript-code-change/SKILL.md +15 -13
  85. package/templates/default/locales/en/.mustflow/skills/line-ending-hygiene/SKILL.md +18 -10
  86. package/templates/default/locales/en/.mustflow/skills/llm-hallucination-control-review/SKILL.md +4 -1
  87. package/templates/default/locales/en/.mustflow/skills/motion-system-contract-review/SKILL.md +155 -0
  88. package/templates/default/locales/en/.mustflow/skills/next-action-menu/SKILL.md +177 -0
  89. package/templates/default/locales/en/.mustflow/skills/node-code-change/SKILL.md +16 -14
  90. package/templates/default/locales/en/.mustflow/skills/observability-debuggability-review/SKILL.md +15 -7
  91. package/templates/default/locales/en/.mustflow/skills/payment-integrity-review/SKILL.md +59 -35
  92. package/templates/default/locales/en/.mustflow/skills/powershell-code-change/SKILL.md +16 -6
  93. package/templates/default/locales/en/.mustflow/skills/prompt-contract-quality-review/SKILL.md +4 -1
  94. package/templates/default/locales/en/.mustflow/skills/python-code-change/SKILL.md +19 -10
  95. package/templates/default/locales/en/.mustflow/skills/rag-pipeline-triage/SKILL.md +206 -0
  96. package/templates/default/locales/en/.mustflow/skills/routes.toml +69 -9
  97. package/templates/default/locales/en/.mustflow/skills/rust-code-change/SKILL.md +10 -4
  98. package/templates/default/locales/en/.mustflow/skills/search-index-integrity-review/SKILL.md +181 -0
  99. package/templates/default/locales/en/.mustflow/skills/security-privacy-review/SKILL.md +3 -1
  100. package/templates/default/locales/en/.mustflow/skills/service-boundary-architecture/SKILL.md +37 -23
  101. package/templates/default/locales/en/.mustflow/skills/test-suite-performance-review/SKILL.md +323 -0
  102. package/templates/default/locales/en/.mustflow/skills/typescript-code-change/SKILL.md +18 -10
  103. package/templates/default/locales/en/.mustflow/skills/vector-search-integrity-review/SKILL.md +209 -0
  104. package/templates/default/locales/en/.mustflow/skills/version-freshness-check/SKILL.md +16 -14
  105. package/templates/default/manifest.toml +71 -1
@@ -0,0 +1,82 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { isRecord, readMustflowOwnedTomlFile } from './config-loading.js';
5
+ import { detectVersionSources, releaseVersioningIsEnabled, VERSIONING_CONFIG_PATH, } from './version-sources.js';
6
+ export const REPO_VERSION_SOURCE_PACK_ID = 'repo';
7
+ export const REPO_VERSION_SOURCE_SCRIPT_ID = 'version-source';
8
+ export const REPO_VERSION_SOURCE_SCRIPT_REF = `${REPO_VERSION_SOURCE_PACK_ID}/${REPO_VERSION_SOURCE_SCRIPT_ID}`;
9
+ export const REPO_VERSION_SOURCE_PREFERENCES_PATH = '.mustflow/config/preferences.toml';
10
+ function sha256(value) {
11
+ return `sha256:${createHash('sha256').update(value).digest('hex')}`;
12
+ }
13
+ function readPreferences(projectRoot, issues) {
14
+ const preferencesPath = path.join(projectRoot, ...REPO_VERSION_SOURCE_PREFERENCES_PATH.split('/'));
15
+ if (!existsSync(preferencesPath)) {
16
+ return undefined;
17
+ }
18
+ try {
19
+ const parsed = readMustflowOwnedTomlFile(projectRoot, REPO_VERSION_SOURCE_PREFERENCES_PATH);
20
+ return isRecord(parsed) ? parsed : undefined;
21
+ }
22
+ catch (error) {
23
+ const message = error instanceof Error ? error.message : String(error);
24
+ issues.push(`Could not read ${REPO_VERSION_SOURCE_PREFERENCES_PATH}: ${message}`);
25
+ return undefined;
26
+ }
27
+ }
28
+ function countSources(sources) {
29
+ return {
30
+ sources: sources.length,
31
+ declared_sources: sources.filter((source) => source.declared === true).length,
32
+ source_authority_sources: sources.filter((source) => source.authority === 'source').length,
33
+ derived_authority_sources: sources.filter((source) => source.authority === 'derived').length,
34
+ unclassified_authority_sources: sources.filter((source) => source.authority === undefined).length,
35
+ };
36
+ }
37
+ function createInputHash(reportInput) {
38
+ return sha256(JSON.stringify(reportInput));
39
+ }
40
+ export function inspectRepoVersionSource(projectRoot) {
41
+ const root = path.resolve(projectRoot);
42
+ const issues = [];
43
+ const preferences = readPreferences(root, issues);
44
+ const versioningEnabled = releaseVersioningIsEnabled(preferences);
45
+ const sources = detectVersionSources(root);
46
+ const findings = [];
47
+ if (versioningEnabled && sources.length === 0) {
48
+ findings.push({
49
+ code: 'versioning_enabled_without_sources',
50
+ severity: 'high',
51
+ path: REPO_VERSION_SOURCE_PREFERENCES_PATH,
52
+ message: 'Release versioning preferences are enabled, but no version source was detected.',
53
+ json_pointer: null,
54
+ metric: null,
55
+ actual: 0,
56
+ expected: 1,
57
+ });
58
+ }
59
+ const counts = countSources(sources);
60
+ const status = issues.length > 0 ? 'error' : findings.length > 0 ? 'failed' : 'passed';
61
+ return {
62
+ schema_version: '1',
63
+ command: 'script-pack',
64
+ pack_id: REPO_VERSION_SOURCE_PACK_ID,
65
+ script_id: REPO_VERSION_SOURCE_SCRIPT_ID,
66
+ script_ref: REPO_VERSION_SOURCE_SCRIPT_REF,
67
+ action: 'inspect',
68
+ status,
69
+ ok: status === 'passed',
70
+ mustflow_root: root,
71
+ input: {
72
+ preferences_path: REPO_VERSION_SOURCE_PREFERENCES_PATH,
73
+ declared_sources_path: VERSIONING_CONFIG_PATH,
74
+ },
75
+ input_hash: createInputHash({ versioningEnabled, counts, sources, findings, issues }),
76
+ versioning_enabled: versioningEnabled,
77
+ counts,
78
+ sources,
79
+ findings,
80
+ issues,
81
+ };
82
+ }
@@ -821,20 +821,72 @@ function extractNestjsLifecycleDecorator(line) {
821
821
  : null;
822
822
  }
823
823
  function extractNestjsHandlerName(line) {
824
- const match = /^\s*(?:public\s+|private\s+|protected\s+|async\s+|static\s+|readonly\s+|\*?\s*)*[$A-Z_a-z][$\w]*\s*\(/u.exec(line);
825
- if (!match) {
824
+ const signature = line.trimStart();
825
+ if (signature.length === 0) {
826
826
  return null;
827
827
  }
828
- const named = /(?<name>[$A-Z_a-z][$\w]*)\s*\(/u.exec(line);
829
- const name = named?.groups?.name;
830
- if (!name) {
828
+ let offset = signature.startsWith('*') ? 1 : 0;
829
+ offset = skipAsciiWhitespace(signature, offset);
830
+ while (true) {
831
+ const next = readIdentifier(signature, offset);
832
+ if (next === null || !isNestjsHandlerModifier(next.value)) {
833
+ break;
834
+ }
835
+ offset = skipAsciiWhitespace(signature, next.end);
836
+ }
837
+ if (signature.charAt(offset) === '*') {
838
+ offset = skipAsciiWhitespace(signature, offset + 1);
839
+ }
840
+ const nameToken = readIdentifier(signature, offset);
841
+ if (nameToken === null) {
831
842
  return null;
832
843
  }
844
+ const callStart = skipAsciiWhitespace(signature, nameToken.end);
845
+ if (signature.charAt(callStart) !== '(') {
846
+ return null;
847
+ }
848
+ const name = nameToken.value;
833
849
  if (/\b(?:if|for|while|switch|return|class|interface|function|new|throw|typeof|in|of)\b/u.test(name)) {
834
850
  return null;
835
851
  }
836
852
  return name;
837
853
  }
854
+ function skipAsciiWhitespace(text, offset) {
855
+ let index = offset;
856
+ while (index < text.length) {
857
+ const code = text.charCodeAt(index);
858
+ if (code !== 9 && code !== 10 && code !== 11 && code !== 12 && code !== 13 && code !== 32) {
859
+ break;
860
+ }
861
+ index += 1;
862
+ }
863
+ return index;
864
+ }
865
+ function readIdentifier(text, offset) {
866
+ const first = text.charCodeAt(offset);
867
+ if (!isIdentifierStart(first)) {
868
+ return null;
869
+ }
870
+ let end = offset + 1;
871
+ while (end < text.length && isIdentifierPart(text.charCodeAt(end))) {
872
+ end += 1;
873
+ }
874
+ return { value: text.slice(offset, end), end };
875
+ }
876
+ function isIdentifierStart(code) {
877
+ return code === 36 || code === 95 || (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
878
+ }
879
+ function isIdentifierPart(code) {
880
+ return isIdentifierStart(code) || (code >= 48 && code <= 57);
881
+ }
882
+ function isNestjsHandlerModifier(value) {
883
+ return (value === 'public' ||
884
+ value === 'private' ||
885
+ value === 'protected' ||
886
+ value === 'async' ||
887
+ value === 'static' ||
888
+ value === 'readonly');
889
+ }
838
890
  function extractNestjsRouteEntries(relativePath, language, contentSha256, lines, block) {
839
891
  const routes = [];
840
892
  let controllerLifecycle = [];
@@ -2,13 +2,15 @@ import { spawnSync } from 'node:child_process';
2
2
  import path from 'node:path';
3
3
  const CODE_NAVIGATION_SCRIPT_REFS = new Set([
4
4
  'code/outline',
5
+ 'code/dependency-graph',
6
+ 'code/import-cycle',
5
7
  'code/symbol-read',
6
8
  'code/route-outline',
7
9
  'code/export-diff',
8
10
  'repo/related-files',
9
11
  ]);
10
12
  const CONFIG_CHAIN_SURFACES = new Set(['config', 'package', 'source', 'test']);
11
- const CONFIG_FILE_PATTERN = /(?:^|\/)(?:tsconfig(?:\..*)?\.json|eslint\.config\.[cm]?[jt]s|\.eslintrc(?:\.json)?|\.prettierrc(?:\.json)?|prettier\.config\.[cm]?[jt]s|vite\.config\.[cm]?[jt]s|vitest\.config\.[cm]?[jt]s|tailwind\.config\.[cm]?[jt]s|jest\.config\.[cm]?[jt]s|playwright\.config\.[cm]?[jt]s|astro\.config\.mjs|svelte\.config\.js)$/u;
13
+ const CONFIG_FILE_PATTERN = /(?:^|\/)(?:\.gitignore|\.env\.(?:example|sample|template|defaults)|\.dev\.vars\.example|tsconfig(?:\..*)?\.json|eslint\.config\.[cm]?[jt]s|\.eslintrc(?:\.json)?|\.prettierrc(?:\.json)?|prettier\.config\.[cm]?[jt]s|vite\.config\.[cm]?[jt]s|vitest\.config\.[cm]?[jt]s|tailwind\.config\.[cm]?[jt]s|jest\.config\.[cm]?[jt]s|playwright\.config\.[cm]?[jt]s|astro\.config\.mjs|svelte\.config\.js)$/u;
12
14
  export function isScriptPackSuggestionPhase(value) {
13
15
  return ['before_change', 'during_change', 'after_change', 'review'].includes(value);
14
16
  }
@@ -121,7 +123,13 @@ function surfacesForScript(script) {
121
123
  addIf('generated', /generated|protected|vendor|cache|boundary/u);
122
124
  addIf('config', /config|command/u);
123
125
  addIf('package', /package|release/u);
126
+ addIf('test', /test|suite|fixture|coverage|selection|timing|performance/u);
124
127
  addIf('source', /code|source|symbol/u);
128
+ if (script.ref === 'repo/manifest-lock-drift') {
129
+ surfaces.add('config');
130
+ surfaces.add('generated');
131
+ surfaces.add('template');
132
+ }
125
133
  return uniqueSortedSurfaces(surfaces);
126
134
  }
127
135
  function confidenceForScore(score) {
@@ -139,6 +147,10 @@ function pathsWithSurface(analyzedPaths, surface) {
139
147
  function hasPathWithSurface(analyzedPaths, surface) {
140
148
  return analyzedPaths.some((entry) => entry.surfaces.includes(surface));
141
149
  }
150
+ function isGitIgnoreAuditPriorityPath(relativePath) {
151
+ const normalized = relativePath.replace(/\\/gu, '/').replace(/^\.\/+/u, '');
152
+ return normalized === '.gitignore' || normalized.endsWith('/.gitignore') || normalized === '.git/info/exclude';
153
+ }
142
154
  function firstAvailablePath(analyzedPaths, preferredSurfaces) {
143
155
  for (const surface of preferredSurfaces) {
144
156
  const [candidate] = pathsWithSurface(analyzedPaths, surface);
@@ -166,6 +178,17 @@ function createRunHint(script, analyzedPaths) {
166
178
  }
167
179
  return 'After code/outline returns a source anchor, run: mf script-pack run code/symbol-read read --anchor <anchor-id> --json';
168
180
  }
181
+ if (script.ref === 'code/dependency-graph') {
182
+ const sourcePaths = pathsWithSurface(analyzedPaths, 'source');
183
+ return createConcretePathHint('mf script-pack run code/dependency-graph scan', sourcePaths, script.usage);
184
+ }
185
+ if (script.ref === 'code/import-cycle') {
186
+ const sourcePaths = pathsWithSurface(analyzedPaths, 'source');
187
+ return createConcretePathHint('mf script-pack run code/import-cycle check', sourcePaths, script.usage);
188
+ }
189
+ if (script.ref === 'code/change-impact') {
190
+ return 'mf script-pack run code/change-impact analyze --base HEAD --json';
191
+ }
169
192
  if (script.ref === 'code/route-outline') {
170
193
  const sourcePaths = pathsWithSurface(analyzedPaths, 'source');
171
194
  return createConcretePathHint('mf script-pack run code/route-outline scan', sourcePaths, script.usage);
@@ -191,15 +214,64 @@ function createRunHint(script, analyzedPaths) {
191
214
  .map((entry) => entry.path);
192
215
  return createConcretePathHint('mf script-pack run docs/reference-drift check', docsPaths, script.usage);
193
216
  }
217
+ if (script.ref === 'docs/link-integrity') {
218
+ const docsPaths = analyzedPaths
219
+ .filter((entry) => entry.surfaces.some((surface) => surface === 'docs' || surface === 'schema'))
220
+ .map((entry) => entry.path);
221
+ return createConcretePathHint('mf script-pack run docs/link-integrity check', docsPaths, script.usage);
222
+ }
223
+ if (script.ref === 'test/performance-report') {
224
+ return 'mf script-pack run test/performance-report summarize --json';
225
+ }
226
+ if (script.ref === 'test/regression-selector') {
227
+ const testSelectionPaths = analyzedPaths
228
+ .filter((entry) => entry.surfaces.some((surface) => surface === 'source' || surface === 'test'))
229
+ .map((entry) => entry.path);
230
+ const pathPart = testSelectionPaths.length > 0 ? ` ${testSelectionPaths.map(quoteCliArg).join(' ')}` : '';
231
+ return `mf script-pack run test/regression-selector select${pathPart} --base HEAD --json`;
232
+ }
194
233
  if (script.ref === 'repo/generated-boundary') {
195
234
  return createConcretePathHint('mf script-pack run repo/generated-boundary check', analyzedPaths.map((entry) => entry.path), script.usage);
196
235
  }
236
+ if (script.ref === 'repo/merge-conflict-scan') {
237
+ return createConcretePathHint('mf script-pack run repo/merge-conflict-scan check', analyzedPaths.map((entry) => entry.path), 'mf script-pack run repo/merge-conflict-scan check --json');
238
+ }
239
+ if (script.ref === 'repo/git-ignore-audit') {
240
+ return createConcretePathHint('mf script-pack run repo/git-ignore-audit audit', analyzedPaths.map((entry) => entry.path), 'mf script-pack run repo/git-ignore-audit audit --json');
241
+ }
242
+ if (script.ref === 'repo/manifest-lock-drift') {
243
+ const manifestPaths = analyzedPaths
244
+ .filter((entry) => entry.surfaces.some((surface) => surface === 'config' || surface === 'template' || surface === 'generated'))
245
+ .map((entry) => entry.path);
246
+ return createConcretePathHint('mf script-pack run repo/manifest-lock-drift check', manifestPaths, 'mf script-pack run repo/manifest-lock-drift check --json');
247
+ }
248
+ if (script.ref === 'repo/skill-route-audit') {
249
+ return 'mf script-pack run repo/skill-route-audit audit --json';
250
+ }
251
+ if (script.ref === 'repo/version-source') {
252
+ return 'mf script-pack run repo/version-source inspect --json';
253
+ }
254
+ if (script.ref === 'repo/approval-gate') {
255
+ return 'mf script-pack run repo/approval-gate check --action <action_type> --json';
256
+ }
197
257
  if (script.ref === 'repo/config-chain') {
198
258
  const configPaths = analyzedPaths
199
259
  .filter((entry) => entry.surfaces.some((surface) => CONFIG_CHAIN_SURFACES.has(surface)))
200
260
  .map((entry) => entry.path);
201
261
  return createConcretePathHint('mf script-pack run repo/config-chain inspect', configPaths, script.usage);
202
262
  }
263
+ if (script.ref === 'repo/env-contract') {
264
+ const envPaths = analyzedPaths
265
+ .filter((entry) => entry.surfaces.some((surface) => surface === 'config' || surface === 'source' || surface === 'docs' || surface === 'package'))
266
+ .map((entry) => entry.path);
267
+ return createConcretePathHint('mf script-pack run repo/env-contract scan', envPaths, script.usage);
268
+ }
269
+ if (script.ref === 'repo/secret-risk-scan') {
270
+ const secretRiskPaths = analyzedPaths
271
+ .filter((entry) => entry.surfaces.some((surface) => surface === 'config' || surface === 'source' || surface === 'docs' || surface === 'package' || surface === 'test'))
272
+ .map((entry) => entry.path);
273
+ return createConcretePathHint('mf script-pack run repo/secret-risk-scan scan', secretRiskPaths, script.usage);
274
+ }
203
275
  if (script.ref === 'repo/related-files') {
204
276
  const relatedPaths = analyzedPaths
205
277
  .filter((entry) => entry.surfaces.some((surface) => surface === 'source' || surface === 'test'))
@@ -260,6 +332,30 @@ export function createScriptPackSuggestionReport(mustflowRoot, options) {
260
332
  score += 2;
261
333
  reasons.push('Prioritizes generated-boundary checks for generated paths.');
262
334
  }
335
+ if (script.ref === 'repo/merge-conflict-scan' && requestedSurfaces.size > 0) {
336
+ score += 1;
337
+ reasons.push('Prioritizes merge-conflict marker scans for changed repository paths.');
338
+ }
339
+ if (script.ref === 'repo/git-ignore-audit' &&
340
+ analyzedPaths.some((entry) => isGitIgnoreAuditPriorityPath(entry.path))) {
341
+ score += 1;
342
+ reasons.push('Prioritizes Git ignore evidence for explicit ignore-control paths.');
343
+ }
344
+ if (script.ref === 'repo/skill-route-audit' &&
345
+ (requestedSurfaces.has('skill') || requestedSurfaces.has('template') || requestedSurfaces.has('config'))) {
346
+ score += 3;
347
+ reasons.push('Prioritizes skill-route audits for skill, template, and workflow metadata surfaces.');
348
+ }
349
+ if (script.ref === 'repo/version-source' &&
350
+ (requestedSurfaces.has('package') || requestedSurfaces.has('template') || requestedSurfaces.has('config'))) {
351
+ score += 2;
352
+ reasons.push('Prioritizes version-source inspection for package, template, and versioning metadata surfaces.');
353
+ }
354
+ if (script.ref === 'repo/approval-gate' &&
355
+ (requestedSurfaces.has('config') || requestedSurfaces.has('package') || requestedSurfaces.has('template'))) {
356
+ score += 2;
357
+ reasons.push('Prioritizes approval-gate checks for approval-sensitive workflow and release surfaces.');
358
+ }
263
359
  if (score === 0) {
264
360
  return null;
265
361
  }