mustflow 2.103.22 → 2.103.31

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 (34) hide show
  1. package/README.md +5 -2
  2. package/dist/cli/commands/flow.js +93 -0
  3. package/dist/cli/commands/run/executor.js +28 -3
  4. package/dist/cli/commands/run/windows-command-script.js +23 -0
  5. package/dist/cli/i18n/en.js +11 -0
  6. package/dist/cli/i18n/es.js +11 -0
  7. package/dist/cli/i18n/fr.js +11 -0
  8. package/dist/cli/i18n/hi.js +11 -0
  9. package/dist/cli/i18n/ko.js +11 -0
  10. package/dist/cli/i18n/zh.js +11 -0
  11. package/dist/cli/index.js +1 -0
  12. package/dist/cli/lib/active-command-lock.js +4 -0
  13. package/dist/cli/lib/command-registry.js +7 -0
  14. package/dist/cli/lib/repo-flow-frontmatter.js +35 -0
  15. package/dist/cli/lib/repo-flow.js +209 -0
  16. package/dist/cli/lib/repo-map.js +3 -0
  17. package/dist/cli/lib/run-plan.js +8 -4
  18. package/dist/cli/lib/validation/constants.js +10 -0
  19. package/dist/cli/lib/validation/index.js +54 -1
  20. package/dist/core/generated-boundary.js +1 -0
  21. package/package.json +2 -1
  22. package/templates/default/i18n.toml +30 -6
  23. package/templates/default/locales/en/.mustflow/skills/INDEX.md +29 -6
  24. package/templates/default/locales/en/.mustflow/skills/astro-code-change/SKILL.md +95 -23
  25. package/templates/default/locales/en/.mustflow/skills/axum-code-change/SKILL.md +219 -0
  26. package/templates/default/locales/en/.mustflow/skills/babylon-code-change/SKILL.md +318 -0
  27. package/templates/default/locales/en/.mustflow/skills/bun-code-change/SKILL.md +27 -12
  28. package/templates/default/locales/en/.mustflow/skills/elysia-code-change/SKILL.md +74 -20
  29. package/templates/default/locales/en/.mustflow/skills/godot-code-change/SKILL.md +272 -0
  30. package/templates/default/locales/en/.mustflow/skills/hono-code-change/SKILL.md +37 -23
  31. package/templates/default/locales/en/.mustflow/skills/routes.toml +28 -4
  32. package/templates/default/locales/en/.mustflow/skills/svelte-code-change/SKILL.md +65 -40
  33. package/templates/default/locales/en/.mustflow/skills/vue-code-change/SKILL.md +305 -0
  34. package/templates/default/manifest.toml +29 -1
package/README.md CHANGED
@@ -143,7 +143,7 @@ mustflow installs and validates an agent workflow for user projects.
143
143
  - Records blockers, contradictions, verification gaps, and remaining risks as a structured conflict ledger in verify, evidence, and dashboard reports.
144
144
  - Stores bounded failure replay capsules for failed `mf verify` runs so future agents can reproduce the intent, receipt, command fingerprint, and changed-file state without copying raw command output.
145
145
  - Writes bounded command receipts under `.mustflow/state/runs/run-*`, atomically updates `.mustflow/state/runs/latest.json`, and rebuilds `.mustflow/state/runs/latest.index.json` for recent retained runs.
146
- - Generates a concise repository navigation map, `REPO_MAP.md`, with `mf map`.
146
+ - Generates a concise repository navigation map, `REPO_MAP.md`, with `mf map`, and a design-flow map, `REPO_FLOW.md`, with `mf flow`.
147
147
  - Indexes and searches mustflow docs, skills, skill routes, command rules, command-effect locks, file fingerprints, and opt-in source anchor metadata with SQLite via `mf index` and `mf search`. The local SQLite file is a rebuildable lookup cache, not a memory store, audit log, command transcript store, command-authority source, or source-content database.
148
148
  - Tracks agent-created or agent-modified documentation needing prose review with `mf docs review`.
149
149
  - Validates restricted work-item or handoff JSON records with `mf handoff validate` without creating backlog files, storing transcripts, or granting command authority.
@@ -199,7 +199,7 @@ The default template does not create project-owned root documents or contract fi
199
199
 
200
200
  `mf init` creates `.gitignore` if it is missing. If `.gitignore` exists, mustflow updates only its managed block and preserves user rules.
201
201
 
202
- `REPO_MAP.md` is not copied from the template. Generate it when needed with `mf map --write`. `.mustflow/cache/mustflow.sqlite` is also a regenerable local index created by `mf index`. `.mustflow/review/docs.toml` is not copied from the template; `mf docs review` creates it only when a document is added to the review queue.
202
+ `REPO_MAP.md` and `REPO_FLOW.md` are not copied from the template. Generate them when needed with `mf map --write` and `mf flow --write`. `.mustflow/cache/mustflow.sqlite` is also a regenerable local index created by `mf index`. `.mustflow/review/docs.toml` is not copied from the template; `mf docs review` creates it only when a document is added to the review queue.
203
203
 
204
204
  If a project already has optional root Markdown files such as `README.md`, `PROJECT.md`, `ROADMAP.md`, `DESIGN.md`, `GOVERNANCE.md`, `TESTING.md`, `DEPLOYMENT.md`, `ARCHITECTURE.md`, or `API.md`, the repository map can use them as navigation anchors. It can also discover purpose-specific machine-readable contracts such as `project.contract.json`, `project.constants.json`, `design-tokens.json`, `openapi.yaml`, `asyncapi.yaml`, `schema.graphql`, and `schema.prisma`. Generic catch-all names like `SSOT.json` are not default anchors. `mf init` does not create or overwrite those project-owned files by default.
205
205
 
@@ -290,6 +290,9 @@ mf run mustflow_update_apply
290
290
  | `mf skill route` | Resolve compact skill route candidates from task text, paths, and reasons before reading selected skill documents. |
291
291
  | `mf map --stdout` | Print the current mustflow root map to stdout. |
292
292
  | `mf map --write` | Create or update `REPO_MAP.md`. |
293
+ | `mf flow --stdout` | Print the current mustflow root design-flow map to stdout. |
294
+ | `mf flow --write` | Create or update `REPO_FLOW.md`. |
295
+ | `mf flow --check` | Check whether `REPO_FLOW.md` is current. |
293
296
  | `mf quality check` | Inspect changed files for quality-gaming patterns without writing files. |
294
297
  | `mf quality check --all` | Inspect every tracked text file for quality-gaming patterns. |
295
298
  | `mf script-pack list` | List bundled script packs, script refs, routing hints, side-effect flags, input/output labels, and JSON schema files. |
@@ -0,0 +1,93 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { printUsageError, renderHelp } from '../lib/cli-output.js';
4
+ import { t } from '../lib/i18n.js';
5
+ import { acquireActiveCommandLock, REPO_FLOW_WRITE_EFFECTS, reportActiveCommandLockConflict, } from '../lib/active-command-lock.js';
6
+ import { formatCliOptionParseError, hasCliOptionToken, hasParsedCliOption, parseCliOptions, } from '../lib/option-parser.js';
7
+ import { resolveMustflowRoot } from '../lib/project-root.js';
8
+ import { generateRepoFlow, getExpectedRepoFlowSourceFingerprint, writeRepoFlow } from '../lib/repo-flow.js';
9
+ import { parseSimpleFrontmatter } from '../lib/validation/frontmatter.js';
10
+ const FLOW_OPTIONS = [
11
+ { name: '--stdout', kind: 'boolean' },
12
+ { name: '--write', kind: 'boolean' },
13
+ { name: '--check', kind: 'boolean' },
14
+ ];
15
+ export function getFlowHelp(lang = 'en') {
16
+ return renderHelp({
17
+ usage: 'mf flow [options]',
18
+ summary: t(lang, 'flow.help.summary'),
19
+ options: [
20
+ { label: '-h, --help', description: t(lang, 'cli.option.help') },
21
+ { label: '--stdout', description: t(lang, 'flow.help.option.stdout') },
22
+ { label: '--write', description: t(lang, 'flow.help.option.write') },
23
+ { label: '--check', description: t(lang, 'flow.help.option.check') },
24
+ ],
25
+ examples: ['mf flow --stdout', 'mf flow --write', 'mf flow --check'],
26
+ exitCodes: [
27
+ { label: '0', description: t(lang, 'flow.help.exit.ok') },
28
+ { label: '1', description: t(lang, 'cli.common.invalidInput') },
29
+ ],
30
+ }, lang);
31
+ }
32
+ function checkRepoFlow(projectRoot, reporter, lang) {
33
+ const repoFlowPath = path.join(projectRoot, 'REPO_FLOW.md');
34
+ if (!existsSync(repoFlowPath)) {
35
+ reporter.stderr(t(lang, 'flow.check.missing'));
36
+ return 1;
37
+ }
38
+ const content = readFileSync(repoFlowPath, 'utf8');
39
+ const frontmatter = parseSimpleFrontmatter(content);
40
+ const expectedFingerprint = getExpectedRepoFlowSourceFingerprint(projectRoot);
41
+ if (frontmatter.source_fingerprint !== expectedFingerprint) {
42
+ reporter.stderr(t(lang, 'flow.check.stale'));
43
+ return 1;
44
+ }
45
+ reporter.stdout(t(lang, 'flow.check.current'));
46
+ return 0;
47
+ }
48
+ export function runFlow(args, reporter, lang = 'en') {
49
+ if (hasCliOptionToken(args, '--help', ['-h'])) {
50
+ reporter.stdout(getFlowHelp(lang));
51
+ return 0;
52
+ }
53
+ const parsed = parseCliOptions(args, FLOW_OPTIONS);
54
+ if (parsed.error) {
55
+ printUsageError(reporter, formatCliOptionParseError(parsed.error, lang), 'mf flow --help', getFlowHelp(lang), lang);
56
+ return 1;
57
+ }
58
+ let shouldPrint = hasParsedCliOption(parsed, '--stdout');
59
+ const shouldWrite = hasParsedCliOption(parsed, '--write');
60
+ const shouldCheck = hasParsedCliOption(parsed, '--check');
61
+ if (shouldCheck && (shouldPrint || shouldWrite)) {
62
+ printUsageError(reporter, t(lang, 'flow.error.checkConflict'), 'mf flow --help', getFlowHelp(lang), lang);
63
+ return 1;
64
+ }
65
+ if (!shouldPrint && !shouldWrite && !shouldCheck) {
66
+ shouldPrint = true;
67
+ }
68
+ const projectRoot = resolveMustflowRoot();
69
+ if (shouldCheck) {
70
+ return checkRepoFlow(projectRoot, reporter, lang);
71
+ }
72
+ const activeLock = shouldWrite ? acquireActiveCommandLock(projectRoot, 'mf flow --write', REPO_FLOW_WRITE_EFFECTS) : null;
73
+ if (activeLock && !activeLock.ok) {
74
+ reportActiveCommandLockConflict(reporter, 'mf flow --write', activeLock.conflicts, 'mf flow --help', lang);
75
+ return 1;
76
+ }
77
+ try {
78
+ const content = generateRepoFlow(projectRoot);
79
+ if (shouldWrite) {
80
+ writeRepoFlow(projectRoot, content);
81
+ reporter.stdout(t(lang, 'flow.wrote'));
82
+ }
83
+ if (shouldPrint) {
84
+ reporter.stdout(content);
85
+ }
86
+ return 0;
87
+ }
88
+ finally {
89
+ if (activeLock?.ok) {
90
+ activeLock.handle.release();
91
+ }
92
+ }
93
+ }
@@ -2,6 +2,7 @@ import { spawn } from 'node:child_process';
2
2
  import { BoundedOutputBuffer } from '../../../core/bounded-output.js';
3
3
  import { createPendingTimeoutTermination, forceTerminateProcessTree, getKillMethod, terminateProcessTree, } from './process-tree.js';
4
4
  import { createOutputLimitError, isOutputLimitExceededError, writeOutputLimitTerminationMarker, writeStreamChunk, writeStreamChunkPrefix, } from './output.js';
5
+ import { createWindowsCommandScriptSpawn } from './windows-command-script.js';
5
6
  const TERMINATION_CONFIRMATION_FALLBACK_MS = 1000;
6
7
  function createEmptyOutputSnapshot(maxBytes) {
7
8
  return new BoundedOutputBuffer(maxBytes).toSnapshot();
@@ -9,6 +10,23 @@ function createEmptyOutputSnapshot(maxBytes) {
9
10
  function createInvalidExecutableError() {
10
11
  return Object.assign(new Error('Command executable must not be empty'), { code: 'EINVAL' });
11
12
  }
13
+ function normalizeSpawnedCommandInput(command) {
14
+ if (process.platform === 'win32' && command.windowsCommandScript === true) {
15
+ const windowsCommand = createWindowsCommandScriptSpawn(command.executable, command.args ?? []);
16
+ return {
17
+ executable: windowsCommand.executable,
18
+ args: windowsCommand.args,
19
+ shell: windowsCommand.shell,
20
+ windowsVerbatimArguments: windowsCommand.windowsVerbatimArguments,
21
+ };
22
+ }
23
+ return {
24
+ executable: command.executable,
25
+ args: command.args ?? [],
26
+ shell: command.shell,
27
+ windowsVerbatimArguments: false,
28
+ };
29
+ }
12
30
  function runSpawnedCommandStreaming(command, cwd, env, timeoutSeconds, killAfterSeconds, maxOutputBytes, stdoutTailBytes, stderrTailBytes, reporter, streamOutput, enforceOutputLimit) {
13
31
  if (command.executable.trim().length === 0) {
14
32
  return Promise.resolve({
@@ -35,12 +53,14 @@ function runSpawnedCommandStreaming(command, cwd, env, timeoutSeconds, killAfter
35
53
  let terminationStarted = false;
36
54
  let outputLimitMarkerWritten = false;
37
55
  let termination = null;
38
- const child = spawn(command.executable, command.args ?? [], {
56
+ const spawnCommand = normalizeSpawnedCommandInput(command);
57
+ const child = spawn(spawnCommand.executable, spawnCommand.args, {
39
58
  cwd,
40
59
  env,
41
- shell: command.shell,
60
+ shell: spawnCommand.shell,
42
61
  stdio: ['ignore', 'pipe', 'pipe'],
43
62
  windowsHide: true,
63
+ windowsVerbatimArguments: spawnCommand.windowsVerbatimArguments,
44
64
  detached: process.platform !== 'win32',
45
65
  });
46
66
  childPid = child.pid;
@@ -164,7 +184,12 @@ function runSpawnedCommandStreaming(command, cwd, env, timeoutSeconds, killAfter
164
184
  });
165
185
  }
166
186
  export function runArgvCommandStreaming(command, cwd, env, timeoutSeconds, killAfterSeconds, maxOutputBytes, stdoutTailBytes, stderrTailBytes, reporter, streamOutput, enforceOutputLimit) {
167
- return runSpawnedCommandStreaming({ executable: command?.executable ?? '', args: command?.args ?? [], shell: command?.shell ?? false }, cwd, env, timeoutSeconds, killAfterSeconds, maxOutputBytes, stdoutTailBytes, stderrTailBytes, reporter, streamOutput, enforceOutputLimit);
187
+ return runSpawnedCommandStreaming({
188
+ executable: command?.executable ?? '',
189
+ args: command?.args ?? [],
190
+ shell: command?.shell ?? false,
191
+ windowsCommandScript: command?.windowsCommandScript ?? false,
192
+ }, cwd, env, timeoutSeconds, killAfterSeconds, maxOutputBytes, stdoutTailBytes, stderrTailBytes, reporter, streamOutput, enforceOutputLimit);
168
193
  }
169
194
  export function runShellCommandStreaming(command, cwd, env, timeoutSeconds, killAfterSeconds, maxOutputBytes, stdoutTailBytes, stderrTailBytes, reporter, streamOutput, enforceOutputLimit) {
170
195
  return runSpawnedCommandStreaming({ executable: command ?? '', shell: true }, cwd, env, timeoutSeconds, killAfterSeconds, maxOutputBytes, stdoutTailBytes, stderrTailBytes, reporter, streamOutput, enforceOutputLimit);
@@ -0,0 +1,23 @@
1
+ export function isWindowsCommandScriptPath(executablePath) {
2
+ return /\.(?:cmd|bat)$/iu.test(executablePath);
3
+ }
4
+ export function quoteWindowsCommandScriptToken(value) {
5
+ if (/[\u0000\r\n]/u.test(value)) {
6
+ throw Object.assign(new Error('Windows command script arguments must not contain NUL or line breaks'), { code: 'EINVAL' });
7
+ }
8
+ if (/^[A-Za-z0-9_./:\\@+=,-]+$/u.test(value)) {
9
+ return value;
10
+ }
11
+ return `"${value.replace(/"/gu, '""')}"`;
12
+ }
13
+ export function createWindowsCommandScriptLine(executablePath, args) {
14
+ return ['call', quoteWindowsCommandScriptToken(executablePath), ...args.map(quoteWindowsCommandScriptToken)].join(' ');
15
+ }
16
+ export function createWindowsCommandScriptSpawn(executablePath, args, comspec = process.env.ComSpec ?? process.env.COMSPEC) {
17
+ return {
18
+ executable: comspec && comspec.trim().length > 0 ? comspec : 'cmd.exe',
19
+ args: ['/d', '/s', '/c', createWindowsCommandScriptLine(executablePath, args)],
20
+ shell: false,
21
+ windowsVerbatimArguments: true,
22
+ };
23
+ }
@@ -38,6 +38,7 @@ export const enMessages = {
38
38
  "command.update.summary": "Preview or apply mustflow workflow updates",
39
39
  "command.upgrade.summary": "Check the package version and safely update installed workflow files",
40
40
  "command.map.summary": "Generate REPO_MAP.md",
41
+ "command.flow.summary": "Generate REPO_FLOW.md",
41
42
  "command.lineEndings.summary": "Inspect and normalize line-ending policy",
42
43
  "command.quality.summary": "Inspect changed files for quality-gaming patterns",
43
44
  "command.scriptPack.summary": "List, suggest, and run bundled mustflow script packs",
@@ -723,6 +724,16 @@ Read these files before working:
723
724
  "map.error.nestedConflict": "Cannot combine --include-nested and --root-only",
724
725
  "map.error.invalidDepth": "Invalid value for --depth",
725
726
  "map.wrote": "Wrote REPO_MAP.md",
727
+ "flow.help.summary": "Generate REPO_FLOW.md, a design-flow map for the current mustflow root.",
728
+ "flow.help.option.stdout": "Print the generated flow map",
729
+ "flow.help.option.write": "Write REPO_FLOW.md",
730
+ "flow.help.option.check": "Check whether REPO_FLOW.md is current",
731
+ "flow.help.exit.ok": "Flow map was generated, written, or checked",
732
+ "flow.error.checkConflict": "Cannot combine --check with --stdout or --write",
733
+ "flow.check.missing": "REPO_FLOW.md is missing; regenerate with mf flow --write",
734
+ "flow.check.stale": "REPO_FLOW.md is stale; regenerate with mf flow --write",
735
+ "flow.check.current": "REPO_FLOW.md is current",
736
+ "flow.wrote": "Wrote REPO_FLOW.md",
726
737
  "lineEndings.help.summary": "Inspect Git-tracked files for line-ending policy drift and normalize them to LF when requested.",
727
738
  "lineEndings.help.option.all": "Inspect every tracked file instead of only changed files",
728
739
  "lineEndings.help.option.dryRun": "Preview normalization targets without writing files",
@@ -38,6 +38,7 @@ export const esMessages = {
38
38
  "command.update.summary": "Previsualiza o aplica actualizaciones del flujo de trabajo mustflow",
39
39
  "command.upgrade.summary": "Comprueba la versión del paquete y actualiza con seguridad los archivos de flujo instalados",
40
40
  "command.map.summary": "Genera REPO_MAP.md",
41
+ "command.flow.summary": "Genera REPO_FLOW.md",
41
42
  "command.lineEndings.summary": "Inspecciona y normaliza la política de finales de línea",
42
43
  "command.quality.summary": "Inspect changed files for quality-gaming patterns",
43
44
  "command.scriptPack.summary": "List, suggest, and run bundled mustflow script packs",
@@ -723,6 +724,16 @@ Lee estos archivos antes de trabajar:
723
724
  "map.error.nestedConflict": "No se pueden combinar --include-nested y --root-only",
724
725
  "map.error.invalidDepth": "Valor no valido para --depth",
725
726
  "map.wrote": "Se escribio REPO_MAP.md",
727
+ "flow.help.summary": "Genera REPO_FLOW.md, un mapa de flujo de diseno para la raiz mustflow actual.",
728
+ "flow.help.option.stdout": "Imprime el mapa de flujo generado",
729
+ "flow.help.option.write": "Escribe REPO_FLOW.md",
730
+ "flow.help.option.check": "Comprueba si REPO_FLOW.md esta actualizado",
731
+ "flow.help.exit.ok": "El mapa de flujo se genero, escribio o comprobo",
732
+ "flow.error.checkConflict": "No se puede combinar --check con --stdout o --write",
733
+ "flow.check.missing": "Falta REPO_FLOW.md; regeneralo con mf flow --write",
734
+ "flow.check.stale": "REPO_FLOW.md esta obsoleto; regeneralo con mf flow --write",
735
+ "flow.check.current": "REPO_FLOW.md esta actualizado",
736
+ "flow.wrote": "Se escribio REPO_FLOW.md",
726
737
  "lineEndings.help.summary": "Inspect Git-tracked files for line-ending policy drift and normalize them to LF when requested.",
727
738
  "lineEndings.help.option.all": "Inspect every tracked file instead of only changed files",
728
739
  "lineEndings.help.option.dryRun": "Preview normalization targets without writing files",
@@ -38,6 +38,7 @@ export const frMessages = {
38
38
  "command.update.summary": "Prévisualise ou applique les mises à jour du flux de travail mustflow",
39
39
  "command.upgrade.summary": "Vérifie la version du paquet et met à jour en sécurité les fichiers de workflow installés",
40
40
  "command.map.summary": "Génère REPO_MAP.md",
41
+ "command.flow.summary": "Génère REPO_FLOW.md",
41
42
  "command.lineEndings.summary": "Inspecte et normalise la politique de fins de ligne",
42
43
  "command.quality.summary": "Inspect changed files for quality-gaming patterns",
43
44
  "command.scriptPack.summary": "List, suggest, and run bundled mustflow script packs",
@@ -723,6 +724,16 @@ Lisez ces fichiers avant de travailler :
723
724
  "map.error.nestedConflict": "Impossible de combiner --include-nested et --root-only",
724
725
  "map.error.invalidDepth": "Valeur non valide pour --depth",
725
726
  "map.wrote": "REPO_MAP.md écrit",
727
+ "flow.help.summary": "Génère REPO_FLOW.md, une carte du flux de conception pour la racine mustflow actuelle.",
728
+ "flow.help.option.stdout": "Imprime la carte de flux générée",
729
+ "flow.help.option.write": "Écrit REPO_FLOW.md",
730
+ "flow.help.option.check": "Vérifie si REPO_FLOW.md est à jour",
731
+ "flow.help.exit.ok": "La carte de flux a été générée, écrite ou vérifiée",
732
+ "flow.error.checkConflict": "Impossible de combiner --check avec --stdout ou --write",
733
+ "flow.check.missing": "REPO_FLOW.md est manquant; régénérez-le avec mf flow --write",
734
+ "flow.check.stale": "REPO_FLOW.md est obsolète; régénérez-le avec mf flow --write",
735
+ "flow.check.current": "REPO_FLOW.md est à jour",
736
+ "flow.wrote": "REPO_FLOW.md écrit",
726
737
  "lineEndings.help.summary": "Inspect Git-tracked files for line-ending policy drift and normalize them to LF when requested.",
727
738
  "lineEndings.help.option.all": "Inspect every tracked file instead of only changed files",
728
739
  "lineEndings.help.option.dryRun": "Preview normalization targets without writing files",
@@ -38,6 +38,7 @@ export const hiMessages = {
38
38
  "command.update.summary": "mustflow वर्कफ़्लो अपडेट का पूर्वावलोकन करें या लागू करें",
39
39
  "command.upgrade.summary": "Package version जाँचें और installed workflow files सुरक्षित रूप से update करें",
40
40
  "command.map.summary": "REPO_MAP.md बनाएँ",
41
+ "command.flow.summary": "REPO_FLOW.md बनाएँ",
41
42
  "command.lineEndings.summary": "लाइन-एंडिंग नीति की जाँच और सामान्यीकरण करें",
42
43
  "command.quality.summary": "Inspect changed files for quality-gaming patterns",
43
44
  "command.scriptPack.summary": "List, suggest, and run bundled mustflow script packs",
@@ -723,6 +724,16 @@ export const hiMessages = {
723
724
  "map.error.nestedConflict": "--include-nested और --root-only को साथ नहीं रखा जा सकता",
724
725
  "map.error.invalidDepth": "--depth के लिए अमान्य मान",
725
726
  "map.wrote": "REPO_MAP.md लिखा गया",
727
+ "flow.help.summary": "मौजूदा mustflow root के लिए design-flow map REPO_FLOW.md बनाता है।",
728
+ "flow.help.option.stdout": "Generated flow map print करें",
729
+ "flow.help.option.write": "REPO_FLOW.md लिखें",
730
+ "flow.help.option.check": "जांचें कि REPO_FLOW.md current है या नहीं",
731
+ "flow.help.exit.ok": "Flow map बनाया, लिखा, या check किया गया",
732
+ "flow.error.checkConflict": "--check को --stdout या --write के साथ नहीं रखा जा सकता",
733
+ "flow.check.missing": "REPO_FLOW.md missing है; mf flow --write से regenerate करें",
734
+ "flow.check.stale": "REPO_FLOW.md stale है; mf flow --write से regenerate करें",
735
+ "flow.check.current": "REPO_FLOW.md current है",
736
+ "flow.wrote": "REPO_FLOW.md लिखा गया",
726
737
  "lineEndings.help.summary": "Inspect Git-tracked files for line-ending policy drift and normalize them to LF when requested.",
727
738
  "lineEndings.help.option.all": "Inspect every tracked file instead of only changed files",
728
739
  "lineEndings.help.option.dryRun": "Preview normalization targets without writing files",
@@ -38,6 +38,7 @@ export const koMessages = {
38
38
  "command.update.summary": "mustflow 워크플로우 갱신을 미리 보거나 적용합니다",
39
39
  "command.upgrade.summary": "패키지 버전을 확인하고 설치된 워크플로우 파일을 안전하게 갱신합니다",
40
40
  "command.map.summary": "REPO_MAP.md를 작성합니다",
41
+ "command.flow.summary": "REPO_FLOW.md를 작성합니다",
41
42
  "command.lineEndings.summary": "줄바꿈 정책을 검사하고 정규화합니다",
42
43
  "command.quality.summary": "변경 파일의 품질 지표 꼼수를 검사합니다",
43
44
  "command.scriptPack.summary": "mustflow 내장 script pack을 나열, 추천, 실행합니다",
@@ -723,6 +724,16 @@ export const koMessages = {
723
724
  "map.error.nestedConflict": "--include-nested와 --root-only는 함께 사용할 수 없습니다",
724
725
  "map.error.invalidDepth": "--depth 값이 올바르지 않습니다",
725
726
  "map.wrote": "REPO_MAP.md를 작성했습니다",
727
+ "flow.help.summary": "현재 mustflow 루트의 설계 흐름 지도인 REPO_FLOW.md를 생성합니다.",
728
+ "flow.help.option.stdout": "생성한 흐름 지도를 출력합니다",
729
+ "flow.help.option.write": "REPO_FLOW.md를 작성합니다",
730
+ "flow.help.option.check": "REPO_FLOW.md가 최신인지 확인합니다",
731
+ "flow.help.exit.ok": "흐름 지도를 생성, 작성, 또는 확인했습니다",
732
+ "flow.error.checkConflict": "--check는 --stdout 또는 --write와 함께 사용할 수 없습니다",
733
+ "flow.check.missing": "REPO_FLOW.md가 없습니다. mf flow --write로 다시 생성하세요",
734
+ "flow.check.stale": "REPO_FLOW.md가 오래되었습니다. mf flow --write로 다시 생성하세요",
735
+ "flow.check.current": "REPO_FLOW.md가 최신입니다",
736
+ "flow.wrote": "REPO_FLOW.md를 작성했습니다",
726
737
  "lineEndings.help.summary": "Git 추적 파일의 줄바꿈 정책을 검사하고 필요할 때 LF로 정규화합니다.",
727
738
  "lineEndings.help.option.all": "변경된 파일만 보지 않고 모든 추적 파일을 검사합니다",
728
739
  "lineEndings.help.option.dryRun": "파일을 쓰지 않고 정규화 대상을 미리 봅니다",
@@ -38,6 +38,7 @@ export const zhMessages = {
38
38
  "command.update.summary": "预览或应用 mustflow 工作流更新",
39
39
  "command.upgrade.summary": "检查包版本并安全更新已安装的工作流文件",
40
40
  "command.map.summary": "生成 REPO_MAP.md",
41
+ "command.flow.summary": "生成 REPO_FLOW.md",
41
42
  "command.lineEndings.summary": "检查并规范化换行符策略",
42
43
  "command.quality.summary": "Inspect changed files for quality-gaming patterns",
43
44
  "command.scriptPack.summary": "List, suggest, and run bundled mustflow script packs",
@@ -723,6 +724,16 @@ export const zhMessages = {
723
724
  "map.error.nestedConflict": "不能同时使用 --include-nested 和 --root-only",
724
725
  "map.error.invalidDepth": "--depth 的值无效",
725
726
  "map.wrote": "已写入 REPO_MAP.md",
727
+ "flow.help.summary": "为当前 mustflow 根生成设计流程图 REPO_FLOW.md。",
728
+ "flow.help.option.stdout": "输出生成的流程图",
729
+ "flow.help.option.write": "写入 REPO_FLOW.md",
730
+ "flow.help.option.check": "检查 REPO_FLOW.md 是否为最新",
731
+ "flow.help.exit.ok": "流程图已生成、写入或检查",
732
+ "flow.error.checkConflict": "不能将 --check 与 --stdout 或 --write 组合使用",
733
+ "flow.check.missing": "REPO_FLOW.md 缺失;请用 mf flow --write 重新生成",
734
+ "flow.check.stale": "REPO_FLOW.md 已过期;请用 mf flow --write 重新生成",
735
+ "flow.check.current": "REPO_FLOW.md 是最新的",
736
+ "flow.wrote": "已写入 REPO_FLOW.md",
726
737
  "lineEndings.help.summary": "Inspect Git-tracked files for line-ending policy drift and normalize them to LF when requested.",
727
738
  "lineEndings.help.option.all": "Inspect every tracked file instead of only changed files",
728
739
  "lineEndings.help.option.dryRun": "Preview normalization targets without writing files",
package/dist/cli/index.js CHANGED
@@ -45,6 +45,7 @@ function getTopLevelHelp(lang) {
45
45
  'mf context --json',
46
46
  'mf tech suggest --scope frontend',
47
47
  'mf map --write',
48
+ 'mf flow --write',
48
49
  'mf search mustflow_check',
49
50
  'mf explain authority AGENTS.md',
50
51
  'mf explain --why-blocked test',
@@ -4,6 +4,9 @@ import { t } from './i18n.js';
4
4
  export const REPO_MAP_WRITE_EFFECTS = [
5
5
  { type: 'write', mode: 'replace', path: 'REPO_MAP.md', concurrency: 'exclusive' },
6
6
  ];
7
+ export const REPO_FLOW_WRITE_EFFECTS = [
8
+ { type: 'write', mode: 'replace', path: 'REPO_FLOW.md', concurrency: 'exclusive' },
9
+ ];
7
10
  export const LOCAL_INDEX_WRITE_EFFECTS = [
8
11
  {
9
12
  type: 'write',
@@ -26,6 +29,7 @@ export const MUSTFLOW_UPDATE_APPLY_EFFECTS = [
26
29
  ];
27
30
  export const GENERATED_SURFACE_READ_EFFECTS = [
28
31
  { type: 'read', mode: 'read', path: 'REPO_MAP.md', concurrency: 'shared' },
32
+ { type: 'read', mode: 'read', path: 'REPO_FLOW.md', concurrency: 'shared' },
29
33
  { type: 'read', mode: 'read', path: '.mustflow/config/manifest.lock.toml', concurrency: 'shared' },
30
34
  {
31
35
  type: 'read',
@@ -122,6 +122,13 @@ export const COMMAND_DEFINITIONS = [
122
122
  contract: commandContract(TEXT_OUTPUT),
123
123
  loadRunner: async () => (await import('../commands/map.js')).runMap,
124
124
  },
125
+ {
126
+ id: 'flow',
127
+ usage: 'mf flow',
128
+ summaryKey: 'command.flow.summary',
129
+ contract: commandContract(TEXT_OUTPUT),
130
+ loadRunner: async () => (await import('../commands/flow.js')).runFlow,
131
+ },
125
132
  {
126
133
  id: 'line-endings',
127
134
  usage: 'mf line-endings',
@@ -0,0 +1,35 @@
1
+ import { createHash } from 'node:crypto';
2
+ const REPO_FLOW_DOC_ID = 'repo-flow';
3
+ const REPO_FLOW_LIFECYCLE = 'generated';
4
+ const REPO_FLOW_GENERATOR = 'mustflow';
5
+ const REPO_FLOW_RELATIVE_ROOT = '.';
6
+ const REPO_FLOW_SOURCE_POLICY = 'flow_contract';
7
+ const REPO_FLOW_PRIVACY_MODE = 'minimal';
8
+ export function getRepoFlowSourceFingerprint(input) {
9
+ const payload = {
10
+ presentInputs: [...input.presentInputs].sort(),
11
+ configuredCommandIntents: [...input.configuredCommandIntents].sort(),
12
+ configuredReadOrder: [...input.configuredReadOrder].sort(),
13
+ configuredOptionalReadOrder: [...input.configuredOptionalReadOrder].sort(),
14
+ generatedDocuments: [...input.generatedDocuments].sort(),
15
+ flowIds: [...input.flowIds].sort(),
16
+ };
17
+ const digest = createHash('sha256').update(JSON.stringify(payload)).digest('hex');
18
+ return `sha256:${digest}`;
19
+ }
20
+ export function renderRepoFlowFrontmatter(flowCount, sourceFingerprint) {
21
+ return [
22
+ '---',
23
+ `mustflow_doc: ${REPO_FLOW_DOC_ID}`,
24
+ `lifecycle: ${REPO_FLOW_LIFECYCLE}`,
25
+ `generated_by: ${REPO_FLOW_GENERATOR}`,
26
+ `relative_root: "${REPO_FLOW_RELATIVE_ROOT}"`,
27
+ `source_policy: ${REPO_FLOW_SOURCE_POLICY}`,
28
+ `privacy_mode: ${REPO_FLOW_PRIVACY_MODE}`,
29
+ `flow_count: ${flowCount}`,
30
+ 'degraded: false',
31
+ `source_fingerprint: "${sourceFingerprint}"`,
32
+ '---',
33
+ '',
34
+ ];
35
+ }