mustflow 2.85.4 → 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 (78) hide show
  1. package/dist/cli/commands/script-pack.js +10 -0
  2. package/dist/cli/i18n/en.js +183 -0
  3. package/dist/cli/i18n/es.js +183 -0
  4. package/dist/cli/i18n/fr.js +183 -0
  5. package/dist/cli/i18n/hi.js +183 -0
  6. package/dist/cli/i18n/ko.js +183 -0
  7. package/dist/cli/i18n/zh.js +183 -0
  8. package/dist/cli/lib/script-pack-registry.js +284 -1
  9. package/dist/cli/script-packs/code-change-impact.js +6 -0
  10. package/dist/cli/script-packs/code-import-cycle.js +193 -0
  11. package/dist/cli/script-packs/docs-link-integrity.js +145 -0
  12. package/dist/cli/script-packs/repo-approval-gate.js +100 -0
  13. package/dist/cli/script-packs/repo-git-ignore-audit.js +119 -0
  14. package/dist/cli/script-packs/repo-manifest-lock-drift.js +122 -0
  15. package/dist/cli/script-packs/repo-merge-conflict-scan.js +123 -0
  16. package/dist/cli/script-packs/repo-skill-route-audit.js +86 -0
  17. package/dist/cli/script-packs/repo-version-source.js +92 -0
  18. package/dist/cli/script-packs/test-performance-report.js +247 -0
  19. package/dist/cli/script-packs/test-regression-selector.js +167 -0
  20. package/dist/core/change-impact.js +23 -51
  21. package/dist/core/change-surface-classification.js +198 -0
  22. package/dist/core/docs-link-integrity.js +443 -0
  23. package/dist/core/import-cycle.js +152 -0
  24. package/dist/core/public-json-contracts.js +116 -0
  25. package/dist/core/repo-approval-gate.js +116 -0
  26. package/dist/core/repo-git-ignore-audit.js +302 -0
  27. package/dist/core/repo-manifest-lock-drift.js +321 -0
  28. package/dist/core/repo-merge-conflict-scan.js +335 -0
  29. package/dist/core/repo-version-source.js +82 -0
  30. package/dist/core/script-pack-suggestions.js +77 -1
  31. package/dist/core/skill-route-audit.js +354 -0
  32. package/dist/core/test-performance-report.js +697 -0
  33. package/dist/core/test-regression-selector.js +335 -0
  34. package/package.json +1 -1
  35. package/schemas/README.md +40 -2
  36. package/schemas/change-impact-report.schema.json +35 -1
  37. package/schemas/import-cycle-report.schema.json +157 -0
  38. package/schemas/link-integrity-report.schema.json +176 -0
  39. package/schemas/repo-approval-gate-report.schema.json +115 -0
  40. package/schemas/repo-git-ignore-audit-report.schema.json +201 -0
  41. package/schemas/repo-manifest-lock-drift-report.schema.json +202 -0
  42. package/schemas/repo-merge-conflict-scan-report.schema.json +169 -0
  43. package/schemas/repo-version-source-report.schema.json +127 -0
  44. package/schemas/skill-route-audit-report.schema.json +144 -0
  45. package/schemas/test-performance-report.schema.json +319 -0
  46. package/schemas/test-regression-selector-report.schema.json +187 -0
  47. package/templates/default/i18n.toml +66 -18
  48. package/templates/default/locales/en/.mustflow/skills/INDEX.md +45 -8
  49. package/templates/default/locales/en/.mustflow/skills/api-access-control-review/SKILL.md +48 -27
  50. package/templates/default/locales/en/.mustflow/skills/api-failure-triage/SKILL.md +270 -0
  51. package/templates/default/locales/en/.mustflow/skills/auth-flow-triage/SKILL.md +192 -0
  52. package/templates/default/locales/en/.mustflow/skills/auth-permission-change/SKILL.md +59 -13
  53. package/templates/default/locales/en/.mustflow/skills/backend-log-evidence-review/SKILL.md +14 -5
  54. package/templates/default/locales/en/.mustflow/skills/cache-integrity-review/SKILL.md +30 -15
  55. package/templates/default/locales/en/.mustflow/skills/change-blast-radius-review/SKILL.md +45 -32
  56. package/templates/default/locales/en/.mustflow/skills/ci-pipeline-triage/SKILL.md +200 -0
  57. package/templates/default/locales/en/.mustflow/skills/clarifying-question-gate/SKILL.md +87 -13
  58. package/templates/default/locales/en/.mustflow/skills/docker-runtime-triage/SKILL.md +191 -0
  59. package/templates/default/locales/en/.mustflow/skills/go-code-change/SKILL.md +18 -13
  60. package/templates/default/locales/en/.mustflow/skills/line-ending-hygiene/SKILL.md +18 -10
  61. package/templates/default/locales/en/.mustflow/skills/llm-hallucination-control-review/SKILL.md +4 -1
  62. package/templates/default/locales/en/.mustflow/skills/motion-system-contract-review/SKILL.md +155 -0
  63. package/templates/default/locales/en/.mustflow/skills/next-action-menu/SKILL.md +177 -0
  64. package/templates/default/locales/en/.mustflow/skills/observability-debuggability-review/SKILL.md +15 -7
  65. package/templates/default/locales/en/.mustflow/skills/payment-integrity-review/SKILL.md +59 -35
  66. package/templates/default/locales/en/.mustflow/skills/powershell-code-change/SKILL.md +16 -6
  67. package/templates/default/locales/en/.mustflow/skills/prompt-contract-quality-review/SKILL.md +4 -1
  68. package/templates/default/locales/en/.mustflow/skills/python-code-change/SKILL.md +19 -10
  69. package/templates/default/locales/en/.mustflow/skills/rag-pipeline-triage/SKILL.md +206 -0
  70. package/templates/default/locales/en/.mustflow/skills/routes.toml +54 -0
  71. package/templates/default/locales/en/.mustflow/skills/rust-code-change/SKILL.md +10 -4
  72. package/templates/default/locales/en/.mustflow/skills/search-index-integrity-review/SKILL.md +181 -0
  73. package/templates/default/locales/en/.mustflow/skills/service-boundary-architecture/SKILL.md +37 -23
  74. package/templates/default/locales/en/.mustflow/skills/test-suite-performance-review/SKILL.md +9 -0
  75. package/templates/default/locales/en/.mustflow/skills/typescript-code-change/SKILL.md +14 -9
  76. package/templates/default/locales/en/.mustflow/skills/vector-search-integrity-review/SKILL.md +209 -0
  77. package/templates/default/locales/en/.mustflow/skills/version-freshness-check/SKILL.md +16 -14
  78. package/templates/default/manifest.toml +64 -1
@@ -0,0 +1,100 @@
1
+ import { printUsageError, renderHelp } from '../lib/cli-output.js';
2
+ import { t } from '../lib/i18n.js';
3
+ import { formatCliOptionParseError, hasCliOptionToken, hasParsedCliOption, parseCliOptions, } from '../lib/option-parser.js';
4
+ import { resolveMustflowRoot } from '../lib/project-root.js';
5
+ import { checkRepoApprovalGate, REPO_APPROVAL_GATE_SCRIPT_REF, } from '../../core/repo-approval-gate.js';
6
+ const REPO_APPROVAL_GATE_OPTIONS = [
7
+ { name: '--json', kind: 'boolean' },
8
+ { name: '--action', kind: 'string' },
9
+ ];
10
+ export function getRepoApprovalGateHelp(lang = 'en') {
11
+ return renderHelp({
12
+ usage: 'mf script-pack run repo/approval-gate check --action <type> [options]',
13
+ summary: t(lang, 'approvalGate.help.summary'),
14
+ options: [
15
+ { label: '--action <type>', description: t(lang, 'approvalGate.help.option.action') },
16
+ { label: '--json', description: t(lang, 'cli.option.json') },
17
+ { label: '-h, --help', description: t(lang, 'cli.option.help') },
18
+ ],
19
+ examples: [
20
+ 'mf script-pack run repo/approval-gate check --action git_commit',
21
+ 'mf script-pack run repo/approval-gate check --action dependency_install --json',
22
+ ],
23
+ exitCodes: [
24
+ { label: '0', description: t(lang, 'approvalGate.help.exit.ok') },
25
+ { label: '1', description: t(lang, 'approvalGate.help.exit.fail') },
26
+ ],
27
+ }, lang);
28
+ }
29
+ function parsedStringOccurrences(parsed, name) {
30
+ return parsed.occurrences
31
+ .filter((occurrence) => occurrence.name === name && typeof occurrence.value === 'string')
32
+ .map((occurrence) => String(occurrence.value));
33
+ }
34
+ function parseRepoApprovalGateOptions(args, lang) {
35
+ const [action, ...rest] = args;
36
+ const parsed = parseCliOptions(rest, REPO_APPROVAL_GATE_OPTIONS, { allowPositionals: false });
37
+ const json = hasParsedCliOption(parsed, '--json');
38
+ const actionTypes = parsedStringOccurrences(parsed, '--action').map((entry) => entry.trim()).filter(Boolean);
39
+ if (action !== 'check') {
40
+ return {
41
+ action: 'check',
42
+ json,
43
+ actionTypes,
44
+ error: action
45
+ ? t(lang, 'approvalGate.error.unknownAction', { action })
46
+ : t(lang, 'approvalGate.error.missingAction'),
47
+ };
48
+ }
49
+ if (parsed.error) {
50
+ return { action, json, actionTypes, error: formatCliOptionParseError(parsed.error, lang) };
51
+ }
52
+ if (actionTypes.length === 0) {
53
+ return { action, json, actionTypes, error: t(lang, 'approvalGate.error.missingActionType') };
54
+ }
55
+ return { action, json, actionTypes };
56
+ }
57
+ function renderRepoApprovalGateSummary(report, lang) {
58
+ const lines = [
59
+ t(lang, 'approvalGate.title'),
60
+ `${t(lang, 'scriptPack.label.script')}: ${REPO_APPROVAL_GATE_SCRIPT_REF}`,
61
+ `${t(lang, 'label.status')}: ${report.status}`,
62
+ `${t(lang, 'approvalGate.label.approvalRequired')}: ${report.approval_required ? t(lang, 'value.yes') : t(lang, 'value.no')}`,
63
+ `${t(lang, 'approvalGate.label.configuredRequiredActions')}: ${report.policy.required_for.length}`,
64
+ ];
65
+ if (report.decisions.length > 0) {
66
+ lines.push(t(lang, 'approvalGate.label.decisions'));
67
+ for (const decision of report.decisions) {
68
+ const state = decision.approval_required ? t(lang, 'value.yes') : t(lang, 'value.no');
69
+ lines.push(`- ${decision.action_type}: ${state} (${decision.reason})`);
70
+ }
71
+ }
72
+ if (report.findings.length > 0) {
73
+ lines.push(t(lang, 'approvalGate.label.findings'));
74
+ for (const finding of report.findings) {
75
+ lines.push(`- ${finding.code}: ${finding.message}`);
76
+ }
77
+ }
78
+ if (report.issues.length > 0) {
79
+ lines.push(t(lang, 'approvalGate.label.issues'), ...report.issues.map((issue) => `- ${issue}`));
80
+ }
81
+ return lines.join('\n');
82
+ }
83
+ export function runRepoApprovalGateScript(args, reporter, lang = 'en') {
84
+ if (hasCliOptionToken(args, '--help', ['-h'])) {
85
+ reporter.stdout(getRepoApprovalGateHelp(lang));
86
+ return 0;
87
+ }
88
+ const options = parseRepoApprovalGateOptions(args, lang);
89
+ if (options.error) {
90
+ printUsageError(reporter, options.error, 'mf script-pack run repo/approval-gate --help', getRepoApprovalGateHelp(lang), lang);
91
+ return 1;
92
+ }
93
+ const report = checkRepoApprovalGate(resolveMustflowRoot(), options.actionTypes);
94
+ if (options.json) {
95
+ reporter.stdout(JSON.stringify(report, null, 2));
96
+ return report.ok ? 0 : 1;
97
+ }
98
+ reporter.stdout(renderRepoApprovalGateSummary(report, lang));
99
+ return report.ok ? 0 : 1;
100
+ }
@@ -0,0 +1,119 @@
1
+ import { printUsageError, renderHelp } from '../lib/cli-output.js';
2
+ import { t } from '../lib/i18n.js';
3
+ import { formatCliOptionParseError, getParsedCliStringOption, hasCliOptionToken, hasParsedCliOption, parseCliOptions, } from '../lib/option-parser.js';
4
+ import { resolveMustflowRoot } from '../lib/project-root.js';
5
+ import { auditRepoGitIgnore, REPO_GIT_IGNORE_AUDIT_SCRIPT_REF, } from '../../core/repo-git-ignore-audit.js';
6
+ const REPO_GIT_IGNORE_AUDIT_OPTIONS = [
7
+ { name: '--json', kind: 'boolean' },
8
+ { name: '--max-paths', kind: 'string' },
9
+ ];
10
+ export function getRepoGitIgnoreAuditHelp(lang = 'en') {
11
+ return renderHelp({
12
+ usage: 'mf script-pack run repo/git-ignore-audit audit [path...] [options]',
13
+ summary: t(lang, 'gitIgnoreAudit.help.summary'),
14
+ options: [
15
+ { label: '--max-paths <n>', description: t(lang, 'gitIgnoreAudit.help.option.maxPaths') },
16
+ { label: '--json', description: t(lang, 'cli.option.json') },
17
+ { label: '-h, --help', description: t(lang, 'cli.option.help') },
18
+ ],
19
+ examples: [
20
+ 'mf script-pack run repo/git-ignore-audit audit --json',
21
+ 'mf script-pack run repo/git-ignore-audit audit .env.local dist/app.js --json',
22
+ ],
23
+ exitCodes: [
24
+ { label: '0', description: t(lang, 'gitIgnoreAudit.help.exit.ok') },
25
+ { label: '1', description: t(lang, 'gitIgnoreAudit.help.exit.fail') },
26
+ ],
27
+ }, lang);
28
+ }
29
+ function parsePositiveInteger(value, label, lang) {
30
+ if (value === undefined) {
31
+ return undefined;
32
+ }
33
+ const parsed = Number(value);
34
+ if (!Number.isInteger(parsed) || parsed <= 0) {
35
+ return t(lang, 'gitIgnoreAudit.error.invalidPositiveInteger', { option: label });
36
+ }
37
+ return parsed;
38
+ }
39
+ function parseRepoGitIgnoreAuditOptions(args, lang) {
40
+ const [action, ...rest] = args;
41
+ const parsed = parseCliOptions(rest, REPO_GIT_IGNORE_AUDIT_OPTIONS, { allowPositionals: true });
42
+ const json = hasParsedCliOption(parsed, '--json');
43
+ if (action !== 'audit') {
44
+ return {
45
+ action: 'audit',
46
+ paths: parsed.positionals,
47
+ json,
48
+ error: action
49
+ ? t(lang, 'gitIgnoreAudit.error.unknownAction', { action })
50
+ : t(lang, 'gitIgnoreAudit.error.missingAction'),
51
+ };
52
+ }
53
+ if (parsed.error) {
54
+ return { action, paths: parsed.positionals, json, error: formatCliOptionParseError(parsed.error, lang) };
55
+ }
56
+ const maxPaths = parsePositiveInteger(getParsedCliStringOption(parsed, '--max-paths') ?? undefined, '--max-paths', lang);
57
+ if (typeof maxPaths === 'string') {
58
+ return { action, paths: parsed.positionals, json, error: maxPaths };
59
+ }
60
+ return {
61
+ action,
62
+ paths: parsed.positionals,
63
+ json,
64
+ maxPaths,
65
+ };
66
+ }
67
+ function renderRepoGitIgnoreAuditSummary(report, lang) {
68
+ const lines = [
69
+ t(lang, 'gitIgnoreAudit.title'),
70
+ `${t(lang, 'scriptPack.label.script')}: ${REPO_GIT_IGNORE_AUDIT_SCRIPT_REF}`,
71
+ `${t(lang, 'label.status')}: ${report.status}`,
72
+ `${t(lang, 'gitIgnoreAudit.label.pathsChecked')}: ${report.summary.paths_checked}`,
73
+ `${t(lang, 'gitIgnoreAudit.label.ignoredPaths')}: ${report.summary.ignored_paths}`,
74
+ `${t(lang, 'gitIgnoreAudit.label.ignoreSources')}: ${report.summary.ignore_sources}`,
75
+ ];
76
+ if (report.paths.length > 0) {
77
+ lines.push(t(lang, 'gitIgnoreAudit.label.paths'));
78
+ for (const entry of report.paths) {
79
+ const evidence = entry.source_path && entry.source_line
80
+ ? ` (${entry.source_path}:${entry.source_line} ${entry.pattern ?? ''})`
81
+ : '';
82
+ lines.push(`- ${entry.path}: ${entry.status}${evidence}`);
83
+ }
84
+ }
85
+ if (report.findings.length > 0) {
86
+ lines.push(t(lang, 'gitIgnoreAudit.label.findings'));
87
+ for (const finding of report.findings) {
88
+ lines.push(`- ${finding.path}: ${finding.code} (${finding.message})`);
89
+ }
90
+ }
91
+ if (report.issues.length > 0) {
92
+ lines.push(t(lang, 'gitIgnoreAudit.label.issues'), ...report.issues.map((issue) => `- ${issue}`));
93
+ }
94
+ if (report.paths.length === 0 && report.findings.length === 0 && report.issues.length === 0) {
95
+ lines.push(t(lang, 'gitIgnoreAudit.clean'));
96
+ }
97
+ return lines.join('\n');
98
+ }
99
+ export function runRepoGitIgnoreAuditScript(args, reporter, lang = 'en') {
100
+ if (hasCliOptionToken(args, '--help', ['-h'])) {
101
+ reporter.stdout(getRepoGitIgnoreAuditHelp(lang));
102
+ return 0;
103
+ }
104
+ const options = parseRepoGitIgnoreAuditOptions(args, lang);
105
+ if (options.error) {
106
+ printUsageError(reporter, options.error, 'mf script-pack run repo/git-ignore-audit --help', getRepoGitIgnoreAuditHelp(lang), lang);
107
+ return 1;
108
+ }
109
+ const report = auditRepoGitIgnore(resolveMustflowRoot(), {
110
+ paths: options.paths,
111
+ maxPaths: options.maxPaths,
112
+ });
113
+ if (options.json) {
114
+ reporter.stdout(JSON.stringify(report, null, 2));
115
+ return report.ok ? 0 : 1;
116
+ }
117
+ reporter.stdout(renderRepoGitIgnoreAuditSummary(report, lang));
118
+ return report.ok ? 0 : 1;
119
+ }
@@ -0,0 +1,122 @@
1
+ import { printUsageError, renderHelp } from '../lib/cli-output.js';
2
+ import { t } from '../lib/i18n.js';
3
+ import { formatCliOptionParseError, getParsedCliStringOption, hasCliOptionToken, hasParsedCliOption, parseCliOptions, } from '../lib/option-parser.js';
4
+ import { resolveMustflowRoot } from '../lib/project-root.js';
5
+ import { checkRepoManifestLockDrift, REPO_MANIFEST_LOCK_DRIFT_SCRIPT_REF, } from '../../core/repo-manifest-lock-drift.js';
6
+ const REPO_MANIFEST_LOCK_DRIFT_OPTIONS = [
7
+ { name: '--json', kind: 'boolean' },
8
+ { name: '--max-entries', kind: 'string' },
9
+ ];
10
+ export function getRepoManifestLockDriftHelp(lang = 'en') {
11
+ return renderHelp({
12
+ usage: 'mf script-pack run repo/manifest-lock-drift check [path...] [options]',
13
+ summary: t(lang, 'manifestLockDrift.help.summary'),
14
+ options: [
15
+ { label: '--max-entries <n>', description: t(lang, 'manifestLockDrift.help.option.maxEntries') },
16
+ { label: '--json', description: t(lang, 'cli.option.json') },
17
+ { label: '-h, --help', description: t(lang, 'cli.option.help') },
18
+ ],
19
+ examples: [
20
+ 'mf script-pack run repo/manifest-lock-drift check --json',
21
+ 'mf script-pack run repo/manifest-lock-drift check AGENTS.md .mustflow/config/commands.toml --json',
22
+ ],
23
+ exitCodes: [
24
+ { label: '0', description: t(lang, 'manifestLockDrift.help.exit.ok') },
25
+ { label: '1', description: t(lang, 'manifestLockDrift.help.exit.fail') },
26
+ ],
27
+ }, lang);
28
+ }
29
+ function parsePositiveInteger(value, label, lang) {
30
+ if (value === undefined) {
31
+ return undefined;
32
+ }
33
+ const parsed = Number(value);
34
+ if (!Number.isInteger(parsed) || parsed <= 0) {
35
+ return t(lang, 'manifestLockDrift.error.invalidPositiveInteger', { option: label });
36
+ }
37
+ return parsed;
38
+ }
39
+ function parseRepoManifestLockDriftOptions(args, lang) {
40
+ const [action, ...rest] = args;
41
+ const parsed = parseCliOptions(rest, REPO_MANIFEST_LOCK_DRIFT_OPTIONS, { allowPositionals: true });
42
+ const json = hasParsedCliOption(parsed, '--json');
43
+ if (action !== 'check') {
44
+ return {
45
+ action: 'check',
46
+ paths: parsed.positionals,
47
+ json,
48
+ error: action
49
+ ? t(lang, 'manifestLockDrift.error.unknownAction', { action })
50
+ : t(lang, 'manifestLockDrift.error.missingAction'),
51
+ };
52
+ }
53
+ if (parsed.error) {
54
+ return { action, paths: parsed.positionals, json, error: formatCliOptionParseError(parsed.error, lang) };
55
+ }
56
+ const maxEntries = parsePositiveInteger(getParsedCliStringOption(parsed, '--max-entries') ?? undefined, '--max-entries', lang);
57
+ if (typeof maxEntries === 'string') {
58
+ return { action, paths: parsed.positionals, json, error: maxEntries };
59
+ }
60
+ return {
61
+ action,
62
+ paths: parsed.positionals,
63
+ json,
64
+ maxEntries,
65
+ };
66
+ }
67
+ function renderRepoManifestLockDriftSummary(report, lang) {
68
+ const lines = [
69
+ t(lang, 'manifestLockDrift.title'),
70
+ `${t(lang, 'scriptPack.label.script')}: ${REPO_MANIFEST_LOCK_DRIFT_SCRIPT_REF}`,
71
+ `${t(lang, 'label.status')}: ${report.status}`,
72
+ `${t(lang, 'manifestLockDrift.label.entriesChecked')}: ${report.summary.entries_checked}`,
73
+ `${t(lang, 'manifestLockDrift.label.hashMismatches')}: ${report.summary.hash_mismatches}`,
74
+ `${t(lang, 'manifestLockDrift.label.missingEntries')}: ${report.summary.missing_entries}`,
75
+ ];
76
+ if (report.entries.length > 0) {
77
+ lines.push(t(lang, 'manifestLockDrift.label.entries'));
78
+ for (const entry of report.entries) {
79
+ if (entry.status === 'skipped') {
80
+ continue;
81
+ }
82
+ const evidence = entry.lock_hash && entry.actual_hash && entry.lock_hash !== entry.actual_hash
83
+ ? ` (${entry.lock_hash} != ${entry.actual_hash})`
84
+ : '';
85
+ lines.push(`- ${entry.path}: ${entry.status}${evidence}`);
86
+ }
87
+ }
88
+ if (report.findings.length > 0) {
89
+ lines.push(t(lang, 'manifestLockDrift.label.findings'));
90
+ for (const finding of report.findings) {
91
+ lines.push(`- ${finding.path}: ${finding.code} (${finding.message})`);
92
+ }
93
+ }
94
+ if (report.issues.length > 0) {
95
+ lines.push(t(lang, 'manifestLockDrift.label.issues'), ...report.issues.map((issue) => `- ${issue}`));
96
+ }
97
+ if (report.findings.length === 0 && report.issues.length === 0) {
98
+ lines.push(t(lang, 'manifestLockDrift.clean'));
99
+ }
100
+ return lines.join('\n');
101
+ }
102
+ export function runRepoManifestLockDriftScript(args, reporter, lang = 'en') {
103
+ if (hasCliOptionToken(args, '--help', ['-h'])) {
104
+ reporter.stdout(getRepoManifestLockDriftHelp(lang));
105
+ return 0;
106
+ }
107
+ const options = parseRepoManifestLockDriftOptions(args, lang);
108
+ if (options.error) {
109
+ printUsageError(reporter, options.error, 'mf script-pack run repo/manifest-lock-drift --help', getRepoManifestLockDriftHelp(lang), lang);
110
+ return 1;
111
+ }
112
+ const report = checkRepoManifestLockDrift(resolveMustflowRoot(), {
113
+ paths: options.paths,
114
+ maxEntries: options.maxEntries,
115
+ });
116
+ if (options.json) {
117
+ reporter.stdout(JSON.stringify(report, null, 2));
118
+ return report.ok ? 0 : 1;
119
+ }
120
+ reporter.stdout(renderRepoManifestLockDriftSummary(report, lang));
121
+ return report.ok ? 0 : 1;
122
+ }
@@ -0,0 +1,123 @@
1
+ import { printUsageError, renderHelp } from '../lib/cli-output.js';
2
+ import { t } from '../lib/i18n.js';
3
+ import { formatCliOptionParseError, getParsedCliStringOption, hasCliOptionToken, hasParsedCliOption, parseCliOptions, } from '../lib/option-parser.js';
4
+ import { resolveMustflowRoot } from '../lib/project-root.js';
5
+ import { checkRepoMergeConflictScan, REPO_MERGE_CONFLICT_SCAN_SCRIPT_REF, } from '../../core/repo-merge-conflict-scan.js';
6
+ const REPO_MERGE_CONFLICT_SCAN_OPTIONS = [
7
+ { name: '--json', kind: 'boolean' },
8
+ { name: '--max-files', kind: 'string' },
9
+ { name: '--max-file-bytes', kind: 'string' },
10
+ ];
11
+ export function getRepoMergeConflictScanHelp(lang = 'en') {
12
+ return renderHelp({
13
+ usage: 'mf script-pack run repo/merge-conflict-scan check [path...] [options]',
14
+ summary: t(lang, 'mergeConflictScan.help.summary'),
15
+ options: [
16
+ { label: '--max-files <n>', description: t(lang, 'mergeConflictScan.help.option.maxFiles') },
17
+ { label: '--max-file-bytes <n>', description: t(lang, 'mergeConflictScan.help.option.maxFileBytes') },
18
+ { label: '--json', description: t(lang, 'cli.option.json') },
19
+ { label: '-h, --help', description: t(lang, 'cli.option.help') },
20
+ ],
21
+ examples: [
22
+ 'mf script-pack run repo/merge-conflict-scan check --json',
23
+ 'mf script-pack run repo/merge-conflict-scan check src README.md --json',
24
+ ],
25
+ exitCodes: [
26
+ { label: '0', description: t(lang, 'mergeConflictScan.help.exit.ok') },
27
+ { label: '1', description: t(lang, 'mergeConflictScan.help.exit.fail') },
28
+ ],
29
+ }, lang);
30
+ }
31
+ function parsePositiveInteger(value, label, lang) {
32
+ if (value === undefined) {
33
+ return undefined;
34
+ }
35
+ const parsed = Number(value);
36
+ if (!Number.isInteger(parsed) || parsed <= 0) {
37
+ return t(lang, 'mergeConflictScan.error.invalidPositiveInteger', { option: label });
38
+ }
39
+ return parsed;
40
+ }
41
+ function parseRepoMergeConflictScanOptions(args, lang) {
42
+ const [action, ...rest] = args;
43
+ const parsed = parseCliOptions(rest, REPO_MERGE_CONFLICT_SCAN_OPTIONS, { allowPositionals: true });
44
+ const json = hasParsedCliOption(parsed, '--json');
45
+ if (action !== 'check') {
46
+ return {
47
+ action: 'check',
48
+ paths: parsed.positionals,
49
+ json,
50
+ error: action
51
+ ? t(lang, 'mergeConflictScan.error.unknownAction', { action })
52
+ : t(lang, 'mergeConflictScan.error.missingAction'),
53
+ };
54
+ }
55
+ if (parsed.error) {
56
+ return { action, paths: parsed.positionals, json, error: formatCliOptionParseError(parsed.error, lang) };
57
+ }
58
+ const maxFiles = parsePositiveInteger(getParsedCliStringOption(parsed, '--max-files') ?? undefined, '--max-files', lang);
59
+ if (typeof maxFiles === 'string') {
60
+ return { action, paths: parsed.positionals, json, error: maxFiles };
61
+ }
62
+ const maxFileBytes = parsePositiveInteger(getParsedCliStringOption(parsed, '--max-file-bytes') ?? undefined, '--max-file-bytes', lang);
63
+ if (typeof maxFileBytes === 'string') {
64
+ return { action, paths: parsed.positionals, json, error: maxFileBytes };
65
+ }
66
+ return {
67
+ action,
68
+ paths: parsed.positionals,
69
+ json,
70
+ maxFiles,
71
+ maxFileBytes,
72
+ };
73
+ }
74
+ function renderRepoMergeConflictScanSummary(report, lang) {
75
+ const lines = [
76
+ t(lang, 'mergeConflictScan.title'),
77
+ `${t(lang, 'scriptPack.label.script')}: ${REPO_MERGE_CONFLICT_SCAN_SCRIPT_REF}`,
78
+ `${t(lang, 'label.status')}: ${report.status}`,
79
+ `${t(lang, 'mergeConflictScan.label.filesChecked')}: ${report.summary.files_checked}`,
80
+ `${t(lang, 'mergeConflictScan.label.markersFound')}: ${report.summary.markers_found}`,
81
+ ];
82
+ if (report.markers.length > 0) {
83
+ lines.push(t(lang, 'mergeConflictScan.label.markers'));
84
+ for (const marker of report.markers) {
85
+ lines.push(`- ${marker.path}:${marker.line}:${marker.column} ${marker.marker}`);
86
+ }
87
+ }
88
+ if (report.findings.length > 0) {
89
+ lines.push(t(lang, 'mergeConflictScan.label.findings'));
90
+ for (const finding of report.findings) {
91
+ lines.push(`- ${finding.path}: ${finding.code} (${finding.message})`);
92
+ }
93
+ }
94
+ if (report.issues.length > 0) {
95
+ lines.push(t(lang, 'mergeConflictScan.label.issues'), ...report.issues.map((issue) => `- ${issue}`));
96
+ }
97
+ if (report.markers.length === 0 && report.issues.length === 0) {
98
+ lines.push(t(lang, 'mergeConflictScan.clean'));
99
+ }
100
+ return lines.join('\n');
101
+ }
102
+ export function runRepoMergeConflictScanScript(args, reporter, lang = 'en') {
103
+ if (hasCliOptionToken(args, '--help', ['-h'])) {
104
+ reporter.stdout(getRepoMergeConflictScanHelp(lang));
105
+ return 0;
106
+ }
107
+ const options = parseRepoMergeConflictScanOptions(args, lang);
108
+ if (options.error) {
109
+ printUsageError(reporter, options.error, 'mf script-pack run repo/merge-conflict-scan --help', getRepoMergeConflictScanHelp(lang), lang);
110
+ return 1;
111
+ }
112
+ const report = checkRepoMergeConflictScan(resolveMustflowRoot(), {
113
+ paths: options.paths,
114
+ maxFiles: options.maxFiles,
115
+ maxFileBytes: options.maxFileBytes,
116
+ });
117
+ if (options.json) {
118
+ reporter.stdout(JSON.stringify(report, null, 2));
119
+ return report.ok ? 0 : 1;
120
+ }
121
+ reporter.stdout(renderRepoMergeConflictScanSummary(report, lang));
122
+ return report.ok ? 0 : 1;
123
+ }
@@ -0,0 +1,86 @@
1
+ import { printUsageError, renderHelp } from '../lib/cli-output.js';
2
+ import { t } from '../lib/i18n.js';
3
+ import { formatCliOptionParseError, hasCliOptionToken, hasParsedCliOption, parseCliOptions, } from '../lib/option-parser.js';
4
+ import { resolveMustflowRoot } from '../lib/project-root.js';
5
+ import { auditSkillRoutes, SKILL_ROUTE_AUDIT_SCRIPT_REF, } from '../../core/skill-route-audit.js';
6
+ const SKILL_ROUTE_AUDIT_OPTIONS = [{ name: '--json', kind: 'boolean' }];
7
+ export function getRepoSkillRouteAuditHelp(lang = 'en') {
8
+ return renderHelp({
9
+ usage: 'mf script-pack run repo/skill-route-audit audit [options]',
10
+ summary: t(lang, 'skillRouteAudit.help.summary'),
11
+ options: [
12
+ { label: '--json', description: t(lang, 'cli.option.json') },
13
+ { label: '-h, --help', description: t(lang, 'cli.option.help') },
14
+ ],
15
+ examples: [
16
+ 'mf script-pack run repo/skill-route-audit audit',
17
+ 'mf script-pack run repo/skill-route-audit audit --json',
18
+ ],
19
+ exitCodes: [
20
+ { label: '0', description: t(lang, 'skillRouteAudit.help.exit.ok') },
21
+ { label: '1', description: t(lang, 'skillRouteAudit.help.exit.fail') },
22
+ ],
23
+ }, lang);
24
+ }
25
+ function parseSkillRouteAuditOptions(args, lang) {
26
+ const [action, ...rest] = args;
27
+ const parsed = parseCliOptions(rest, SKILL_ROUTE_AUDIT_OPTIONS, { allowPositionals: false });
28
+ const json = hasParsedCliOption(parsed, '--json');
29
+ if (action !== 'audit') {
30
+ return {
31
+ action: 'audit',
32
+ json,
33
+ error: action
34
+ ? t(lang, 'skillRouteAudit.error.unknownAction', { action })
35
+ : t(lang, 'skillRouteAudit.error.missingAction'),
36
+ };
37
+ }
38
+ if (parsed.error) {
39
+ return { action, json, error: formatCliOptionParseError(parsed.error, lang) };
40
+ }
41
+ return { action, json };
42
+ }
43
+ function renderSkillRouteAuditSummary(report, lang) {
44
+ const lines = [
45
+ t(lang, 'skillRouteAudit.title'),
46
+ `${t(lang, 'scriptPack.label.script')}: ${SKILL_ROUTE_AUDIT_SCRIPT_REF}`,
47
+ `${t(lang, 'label.status')}: ${report.status}`,
48
+ `${t(lang, 'skillRouteAudit.label.sourceSkills')}: ${report.counts.source_skills}`,
49
+ `${t(lang, 'skillRouteAudit.label.routeMetadata')}: ${report.counts.route_metadata}`,
50
+ `${t(lang, 'skillRouteAudit.label.indexRoutes')}: ${report.counts.index_routes}`,
51
+ `${t(lang, 'skillRouteAudit.label.templateSkills')}: ${report.counts.template_skills}`,
52
+ `${t(lang, 'skillRouteAudit.label.findings')}: ${report.findings.length}`,
53
+ ];
54
+ if (report.findings.length > 0) {
55
+ lines.push(t(lang, 'skillRouteAudit.label.findings'));
56
+ for (const finding of report.findings) {
57
+ const target = finding.skill ?? finding.route ?? finding.path;
58
+ lines.push(`- ${target}: ${finding.code} (${finding.message})`);
59
+ }
60
+ }
61
+ if (report.issues.length > 0) {
62
+ lines.push(t(lang, 'generatedBoundary.label.issues'), ...report.issues.map((issue) => `- ${issue}`));
63
+ }
64
+ if (report.findings.length === 0 && report.issues.length === 0) {
65
+ lines.push(t(lang, 'skillRouteAudit.clean'));
66
+ }
67
+ return lines.join('\n');
68
+ }
69
+ export function runRepoSkillRouteAuditScript(args, reporter, lang = 'en') {
70
+ if (hasCliOptionToken(args, '--help', ['-h'])) {
71
+ reporter.stdout(getRepoSkillRouteAuditHelp(lang));
72
+ return 0;
73
+ }
74
+ const options = parseSkillRouteAuditOptions(args, lang);
75
+ if (options.error) {
76
+ printUsageError(reporter, options.error, 'mf script-pack run repo/skill-route-audit --help', getRepoSkillRouteAuditHelp(lang), lang);
77
+ return 1;
78
+ }
79
+ const report = auditSkillRoutes(resolveMustflowRoot());
80
+ if (options.json) {
81
+ reporter.stdout(JSON.stringify(report, null, 2));
82
+ return report.ok ? 0 : 1;
83
+ }
84
+ reporter.stdout(renderSkillRouteAuditSummary(report, lang));
85
+ return report.ok ? 0 : 1;
86
+ }
@@ -0,0 +1,92 @@
1
+ import { printUsageError, renderHelp } from '../lib/cli-output.js';
2
+ import { t } from '../lib/i18n.js';
3
+ import { formatCliOptionParseError, hasCliOptionToken, hasParsedCliOption, parseCliOptions, } from '../lib/option-parser.js';
4
+ import { resolveMustflowRoot } from '../lib/project-root.js';
5
+ import { inspectRepoVersionSource, REPO_VERSION_SOURCE_SCRIPT_REF, } from '../../core/repo-version-source.js';
6
+ const REPO_VERSION_SOURCE_OPTIONS = [{ name: '--json', kind: 'boolean' }];
7
+ export function getRepoVersionSourceHelp(lang = 'en') {
8
+ return renderHelp({
9
+ usage: 'mf script-pack run repo/version-source inspect [options]',
10
+ summary: t(lang, 'versionSource.help.summary'),
11
+ options: [
12
+ { label: '--json', description: t(lang, 'cli.option.json') },
13
+ { label: '-h, --help', description: t(lang, 'cli.option.help') },
14
+ ],
15
+ examples: [
16
+ 'mf script-pack run repo/version-source inspect',
17
+ 'mf script-pack run repo/version-source inspect --json',
18
+ ],
19
+ exitCodes: [
20
+ { label: '0', description: t(lang, 'versionSource.help.exit.ok') },
21
+ { label: '1', description: t(lang, 'versionSource.help.exit.fail') },
22
+ ],
23
+ }, lang);
24
+ }
25
+ function parseRepoVersionSourceOptions(args, lang) {
26
+ const [action, ...rest] = args;
27
+ const parsed = parseCliOptions(rest, REPO_VERSION_SOURCE_OPTIONS, { allowPositionals: false });
28
+ const json = hasParsedCliOption(parsed, '--json');
29
+ if (action !== 'inspect') {
30
+ return {
31
+ action: 'inspect',
32
+ json,
33
+ error: action
34
+ ? t(lang, 'versionSource.error.unknownAction', { action })
35
+ : t(lang, 'versionSource.error.missingAction'),
36
+ };
37
+ }
38
+ if (parsed.error) {
39
+ return { action, json, error: formatCliOptionParseError(parsed.error, lang) };
40
+ }
41
+ return { action, json };
42
+ }
43
+ function renderRepoVersionSourceSummary(report, lang) {
44
+ const authorityParts = [
45
+ `source ${report.counts.source_authority_sources}`,
46
+ `derived ${report.counts.derived_authority_sources}`,
47
+ `unclassified ${report.counts.unclassified_authority_sources}`,
48
+ ];
49
+ const lines = [
50
+ t(lang, 'versionSource.title'),
51
+ `${t(lang, 'scriptPack.label.script')}: ${REPO_VERSION_SOURCE_SCRIPT_REF}`,
52
+ `${t(lang, 'label.status')}: ${report.status}`,
53
+ `${t(lang, 'versionSource.label.versioning')}: ${report.versioning_enabled ? t(lang, 'versionSources.value.enabled') : t(lang, 'versionSources.value.disabled')}`,
54
+ `${t(lang, 'versionSource.label.sources')}: ${report.counts.sources}`,
55
+ `${t(lang, 'versionSource.label.sourceAuthorities')}: ${authorityParts.join(', ')}`,
56
+ ];
57
+ for (const source of report.sources) {
58
+ const metadata = [source.kind, source.declared ? 'declared' : undefined, source.authority].filter(Boolean).join(', ');
59
+ lines.push(`- ${source.path} (${metadata})`);
60
+ }
61
+ if (report.findings.length > 0) {
62
+ lines.push(t(lang, 'versionSource.label.findings'));
63
+ for (const finding of report.findings) {
64
+ lines.push(`- ${finding.path}: ${finding.code} (${finding.message})`);
65
+ }
66
+ }
67
+ if (report.issues.length > 0) {
68
+ lines.push(t(lang, 'versionSource.label.issues'), ...report.issues.map((issue) => `- ${issue}`));
69
+ }
70
+ if (report.sources.length === 0 && report.findings.length === 0 && report.issues.length === 0) {
71
+ lines.push(t(lang, 'versionSources.noSources'));
72
+ }
73
+ return lines.join('\n');
74
+ }
75
+ export function runRepoVersionSourceScript(args, reporter, lang = 'en') {
76
+ if (hasCliOptionToken(args, '--help', ['-h'])) {
77
+ reporter.stdout(getRepoVersionSourceHelp(lang));
78
+ return 0;
79
+ }
80
+ const options = parseRepoVersionSourceOptions(args, lang);
81
+ if (options.error) {
82
+ printUsageError(reporter, options.error, 'mf script-pack run repo/version-source --help', getRepoVersionSourceHelp(lang), lang);
83
+ return 1;
84
+ }
85
+ const report = inspectRepoVersionSource(resolveMustflowRoot());
86
+ if (options.json) {
87
+ reporter.stdout(JSON.stringify(report, null, 2));
88
+ return report.ok ? 0 : 1;
89
+ }
90
+ reporter.stdout(renderRepoVersionSourceSummary(report, lang));
91
+ return report.ok ? 0 : 1;
92
+ }