mustflow 2.106.0 → 2.107.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/dist/cli/commands/run/args.js +27 -2
- package/dist/cli/commands/run/execution.js +4 -1
- package/dist/cli/commands/run.js +14 -6
- package/dist/cli/commands/verify.js +1 -0
- package/dist/cli/i18n/en.js +2 -0
- package/dist/cli/i18n/es.js +2 -0
- package/dist/cli/i18n/fr.js +2 -0
- package/dist/cli/i18n/hi.js +2 -0
- package/dist/cli/i18n/ko.js +2 -0
- package/dist/cli/i18n/zh.js +2 -0
- package/dist/cli/lib/run-plan.js +9 -5
- package/dist/core/source-anchors.js +2 -0
- package/package.json +1 -1
- package/templates/default/manifest.toml +1 -1
|
@@ -3,6 +3,7 @@ import { t } from '../../lib/i18n.js';
|
|
|
3
3
|
import { getParsedCliStringOption, hasCliOptionToken, hasParsedCliOption, parseCliOptions, } from '../../lib/option-parser.js';
|
|
4
4
|
import { ALLOW_UNTRUSTED_ROOT_OPTION } from '../../lib/run-root-trust.js';
|
|
5
5
|
const DEFAULT_ACTIVE_LOCK_WAIT_TIMEOUT_SECONDS = 300;
|
|
6
|
+
const SUPPORTED_RUN_APPROVAL_ACTIONS = new Set(['network_access', 'destructive_command']);
|
|
6
7
|
const RUN_OPTIONS = [
|
|
7
8
|
{ name: '--json', kind: 'boolean' },
|
|
8
9
|
{ name: '--dry-run', kind: 'boolean' },
|
|
@@ -10,13 +11,28 @@ const RUN_OPTIONS = [
|
|
|
10
11
|
{ name: '--wait', kind: 'boolean' },
|
|
11
12
|
{ name: ALLOW_UNTRUSTED_ROOT_OPTION, kind: 'boolean' },
|
|
12
13
|
{ name: '--wait-timeout', kind: 'string' },
|
|
14
|
+
{ name: '--allow-approval', kind: 'string' },
|
|
13
15
|
];
|
|
14
16
|
export function hasRunHelpOption(args) {
|
|
15
17
|
return hasCliOptionToken(args, '--help', ['-h']);
|
|
16
18
|
}
|
|
19
|
+
export function getSupportedRunApprovalActions() {
|
|
20
|
+
return [...SUPPORTED_RUN_APPROVAL_ACTIONS].sort((left, right) => left.localeCompare(right));
|
|
21
|
+
}
|
|
22
|
+
function getAllowApprovalValues(parsed) {
|
|
23
|
+
const values = parsed.occurrences
|
|
24
|
+
.filter((occurrence) => occurrence.name === '--allow-approval')
|
|
25
|
+
.map((occurrence) => occurrence.value)
|
|
26
|
+
.filter((value) => typeof value === 'string');
|
|
27
|
+
return [...new Set(values)];
|
|
28
|
+
}
|
|
29
|
+
function findInvalidApprovalAction(values) {
|
|
30
|
+
return values.find((value) => !SUPPORTED_RUN_APPROVAL_ACTIONS.has(value)) ?? null;
|
|
31
|
+
}
|
|
17
32
|
export function parseRunArguments(args) {
|
|
18
33
|
const parsed = parseCliOptions(args, RUN_OPTIONS, { allowPositionals: true });
|
|
19
34
|
let waitTimeoutSeconds = DEFAULT_ACTIVE_LOCK_WAIT_TIMEOUT_SECONDS;
|
|
35
|
+
const allowApprovals = getAllowApprovalValues(parsed);
|
|
20
36
|
if (parsed.error) {
|
|
21
37
|
const [intentName, ...extra] = parsed.positionals;
|
|
22
38
|
return {
|
|
@@ -24,16 +40,22 @@ export function parseRunArguments(args) {
|
|
|
24
40
|
dryRun: hasParsedCliOption(parsed, '--dry-run'),
|
|
25
41
|
planOnly: hasParsedCliOption(parsed, '--plan-only'),
|
|
26
42
|
allowUntrustedRoot: hasParsedCliOption(parsed, ALLOW_UNTRUSTED_ROOT_OPTION),
|
|
43
|
+
allowApprovals,
|
|
27
44
|
wait: hasParsedCliOption(parsed, '--wait'),
|
|
28
45
|
waitTimeoutSeconds,
|
|
29
46
|
intentName: intentName ?? null,
|
|
30
47
|
extra,
|
|
48
|
+
invalidApprovalAction: null,
|
|
31
49
|
error: parsed.error,
|
|
32
50
|
};
|
|
33
51
|
}
|
|
52
|
+
const invalidApprovalAction = findInvalidApprovalAction(allowApprovals);
|
|
34
53
|
const waitTimeoutValue = getParsedCliStringOption(parsed, '--wait-timeout');
|
|
35
54
|
let error = null;
|
|
36
|
-
if (
|
|
55
|
+
if (invalidApprovalAction) {
|
|
56
|
+
error = 'invalid_approval_action';
|
|
57
|
+
}
|
|
58
|
+
else if (waitTimeoutValue !== null) {
|
|
37
59
|
const parsedWaitTimeout = Number(waitTimeoutValue);
|
|
38
60
|
if (!Number.isInteger(parsedWaitTimeout) || parsedWaitTimeout <= 0) {
|
|
39
61
|
error = 'invalid_wait_timeout';
|
|
@@ -48,10 +70,12 @@ export function parseRunArguments(args) {
|
|
|
48
70
|
dryRun: hasParsedCliOption(parsed, '--dry-run'),
|
|
49
71
|
planOnly: hasParsedCliOption(parsed, '--plan-only'),
|
|
50
72
|
allowUntrustedRoot: hasParsedCliOption(parsed, ALLOW_UNTRUSTED_ROOT_OPTION),
|
|
73
|
+
allowApprovals,
|
|
51
74
|
wait: hasParsedCliOption(parsed, '--wait'),
|
|
52
75
|
waitTimeoutSeconds,
|
|
53
76
|
intentName: intentName ?? null,
|
|
54
77
|
extra,
|
|
78
|
+
invalidApprovalAction,
|
|
55
79
|
error,
|
|
56
80
|
};
|
|
57
81
|
}
|
|
@@ -65,10 +89,11 @@ export function getRunHelp(lang = 'en') {
|
|
|
65
89
|
{ label: '--json', description: t(lang, 'run.help.option.json') },
|
|
66
90
|
{ label: '--wait', description: t(lang, 'run.help.option.wait') },
|
|
67
91
|
{ label: '--wait-timeout <seconds>', description: t(lang, 'run.help.option.waitTimeout') },
|
|
92
|
+
{ label: '--allow-approval <action>', description: t(lang, 'run.help.option.allowApproval') },
|
|
68
93
|
{ label: ALLOW_UNTRUSTED_ROOT_OPTION, description: t(lang, 'run.help.option.allowUntrustedRoot') },
|
|
69
94
|
{ label: '-h, --help', description: t(lang, 'cli.option.help') },
|
|
70
95
|
],
|
|
71
|
-
examples: ['mf run test', 'mf run lint --json', 'mf run
|
|
96
|
+
examples: ['mf run test', 'mf run lint --json', 'mf run release_npm_version_available --allow-approval network_access --json'],
|
|
72
97
|
exitCodes: [
|
|
73
98
|
{
|
|
74
99
|
label: '0',
|
|
@@ -188,7 +188,10 @@ export async function executeRunCommand(request, reporter, lang = 'en', options
|
|
|
188
188
|
return { exitCode: 1, receipt: null };
|
|
189
189
|
}
|
|
190
190
|
const contract = profiler.measure('command_contract', () => readCommandContract(projectRoot));
|
|
191
|
-
const plan = profiler.measure('plan_creation', () => createRunPlan(projectRoot, contract, request.intentName, {
|
|
191
|
+
const plan = profiler.measure('plan_creation', () => createRunPlan(projectRoot, contract, request.intentName, {
|
|
192
|
+
testTargets: options.testTargets,
|
|
193
|
+
approvedActions: request.allowApprovals,
|
|
194
|
+
}));
|
|
192
195
|
if (!plan.ok) {
|
|
193
196
|
if (request.outputMode === 'json') {
|
|
194
197
|
reporter.stdout(JSON.stringify(createRunPreview(plan, 'plan-only'), null, 2));
|
package/dist/cli/commands/run.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { printUsageError } from '../lib/cli-output.js';
|
|
2
2
|
import { t } from '../lib/i18n.js';
|
|
3
3
|
import { formatCliOptionParseError } from '../lib/option-parser.js';
|
|
4
|
-
import { getRunHelp, hasRunHelpOption, parseRunArguments } from './run/args.js';
|
|
4
|
+
import { getRunHelp, getSupportedRunApprovalActions, hasRunHelpOption, parseRunArguments } from './run/args.js';
|
|
5
5
|
import { executeRunCommand } from './run/execution.js';
|
|
6
6
|
import { executeRunPreviewCommand, getRunPreviewMode } from './run/preview.js';
|
|
7
7
|
export { getRunHelp } from './run/args.js';
|
|
@@ -19,7 +19,18 @@ export async function runRun(args, reporter, lang = 'en', options = {}) {
|
|
|
19
19
|
return 0;
|
|
20
20
|
}
|
|
21
21
|
const parsedArgs = parseRunArguments(args);
|
|
22
|
-
if (parsedArgs.error
|
|
22
|
+
if (parsedArgs.error === 'invalid_wait_timeout') {
|
|
23
|
+
printUsageError(reporter, t(lang, 'run.error.invalidWaitTimeout'), 'mf run --help', getRunHelp(lang), lang);
|
|
24
|
+
return 1;
|
|
25
|
+
}
|
|
26
|
+
if (parsedArgs.error === 'invalid_approval_action') {
|
|
27
|
+
printUsageError(reporter, t(lang, 'run.error.invalidApprovalAction', {
|
|
28
|
+
action: parsedArgs.invalidApprovalAction ?? 'unknown',
|
|
29
|
+
allowed: getSupportedRunApprovalActions().join(', '),
|
|
30
|
+
}), 'mf run --help', getRunHelp(lang), lang);
|
|
31
|
+
return 1;
|
|
32
|
+
}
|
|
33
|
+
if (parsedArgs.error) {
|
|
23
34
|
if (parsedArgs.error.kind === 'missing_value' && parsedArgs.error.option === '--wait-timeout') {
|
|
24
35
|
printUsageError(reporter, t(lang, 'run.error.invalidWaitTimeout'), 'mf run --help', getRunHelp(lang), lang);
|
|
25
36
|
return 1;
|
|
@@ -27,10 +38,6 @@ export async function runRun(args, reporter, lang = 'en', options = {}) {
|
|
|
27
38
|
printUsageError(reporter, formatCliOptionParseError(parsedArgs.error, lang), 'mf run --help', getRunHelp(lang), lang);
|
|
28
39
|
return 1;
|
|
29
40
|
}
|
|
30
|
-
if (parsedArgs.error === 'invalid_wait_timeout') {
|
|
31
|
-
printUsageError(reporter, t(lang, 'run.error.invalidWaitTimeout'), 'mf run --help', getRunHelp(lang), lang);
|
|
32
|
-
return 1;
|
|
33
|
-
}
|
|
34
41
|
const json = parsedArgs.json;
|
|
35
42
|
const dryRun = parsedArgs.dryRun;
|
|
36
43
|
const planOnly = parsedArgs.planOnly;
|
|
@@ -59,6 +66,7 @@ export async function runRun(args, reporter, lang = 'en', options = {}) {
|
|
|
59
66
|
intentName,
|
|
60
67
|
outputMode: json ? 'json' : 'text',
|
|
61
68
|
allowUntrustedRoot,
|
|
69
|
+
allowApprovals: parsedArgs.allowApprovals,
|
|
62
70
|
wait: parsedArgs.wait,
|
|
63
71
|
waitTimeoutSeconds: parsedArgs.waitTimeoutSeconds,
|
|
64
72
|
}, reporter, lang, options);
|
|
@@ -161,6 +161,7 @@ async function runVerificationIntent(intent, lang, verificationPlanId, correlati
|
|
|
161
161
|
intentName: intent,
|
|
162
162
|
outputMode: 'silent',
|
|
163
163
|
allowUntrustedRoot: false,
|
|
164
|
+
allowApprovals: [],
|
|
164
165
|
wait: false,
|
|
165
166
|
waitTimeoutSeconds: 1,
|
|
166
167
|
}, output.reporter, lang, {
|
package/dist/cli/i18n/en.js
CHANGED
|
@@ -1287,6 +1287,7 @@ Read these files before working:
|
|
|
1287
1287
|
"run.help.option.json": "Print the run record or command plan as JSON",
|
|
1288
1288
|
"run.help.option.wait": "Wait for conflicting active run locks before executing",
|
|
1289
1289
|
"run.help.option.waitTimeout": "Maximum seconds to wait for active run locks. Default: 300",
|
|
1290
|
+
"run.help.option.allowApproval": "Allow this execution to satisfy one approval-gated action such as network_access",
|
|
1290
1291
|
"run.help.option.allowUntrustedRoot": "Allow one execution from a root with a missing or invalid manifest lock after manual review",
|
|
1291
1292
|
"run.help.exit.ok": "The command completed with an allowed exit code",
|
|
1292
1293
|
"run.help.exit.fail": "The command was invalid, refused, timed out, or failed",
|
|
@@ -1319,6 +1320,7 @@ Read these files before working:
|
|
|
1319
1320
|
"run.error.maxOutputBytesDetail": "The output limit must stay within the allowed maximum.",
|
|
1320
1321
|
"run.error.conflictingPreviewModes": "Use either --dry-run or --plan-only, not both",
|
|
1321
1322
|
"run.error.invalidWaitTimeout": "--wait-timeout must be a positive integer",
|
|
1323
|
+
"run.error.invalidApprovalAction": 'Unsupported approval action "{action}". Supported actions: {allowed}',
|
|
1322
1324
|
"run.error.waitRequiresExecution": "--wait can only be used when executing a command, not with --dry-run or --plan-only",
|
|
1323
1325
|
"run.error.untrustedRootMissing": "Refused to execute commands because {path} is missing. Run mf init/update to install the workflow, or pass --allow-untrusted-root after reviewing AGENTS.md and .mustflow/config/commands.toml.",
|
|
1324
1326
|
"run.error.untrustedRootInvalid": "Refused to execute commands because the manifest lock is invalid: {detail}. Restore or regenerate it, or pass --allow-untrusted-root after reviewing AGENTS.md and .mustflow/config/commands.toml.",
|
package/dist/cli/i18n/es.js
CHANGED
|
@@ -1287,6 +1287,7 @@ Lee estos archivos antes de trabajar:
|
|
|
1287
1287
|
"run.help.option.json": "Imprime el registro de ejecución o el plan de comando como JSON",
|
|
1288
1288
|
"run.help.option.wait": "Espera bloqueos activos en conflicto antes de ejecutar",
|
|
1289
1289
|
"run.help.option.waitTimeout": "Segundos máximos para esperar bloqueos activos. Predeterminado: 300",
|
|
1290
|
+
"run.help.option.allowApproval": "Permite que esta ejecución satisfaga una acción con aprobación como network_access",
|
|
1290
1291
|
"run.help.option.allowUntrustedRoot": "Permite una ejecución desde una raíz con bloqueo de manifiesto ausente o inválido tras revisión manual",
|
|
1291
1292
|
"run.help.exit.ok": "El comando se completo con un codigo de salida permitido",
|
|
1292
1293
|
"run.help.exit.fail": "El comando no era válido, fue rechazado, agotó el tiempo o falló",
|
|
@@ -1319,6 +1320,7 @@ Lee estos archivos antes de trabajar:
|
|
|
1319
1320
|
"run.error.maxOutputBytesDetail": "El límite de salida debe permanecer dentro del máximo permitido.",
|
|
1320
1321
|
"run.error.conflictingPreviewModes": "Usa --dry-run o --plan-only, no ambos",
|
|
1321
1322
|
"run.error.invalidWaitTimeout": "--wait-timeout debe ser un entero positivo",
|
|
1323
|
+
"run.error.invalidApprovalAction": 'Acción de aprobación no admitida "{action}". Acciones admitidas: {allowed}',
|
|
1322
1324
|
"run.error.waitRequiresExecution": "--wait solo se puede usar al ejecutar un comando, no con --dry-run o --plan-only",
|
|
1323
1325
|
"run.error.untrustedRootMissing": "Se rechazó ejecutar comandos porque falta {path}. Ejecuta mf init/update para instalar el flujo, o usa --allow-untrusted-root tras revisar AGENTS.md y .mustflow/config/commands.toml.",
|
|
1324
1326
|
"run.error.untrustedRootInvalid": "Se rechazó ejecutar comandos porque el bloqueo de manifiesto no es válido: {detail}. Restáuralo o regenéralo, o usa --allow-untrusted-root tras revisar AGENTS.md y .mustflow/config/commands.toml.",
|
package/dist/cli/i18n/fr.js
CHANGED
|
@@ -1287,6 +1287,7 @@ Lisez ces fichiers avant de travailler :
|
|
|
1287
1287
|
"run.help.option.json": "Imprime l'enregistrement d'exécution ou le plan de commande en JSON",
|
|
1288
1288
|
"run.help.option.wait": "Attend les verrous actifs en conflit avant d'exécuter",
|
|
1289
1289
|
"run.help.option.waitTimeout": "Nombre maximal de secondes d'attente des verrous actifs. Par défaut : 300",
|
|
1290
|
+
"run.help.option.allowApproval": "Autorise cette exécution à satisfaire une action soumise à approbation comme network_access",
|
|
1290
1291
|
"run.help.option.allowUntrustedRoot": "Autorise une seule exécution depuis une racine sans verrou de manifeste valide après revue manuelle",
|
|
1291
1292
|
"run.help.exit.ok": "La commande s'est terminée avec un code de sortie autorisé",
|
|
1292
1293
|
"run.help.exit.fail": "La commande était non valide, refusée, expirée ou a échoué",
|
|
@@ -1319,6 +1320,7 @@ Lisez ces fichiers avant de travailler :
|
|
|
1319
1320
|
"run.error.maxOutputBytesDetail": "La limite de sortie doit rester dans le maximum autorisé.",
|
|
1320
1321
|
"run.error.conflictingPreviewModes": "Utilisez --dry-run ou --plan-only, pas les deux",
|
|
1321
1322
|
"run.error.invalidWaitTimeout": "--wait-timeout doit être un entier positif",
|
|
1323
|
+
"run.error.invalidApprovalAction": 'Action d’approbation non prise en charge "{action}". Actions prises en charge : {allowed}',
|
|
1322
1324
|
"run.error.waitRequiresExecution": "--wait ne peut être utilisé que lors de l'exécution d'une commande, pas avec --dry-run ou --plan-only",
|
|
1323
1325
|
"run.error.untrustedRootMissing": "Exécution refusée car {path} est absent. Lancez mf init/update pour installer le workflow, ou ajoutez --allow-untrusted-root après avoir relu AGENTS.md et .mustflow/config/commands.toml.",
|
|
1324
1326
|
"run.error.untrustedRootInvalid": "Exécution refusée car le verrou de manifeste est invalide : {detail}. Restaurez-le ou régénérez-le, ou ajoutez --allow-untrusted-root après avoir relu AGENTS.md et .mustflow/config/commands.toml.",
|
package/dist/cli/i18n/hi.js
CHANGED
|
@@ -1287,6 +1287,7 @@ export const hiMessages = {
|
|
|
1287
1287
|
"run.help.option.json": "Run record या command plan को JSON के रूप में प्रिंट करें",
|
|
1288
1288
|
"run.help.option.wait": "चलाने से पहले conflicting active run locks के लिए wait करें",
|
|
1289
1289
|
"run.help.option.waitTimeout": "active run locks के लिए wait करने की maximum seconds. Default: 300",
|
|
1290
|
+
"run.help.option.allowApproval": "इस execution को network_access जैसे approval-gated action को satisfy करने दें",
|
|
1290
1291
|
"run.help.option.allowUntrustedRoot": "Manual review के बाद missing या invalid manifest lock वाली root से एक execution allow करें",
|
|
1291
1292
|
"run.help.exit.ok": "कमांड अनुमत exit code के साथ पूरी हुई",
|
|
1292
1293
|
"run.help.exit.fail": "कमांड अमान्य थी, अस्वीकार हुई, timed out हुई या विफल हुई",
|
|
@@ -1319,6 +1320,7 @@ export const hiMessages = {
|
|
|
1319
1320
|
"run.error.maxOutputBytesDetail": "Output limit अनुमत maximum के अंदर रहनी चाहिए।",
|
|
1320
1321
|
"run.error.conflictingPreviewModes": "--dry-run या --plan-only में से एक इस्तेमाल करें, दोनों नहीं",
|
|
1321
1322
|
"run.error.invalidWaitTimeout": "--wait-timeout positive integer होना चाहिए",
|
|
1323
|
+
"run.error.invalidApprovalAction": 'Unsupported approval action "{action}". Supported actions: {allowed}',
|
|
1322
1324
|
"run.error.waitRequiresExecution": "--wait केवल command execute करते समय इस्तेमाल हो सकता है, --dry-run या --plan-only के साथ नहीं",
|
|
1323
1325
|
"run.error.untrustedRootMissing": "{path} missing है, इसलिए commands execute करने से मना किया गया। Workflow install करने के लिए mf init/update चलाएँ, या AGENTS.md और .mustflow/config/commands.toml review करने के बाद --allow-untrusted-root पास करें।",
|
|
1324
1326
|
"run.error.untrustedRootInvalid": "Manifest lock invalid है, इसलिए commands execute करने से मना किया गया: {detail}. इसे restore या regenerate करें, या AGENTS.md और .mustflow/config/commands.toml review करने के बाद --allow-untrusted-root पास करें।",
|
package/dist/cli/i18n/ko.js
CHANGED
|
@@ -1287,6 +1287,7 @@ export const koMessages = {
|
|
|
1287
1287
|
"run.help.option.json": "실행 결과 또는 명령 계획을 JSON으로 출력합니다",
|
|
1288
1288
|
"run.help.option.wait": "충돌하는 활성 실행 잠금이 풀릴 때까지 기다린 뒤 실행합니다",
|
|
1289
1289
|
"run.help.option.waitTimeout": "활성 실행 잠금을 기다릴 최대 초입니다. 기본값: 300",
|
|
1290
|
+
"run.help.option.allowApproval": "이번 실행에서 network_access 같은 승인 게이트 action 하나를 허용합니다",
|
|
1290
1291
|
"run.help.option.allowUntrustedRoot": "잠금 파일이 없거나 올바르지 않은 루트에서 수동 검토 후 이번 실행만 허용합니다",
|
|
1291
1292
|
"run.help.exit.ok": "명령이 허용된 종료 코드로 완료되었습니다",
|
|
1292
1293
|
"run.help.exit.fail": "명령이 잘못되었거나, 거부되었거나, 시간 초과되었거나, 실패했습니다",
|
|
@@ -1319,6 +1320,7 @@ export const koMessages = {
|
|
|
1319
1320
|
"run.error.maxOutputBytesDetail": "출력 상한은 허용된 최댓값 안에 있어야 합니다.",
|
|
1320
1321
|
"run.error.conflictingPreviewModes": "--dry-run과 --plan-only 중 하나만 사용하세요",
|
|
1321
1322
|
"run.error.invalidWaitTimeout": "--wait-timeout은 양의 정수여야 합니다",
|
|
1323
|
+
"run.error.invalidApprovalAction": '지원하지 않는 승인 action입니다: "{action}". 지원 action: {allowed}',
|
|
1322
1324
|
"run.error.waitRequiresExecution": "--wait는 --dry-run 또는 --plan-only가 아닌 실제 명령 실행에만 사용할 수 있습니다",
|
|
1323
1325
|
"run.error.untrustedRootMissing": "{path}이 없어 명령 실행을 거부했습니다. mf init/update로 워크플로우를 설치하거나, AGENTS.md와 .mustflow/config/commands.toml을 검토한 뒤 --allow-untrusted-root를 붙이세요.",
|
|
1324
1326
|
"run.error.untrustedRootInvalid": "잠금 파일이 올바르지 않아 명령 실행을 거부했습니다: {detail}. 파일을 복구하거나 다시 생성하거나, AGENTS.md와 .mustflow/config/commands.toml을 검토한 뒤 --allow-untrusted-root를 붙이세요.",
|
package/dist/cli/i18n/zh.js
CHANGED
|
@@ -1287,6 +1287,7 @@ export const zhMessages = {
|
|
|
1287
1287
|
"run.help.option.json": "将运行记录或命令计划输出为 JSON",
|
|
1288
1288
|
"run.help.option.wait": "执行前等待冲突的活动运行锁释放",
|
|
1289
1289
|
"run.help.option.waitTimeout": "等待活动运行锁的最大秒数。默认值:300",
|
|
1290
|
+
"run.help.option.allowApproval": "允许本次执行满足一个需要审批的动作,例如 network_access",
|
|
1290
1291
|
"run.help.option.allowUntrustedRoot": "人工复核后,允许从缺失或无效清单锁的根目录执行一次命令",
|
|
1291
1292
|
"run.help.exit.ok": "命令已以允许的退出码完成",
|
|
1292
1293
|
"run.help.exit.fail": "命令无效、被拒绝、超时或失败",
|
|
@@ -1319,6 +1320,7 @@ export const zhMessages = {
|
|
|
1319
1320
|
"run.error.maxOutputBytesDetail": "输出限制必须保持在允许的最大值内。",
|
|
1320
1321
|
"run.error.conflictingPreviewModes": "只能使用 --dry-run 或 --plan-only,不能同时使用",
|
|
1321
1322
|
"run.error.invalidWaitTimeout": "--wait-timeout 必须是正整数",
|
|
1323
|
+
"run.error.invalidApprovalAction": '不支持的审批动作 "{action}"。支持的动作:{allowed}',
|
|
1322
1324
|
"run.error.waitRequiresExecution": "--wait 只能用于实际执行命令,不能与 --dry-run 或 --plan-only 一起使用",
|
|
1323
1325
|
"run.error.untrustedRootMissing": "已拒绝执行命令,因为缺少 {path}。请运行 mf init/update 安装工作流,或在检查 AGENTS.md 和 .mustflow/config/commands.toml 后传入 --allow-untrusted-root。",
|
|
1324
1326
|
"run.error.untrustedRootInvalid": "已拒绝执行命令,因为清单锁无效:{detail}。请恢复或重新生成它,或在检查 AGENTS.md 和 .mustflow/config/commands.toml 后传入 --allow-untrusted-root。",
|
package/dist/cli/lib/run-plan.js
CHANGED
|
@@ -51,6 +51,9 @@ function commandAcceptsTestTargets(intent) {
|
|
|
51
51
|
function isResolvedWindowsCommandScript(executablePath) {
|
|
52
52
|
return process.platform === 'win32' && isWindowsCommandScriptPath(executablePath);
|
|
53
53
|
}
|
|
54
|
+
function createApprovedActionSet(actions) {
|
|
55
|
+
return new Set((actions ?? []).map((action) => action.trim()).filter((action) => action.length > 0));
|
|
56
|
+
}
|
|
54
57
|
export function isMustflowBuiltinIntent(intent) {
|
|
55
58
|
return readString(intent, 'kind') === 'mustflow_builtin';
|
|
56
59
|
}
|
|
@@ -129,7 +132,7 @@ function readRunIntentMetadata(contract, intent) {
|
|
|
129
132
|
relatedOneshotChecks: readStringArray(intent, 'related_oneshot_checks') ?? [],
|
|
130
133
|
};
|
|
131
134
|
}
|
|
132
|
-
function createApprovalBlock(projectRoot, metadata) {
|
|
135
|
+
function createApprovalBlock(projectRoot, metadata, approvedActions) {
|
|
133
136
|
const actionTypes = [];
|
|
134
137
|
if (metadata.network === true) {
|
|
135
138
|
actionTypes.push('network_access');
|
|
@@ -150,15 +153,16 @@ function createApprovalBlock(projectRoot, metadata) {
|
|
|
150
153
|
const requiredActions = approvalReport.decisions
|
|
151
154
|
.filter((decision) => decision.approval_required)
|
|
152
155
|
.map((decision) => decision.action_type);
|
|
153
|
-
|
|
156
|
+
const missingActions = requiredActions.filter((action) => !approvedActions.has(action));
|
|
157
|
+
if (missingActions.length === 0) {
|
|
154
158
|
return null;
|
|
155
159
|
}
|
|
156
|
-
const reasonCode =
|
|
160
|
+
const reasonCode = missingActions.includes('destructive_command')
|
|
157
161
|
? 'destructive_requires_approval'
|
|
158
162
|
: 'network_requires_approval';
|
|
159
163
|
return {
|
|
160
164
|
reasonCode,
|
|
161
|
-
detail: `Action ${
|
|
165
|
+
detail: `Action ${missingActions.map((action) => JSON.stringify(action)).join(', ')} requires explicit approval before mf run can execute this intent.`,
|
|
162
166
|
};
|
|
163
167
|
}
|
|
164
168
|
function createBlockedRunPlan(contract, intentName, intent, eligibility, reasonCode, detail, preconditions = []) {
|
|
@@ -214,7 +218,7 @@ export function createRunPlan(projectRoot, contract, intentName, options = {}) {
|
|
|
214
218
|
return createBlockedRunPlan(contract, intentName, rawIntent, eligibility, eligibility.code, eligibility.detail, preconditions);
|
|
215
219
|
}
|
|
216
220
|
const metadata = readRunIntentMetadata(contract, rawIntent);
|
|
217
|
-
const approvalBlock = createApprovalBlock(projectRoot, metadata);
|
|
221
|
+
const approvalBlock = createApprovalBlock(projectRoot, metadata, createApprovedActionSet(options.approvedActions));
|
|
218
222
|
if (approvalBlock) {
|
|
219
223
|
return createBlockedRunPlan(contract, intentName, rawIntent, eligibility, approvalBlock.reasonCode, approvalBlock.detail, preconditions);
|
|
220
224
|
}
|
package/package.json
CHANGED