mustflow 2.75.1 → 2.84.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.
- package/README.md +31 -3
- package/dist/cli/commands/docs.js +86 -2
- package/dist/cli/commands/script-pack.js +5 -0
- package/dist/cli/i18n/en.js +101 -2
- package/dist/cli/i18n/es.js +101 -2
- package/dist/cli/i18n/fr.js +101 -2
- package/dist/cli/i18n/hi.js +101 -2
- package/dist/cli/i18n/ko.js +101 -2
- package/dist/cli/i18n/zh.js +101 -2
- package/dist/cli/lib/script-pack-registry.js +162 -7
- package/dist/cli/script-packs/code-export-diff.js +160 -0
- package/dist/cli/script-packs/code-outline.js +33 -5
- package/dist/cli/script-packs/code-route-outline.js +155 -0
- package/dist/cli/script-packs/docs-reference-drift.js +150 -0
- package/dist/cli/script-packs/repo-config-chain.js +163 -0
- package/dist/cli/script-packs/repo-related-files.js +161 -0
- package/dist/core/code-outline.js +527 -80
- package/dist/core/config-chain.js +595 -0
- package/dist/core/export-diff.js +359 -0
- package/dist/core/public-json-contracts.js +75 -0
- package/dist/core/reference-drift.js +388 -0
- package/dist/core/related-files.js +493 -0
- package/dist/core/route-outline.js +912 -0
- package/dist/core/script-pack-suggestions.js +111 -5
- package/dist/core/source-anchors.js +13 -1
- package/package.json +1 -1
- package/schemas/README.md +28 -5
- package/schemas/code-outline-report.schema.json +47 -1
- package/schemas/code-symbol-read-report.schema.json +64 -4
- package/schemas/config-chain-report.schema.json +187 -0
- package/schemas/export-diff-report.schema.json +220 -0
- package/schemas/reference-drift-report.schema.json +166 -0
- package/schemas/related-files-report.schema.json +145 -0
- package/schemas/route-outline-report.schema.json +200 -0
- package/templates/default/common/.mustflow/config/commands.toml +21 -0
- package/templates/default/i18n.toml +7 -1
- package/templates/default/locales/en/.mustflow/docs/agent-workflow.md +1 -1
- package/templates/default/locales/en/.mustflow/skills/INDEX.md +2 -1
- package/templates/default/locales/en/.mustflow/skills/cross-agent-session-reference/SKILL.md +131 -0
- package/templates/default/locales/en/.mustflow/skills/routes.toml +6 -0
- package/templates/default/manifest.toml +8 -1
package/dist/cli/i18n/zh.js
CHANGED
|
@@ -585,6 +585,7 @@ export const zhMessages = {
|
|
|
585
585
|
"docs.help.summary": "跟踪由 LLM 创建或修改后需要文字审阅的文档。",
|
|
586
586
|
"docs.help.option.all": "包含已批准和已忽略的文档",
|
|
587
587
|
"docs.help.option.status": "按审阅状态过滤",
|
|
588
|
+
"docs.help.option.changed": "从 git status 添加所有已更改的文档审阅候选项",
|
|
588
589
|
"docs.help.option.reason": "记录文档需要审阅的原因",
|
|
589
590
|
"docs.help.option.origin": "记录审阅来源,例如 llm_modified",
|
|
590
591
|
"docs.help.option.actorKind": "记录谁修改了文档:human、llm、tool 或 external",
|
|
@@ -600,6 +601,8 @@ export const zhMessages = {
|
|
|
600
601
|
"docs.review.empty": "没有需要审阅的文档。",
|
|
601
602
|
"docs.review.wrote": "写入",
|
|
602
603
|
"docs.review.added": "已添加",
|
|
604
|
+
"docs.review.changed.none": "没有已更改的文档需要审阅。",
|
|
605
|
+
"docs.review.changed.added": "已添加更改文档:{count}",
|
|
603
606
|
"docs.review.commented": "已添加评论",
|
|
604
607
|
"docs.review.marked.approved": "已批准",
|
|
605
608
|
"docs.review.marked.needs_human": "已标记为 needs_human",
|
|
@@ -612,6 +615,9 @@ export const zhMessages = {
|
|
|
612
615
|
"docs.error.emptyComment": "审核评论不能为空",
|
|
613
616
|
"docs.error.commentSourceConflict": "只能使用 --comment 或 --comment-file 其中一个",
|
|
614
617
|
"docs.error.commentFileIsDocument": "--comment-file 不能指向正在审核的文档",
|
|
618
|
+
"docs.error.changedPathConflict": "使用 --changed 时不要提供文档路径",
|
|
619
|
+
"docs.error.changedCommentConflict": "使用 --changed 时不要提供 --comment 或 --comment-file",
|
|
620
|
+
"docs.error.changedFilesUnavailable": "无法通过 git status 检查更改文件:{message}",
|
|
615
621
|
"docs.error.invalidStatus": "无效审阅状态。请使用:{statuses}",
|
|
616
622
|
"docs.error.invalidReviewerKind": "无效审阅者类型。请使用:{kinds}",
|
|
617
623
|
"docs.error.missingReviewerKind": "缺少 --reviewer-kind。请使用:{kinds}",
|
|
@@ -765,11 +771,17 @@ export const zhMessages = {
|
|
|
765
771
|
"scriptPack.suggest.empty": "No script-pack suggestions matched the supplied paths, skills, or phases.",
|
|
766
772
|
"scriptPack.pack.code.summary": "Source-code orientation utility scripts",
|
|
767
773
|
"scriptPack.pack.core.summary": "Core built-in utility scripts",
|
|
774
|
+
"scriptPack.pack.docs.summary": "Documentation reference utility scripts",
|
|
768
775
|
"scriptPack.pack.repo.summary": "Repository-boundary utility scripts",
|
|
769
776
|
"scriptPack.script.codeOutline.summary": "Scan TypeScript and JavaScript files for symbol headers and line ranges",
|
|
770
|
-
"scriptPack.script.codeSymbolRead.summary": "Read a bounded source snippet by symbol line or explicit line range",
|
|
777
|
+
"scriptPack.script.codeSymbolRead.summary": "Read a bounded source snippet by source anchor, symbol line, or explicit line range",
|
|
778
|
+
"scriptPack.script.codeRouteOutline.summary": "Scan Hono, Elysia, Axum, and NestJS route methods, paths, handlers, and lifecycle chains",
|
|
779
|
+
"scriptPack.script.codeExportDiff.summary": "Compare exported source signatures and return metadata across git refs",
|
|
771
780
|
"scriptPack.script.textBudget.summary": "Check exact text length budgets for files or JSON string fields",
|
|
781
|
+
"scriptPack.script.referenceDrift.summary": "Check documented command, script-pack, schema, and path references for drift",
|
|
782
|
+
"scriptPack.script.configChain.summary": "Inspect nearby config files and static config inheritance",
|
|
772
783
|
"scriptPack.script.generatedBoundary.summary": "Check whether candidate paths cross generated, ignored, protected, vendor, or cache boundaries",
|
|
784
|
+
"scriptPack.script.relatedFiles.summary": "Map likely related files for source-oriented repository navigation",
|
|
773
785
|
"scriptPack.label.script": "Script",
|
|
774
786
|
"scriptPack.label.actions": "actions",
|
|
775
787
|
"scriptPack.label.schema": "schema",
|
|
@@ -796,7 +808,8 @@ export const zhMessages = {
|
|
|
796
808
|
"codeOutline.error.missingPath": "Provide at least one source file or directory to scan",
|
|
797
809
|
"codeOutline.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
|
|
798
810
|
"codeOutline.error.invalidNonNegativeInteger": "{option} must be a non-negative safe integer: {value}",
|
|
799
|
-
"codeSymbolRead.help.summary": "Read a bounded TypeScript or JavaScript source snippet from a symbol line or explicit line range.",
|
|
811
|
+
"codeSymbolRead.help.summary": "Read a bounded TypeScript or JavaScript source snippet from a source anchor, symbol line, or explicit line range.",
|
|
812
|
+
"codeSymbolRead.help.option.anchor": "Source anchor id to resolve to its target symbol",
|
|
800
813
|
"codeSymbolRead.help.option.startLine": "1-based source line to resolve to a symbol or range",
|
|
801
814
|
"codeSymbolRead.help.option.endLine": "Optional explicit 1-based end line; when omitted, the containing outline symbol is read",
|
|
802
815
|
"codeSymbolRead.help.option.contextLines": "Number of surrounding context lines to include. Default: 0",
|
|
@@ -813,6 +826,56 @@ export const zhMessages = {
|
|
|
813
826
|
"codeSymbolRead.error.missingPath": "Provide exactly one source file to read",
|
|
814
827
|
"codeSymbolRead.error.tooManyPaths": "Provide only one source file to read",
|
|
815
828
|
"codeSymbolRead.error.missingStartLine": "Provide --start-line <line>",
|
|
829
|
+
"codeSymbolRead.error.anchorConflict": "Use either --anchor <id> or <path> with --start-line/--end-line, not both",
|
|
830
|
+
"codeRouteOutline.help.summary": "Scan Hono, Elysia, Axum, and NestJS route source files for method, path, handler, lifecycle, and line metadata.",
|
|
831
|
+
"codeRouteOutline.help.option.maxFiles": "Maximum number of source files to scan. Default: 200",
|
|
832
|
+
"codeRouteOutline.help.option.maxFileBytes": "Maximum bytes to read from each source file. Default: 1048576",
|
|
833
|
+
"codeRouteOutline.help.exit.ok": "The route outline was scanned without findings",
|
|
834
|
+
"codeRouteOutline.help.exit.fail": "The route outline found invalid input, unreadable files, unsupported files, or scan limits",
|
|
835
|
+
"codeRouteOutline.title": "mustflow route outline",
|
|
836
|
+
"codeRouteOutline.label.files": "Files",
|
|
837
|
+
"codeRouteOutline.label.routes": "Routes",
|
|
838
|
+
"codeRouteOutline.label.findings": "Findings",
|
|
839
|
+
"codeRouteOutline.label.outline": "Route outline",
|
|
840
|
+
"codeRouteOutline.label.issues": "Issues",
|
|
841
|
+
"codeRouteOutline.clean": "No Hono, Elysia, Axum, or NestJS routes were found.",
|
|
842
|
+
"codeRouteOutline.error.missingAction": "Specify a route-outline action: scan",
|
|
843
|
+
"codeRouteOutline.error.unknownAction": "Unknown route-outline action: {action}",
|
|
844
|
+
"codeRouteOutline.error.missingPath": "Provide at least one source file or directory to scan",
|
|
845
|
+
"codeRouteOutline.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
|
|
846
|
+
"exportDiff.help.summary": "Compare exported TS/JS signatures, return metadata, and package surface hints across a git base and head.",
|
|
847
|
+
"exportDiff.help.option.base": "Git base ref to compare from. Default: HEAD",
|
|
848
|
+
"exportDiff.help.option.head": "Git head ref to compare to. Omit to compare the base with the working tree.",
|
|
849
|
+
"exportDiff.help.option.maxFiles": "Maximum number of changed source files to inspect. Default: 100",
|
|
850
|
+
"exportDiff.help.option.maxFileBytes": "Maximum bytes to read from each source file snapshot. Default: 1048576",
|
|
851
|
+
"exportDiff.help.exit.ok": "The export diff completed without input errors",
|
|
852
|
+
"exportDiff.help.exit.fail": "The export diff could not read git input or exceeded configured limits",
|
|
853
|
+
"exportDiff.title": "mustflow export diff",
|
|
854
|
+
"exportDiff.label.files": "Files",
|
|
855
|
+
"exportDiff.label.added": "Added",
|
|
856
|
+
"exportDiff.label.removed": "Removed",
|
|
857
|
+
"exportDiff.label.changed": "Changed",
|
|
858
|
+
"exportDiff.label.exports": "Exports",
|
|
859
|
+
"exportDiff.label.findings": "Findings",
|
|
860
|
+
"exportDiff.label.issues": "Issues",
|
|
861
|
+
"exportDiff.clean": "No exported TypeScript or JavaScript declaration changes were found.",
|
|
862
|
+
"exportDiff.error.missingAction": "Specify an export-diff action: compare",
|
|
863
|
+
"exportDiff.error.unknownAction": "Unknown export-diff action: {action}",
|
|
864
|
+
"exportDiff.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
|
|
865
|
+
"referenceDrift.help.summary": "Check documentation references against current mf commands, script-pack refs, schema files, and repository paths.",
|
|
866
|
+
"referenceDrift.help.option.maxFiles": "Maximum number of document files to inspect. Default: 200",
|
|
867
|
+
"referenceDrift.help.option.maxFileBytes": "Maximum bytes to read from each document file. Default: 524288",
|
|
868
|
+
"referenceDrift.help.exit.ok": "All checked documentation references resolved against current repository surfaces",
|
|
869
|
+
"referenceDrift.help.exit.fail": "A documentation reference was stale, missing, unknown, unreadable, or over a configured limit",
|
|
870
|
+
"referenceDrift.title": "mustflow reference drift",
|
|
871
|
+
"referenceDrift.label.files": "Files",
|
|
872
|
+
"referenceDrift.label.references": "References",
|
|
873
|
+
"referenceDrift.label.findings": "Findings",
|
|
874
|
+
"referenceDrift.label.issues": "Issues",
|
|
875
|
+
"referenceDrift.clean": "No documentation references were found.",
|
|
876
|
+
"referenceDrift.error.missingAction": "Specify a reference-drift action: check",
|
|
877
|
+
"referenceDrift.error.unknownAction": "Unknown reference-drift action: {action}",
|
|
878
|
+
"referenceDrift.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
|
|
816
879
|
"textBudget.help.summary": "Check exact text length budgets for files or JSON string fields using grapheme counts by default.",
|
|
817
880
|
"textBudget.help.option.min": "Require at least this many units",
|
|
818
881
|
"textBudget.help.option.max": "Require at most this many units",
|
|
@@ -849,6 +912,42 @@ export const zhMessages = {
|
|
|
849
912
|
"generatedBoundary.error.missingAction": "Specify a generated-boundary action: check",
|
|
850
913
|
"generatedBoundary.error.unknownAction": "Unknown generated-boundary action: {action}",
|
|
851
914
|
"generatedBoundary.error.missingPath": "Provide at least one path to check",
|
|
915
|
+
"relatedFiles.help.summary": "Map direct imports, importers, sibling files, and nearby config boundaries for source-oriented repository navigation.",
|
|
916
|
+
"relatedFiles.help.option.maxFiles": "Maximum number of source or related files to scan. Default: 1000",
|
|
917
|
+
"relatedFiles.help.option.maxFileBytes": "Maximum bytes to read from each source file. Default: 262144",
|
|
918
|
+
"relatedFiles.help.option.maxCandidates": "Maximum number of related-file candidates to report. Default: 200",
|
|
919
|
+
"relatedFiles.help.exit.ok": "The related-file map completed without input or scan-limit findings",
|
|
920
|
+
"relatedFiles.help.exit.fail": "The related-file map found invalid input, unreadable paths, or scan limits",
|
|
921
|
+
"relatedFiles.title": "mustflow related files",
|
|
922
|
+
"relatedFiles.label.targets": "Targets",
|
|
923
|
+
"relatedFiles.label.candidates": "Candidates",
|
|
924
|
+
"relatedFiles.label.truncated": "Truncated",
|
|
925
|
+
"relatedFiles.label.related": "Related files",
|
|
926
|
+
"relatedFiles.label.confidence": "confidence",
|
|
927
|
+
"relatedFiles.label.findings": "Findings",
|
|
928
|
+
"relatedFiles.label.issues": "Issues",
|
|
929
|
+
"relatedFiles.clean": "No related-file candidates were found.",
|
|
930
|
+
"relatedFiles.error.missingAction": "Specify a related-files action: map",
|
|
931
|
+
"relatedFiles.error.unknownAction": "Unknown related-files action: {action}",
|
|
932
|
+
"relatedFiles.error.missingPath": "Provide at least one path to map",
|
|
933
|
+
"relatedFiles.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
|
|
934
|
+
"configChain.help.summary": "Inspect nearby config files, static inheritance, workspace hints, and dynamic config boundaries.",
|
|
935
|
+
"configChain.help.option.maxConfigs": "Maximum number of config files to inspect. Default: 120",
|
|
936
|
+
"configChain.help.option.maxFileBytes": "Maximum bytes to read from each config file. Default: 262144",
|
|
937
|
+
"configChain.help.exit.ok": "The config chain was inspected without blocking findings",
|
|
938
|
+
"configChain.help.exit.fail": "The config chain found invalid input, unreadable files, parse errors, or scan limits",
|
|
939
|
+
"configChain.title": "mustflow config chain",
|
|
940
|
+
"configChain.label.targets": "Targets",
|
|
941
|
+
"configChain.label.configs": "Configs",
|
|
942
|
+
"configChain.label.edges": "Edges",
|
|
943
|
+
"configChain.label.findings": "Findings",
|
|
944
|
+
"configChain.label.dynamic": "dynamic",
|
|
945
|
+
"configChain.label.issues": "Issues",
|
|
946
|
+
"configChain.clean": "No nearby config files were found.",
|
|
947
|
+
"configChain.error.missingAction": "Specify a config-chain action: inspect",
|
|
948
|
+
"configChain.error.unknownAction": "Unknown config-chain action: {action}",
|
|
949
|
+
"configChain.error.missingPath": "Provide at least one path to inspect",
|
|
950
|
+
"configChain.error.invalidPositiveInteger": "{option} must be a positive safe integer: {value}",
|
|
852
951
|
"run.help.summary": "从 .mustflow/config/commands.toml 运行已配置的一次性命令。",
|
|
853
952
|
"run.help.option.dryRun": "输出命令计划但不执行",
|
|
854
953
|
"run.help.option.planOnly": "--dry-run 的别名",
|
|
@@ -14,15 +14,16 @@ export const SCRIPT_PACKS = [
|
|
|
14
14
|
summaryKey: 'scriptPack.script.codeOutline.summary',
|
|
15
15
|
actions: ['scan'],
|
|
16
16
|
useWhen: [
|
|
17
|
-
'Scan
|
|
18
|
-
'Build a bounded source outline with file paths, line ranges, signatures,
|
|
17
|
+
'Scan supported source files for symbol headers and source anchors before reading large files chunk by chunk.',
|
|
18
|
+
'Build a bounded source outline with file paths, language metadata, line ranges, signatures, ' +
|
|
19
|
+
'export flags, source-anchor metadata, and content hashes for codebase orientation.',
|
|
19
20
|
],
|
|
20
21
|
phases: ['before_change', 'during_change', 'review'],
|
|
21
22
|
readOnly: true,
|
|
22
23
|
mutates: false,
|
|
23
24
|
network: false,
|
|
24
25
|
inputs: ['path', 'max_files', 'max_file_bytes'],
|
|
25
|
-
outputs: ['human_summary', 'json_report', 'symbol_outline'],
|
|
26
|
+
outputs: ['human_summary', 'json_report', 'symbol_outline', 'source_anchors'],
|
|
26
27
|
relatedSkills: [
|
|
27
28
|
'codebase-orientation',
|
|
28
29
|
'javascript-code-change',
|
|
@@ -39,18 +40,18 @@ export const SCRIPT_PACKS = [
|
|
|
39
40
|
packId: 'code',
|
|
40
41
|
id: 'symbol-read',
|
|
41
42
|
ref: scriptRef('code', 'symbol-read'),
|
|
42
|
-
usage: 'mf script-pack run code/symbol-read read <path> --start-line <line> [options]',
|
|
43
|
+
usage: 'mf script-pack run code/symbol-read read (<path> --start-line <line> | --anchor <id>) [options]',
|
|
43
44
|
summaryKey: 'scriptPack.script.codeSymbolRead.summary',
|
|
44
45
|
actions: ['read'],
|
|
45
46
|
useWhen: [
|
|
46
|
-
'Read only the resolved symbol range or
|
|
47
|
-
'Fetch a focused source snippet with path, line, symbol, and content-hash metadata instead of repeatedly paging through a whole file.',
|
|
47
|
+
'Read only the resolved symbol range, source-anchor target, or explicit bounded line range after a code outline identifies the relevant location.',
|
|
48
|
+
'Fetch a focused source snippet with path, anchor, line, symbol, and content-hash metadata instead of repeatedly paging through a whole file.',
|
|
48
49
|
],
|
|
49
50
|
phases: ['before_change', 'during_change', 'review'],
|
|
50
51
|
readOnly: true,
|
|
51
52
|
mutates: false,
|
|
52
53
|
network: false,
|
|
53
|
-
inputs: ['path', 'start_line', 'end_line', 'context_lines', 'max_file_bytes', 'max_snippet_lines'],
|
|
54
|
+
inputs: ['path', 'anchor_id', 'start_line', 'end_line', 'context_lines', 'max_file_bytes', 'max_snippet_lines'],
|
|
54
55
|
outputs: ['human_summary', 'json_report', 'source_snippet'],
|
|
55
56
|
relatedSkills: [
|
|
56
57
|
'codebase-orientation',
|
|
@@ -64,6 +65,66 @@ export const SCRIPT_PACKS = [
|
|
|
64
65
|
reportSchemaFile: 'code-symbol-read-report.schema.json',
|
|
65
66
|
loadRunner: async () => (await import('../script-packs/code-outline.js')).runCodeSymbolReadScript,
|
|
66
67
|
},
|
|
68
|
+
{
|
|
69
|
+
packId: 'code',
|
|
70
|
+
id: 'route-outline',
|
|
71
|
+
ref: scriptRef('code', 'route-outline'),
|
|
72
|
+
usage: 'mf script-pack run code/route-outline scan <path...> [options]',
|
|
73
|
+
summaryKey: 'scriptPack.script.codeRouteOutline.summary',
|
|
74
|
+
actions: ['scan'],
|
|
75
|
+
useWhen: [
|
|
76
|
+
'Scan Hono, Elysia, Axum, and NestJS route source files for method, path, framework, lifecycle, handler, and line metadata before reading whole modules.',
|
|
77
|
+
'Build a bounded first-pass route outline with paths, line ranges, lifecycle calls, and content hashes for HTTP route orientation.',
|
|
78
|
+
],
|
|
79
|
+
phases: ['before_change', 'during_change', 'after_change', 'review'],
|
|
80
|
+
readOnly: true,
|
|
81
|
+
mutates: false,
|
|
82
|
+
network: false,
|
|
83
|
+
inputs: ['path', 'max_files', 'max_file_bytes'],
|
|
84
|
+
outputs: ['human_summary', 'json_report', 'route_outline', 'route_lifecycle'],
|
|
85
|
+
relatedSkills: [
|
|
86
|
+
'api-contract-change',
|
|
87
|
+
'backend-reliability-change',
|
|
88
|
+
'axum-code-change',
|
|
89
|
+
'elysia-code-change',
|
|
90
|
+
'hono-code-change',
|
|
91
|
+
'nestjs-code-change',
|
|
92
|
+
'http-delivery-streaming',
|
|
93
|
+
],
|
|
94
|
+
riskLevel: 'low',
|
|
95
|
+
cost: 'low',
|
|
96
|
+
reportSchemaFile: 'route-outline-report.schema.json',
|
|
97
|
+
loadRunner: async () => (await import('../script-packs/code-route-outline.js')).runCodeRouteOutlineScript,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
packId: 'code',
|
|
101
|
+
id: 'export-diff',
|
|
102
|
+
ref: scriptRef('code', 'export-diff'),
|
|
103
|
+
usage: 'mf script-pack run code/export-diff compare [path...] [options]',
|
|
104
|
+
summaryKey: 'scriptPack.script.codeExportDiff.summary',
|
|
105
|
+
actions: ['compare'],
|
|
106
|
+
useWhen: [
|
|
107
|
+
'Compare exported TypeScript and JavaScript declaration signatures, return metadata, and package surface hints across a git base and head.',
|
|
108
|
+
'Review public-ish API changes after source edits without reading every changed file from top to bottom.',
|
|
109
|
+
],
|
|
110
|
+
phases: ['after_change', 'review'],
|
|
111
|
+
readOnly: true,
|
|
112
|
+
mutates: false,
|
|
113
|
+
network: false,
|
|
114
|
+
inputs: ['base_ref', 'head_ref', 'path', 'max_files', 'max_file_bytes'],
|
|
115
|
+
outputs: ['human_summary', 'json_report', 'export_diff', 'return_type_changes', 'package_surface'],
|
|
116
|
+
relatedSkills: [
|
|
117
|
+
'api-contract-change',
|
|
118
|
+
'dependency-upgrade-review',
|
|
119
|
+
'javascript-code-change',
|
|
120
|
+
'public-json-contract-change',
|
|
121
|
+
'typescript-code-change',
|
|
122
|
+
],
|
|
123
|
+
riskLevel: 'low',
|
|
124
|
+
cost: 'low',
|
|
125
|
+
reportSchemaFile: 'export-diff-report.schema.json',
|
|
126
|
+
loadRunner: async () => (await import('../script-packs/code-export-diff.js')).runCodeExportDiffScript,
|
|
127
|
+
},
|
|
67
128
|
],
|
|
68
129
|
},
|
|
69
130
|
{
|
|
@@ -100,10 +161,74 @@ export const SCRIPT_PACKS = [
|
|
|
100
161
|
},
|
|
101
162
|
],
|
|
102
163
|
},
|
|
164
|
+
{
|
|
165
|
+
id: 'docs',
|
|
166
|
+
summaryKey: 'scriptPack.pack.docs.summary',
|
|
167
|
+
scripts: [
|
|
168
|
+
{
|
|
169
|
+
packId: 'docs',
|
|
170
|
+
id: 'reference-drift',
|
|
171
|
+
ref: scriptRef('docs', 'reference-drift'),
|
|
172
|
+
usage: 'mf script-pack run docs/reference-drift check [path...] [options]',
|
|
173
|
+
summaryKey: 'scriptPack.script.referenceDrift.summary',
|
|
174
|
+
actions: ['check'],
|
|
175
|
+
useWhen: [
|
|
176
|
+
'Check documentation references to mf commands, script-pack refs, schema files, and repository paths against current local surfaces.',
|
|
177
|
+
'Review docs after CLI, schema, script-pack, or repository structure changes before claiming references are synchronized.',
|
|
178
|
+
],
|
|
179
|
+
phases: ['after_change', 'review'],
|
|
180
|
+
readOnly: true,
|
|
181
|
+
mutates: false,
|
|
182
|
+
network: false,
|
|
183
|
+
inputs: ['path', 'max_files', 'max_file_bytes'],
|
|
184
|
+
outputs: ['human_summary', 'json_report', 'reference_drift', 'stale_reference_findings'],
|
|
185
|
+
relatedSkills: [
|
|
186
|
+
'cli-output-contract-review',
|
|
187
|
+
'docs-prose-review',
|
|
188
|
+
'public-json-contract-change',
|
|
189
|
+
'readme-authoring',
|
|
190
|
+
'release-notes-authoring',
|
|
191
|
+
],
|
|
192
|
+
riskLevel: 'low',
|
|
193
|
+
cost: 'low',
|
|
194
|
+
reportSchemaFile: 'reference-drift-report.schema.json',
|
|
195
|
+
loadRunner: async () => (await import('../script-packs/docs-reference-drift.js')).runDocsReferenceDriftScript,
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
},
|
|
103
199
|
{
|
|
104
200
|
id: 'repo',
|
|
105
201
|
summaryKey: 'scriptPack.pack.repo.summary',
|
|
106
202
|
scripts: [
|
|
203
|
+
{
|
|
204
|
+
packId: 'repo',
|
|
205
|
+
id: 'config-chain',
|
|
206
|
+
ref: scriptRef('repo', 'config-chain'),
|
|
207
|
+
usage: 'mf script-pack run repo/config-chain inspect <path...> [options]',
|
|
208
|
+
summaryKey: 'scriptPack.script.configChain.summary',
|
|
209
|
+
actions: ['inspect'],
|
|
210
|
+
useWhen: [
|
|
211
|
+
'Inspect nearby tsconfig, package, ESLint, Prettier, Vite, Vitest, Tailwind, Jest, and Playwright config files before assuming effective rules.',
|
|
212
|
+
'Build a read-only config chain with extends, references, workspaces, dynamic-config findings, and source path context.',
|
|
213
|
+
],
|
|
214
|
+
phases: ['before_change', 'during_change', 'after_change', 'review'],
|
|
215
|
+
readOnly: true,
|
|
216
|
+
mutates: false,
|
|
217
|
+
network: false,
|
|
218
|
+
inputs: ['path', 'max_configs', 'max_file_bytes'],
|
|
219
|
+
outputs: ['human_summary', 'json_report', 'config_chain', 'config_edges'],
|
|
220
|
+
relatedSkills: [
|
|
221
|
+
'bun-code-change',
|
|
222
|
+
'config-env-change',
|
|
223
|
+
'dependency-reality-check',
|
|
224
|
+
'tailwind-code-change',
|
|
225
|
+
'typescript-code-change',
|
|
226
|
+
],
|
|
227
|
+
riskLevel: 'low',
|
|
228
|
+
cost: 'low',
|
|
229
|
+
reportSchemaFile: 'config-chain-report.schema.json',
|
|
230
|
+
loadRunner: async () => (await import('../script-packs/repo-config-chain.js')).runRepoConfigChainScript,
|
|
231
|
+
},
|
|
107
232
|
{
|
|
108
233
|
packId: 'repo',
|
|
109
234
|
id: 'generated-boundary',
|
|
@@ -133,6 +258,36 @@ export const SCRIPT_PACKS = [
|
|
|
133
258
|
reportSchemaFile: 'generated-boundary-report.schema.json',
|
|
134
259
|
loadRunner: async () => (await import('../script-packs/repo-generated-boundary.js')).runRepoGeneratedBoundaryScript,
|
|
135
260
|
},
|
|
261
|
+
{
|
|
262
|
+
packId: 'repo',
|
|
263
|
+
id: 'related-files',
|
|
264
|
+
ref: scriptRef('repo', 'related-files'),
|
|
265
|
+
usage: 'mf script-pack run repo/related-files map <path...> [options]',
|
|
266
|
+
summaryKey: 'scriptPack.script.relatedFiles.summary',
|
|
267
|
+
actions: ['map'],
|
|
268
|
+
useWhen: [
|
|
269
|
+
'Map direct imports, importers, sibling tests, sibling docs, sibling styles, type siblings, ' +
|
|
270
|
+
'and nearby config files for a source path before widening context reads.',
|
|
271
|
+
'Review likely adjacent files after a partial implementation without treating the result as verification scope or completeness proof.',
|
|
272
|
+
],
|
|
273
|
+
phases: ['before_change', 'during_change', 'after_change', 'review'],
|
|
274
|
+
readOnly: true,
|
|
275
|
+
mutates: false,
|
|
276
|
+
network: false,
|
|
277
|
+
inputs: ['path', 'max_files', 'max_file_bytes', 'max_candidates'],
|
|
278
|
+
outputs: ['human_summary', 'json_report', 'related_file_candidates'],
|
|
279
|
+
relatedSkills: [
|
|
280
|
+
'codebase-orientation',
|
|
281
|
+
'heuristic-candidate-selection',
|
|
282
|
+
'module-boundary-review',
|
|
283
|
+
'typescript-code-change',
|
|
284
|
+
'javascript-code-change',
|
|
285
|
+
],
|
|
286
|
+
riskLevel: 'low',
|
|
287
|
+
cost: 'low',
|
|
288
|
+
reportSchemaFile: 'related-files-report.schema.json',
|
|
289
|
+
loadRunner: async () => (await import('../script-packs/repo-related-files.js')).runRepoRelatedFilesScript,
|
|
290
|
+
},
|
|
136
291
|
],
|
|
137
292
|
},
|
|
138
293
|
];
|
|
@@ -0,0 +1,160 @@
|
|
|
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 { CODE_EXPORT_DIFF_SCRIPT_REF, inspectExportDiff, } from '../../core/export-diff.js';
|
|
6
|
+
const EXPORT_DIFF_OPTIONS = [
|
|
7
|
+
{ name: '--json', kind: 'boolean' },
|
|
8
|
+
{ name: '--base', kind: 'string' },
|
|
9
|
+
{ name: '--head', kind: 'string' },
|
|
10
|
+
{ name: '--max-files', kind: 'string' },
|
|
11
|
+
{ name: '--max-file-bytes', kind: 'string' },
|
|
12
|
+
];
|
|
13
|
+
function parsePositiveInteger(value, option, lang) {
|
|
14
|
+
if (value === null) {
|
|
15
|
+
return { value: null };
|
|
16
|
+
}
|
|
17
|
+
if (!/^[1-9]\d*$/u.test(value)) {
|
|
18
|
+
return { value: null, error: t(lang, 'exportDiff.error.invalidPositiveInteger', { option, value }) };
|
|
19
|
+
}
|
|
20
|
+
const parsed = Number(value);
|
|
21
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
22
|
+
return { value: null, error: t(lang, 'exportDiff.error.invalidPositiveInteger', { option, value }) };
|
|
23
|
+
}
|
|
24
|
+
return { value: parsed };
|
|
25
|
+
}
|
|
26
|
+
export function getCodeExportDiffHelp(lang = 'en') {
|
|
27
|
+
return renderHelp({
|
|
28
|
+
usage: 'mf script-pack run code/export-diff compare [path...] [options]',
|
|
29
|
+
summary: t(lang, 'exportDiff.help.summary'),
|
|
30
|
+
options: [
|
|
31
|
+
{ label: '--base <ref>', description: t(lang, 'exportDiff.help.option.base') },
|
|
32
|
+
{ label: '--head <ref>', description: t(lang, 'exportDiff.help.option.head') },
|
|
33
|
+
{ label: '--max-files <count>', description: t(lang, 'exportDiff.help.option.maxFiles') },
|
|
34
|
+
{ label: '--max-file-bytes <bytes>', description: t(lang, 'exportDiff.help.option.maxFileBytes') },
|
|
35
|
+
{ label: '--json', description: t(lang, 'cli.option.json') },
|
|
36
|
+
{ label: '-h, --help', description: t(lang, 'cli.option.help') },
|
|
37
|
+
],
|
|
38
|
+
examples: [
|
|
39
|
+
'mf script-pack run code/export-diff compare --base HEAD --json',
|
|
40
|
+
'mf script-pack run code/export-diff compare src --base HEAD~1 --head HEAD --json',
|
|
41
|
+
'mf script-pack run code/export-diff compare src/index.ts --max-files 20 --json',
|
|
42
|
+
],
|
|
43
|
+
exitCodes: [
|
|
44
|
+
{ label: '0', description: t(lang, 'exportDiff.help.exit.ok') },
|
|
45
|
+
{ label: '1', description: t(lang, 'exportDiff.help.exit.fail') },
|
|
46
|
+
],
|
|
47
|
+
}, lang);
|
|
48
|
+
}
|
|
49
|
+
function parseExportDiffOptions(args, lang) {
|
|
50
|
+
const [action, ...rest] = args;
|
|
51
|
+
const parsed = parseCliOptions(rest, EXPORT_DIFF_OPTIONS, { allowPositionals: true });
|
|
52
|
+
const json = hasParsedCliOption(parsed, '--json');
|
|
53
|
+
const baseRef = getParsedCliStringOption(parsed, '--base');
|
|
54
|
+
const headRef = getParsedCliStringOption(parsed, '--head');
|
|
55
|
+
const maxFiles = parsePositiveInteger(getParsedCliStringOption(parsed, '--max-files'), '--max-files', lang);
|
|
56
|
+
const maxFileBytes = parsePositiveInteger(getParsedCliStringOption(parsed, '--max-file-bytes'), '--max-file-bytes', lang);
|
|
57
|
+
if (action !== 'compare') {
|
|
58
|
+
return {
|
|
59
|
+
action: 'compare',
|
|
60
|
+
json,
|
|
61
|
+
baseRef,
|
|
62
|
+
headRef,
|
|
63
|
+
paths: parsed.positionals,
|
|
64
|
+
maxFiles: maxFiles.value,
|
|
65
|
+
maxFileBytes: maxFileBytes.value,
|
|
66
|
+
error: action ? t(lang, 'exportDiff.error.unknownAction', { action }) : t(lang, 'exportDiff.error.missingAction'),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (parsed.error) {
|
|
70
|
+
return {
|
|
71
|
+
action,
|
|
72
|
+
json,
|
|
73
|
+
baseRef,
|
|
74
|
+
headRef,
|
|
75
|
+
paths: parsed.positionals,
|
|
76
|
+
maxFiles: maxFiles.value,
|
|
77
|
+
maxFileBytes: maxFileBytes.value,
|
|
78
|
+
error: formatCliOptionParseError(parsed.error, lang),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
for (const candidate of [maxFiles, maxFileBytes]) {
|
|
82
|
+
if (candidate.error) {
|
|
83
|
+
return {
|
|
84
|
+
action,
|
|
85
|
+
json,
|
|
86
|
+
baseRef,
|
|
87
|
+
headRef,
|
|
88
|
+
paths: parsed.positionals,
|
|
89
|
+
maxFiles: maxFiles.value,
|
|
90
|
+
maxFileBytes: maxFileBytes.value,
|
|
91
|
+
error: candidate.error,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
action,
|
|
97
|
+
json,
|
|
98
|
+
baseRef,
|
|
99
|
+
headRef,
|
|
100
|
+
paths: parsed.positionals,
|
|
101
|
+
maxFiles: maxFiles.value,
|
|
102
|
+
maxFileBytes: maxFileBytes.value,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function renderExportDiffSummary(report, lang) {
|
|
106
|
+
const lines = [
|
|
107
|
+
t(lang, 'exportDiff.title'),
|
|
108
|
+
`${t(lang, 'scriptPack.label.script')}: ${CODE_EXPORT_DIFF_SCRIPT_REF}`,
|
|
109
|
+
`${t(lang, 'label.status')}: ${report.status}`,
|
|
110
|
+
`${t(lang, 'exportDiff.label.files')}: ${report.summary.files_changed}`,
|
|
111
|
+
`${t(lang, 'exportDiff.label.added')}: ${report.summary.added}`,
|
|
112
|
+
`${t(lang, 'exportDiff.label.removed')}: ${report.summary.removed}`,
|
|
113
|
+
`${t(lang, 'exportDiff.label.changed')}: ${report.summary.changed}`,
|
|
114
|
+
];
|
|
115
|
+
if (report.exports.length > 0) {
|
|
116
|
+
lines.push(t(lang, 'exportDiff.label.exports'));
|
|
117
|
+
for (const entry of report.exports.filter((candidate) => candidate.change !== 'unchanged')) {
|
|
118
|
+
const beforeReturn = entry.before?.return_type ?? t(lang, 'value.none');
|
|
119
|
+
const afterReturn = entry.after?.return_type ?? t(lang, 'value.none');
|
|
120
|
+
lines.push(`- ${entry.path}: ${entry.change} ${entry.kind} ${entry.name} (${entry.compatibility}, ${beforeReturn} -> ${afterReturn})`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (report.findings.length > 0) {
|
|
124
|
+
lines.push(t(lang, 'exportDiff.label.findings'));
|
|
125
|
+
for (const finding of report.findings) {
|
|
126
|
+
lines.push(`- ${finding.path}: ${finding.code} (${finding.message})`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (report.issues.length > 0) {
|
|
130
|
+
lines.push(t(lang, 'exportDiff.label.issues'), ...report.issues.map((issue) => `- ${issue}`));
|
|
131
|
+
}
|
|
132
|
+
if (report.exports.length === 0 && report.findings.length === 0 && report.issues.length === 0) {
|
|
133
|
+
lines.push(t(lang, 'exportDiff.clean'));
|
|
134
|
+
}
|
|
135
|
+
return lines.join('\n');
|
|
136
|
+
}
|
|
137
|
+
export function runCodeExportDiffScript(args, reporter, lang = 'en') {
|
|
138
|
+
if (hasCliOptionToken(args, '--help', ['-h'])) {
|
|
139
|
+
reporter.stdout(getCodeExportDiffHelp(lang));
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
const options = parseExportDiffOptions(args, lang);
|
|
143
|
+
if (options.error) {
|
|
144
|
+
printUsageError(reporter, options.error, 'mf script-pack run code/export-diff --help', getCodeExportDiffHelp(lang), lang);
|
|
145
|
+
return 1;
|
|
146
|
+
}
|
|
147
|
+
const report = inspectExportDiff(resolveMustflowRoot(), {
|
|
148
|
+
baseRef: options.baseRef ?? undefined,
|
|
149
|
+
headRef: options.headRef,
|
|
150
|
+
paths: options.paths,
|
|
151
|
+
maxFiles: options.maxFiles ?? undefined,
|
|
152
|
+
maxFileBytes: options.maxFileBytes ?? undefined,
|
|
153
|
+
});
|
|
154
|
+
if (options.json) {
|
|
155
|
+
reporter.stdout(JSON.stringify(report, null, 2));
|
|
156
|
+
return report.ok ? 0 : 1;
|
|
157
|
+
}
|
|
158
|
+
reporter.stdout(renderExportDiffSummary(report, lang));
|
|
159
|
+
return report.ok ? 0 : 1;
|
|
160
|
+
}
|