mustflow 2.16.0 → 2.18.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 (36) hide show
  1. package/README.md +5 -5
  2. package/dist/cli/commands/classify.js +13 -3
  3. package/dist/cli/commands/dashboard.js +2 -1
  4. package/dist/cli/commands/impact.js +13 -3
  5. package/dist/cli/commands/run.js +86 -11
  6. package/dist/cli/commands/upgrade.js +3 -1
  7. package/dist/cli/commands/verify.js +9 -1
  8. package/dist/cli/commands/version.js +1 -1
  9. package/dist/cli/i18n/en.js +8 -1
  10. package/dist/cli/i18n/es.js +8 -1
  11. package/dist/cli/i18n/fr.js +8 -1
  12. package/dist/cli/i18n/hi.js +8 -1
  13. package/dist/cli/i18n/ko.js +7 -0
  14. package/dist/cli/i18n/zh.js +7 -0
  15. package/dist/cli/lib/git-changes.js +25 -2
  16. package/dist/cli/lib/local-index/constants.js +4 -1
  17. package/dist/cli/lib/local-index/index.js +22 -5
  18. package/dist/cli/lib/npm-version-check.js +71 -1
  19. package/dist/cli/lib/repo-map.js +81 -28
  20. package/dist/cli/lib/run-plan.js +25 -2
  21. package/dist/cli/lib/validation/index.js +2 -1
  22. package/dist/core/check-issues.js +2 -0
  23. package/dist/core/command-contract-rules.js +104 -2
  24. package/dist/core/command-contract-validation.js +14 -2
  25. package/dist/core/command-intent-eligibility.js +9 -1
  26. package/dist/core/command-output-limits.js +5 -0
  27. package/dist/core/contract-lint.js +10 -1
  28. package/package.json +1 -1
  29. package/schemas/README.md +3 -3
  30. package/schemas/change-verification-report.schema.json +2 -1
  31. package/schemas/contract-lint-report.schema.json +2 -1
  32. package/schemas/explain-report.schema.json +1 -0
  33. package/schemas/latest-run-pointer.schema.json +1 -0
  34. package/schemas/verify-report.schema.json +1 -0
  35. package/schemas/verify-run-manifest.schema.json +1 -0
  36. package/templates/default/manifest.toml +1 -1
package/README.md CHANGED
@@ -103,7 +103,7 @@ available as a direct shell command, install mustflow globally:
103
103
  npm install -g mustflow
104
104
  mf version --check
105
105
 
106
- bun install -g mustflow
106
+ bun add -g mustflow@latest
107
107
  mf version --check
108
108
  ```
109
109
 
@@ -282,10 +282,10 @@ npx mf update --dry-run
282
282
  npx mf update --apply
283
283
  ```
284
284
 
285
- After updating the mustflow package, `mf upgrade` combines the package freshness check with the safe project-file update step. It does not install packages by itself; update npm, pnpm, or Bun first.
285
+ After updating the mustflow package, `mf upgrade` combines the package freshness check with the safe project-file update step. It does not install packages by itself; refresh mustflow with the package manager you used first. When a newer release exists, `mf version --check` and `mf upgrade` print update commands for npm, Bun, pnpm, Yarn, and Deno.
286
286
 
287
287
  ```sh
288
- bun update -g mustflow
288
+ bun add -g mustflow@latest
289
289
  mf upgrade --dry-run
290
290
  mf upgrade
291
291
  ```
@@ -331,7 +331,7 @@ mf run mustflow_update_apply
331
331
  | `mf help <topic>` | Show installed mustflow help. |
332
332
  | `mf dashboard` | Start a local inspection dashboard for status, verification recommendations, release/version-source status, template update readiness, latest run receipt, skill routes, safe preferences, and documentation review. Use `--export-json <path>` or `--export <path>` for a bounded static report. It does not execute commands or apply fixes. |
333
333
  | `mf version` | Print the installed mustflow package version. |
334
- | `mf version --check` | Compare the installed package version with the latest npm release and print an update command if a newer version exists. |
334
+ | `mf version --check` | Compare the installed package version with the latest npm release and print package-manager update commands if a newer version exists. |
335
335
  | `mf version-sources` | Inspect detected package, template, and declared version sources without modifying files. |
336
336
  | `mf impact --changed` | Report whether changed paths require a package or template version decision. |
337
337
  | `mf verify --reason <event>` | Run configured verification intents selected by `required_after` metadata. |
@@ -354,7 +354,7 @@ Runnable work is declared in `.mustflow/config/commands.toml` so agents do not g
354
354
  - `run_policy = "agent_allowed"`
355
355
  - `stdin = "closed"`
356
356
 
357
- Development servers, watch modes, browser UIs, interactive commands, and background processes do not run directly.
357
+ Development servers, watch modes, browser UIs, interactive commands, and background processes do not run directly. `mf run` also rejects obvious long-running `argv` shapes, such as shell-wrapper background payloads, interpreter loops, package-manager development scripts, watchers, and development servers declared as one-shot commands.
358
358
 
359
359
  Use `mf verify --reason <event> --plan-only --json` to inspect matching verification intents, command eligibility, remaining gaps, and missing runnable coverage without executing commands. Use `mf run <intent> --dry-run --json` to inspect one resolved command intent without spawning a process or writing a run receipt. Plan-only verification includes a `decision_graph` that connects changed surfaces, classification reasons, command candidates, eligibility checks, effects, and gaps. When `.mustflow/cache/mustflow.sqlite` is fresh, scheduled entries also include read-only `effectGraph` metadata for write locks and lock conflicts. These graph rows are marked `explanation_only` and never grant command authority; `.mustflow/config/commands.toml` remains the only runnable command source.
360
360
 
@@ -2,7 +2,7 @@ import { mkdirSync, writeFileSync } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { createChangeClassificationReport, } from '../../core/change-classification.js';
4
4
  import { printUsageError, renderHelp } from '../lib/cli-output.js';
5
- import { readGitChangedFiles } from '../lib/git-changes.js';
5
+ import { requireGitChangedFiles } from '../lib/git-changes.js';
6
6
  import { t } from '../lib/i18n.js';
7
7
  import { resolveMustflowRoot } from '../lib/project-root.js';
8
8
  const CLASSIFY_SCHEMA_VERSION = '1';
@@ -67,7 +67,7 @@ function parseClassifyArgs(args) {
67
67
  return { json, changed, writePath, paths };
68
68
  }
69
69
  export function createClassifyOutput(projectRoot, source, paths) {
70
- const files = source === 'changed' ? readGitChangedFiles(projectRoot) : paths;
70
+ const files = source === 'changed' ? requireGitChangedFiles(projectRoot) : paths;
71
71
  return {
72
72
  schema_version: CLASSIFY_SCHEMA_VERSION,
73
73
  command: 'classify',
@@ -136,7 +136,17 @@ export function runClassify(args, reporter, lang = 'en') {
136
136
  return 1;
137
137
  }
138
138
  const projectRoot = resolveMustflowRoot();
139
- const output = createClassifyOutput(projectRoot, parsed.changed ? 'changed' : 'paths', parsed.paths);
139
+ let output;
140
+ try {
141
+ output = createClassifyOutput(projectRoot, parsed.changed ? 'changed' : 'paths', parsed.paths);
142
+ }
143
+ catch (error) {
144
+ const message = error instanceof Error && error.message === 'git_changed_files_unavailable'
145
+ ? t(lang, 'classify.error.changed_files_unavailable')
146
+ : t(lang, 'cli.common.invalidInput');
147
+ printUsageError(reporter, message, 'mf classify --help', getClassifyHelp(lang), lang);
148
+ return 1;
149
+ }
140
150
  if (parsed.writePath) {
141
151
  try {
142
152
  writeClassifyOutput(projectRoot, parsed.writePath, output);
@@ -682,7 +682,8 @@ async function renderStatusResponse(projectRoot) {
682
682
  const activeDocuments = listDocReviewEntries(projectRoot);
683
683
  const rawCommandContract = readDashboardCommandContract(projectRoot);
684
684
  const commandContract = await renderCommandContractResponse(projectRoot, rawCommandContract);
685
- const gitChangedFiles = readGitChangedFiles(projectRoot);
685
+ const gitChangedFilesResult = readGitChangedFiles(projectRoot);
686
+ const gitChangedFiles = gitChangedFilesResult.ok ? gitChangedFilesResult.files : [];
686
687
  const packageMetadata = readPackageMetadata();
687
688
  const verification = createDashboardVerificationSnapshot(projectRoot, rawCommandContract, commandContract.intents, gitChangedFiles, manifest.changedFiles, manifest.missingFiles);
688
689
  const readModel = await readLatestLocalVerificationReadModelQueries(projectRoot);
@@ -3,7 +3,7 @@ import { createChangeClassificationReport } from '../../core/change-classificati
3
3
  import { summarizeVersionImpact } from '../../core/version-impact.js';
4
4
  import { printUsageError, renderHelp } from '../lib/cli-output.js';
5
5
  import { isRecord } from '../lib/command-contract.js';
6
- import { readGitChangedFiles } from '../lib/git-changes.js';
6
+ import { requireGitChangedFiles } from '../lib/git-changes.js';
7
7
  import { t } from '../lib/i18n.js';
8
8
  import { resolveMustflowRoot } from '../lib/project-root.js';
9
9
  import { readTomlFile } from '../lib/toml.js';
@@ -56,7 +56,7 @@ function readPreferences(projectRoot) {
56
56
  }
57
57
  function createImpactOutput(projectRoot, parsed) {
58
58
  const source = parsed.changed ? 'changed' : 'paths';
59
- const files = parsed.changed ? readGitChangedFiles(projectRoot) : parsed.paths;
59
+ const files = parsed.changed ? requireGitChangedFiles(projectRoot) : parsed.paths;
60
60
  const classificationReport = createChangeClassificationReport(source, files);
61
61
  const versionSources = detectVersionSources(projectRoot);
62
62
  return {
@@ -110,7 +110,17 @@ export function runImpact(args, reporter, lang = 'en') {
110
110
  printUsageError(reporter, t(lang, 'impact.error.missingInput'), 'mf impact --help', getImpactHelp(lang), lang);
111
111
  return 1;
112
112
  }
113
- const output = createImpactOutput(resolveMustflowRoot(), parsed);
113
+ let output;
114
+ try {
115
+ output = createImpactOutput(resolveMustflowRoot(), parsed);
116
+ }
117
+ catch (error) {
118
+ const message = error instanceof Error && error.message === 'git_changed_files_unavailable'
119
+ ? t(lang, 'impact.error.changed_files_unavailable')
120
+ : t(lang, 'cli.common.invalidInput');
121
+ printUsageError(reporter, message, 'mf impact --help', getImpactHelp(lang), lang);
122
+ return 1;
123
+ }
114
124
  if (parsed.json) {
115
125
  reporter.stdout(JSON.stringify(output, null, 2));
116
126
  return 0;
@@ -24,7 +24,7 @@ function emitOutput(reporter, output, stream) {
24
24
  }
25
25
  reporter[stream](text);
26
26
  }
27
- function terminateProcessTree(pid) {
27
+ function signalProcessTree(pid, signal) {
28
28
  if (!pid || pid <= 0) {
29
29
  return;
30
30
  }
@@ -33,20 +33,73 @@ function terminateProcessTree(pid) {
33
33
  stdio: 'ignore',
34
34
  windowsHide: true,
35
35
  });
36
+ if (signal === 'SIGKILL') {
37
+ try {
38
+ process.kill(pid, signal);
39
+ }
40
+ catch {
41
+ // taskkill may already have terminated the direct child.
42
+ }
43
+ }
36
44
  return;
37
45
  }
38
46
  try {
39
- process.kill(-pid, 'SIGTERM');
47
+ process.kill(-pid, signal);
40
48
  }
41
49
  catch {
42
50
  try {
43
- process.kill(pid, 'SIGTERM');
51
+ process.kill(pid, signal);
44
52
  }
45
53
  catch {
46
54
  // The child may already be gone after Node's spawn timeout handling.
47
55
  }
48
56
  }
49
57
  }
58
+ function signalProcessTreeNonBlocking(pid, signal) {
59
+ if (!pid || pid <= 0) {
60
+ return;
61
+ }
62
+ if (process.platform === 'win32') {
63
+ const killer = spawn('taskkill', ['/PID', String(pid), '/T', '/F'], {
64
+ stdio: 'ignore',
65
+ windowsHide: true,
66
+ detached: true,
67
+ });
68
+ killer.unref();
69
+ if (signal === 'SIGKILL') {
70
+ try {
71
+ process.kill(pid, signal);
72
+ }
73
+ catch {
74
+ // taskkill may already have terminated the direct child.
75
+ }
76
+ }
77
+ return;
78
+ }
79
+ try {
80
+ process.kill(-pid, signal);
81
+ }
82
+ catch {
83
+ try {
84
+ process.kill(pid, signal);
85
+ }
86
+ catch {
87
+ // The child may already be gone after the timeout fired.
88
+ }
89
+ }
90
+ }
91
+ function terminateProcessTree(pid) {
92
+ signalProcessTree(pid, 'SIGTERM');
93
+ }
94
+ function forceTerminateProcessTree(pid) {
95
+ signalProcessTree(pid, 'SIGKILL');
96
+ }
97
+ function terminateProcessTreeNonBlocking(pid) {
98
+ signalProcessTreeNonBlocking(pid, 'SIGTERM');
99
+ }
100
+ function forceTerminateProcessTreeNonBlocking(pid) {
101
+ signalProcessTreeNonBlocking(pid, 'SIGKILL');
102
+ }
50
103
  function getKillMethod() {
51
104
  return process.platform === 'win32' ? 'taskkill_process_tree' : 'process_group_sigterm';
52
105
  }
@@ -178,14 +231,14 @@ function writeStreamChunk(reporter, stream, chunk) {
178
231
  reporter.writeStdout(chunk);
179
232
  return;
180
233
  }
181
- reporter.stdout(chunk.toString().trimEnd());
234
+ reporter.stdout(chunk.toString());
182
235
  return;
183
236
  }
184
237
  if (reporter.writeStderr) {
185
238
  reporter.writeStderr(chunk);
186
239
  return;
187
240
  }
188
- reporter.stderr(chunk.toString().trimEnd());
241
+ reporter.stderr(chunk.toString());
189
242
  }
190
243
  function runArgvCommandStreaming(command, cwd, env, timeoutSeconds, stdoutTailBytes, stderrTailBytes, reporter) {
191
244
  return new Promise((resolve) => {
@@ -214,8 +267,8 @@ function runArgvCommandStreaming(command, cwd, env, timeoutSeconds, stdoutTailBy
214
267
  clearTimeout(timeout);
215
268
  }
216
269
  resolve({
217
- status,
218
- signal,
270
+ status: timedOut ? null : status,
271
+ signal: timedOut ? null : signal,
219
272
  error: timedOut ? Object.assign(new Error('Command timed out'), { code: 'ETIMEDOUT' }) : childError,
220
273
  stdout: stdout.toSnapshot(),
221
274
  stderr: stderr.toSnapshot(),
@@ -238,7 +291,12 @@ function runArgvCommandStreaming(command, cwd, env, timeoutSeconds, stdoutTailBy
238
291
  });
239
292
  timeout = setTimeout(() => {
240
293
  timedOut = true;
241
- terminateProcessTree(childPid);
294
+ child.stdout?.destroy();
295
+ child.stderr?.destroy();
296
+ child.unref();
297
+ terminateProcessTreeNonBlocking(childPid);
298
+ forceTerminateProcessTreeNonBlocking(childPid);
299
+ finish(null, null);
242
300
  }, timeoutSeconds * 1000);
243
301
  });
244
302
  }
@@ -282,8 +340,8 @@ function runShellCommandStreaming(command, cwd, env, timeoutSeconds, stdoutTailB
282
340
  clearTimeout(timeout);
283
341
  }
284
342
  resolve({
285
- status,
286
- signal,
343
+ status: timedOut ? null : status,
344
+ signal: timedOut ? null : signal,
287
345
  error: timedOut ? Object.assign(new Error('Command timed out'), { code: 'ETIMEDOUT' }) : childError,
288
346
  stdout: stdout.toSnapshot(),
289
347
  stderr: stderr.toSnapshot(),
@@ -306,7 +364,12 @@ function runShellCommandStreaming(command, cwd, env, timeoutSeconds, stdoutTailB
306
364
  });
307
365
  timeout = setTimeout(() => {
308
366
  timedOut = true;
309
- terminateProcessTree(childPid);
367
+ child.stdout?.destroy();
368
+ child.stderr?.destroy();
369
+ child.unref();
370
+ terminateProcessTreeNonBlocking(childPid);
371
+ forceTerminateProcessTreeNonBlocking(childPid);
372
+ finish(null, null);
310
373
  }, timeoutSeconds * 1000);
311
374
  });
312
375
  }
@@ -356,12 +419,24 @@ function reportRunPlanFailure(plan, reporter, lang) {
356
419
  detail: getRunPlanDetail(plan, lang, 'run.error.blockedShellBackgroundDetail'),
357
420
  });
358
421
  break;
422
+ case 'blocked_long_running_command_pattern':
423
+ message = t(lang, 'run.error.blockedLongRunningCommand', {
424
+ intent: plan.intentName,
425
+ detail: getRunPlanDetail(plan, lang, 'run.error.blockedLongRunningCommandDetail'),
426
+ });
427
+ break;
359
428
  case 'cwd_outside_project':
360
429
  message = t(lang, 'run.error.cwdOutsideProject', {
361
430
  intent: plan.intentName,
362
431
  detail: getRunPlanDetail(plan, lang, 'run.error.cwdOutsideProjectDetail'),
363
432
  });
364
433
  break;
434
+ case 'max_output_bytes_exceeds_limit':
435
+ message = t(lang, 'run.error.maxOutputBytes', {
436
+ intent: plan.intentName,
437
+ detail: getRunPlanDetail(plan, lang, 'run.error.maxOutputBytesDetail'),
438
+ });
439
+ break;
365
440
  case 'intent_not_table':
366
441
  default:
367
442
  message = t(lang, 'run.error.unknownIntent', { intent: plan.intentName });
@@ -26,7 +26,9 @@ function printPackageCheck(check, reporter, lang) {
26
26
  if (check.updateAvailable) {
27
27
  reporter.stdout('');
28
28
  reporter.stdout(t(lang, 'version.check.updateCommand'));
29
- reporter.stdout(check.updateCommand);
29
+ for (const entry of check.updateCommands) {
30
+ reporter.stdout(`${entry.manager}: ${entry.command}`);
31
+ }
30
32
  }
31
33
  }
32
34
  export async function runUpgrade(args, reporter, lang = 'en') {
@@ -764,6 +764,8 @@ export function planErrorMessageKey(code) {
764
764
  return 'verify.error.unsupported_plan_source';
765
765
  case 'plan_root_mismatch':
766
766
  return 'verify.error.plan_root_mismatch';
767
+ case 'git_changed_files_unavailable':
768
+ return 'verify.error.changed_files_unavailable';
767
769
  default:
768
770
  return 'verify.error.invalid_plan_file';
769
771
  }
@@ -1293,6 +1295,7 @@ function writeVerifyRunReceipts(projectRoot, output, report, sourceAnchorRisks,
1293
1295
  reasons: outputWithReceiptPaths.reasons,
1294
1296
  plan_source: outputWithReceiptPaths.plan_source,
1295
1297
  verification_plan_id: outputWithReceiptPaths.verification_plan_id,
1298
+ execution_status: outputWithReceiptPaths.execution_status,
1296
1299
  status: outputWithReceiptPaths.status,
1297
1300
  completion_verdict: outputWithReceiptPaths.completion_verdict,
1298
1301
  evidence_model: outputWithReceiptPaths.evidence_model,
@@ -1312,6 +1315,7 @@ function writeVerifyRunReceipts(projectRoot, output, report, sourceAnchorRisks,
1312
1315
  reasons: outputWithReceiptPaths.reasons,
1313
1316
  plan_source: outputWithReceiptPaths.plan_source,
1314
1317
  verification_plan_id: outputWithReceiptPaths.verification_plan_id,
1318
+ execution_status: outputWithReceiptPaths.execution_status,
1315
1319
  status: outputWithReceiptPaths.status,
1316
1320
  completion_verdict: outputWithReceiptPaths.completion_verdict,
1317
1321
  evidence_model: outputWithReceiptPaths.evidence_model,
@@ -1403,6 +1407,7 @@ async function createVerifyOutput(input, planSource, projectRoot, lang, reproEvi
1403
1407
  reasons: input.reasons,
1404
1408
  plan_source: planSource,
1405
1409
  verification_plan_id: verificationPlanId,
1410
+ execution_status: status,
1406
1411
  status,
1407
1412
  completion_verdict: completionVerdict,
1408
1413
  evidence_model: evidenceModel,
@@ -1538,6 +1543,9 @@ export async function runVerify(args, reporter, lang = 'en') {
1538
1543
  let reproEvidence = null;
1539
1544
  let externalChecks = [];
1540
1545
  try {
1546
+ if (parsed.writePlan) {
1547
+ resolvePlanPath(projectRoot, parsed.writePlan);
1548
+ }
1541
1549
  if (parsed.changed) {
1542
1550
  const changedInput = createInputFromChanged(projectRoot);
1543
1551
  input = changedInput.input;
@@ -1587,5 +1595,5 @@ export async function runVerify(args, reporter, lang = 'en') {
1587
1595
  else {
1588
1596
  reporter.stdout(renderVerifyOutput(output, lang));
1589
1597
  }
1590
- return output.status === 'passed' ? 0 : 1;
1598
+ return output.completion_verdict.status === 'verified' ? 0 : 1;
1591
1599
  }
@@ -25,7 +25,7 @@ function renderVersionCheck(check, lang) {
25
25
  : t(lang, 'version.check.upToDate', { version: check.latestVersion }),
26
26
  ];
27
27
  if (check.updateAvailable) {
28
- lines.push('', t(lang, 'version.check.updateCommand'), check.updateCommand);
28
+ lines.push('', t(lang, 'version.check.updateCommand'), ...check.updateCommands.map((entry) => `${entry.manager}: ${entry.command}`));
29
29
  }
30
30
  return lines.join('\n');
31
31
  }
@@ -664,8 +664,12 @@ Read these files before working:
664
664
  "run.error.unsafeIntentDetail": "Use a shell-safe intent name.",
665
665
  "run.error.blockedShellBackground": 'Intent "{intent}" is blocked. {detail}',
666
666
  "run.error.blockedShellBackgroundDetail": "Shell commands must not spawn background work.",
667
+ "run.error.blockedLongRunningCommand": 'Intent "{intent}" is blocked. {detail}',
668
+ "run.error.blockedLongRunningCommandDetail": "Command argv must describe a finite one-shot command, not a development server, watcher, shell wrapper, interpreter loop, or background process.",
667
669
  "run.error.cwdOutsideProject": 'Command "{intent}" has an invalid cwd: {detail}',
668
670
  "run.error.cwdOutsideProjectDetail": "Intent cwd must stay inside the current root.",
671
+ "run.error.maxOutputBytes": 'Command "{intent}" has invalid max_output_bytes. {detail}',
672
+ "run.error.maxOutputBytesDetail": "The output limit must stay within the allowed maximum.",
669
673
  "run.error.conflictingPreviewModes": "Use either --dry-run or --plan-only, not both",
670
674
  "run.error.timedOut": 'Command "{intent}" timed out after {seconds} seconds',
671
675
  "run.error.startFailed": 'Command "{intent}" failed to start: {message}',
@@ -697,7 +701,7 @@ Read these files before working:
697
701
  "version.help.exit.ok": "Version information was printed",
698
702
  "version.check.latestAvailable": "latest {version} available",
699
703
  "version.check.upToDate": "latest {version}; already up to date",
700
- "version.check.updateCommand": "Update command:",
704
+ "version.check.updateCommand": "Update commands:",
701
705
  "version.error.checkFailed": "Could not check npm for a newer version: {message}",
702
706
  "upgrade.help.summary": "Check whether the installed mustflow package is current, then safely apply bundled workflow template updates when possible.",
703
707
  "upgrade.help.option.dryRun": "Check package status and print the project update plan without writing files",
@@ -727,6 +731,7 @@ Read these files before working:
727
731
  "classify.source.changed": "changed files",
728
732
  "classify.source.paths": "explicit paths",
729
733
  "classify.error.missingInput": "Specify --changed or at least one path",
734
+ "classify.error.changed_files_unavailable": "Unable to inspect changed files with git status",
730
735
  "classify.error.write_path_outside_root": "Classification report path must stay inside the mustflow root",
731
736
  "impact.help.summary": "Report whether changed paths require a package or template version decision without modifying files.",
732
737
  "impact.help.option.changed": "Read paths from git status --short --untracked-files=all",
@@ -741,6 +746,7 @@ Read these files before working:
741
746
  "impact.label.affectedVersionSources": "Affected version sources",
742
747
  "impact.label.affectedSurfaces": "Affected surfaces",
743
748
  "impact.error.missingInput": "Specify --changed or at least one path",
749
+ "impact.error.changed_files_unavailable": "Unable to inspect changed files with git status",
744
750
  "verify.help.summary": "Run configured verification intents selected by required_after metadata.",
745
751
  "verify.help.option.reason": "Select the required_after reason to verify",
746
752
  "verify.help.option.fromClassification": "Read verification reasons from an mf classify report inside this repository",
@@ -768,6 +774,7 @@ Read these files before working:
768
774
  "verify.error.plan_root_mismatch": "Classification report must come from this mustflow root",
769
775
  "verify.error.missing_plan_reasons": "Classification report must include summary.validationReasons",
770
776
  "verify.error.plan_path_outside_root": "Classification report path must stay inside the mustflow root",
777
+ "verify.error.changed_files_unavailable": "Unable to inspect changed files with git status",
771
778
  "verify.error.invalid_repro_evidence_file": "Repro evidence must be a readable JSON summary with structured evidence fields",
772
779
  "verify.error.unsupported_repro_evidence_source": "Repro evidence input must use command repro-evidence",
773
780
  "verify.error.invalid_external_evidence_file": "External evidence must be a readable JSON summary with checks",
@@ -664,8 +664,12 @@ Lee estos archivos antes de trabajar:
664
664
  "run.error.unsafeIntentDetail": "Usa un nombre de intención seguro para shell.",
665
665
  "run.error.blockedShellBackground": 'La intención "{intent}" está bloqueada. {detail}',
666
666
  "run.error.blockedShellBackgroundDetail": "Los comandos de shell no deben iniciar trabajo en segundo plano.",
667
+ "run.error.blockedLongRunningCommand": 'La intención "{intent}" está bloqueada. {detail}',
668
+ "run.error.blockedLongRunningCommandDetail": "argv debe describir un comando finito de una sola ejecución, no un servidor de desarrollo, watcher, envoltorio de shell, bucle de intérprete o proceso en segundo plano.",
667
669
  "run.error.cwdOutsideProject": 'El comando "{intent}" tiene un cwd no válido: {detail}',
668
670
  "run.error.cwdOutsideProjectDetail": "El cwd de la intención debe permanecer dentro de la raíz actual.",
671
+ "run.error.maxOutputBytes": 'El comando "{intent}" tiene max_output_bytes no válido. {detail}',
672
+ "run.error.maxOutputBytesDetail": "El límite de salida debe permanecer dentro del máximo permitido.",
669
673
  "run.error.conflictingPreviewModes": "Usa --dry-run o --plan-only, no ambos",
670
674
  "run.error.timedOut": 'El comando "{intent}" agotó el tiempo después de {seconds} segundos',
671
675
  "run.error.startFailed": 'No se pudo iniciar el comando "{intent}": {message}',
@@ -697,7 +701,7 @@ Lee estos archivos antes de trabajar:
697
701
  "version.help.exit.ok": "Se imprimió la información de versión",
698
702
  "version.check.latestAvailable": "última versión {version} disponible",
699
703
  "version.check.upToDate": "última versión {version}; ya está actualizado",
700
- "version.check.updateCommand": "Comando de actualización:",
704
+ "version.check.updateCommand": "Comandos de actualización:",
701
705
  "version.error.checkFailed": "No se pudo consultar npm para una versión nueva: {message}",
702
706
  "upgrade.help.summary": "Comprueba si el paquete mustflow instalado está actualizado y luego aplica de forma segura las actualizaciones de la plantilla incluida cuando sea posible.",
703
707
  "upgrade.help.option.dryRun": "Comprueba el estado del paquete e imprime el plan de actualización del proyecto sin escribir archivos",
@@ -727,6 +731,7 @@ Lee estos archivos antes de trabajar:
727
731
  "classify.source.changed": "archivos cambiados",
728
732
  "classify.source.paths": "rutas explicitas",
729
733
  "classify.error.missingInput": "Indica --changed o al menos una ruta",
734
+ "classify.error.changed_files_unavailable": "No se pudieron inspeccionar los archivos cambiados con git status",
730
735
  "classify.error.write_path_outside_root": "La ruta del informe de clasificacion debe permanecer dentro de la raiz mustflow",
731
736
  "impact.help.summary": "Informa si las rutas cambiadas requieren una decision de version de paquete o plantilla sin modificar archivos.",
732
737
  "impact.help.option.changed": "Lee rutas desde git status --short --untracked-files=all",
@@ -741,6 +746,7 @@ Lee estos archivos antes de trabajar:
741
746
  "impact.label.affectedVersionSources": "Fuentes de version afectadas",
742
747
  "impact.label.affectedSurfaces": "Superficies afectadas",
743
748
  "impact.error.missingInput": "Indica --changed o al menos una ruta",
749
+ "impact.error.changed_files_unavailable": "No se pudieron inspeccionar los archivos cambiados con git status",
744
750
  "verify.help.summary": "Ejecuta intenciones de verificación configuradas seleccionadas por metadatos required_after.",
745
751
  "verify.help.option.reason": "Selecciona la razón required_after que se debe verificar",
746
752
  "verify.help.option.fromClassification": "Lee razones de verificación desde un informe de mf classify dentro de este repositorio",
@@ -768,6 +774,7 @@ Lee estos archivos antes de trabajar:
768
774
  "verify.error.plan_root_mismatch": "El informe de clasificación debe provenir de esta raíz mustflow",
769
775
  "verify.error.missing_plan_reasons": "El informe de clasificación debe incluir summary.validationReasons",
770
776
  "verify.error.plan_path_outside_root": "La ruta del informe de clasificación debe permanecer dentro de la raíz mustflow",
777
+ "verify.error.changed_files_unavailable": "No se pudieron inspeccionar los archivos cambiados con git status",
771
778
  "verify.error.invalid_repro_evidence_file": "La evidencia de reproducción debe ser un resumen JSON legible con campos de evidencia estructurados",
772
779
  "verify.error.unsupported_repro_evidence_source": "La entrada de evidencia de reproducción debe usar command repro-evidence",
773
780
  "verify.error.invalid_external_evidence_file": "La evidencia externa debe ser un resumen JSON legible con checks",
@@ -664,8 +664,12 @@ Lisez ces fichiers avant de travailler :
664
664
  "run.error.unsafeIntentDetail": "Utilisez un nom d’intention sûr pour le shell.",
665
665
  "run.error.blockedShellBackground": 'L’intention "{intent}" est bloquée. {detail}',
666
666
  "run.error.blockedShellBackgroundDetail": "Les commandes shell ne doivent pas lancer de travail en arrière-plan.",
667
+ "run.error.blockedLongRunningCommand": 'L’intention "{intent}" est bloquée. {detail}',
668
+ "run.error.blockedLongRunningCommandDetail": "argv doit décrire une commande ponctuelle finie, pas un serveur de développement, un watcher, un wrapper shell, une boucle d'interpréteur ou un processus en arrière-plan.",
667
669
  "run.error.cwdOutsideProject": 'La commande "{intent}" a un cwd non valide : {detail}',
668
670
  "run.error.cwdOutsideProjectDetail": "Le cwd de l’intention doit rester dans la racine actuelle.",
671
+ "run.error.maxOutputBytes": 'La commande "{intent}" a une valeur max_output_bytes non valide. {detail}',
672
+ "run.error.maxOutputBytesDetail": "La limite de sortie doit rester dans le maximum autorisé.",
669
673
  "run.error.conflictingPreviewModes": "Utilisez --dry-run ou --plan-only, pas les deux",
670
674
  "run.error.timedOut": 'La commande "{intent}" a expiré après {seconds} secondes',
671
675
  "run.error.startFailed": 'Impossible de démarrer la commande "{intent}" : {message}',
@@ -697,7 +701,7 @@ Lisez ces fichiers avant de travailler :
697
701
  "version.help.exit.ok": "Les informations de version ont été affichées",
698
702
  "version.check.latestAvailable": "dernière version {version} disponible",
699
703
  "version.check.upToDate": "dernière version {version}; déjà à jour",
700
- "version.check.updateCommand": "Commande de mise à jour :",
704
+ "version.check.updateCommand": "Commandes de mise à jour :",
701
705
  "version.error.checkFailed": "Impossible de vérifier une nouvelle version sur npm : {message}",
702
706
  "upgrade.help.summary": "Vérifie si le paquet mustflow installé est à jour, puis applique en sécurité les mises à jour du modèle inclus quand c'est possible.",
703
707
  "upgrade.help.option.dryRun": "Vérifie l'état du paquet et affiche le plan de mise à jour du projet sans écrire de fichiers",
@@ -727,6 +731,7 @@ Lisez ces fichiers avant de travailler :
727
731
  "classify.source.changed": "fichiers modifies",
728
732
  "classify.source.paths": "chemins explicites",
729
733
  "classify.error.missingInput": "Indiquez --changed ou au moins un chemin",
734
+ "classify.error.changed_files_unavailable": "Impossible d'inspecter les fichiers modifies avec git status",
730
735
  "classify.error.write_path_outside_root": "Le chemin du rapport de classification doit rester dans la racine mustflow",
731
736
  "impact.help.summary": "Signale si les chemins modifies exigent une decision de version de paquet ou de modele sans modifier les fichiers.",
732
737
  "impact.help.option.changed": "Lire les chemins depuis git status --short --untracked-files=all",
@@ -741,6 +746,7 @@ Lisez ces fichiers avant de travailler :
741
746
  "impact.label.affectedVersionSources": "Sources de version affectees",
742
747
  "impact.label.affectedSurfaces": "Surfaces affectees",
743
748
  "impact.error.missingInput": "Indiquez --changed ou au moins un chemin",
749
+ "impact.error.changed_files_unavailable": "Impossible d'inspecter les fichiers modifies avec git status",
744
750
  "verify.help.summary": "Exécute les intentions de vérification configurées sélectionnées par les métadonnées required_after.",
745
751
  "verify.help.option.reason": "Sélectionne la raison required_after à vérifier",
746
752
  "verify.help.option.fromClassification": "Lit les raisons de vérification depuis un rapport mf classify dans ce dépôt",
@@ -768,6 +774,7 @@ Lisez ces fichiers avant de travailler :
768
774
  "verify.error.plan_root_mismatch": "Le rapport de classification doit venir de cette racine mustflow",
769
775
  "verify.error.missing_plan_reasons": "Le rapport de classification doit inclure summary.validationReasons",
770
776
  "verify.error.plan_path_outside_root": "Le chemin du rapport de classification doit rester dans la racine mustflow",
777
+ "verify.error.changed_files_unavailable": "Impossible d'inspecter les fichiers modifies avec git status",
771
778
  "verify.error.invalid_repro_evidence_file": "La preuve de reproduction doit être un résumé JSON lisible avec des champs de preuve structurés",
772
779
  "verify.error.unsupported_repro_evidence_source": "L'entrée de preuve de reproduction doit utiliser command repro-evidence",
773
780
  "verify.error.invalid_external_evidence_file": "La preuve externe doit être un résumé JSON lisible avec checks",
@@ -664,8 +664,12 @@ export const hiMessages = {
664
664
  "run.error.unsafeIntentDetail": "shell-safe इंटेंट नाम इस्तेमाल करें।",
665
665
  "run.error.blockedShellBackground": 'इंटेंट "{intent}" अवरुद्ध है। {detail}',
666
666
  "run.error.blockedShellBackgroundDetail": "Shell commands background work शुरू नहीं कर सकतीं।",
667
+ "run.error.blockedLongRunningCommand": 'इंटेंट "{intent}" अवरुद्ध है। {detail}',
668
+ "run.error.blockedLongRunningCommandDetail": "argv में finite one-shot command होना चाहिए, development server, watcher, shell wrapper, interpreter loop, या background process नहीं।",
667
669
  "run.error.cwdOutsideProject": 'कमांड "{intent}" का cwd अमान्य है: {detail}',
668
670
  "run.error.cwdOutsideProjectDetail": "Intent cwd current root के अंदर रहना चाहिए।",
671
+ "run.error.maxOutputBytes": 'कमांड "{intent}" में max_output_bytes अमान्य है। {detail}',
672
+ "run.error.maxOutputBytesDetail": "Output limit अनुमत maximum के अंदर रहनी चाहिए।",
669
673
  "run.error.conflictingPreviewModes": "--dry-run या --plan-only में से एक इस्तेमाल करें, दोनों नहीं",
670
674
  "run.error.timedOut": 'कमांड "{intent}" {seconds} सेकंड बाद time out हुई',
671
675
  "run.error.startFailed": 'कमांड "{intent}" शुरू नहीं हो सकी: {message}',
@@ -697,7 +701,7 @@ export const hiMessages = {
697
701
  "version.help.exit.ok": "Version जानकारी प्रिंट की गई",
698
702
  "version.check.latestAvailable": "latest {version} उपलब्ध है",
699
703
  "version.check.upToDate": "latest {version}; पहले से up to date",
700
- "version.check.updateCommand": "Update command:",
704
+ "version.check.updateCommand": "Update commands:",
701
705
  "version.error.checkFailed": "npm पर नया version जाँचा नहीं जा सका: {message}",
702
706
  "upgrade.help.summary": "जाँचें कि installed mustflow package current है या नहीं, फिर संभव होने पर current CLI में bundled workflow template updates सुरक्षित रूप से लागू करें.",
703
707
  "upgrade.help.option.dryRun": "Package status जाँचें और files लिखे बिना project update plan प्रिंट करें",
@@ -727,6 +731,7 @@ export const hiMessages = {
727
731
  "classify.source.changed": "बदली फ़ाइलें",
728
732
  "classify.source.paths": "दिए गए पथ",
729
733
  "classify.error.missingInput": "--changed या कम से कम एक पथ दें",
734
+ "classify.error.changed_files_unavailable": "git status से बदली फ़ाइलें नहीं पढ़ी जा सकीं",
730
735
  "classify.error.write_path_outside_root": "Classification report path mustflow root के अंदर रहना चाहिए",
731
736
  "impact.help.summary": "फ़ाइल बदले बिना बताएं कि बदले पथ package या template version decision मांगते हैं या नहीं.",
732
737
  "impact.help.option.changed": "git status --short --untracked-files=all से पथ पढ़ें",
@@ -741,6 +746,7 @@ export const hiMessages = {
741
746
  "impact.label.affectedVersionSources": "Affected version sources",
742
747
  "impact.label.affectedSurfaces": "Affected surfaces",
743
748
  "impact.error.missingInput": "--changed या कम से कम एक पथ दें",
749
+ "impact.error.changed_files_unavailable": "git status से बदली फ़ाइलें नहीं पढ़ी जा सकीं",
744
750
  "verify.help.summary": "required_after metadata से चुने गए configured verification intents चलाएँ।",
745
751
  "verify.help.option.reason": "Verify करने के लिए required_after reason चुनें",
746
752
  "verify.help.option.fromClassification": "इस repository के अंदर mf classify report से verification reasons पढ़ें",
@@ -768,6 +774,7 @@ export const hiMessages = {
768
774
  "verify.error.plan_root_mismatch": "Classification report इसी mustflow root से आना चाहिए",
769
775
  "verify.error.missing_plan_reasons": "Classification report में summary.validationReasons होना चाहिए",
770
776
  "verify.error.plan_path_outside_root": "Classification report path mustflow root के अंदर रहना चाहिए",
777
+ "verify.error.changed_files_unavailable": "git status से बदली फ़ाइलें नहीं पढ़ी जा सकीं",
771
778
  "verify.error.invalid_repro_evidence_file": "Repro evidence structured evidence fields वाला readable JSON summary होना चाहिए",
772
779
  "verify.error.unsupported_repro_evidence_source": "Repro evidence input को command repro-evidence इस्तेमाल करना चाहिए",
773
780
  "verify.error.invalid_external_evidence_file": "External evidence checks वाला readable JSON summary होना चाहिए",
@@ -664,8 +664,12 @@ export const koMessages = {
664
664
  "run.error.unsafeIntentDetail": "셸에서 안전한 명령 의도 이름을 사용하세요.",
665
665
  "run.error.blockedShellBackground": '명령 의도 "{intent}"가 차단되었습니다. {detail}',
666
666
  "run.error.blockedShellBackgroundDetail": "셸 명령은 백그라운드 작업을 시작하면 안 됩니다.",
667
+ "run.error.blockedLongRunningCommand": '명령 의도 "{intent}"가 차단되었습니다. {detail}',
668
+ "run.error.blockedLongRunningCommandDetail": "argv는 개발 서버, 감시 명령, 셸 래퍼, 인터프리터 반복 작업, 백그라운드 프로세스가 아니라 끝나는 단발성 명령이어야 합니다.",
667
669
  "run.error.cwdOutsideProject": '명령 "{intent}"의 실행 위치(cwd)가 올바르지 않습니다: {detail}',
668
670
  "run.error.cwdOutsideProjectDetail": "명령 실행 위치(cwd)는 현재 루트 안에 있어야 합니다.",
671
+ "run.error.maxOutputBytes": '명령 "{intent}"의 max_output_bytes 값이 올바르지 않습니다. {detail}',
672
+ "run.error.maxOutputBytesDetail": "출력 상한은 허용된 최댓값 안에 있어야 합니다.",
669
673
  "run.error.conflictingPreviewModes": "--dry-run과 --plan-only 중 하나만 사용하세요",
670
674
  "run.error.timedOut": '명령 "{intent}"가 {seconds}초 뒤 시간 초과되었습니다',
671
675
  "run.error.startFailed": '명령 "{intent}"를 시작하지 못했습니다: {message}',
@@ -727,6 +731,7 @@ export const koMessages = {
727
731
  "classify.source.changed": "변경 파일",
728
732
  "classify.source.paths": "지정한 경로",
729
733
  "classify.error.missingInput": "--changed 또는 하나 이상의 경로를 지정하세요",
734
+ "classify.error.changed_files_unavailable": "git status로 변경 파일을 확인할 수 없습니다",
730
735
  "classify.error.write_path_outside_root": "분류 보고서 경로는 mustflow 루트 안에 있어야 합니다",
731
736
  "impact.help.summary": "파일을 수정하지 않고 변경 경로가 패키지나 템플릿 버전 결정을 요구하는지 보고합니다.",
732
737
  "impact.help.option.changed": "git status --short --untracked-files=all에서 경로를 읽습니다",
@@ -741,6 +746,7 @@ export const koMessages = {
741
746
  "impact.label.affectedVersionSources": "영향받은 버전 기준 원본",
742
747
  "impact.label.affectedSurfaces": "영향받은 공개 표면",
743
748
  "impact.error.missingInput": "--changed 또는 하나 이상의 경로를 지정하세요",
749
+ "impact.error.changed_files_unavailable": "git status로 변경 파일을 확인할 수 없습니다",
744
750
  "verify.help.summary": "required_after 메타데이터로 선택된 설정된 검증 의도를 실행합니다.",
745
751
  "verify.help.option.reason": "검증할 required_after 이유를 지정합니다",
746
752
  "verify.help.option.fromClassification": "이 저장소 안의 mf classify 보고서에서 검증 이유를 읽습니다",
@@ -768,6 +774,7 @@ export const koMessages = {
768
774
  "verify.error.plan_root_mismatch": "분류 보고서는 현재 mustflow 루트에서 나온 것이어야 합니다",
769
775
  "verify.error.missing_plan_reasons": "분류 보고서에는 summary.validationReasons가 있어야 합니다",
770
776
  "verify.error.plan_path_outside_root": "분류 보고서 경로는 mustflow 루트 안에 있어야 합니다",
777
+ "verify.error.changed_files_unavailable": "git status로 변경 파일을 확인할 수 없습니다",
771
778
  "verify.error.invalid_repro_evidence_file": "재현 증거는 구조화된 증거 필드를 포함한 읽을 수 있는 JSON 요약이어야 합니다",
772
779
  "verify.error.unsupported_repro_evidence_source": "재현 증거 입력은 command repro-evidence를 사용해야 합니다",
773
780
  "verify.error.invalid_external_evidence_file": "외부 증거는 checks를 포함한 읽을 수 있는 JSON 요약이어야 합니다",