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.
- package/README.md +5 -5
- package/dist/cli/commands/classify.js +13 -3
- package/dist/cli/commands/dashboard.js +2 -1
- package/dist/cli/commands/impact.js +13 -3
- package/dist/cli/commands/run.js +86 -11
- package/dist/cli/commands/upgrade.js +3 -1
- package/dist/cli/commands/verify.js +9 -1
- package/dist/cli/commands/version.js +1 -1
- package/dist/cli/i18n/en.js +8 -1
- package/dist/cli/i18n/es.js +8 -1
- package/dist/cli/i18n/fr.js +8 -1
- package/dist/cli/i18n/hi.js +8 -1
- package/dist/cli/i18n/ko.js +7 -0
- package/dist/cli/i18n/zh.js +7 -0
- package/dist/cli/lib/git-changes.js +25 -2
- package/dist/cli/lib/local-index/constants.js +4 -1
- package/dist/cli/lib/local-index/index.js +22 -5
- package/dist/cli/lib/npm-version-check.js +71 -1
- package/dist/cli/lib/repo-map.js +81 -28
- package/dist/cli/lib/run-plan.js +25 -2
- package/dist/cli/lib/validation/index.js +2 -1
- package/dist/core/check-issues.js +2 -0
- package/dist/core/command-contract-rules.js +104 -2
- package/dist/core/command-contract-validation.js +14 -2
- package/dist/core/command-intent-eligibility.js +9 -1
- package/dist/core/command-output-limits.js +5 -0
- package/dist/core/contract-lint.js +10 -1
- package/package.json +1 -1
- package/schemas/README.md +3 -3
- package/schemas/change-verification-report.schema.json +2 -1
- package/schemas/contract-lint-report.schema.json +2 -1
- package/schemas/explain-report.schema.json +1 -0
- package/schemas/latest-run-pointer.schema.json +1 -0
- package/schemas/verify-report.schema.json +1 -0
- package/schemas/verify-run-manifest.schema.json +1 -0
- package/templates/default/manifest.toml +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { COMMAND_LIFECYCLES, COMMAND_RUN_POLICIES, LONG_RUNNING_LIFECYCLES, isRecord, } from './config-loading.js';
|
|
2
2
|
import { COMMAND_ENV_POLICIES } from './command-env.js';
|
|
3
3
|
import { COMMAND_EFFECT_CONCURRENCY, COMMAND_EFFECT_MODES, COMMAND_EFFECT_TYPES, validateCommandEffectLockWarnings, validateCommandEffects, } from './command-effects.js';
|
|
4
|
-
import { commandIntentHasBlockedShellBackgroundPattern, commandIntentHasCommandSource, commandIntentNameIsSafe, } from './command-contract-rules.js';
|
|
4
|
+
import { commandIntentBlockedCommandPattern, commandIntentHasBlockedShellBackgroundPattern, commandIntentHasCommandSource, commandIntentNameIsSafe, } from './command-contract-rules.js';
|
|
5
|
+
import { MAX_COMMAND_OUTPUT_BYTES, commandMaxOutputBytesLimitMessage } from './command-output-limits.js';
|
|
5
6
|
function commandContractIssue(message) {
|
|
6
7
|
return { message };
|
|
7
8
|
}
|
|
@@ -46,6 +47,12 @@ function validatePositiveIntegerField(table, key, label, issues) {
|
|
|
46
47
|
issues.push(commandContractIssue(`${label} must be a positive integer`));
|
|
47
48
|
}
|
|
48
49
|
}
|
|
50
|
+
function validateMaxOutputBytesField(table, key, label, issues) {
|
|
51
|
+
validatePositiveIntegerField(table, key, label, issues);
|
|
52
|
+
if (isPositiveInteger(table[key]) && Number(table[key]) > MAX_COMMAND_OUTPUT_BYTES) {
|
|
53
|
+
issues.push(commandContractIssue(commandMaxOutputBytesLimitMessage(label)));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
49
56
|
function validateAllowedStringField(table, key, label, allowedValues, issues) {
|
|
50
57
|
if (!hasOwn(table, key)) {
|
|
51
58
|
return;
|
|
@@ -70,7 +77,7 @@ function validateCommandDefaults(commandsToml, issues) {
|
|
|
70
77
|
validateAllowedStringField(defaults, 'env_policy', '[commands.defaults].env_policy', COMMAND_ENV_POLICIES, issues);
|
|
71
78
|
validateStringArrayField(defaults, 'env_allowlist', '[commands.defaults].env_allowlist', issues);
|
|
72
79
|
validatePositiveIntegerField(defaults, 'default_timeout_seconds', '[commands.defaults].default_timeout_seconds', issues);
|
|
73
|
-
|
|
80
|
+
validateMaxOutputBytesField(defaults, 'max_output_bytes', '[commands.defaults].max_output_bytes', issues);
|
|
74
81
|
validatePositiveIntegerField(defaults, 'kill_after_seconds', '[commands.defaults].kill_after_seconds', issues);
|
|
75
82
|
}
|
|
76
83
|
function validateCommandResources(commandsToml, issues) {
|
|
@@ -148,6 +155,7 @@ function validateCommandIntent(intentName, intent, issues) {
|
|
|
148
155
|
validateAllowedStringField(intent, 'run_policy', `[commands.intents.${intentName}].run_policy`, COMMAND_RUN_POLICIES, issues);
|
|
149
156
|
validateAllowedStringField(intent, 'env_policy', `[commands.intents.${intentName}].env_policy`, COMMAND_ENV_POLICIES, issues);
|
|
150
157
|
validateStringArrayField(intent, 'env_allowlist', `[commands.intents.${intentName}].env_allowlist`, issues);
|
|
158
|
+
validateMaxOutputBytesField(intent, 'max_output_bytes', `[commands.intents.${intentName}].max_output_bytes`, issues);
|
|
151
159
|
validateCommandIntentSelection(intentName, intent, issues);
|
|
152
160
|
if (intent.status !== 'configured') {
|
|
153
161
|
return;
|
|
@@ -178,6 +186,10 @@ function validateCommandIntent(intentName, intent, issues) {
|
|
|
178
186
|
if (commandIntentHasBlockedShellBackgroundPattern(intent)) {
|
|
179
187
|
issues.push(commandContractIssue(`Shell intent ${intentName} contains a blocked long-running or background pattern`));
|
|
180
188
|
}
|
|
189
|
+
const blockedCommandPattern = commandIntentBlockedCommandPattern(intent);
|
|
190
|
+
if (blockedCommandPattern?.code === 'long_running_command_pattern') {
|
|
191
|
+
issues.push(commandContractIssue(`Intent ${intentName} contains a blocked long-running or background command pattern`));
|
|
192
|
+
}
|
|
181
193
|
if (hasOwn(intent, 'success_exit_codes')) {
|
|
182
194
|
const value = intent.success_exit_codes;
|
|
183
195
|
if (!Array.isArray(value) || value.length === 0 || value.some((entry) => !Number.isInteger(entry))) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isRecord, readString } from './config-loading.js';
|
|
2
|
-
import { commandIntentHasBlockedShellBackgroundPattern, commandIntentHasCommandSource, commandIntentNameIsSafe, } from './command-contract-rules.js';
|
|
2
|
+
import { commandIntentBlockedCommandPattern, commandIntentHasBlockedShellBackgroundPattern, commandIntentHasCommandSource, commandIntentNameIsSafe, } from './command-contract-rules.js';
|
|
3
3
|
export function evaluateCommandIntentEligibility(intentName, rawIntent) {
|
|
4
4
|
if (!commandIntentNameIsSafe(intentName)) {
|
|
5
5
|
return {
|
|
@@ -68,6 +68,14 @@ export function evaluateCommandIntentEligibility(intentName, rawIntent) {
|
|
|
68
68
|
detail: 'Shell command contains a blocked long-running or background pattern.',
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
+
const blockedPattern = commandIntentBlockedCommandPattern(rawIntent);
|
|
72
|
+
if (blockedPattern?.code === 'long_running_command_pattern') {
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
code: 'blocked_long_running_command_pattern',
|
|
76
|
+
detail: blockedPattern.detail,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
71
79
|
return {
|
|
72
80
|
ok: true,
|
|
73
81
|
code: 'ok',
|
|
@@ -2,7 +2,8 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { COMMAND_LIFECYCLES, COMMAND_RUN_POLICIES, LONG_RUNNING_LIFECYCLES, isRecord, readPositiveInteger, readString, readStringArray, } from './config-loading.js';
|
|
4
4
|
import { evaluateCommandIntentEligibility, } from './command-intent-eligibility.js';
|
|
5
|
-
import { commandIntentHasBlockedShellBackgroundPattern, commandIntentHasCommandSource, commandIntentNameIsSafe, } from './command-contract-rules.js';
|
|
5
|
+
import { commandIntentBlockedCommandPattern, commandIntentHasBlockedShellBackgroundPattern, commandIntentHasCommandSource, commandIntentNameIsSafe, } from './command-contract-rules.js';
|
|
6
|
+
import { MAX_COMMAND_OUTPUT_BYTES } from './command-output-limits.js';
|
|
6
7
|
import { commandEffectsConflict, normalizeCommandEffects } from './command-effects.js';
|
|
7
8
|
import { listChangeClassificationValidationReasons } from './change-classification.js';
|
|
8
9
|
import { parseSkillIndexRoutes } from './skill-route-alignment.js';
|
|
@@ -309,6 +310,10 @@ function lintIntent(name, value, issues) {
|
|
|
309
310
|
if (lifecycle === 'oneshot' && readPositiveInteger(value, 'timeout_seconds') === undefined) {
|
|
310
311
|
pushIssue(issues, 'error', 'oneshot_missing_timeout', name, `Oneshot intent ${name} must define timeout_seconds.`);
|
|
311
312
|
}
|
|
313
|
+
const maxOutputBytes = readPositiveInteger(value, 'max_output_bytes');
|
|
314
|
+
if (maxOutputBytes !== undefined && maxOutputBytes > MAX_COMMAND_OUTPUT_BYTES) {
|
|
315
|
+
pushIssue(issues, 'error', 'max_output_bytes_exceeds_limit', name, `Intent ${name} max_output_bytes must be less than or equal to ${MAX_COMMAND_OUTPUT_BYTES}.`);
|
|
316
|
+
}
|
|
312
317
|
if (lifecycle === 'oneshot' && readString(value, 'stdin') !== 'closed') {
|
|
313
318
|
pushIssue(issues, 'error', 'oneshot_stdin_not_closed', name, `Oneshot intent ${name} must set stdin to closed.`);
|
|
314
319
|
}
|
|
@@ -321,6 +326,10 @@ function lintIntent(name, value, issues) {
|
|
|
321
326
|
if (commandIntentHasBlockedShellBackgroundPattern(value)) {
|
|
322
327
|
pushIssue(issues, 'error', 'shell_background_pattern', name, `Shell intent ${name} contains a blocked long-running or background pattern.`);
|
|
323
328
|
}
|
|
329
|
+
const blockedCommandPattern = commandIntentBlockedCommandPattern(value);
|
|
330
|
+
if (blockedCommandPattern?.code === 'long_running_command_pattern') {
|
|
331
|
+
pushIssue(issues, 'error', 'long_running_command_pattern', name, `Intent ${name} contains a blocked long-running or background command pattern.`);
|
|
332
|
+
}
|
|
324
333
|
if (!successExitCodesAreValid(value)) {
|
|
325
334
|
pushIssue(issues, 'error', 'invalid_success_exit_codes', name, `Intent ${name} success_exit_codes must be an integer array.`);
|
|
326
335
|
}
|
package/package.json
CHANGED
package/schemas/README.md
CHANGED
|
@@ -35,10 +35,10 @@ Current schemas:
|
|
|
35
35
|
`mf explain verify --reason <event> --json`, `mf explain retention --json`, `mf explain skills --json`,
|
|
36
36
|
and `mf explain surface --json`. Verify explanations include the shared `decisionGraph` evidence model.
|
|
37
37
|
- `verify-report.schema.json`: output of `mf verify --reason <event> --json`, including an
|
|
38
|
-
evidence-based completion verdict and evidence model with a
|
|
39
|
-
selected receipts and skipped checks
|
|
38
|
+
explicit execution aggregate, evidence-based completion verdict, and evidence model with a
|
|
39
|
+
conservative coverage matrix for the selected receipts and skipped checks
|
|
40
40
|
- `verify-run-manifest.schema.json`: `.mustflow/state/runs/verify-latest/manifest.json`, including
|
|
41
|
-
the same completion verdict, evidence model, and coverage matrix as the verify report
|
|
41
|
+
the same execution aggregate, completion verdict, evidence model, and coverage matrix as the verify report
|
|
42
42
|
- `change-verification-report.schema.json`: output of `mf verify --reason <event> --plan-only --json` and
|
|
43
43
|
`mf verify --from-classification <classify-report.json> --plan-only --json`, including the `decision_graph` that links
|
|
44
44
|
changed surfaces, classification reasons, command candidates, eligibility, selected or not-selected state,
|
|
@@ -139,7 +139,8 @@
|
|
|
139
139
|
"missing_timeout",
|
|
140
140
|
"missing_command_source",
|
|
141
141
|
"unsafe_intent_name",
|
|
142
|
-
"blocked_shell_background_pattern"
|
|
142
|
+
"blocked_shell_background_pattern",
|
|
143
|
+
"blocked_long_running_command_pattern"
|
|
143
144
|
]
|
|
144
145
|
},
|
|
145
146
|
"runnable": { "type": "boolean" },
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"type": "string",
|
|
34
34
|
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
35
35
|
},
|
|
36
|
+
"execution_status": { "enum": ["passed", "partial", "failed", "blocked"] },
|
|
36
37
|
"status": { "enum": ["passed", "partial", "failed", "blocked"] },
|
|
37
38
|
"completion_verdict": { "$ref": "#/$defs/completionVerdict" },
|
|
38
39
|
"evidence_model": { "$ref": "#/$defs/evidenceModel" },
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"type": "string",
|
|
35
35
|
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
36
36
|
},
|
|
37
|
+
"execution_status": { "enum": ["passed", "partial", "failed", "blocked"] },
|
|
37
38
|
"status": { "enum": ["passed", "partial", "failed", "blocked"] },
|
|
38
39
|
"completion_verdict": { "$ref": "#/$defs/completionVerdict" },
|
|
39
40
|
"evidence_model": { "$ref": "#/$defs/evidenceModel" },
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"type": "string",
|
|
31
31
|
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
32
32
|
},
|
|
33
|
+
"execution_status": { "enum": ["passed", "partial", "failed", "blocked"] },
|
|
33
34
|
"status": { "enum": ["passed", "partial", "failed", "blocked"] },
|
|
34
35
|
"completion_verdict": { "$ref": "#/$defs/completionVerdict" },
|
|
35
36
|
"evidence_model": { "$ref": "#/$defs/evidenceModel" },
|