mustflow 2.22.5 → 2.22.9
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 +8 -0
- package/dist/cli/commands/classify.js +2 -0
- package/dist/cli/commands/dashboard.js +9 -69
- package/dist/cli/commands/run/receipt.js +1 -0
- package/dist/cli/commands/run.js +14 -1
- package/dist/cli/commands/verify/evidence-input.js +269 -0
- package/dist/cli/commands/verify/input.js +212 -0
- package/dist/cli/commands/verify.js +23 -482
- package/dist/cli/i18n/en.js +3 -0
- package/dist/cli/i18n/es.js +3 -0
- package/dist/cli/i18n/fr.js +3 -0
- package/dist/cli/i18n/hi.js +3 -0
- package/dist/cli/i18n/ko.js +3 -0
- package/dist/cli/i18n/zh.js +3 -0
- package/dist/cli/lib/dashboard-export.js +2 -0
- package/dist/cli/lib/dashboard-mutations.js +79 -0
- package/dist/cli/lib/local-index/command-effect-index.js +25 -0
- package/dist/cli/lib/local-index/hashing.js +7 -0
- package/dist/cli/lib/local-index/index.js +127 -826
- package/dist/cli/lib/local-index/source-index.js +137 -0
- package/dist/cli/lib/local-index/verification-evidence.js +451 -0
- package/dist/cli/lib/local-index/workflow-documents.js +204 -0
- package/dist/cli/lib/run-root-trust.js +27 -0
- package/dist/core/change-classification-policy.js +47 -0
- package/dist/core/change-classification.js +10 -43
- package/dist/core/contract-lint.js +6 -2
- package/dist/core/correlation-id.js +16 -0
- package/dist/core/run-receipt.js +1 -0
- package/package.json +4 -1
- package/schemas/README.md +4 -0
- package/schemas/change-verification-report.schema.json +4 -0
- package/schemas/classify-report.schema.json +4 -0
- package/schemas/dashboard-export.schema.json +4 -0
- package/schemas/latest-run-pointer.schema.json +4 -0
- package/schemas/run-receipt.schema.json +4 -0
- package/schemas/verify-report.schema.json +4 -0
- package/schemas/verify-run-manifest.schema.json +4 -0
- package/templates/default/i18n.toml +3 -3
- package/templates/default/locales/en/.mustflow/skills/architecture-deepening-review/SKILL.md +25 -2
- package/templates/default/locales/en/.mustflow/skills/security-privacy-review/SKILL.md +9 -1
- package/templates/default/locales/en/.mustflow/skills/test-design-guard/SKILL.md +9 -1
- package/templates/default/manifest.toml +1 -1
package/dist/cli/i18n/hi.js
CHANGED
|
@@ -652,6 +652,7 @@ export const hiMessages = {
|
|
|
652
652
|
"run.help.option.dryRun": "कमांड चलाए बिना उसका plan प्रिंट करें",
|
|
653
653
|
"run.help.option.planOnly": "--dry-run का alias",
|
|
654
654
|
"run.help.option.json": "Run record या command plan को JSON के रूप में प्रिंट करें",
|
|
655
|
+
"run.help.option.allowUntrustedRoot": "Manual review के बाद missing या invalid manifest lock वाली root से एक execution allow करें",
|
|
655
656
|
"run.help.exit.ok": "कमांड अनुमत exit code के साथ पूरी हुई",
|
|
656
657
|
"run.help.exit.fail": "कमांड अमान्य थी, अस्वीकार हुई, timed out हुई या विफल हुई",
|
|
657
658
|
"run.label.suggestedIntentSnippet": "Suggested command contract snippet",
|
|
@@ -674,6 +675,8 @@ export const hiMessages = {
|
|
|
674
675
|
"run.error.maxOutputBytes": 'कमांड "{intent}" में max_output_bytes अमान्य है। {detail}',
|
|
675
676
|
"run.error.maxOutputBytesDetail": "Output limit अनुमत maximum के अंदर रहनी चाहिए।",
|
|
676
677
|
"run.error.conflictingPreviewModes": "--dry-run या --plan-only में से एक इस्तेमाल करें, दोनों नहीं",
|
|
678
|
+
"run.error.untrustedRootMissing": "{path} missing है, इसलिए commands execute करने से मना किया गया। Workflow install करने के लिए mf init/update चलाएँ, या AGENTS.md और .mustflow/config/commands.toml review करने के बाद --allow-untrusted-root पास करें।",
|
|
679
|
+
"run.error.untrustedRootInvalid": "Manifest lock invalid है, इसलिए commands execute करने से मना किया गया: {detail}. इसे restore या regenerate करें, या AGENTS.md और .mustflow/config/commands.toml review करने के बाद --allow-untrusted-root पास करें।",
|
|
677
680
|
"run.error.timedOut": 'कमांड "{intent}" {seconds} सेकंड बाद time out हुई',
|
|
678
681
|
"run.error.outputLimitExceeded": 'कमांड "{intent}" ने max_output_bytes सीमा पार की: {message}',
|
|
679
682
|
"run.error.startFailed": 'कमांड "{intent}" शुरू नहीं हो सकी: {message}',
|
package/dist/cli/i18n/ko.js
CHANGED
|
@@ -652,6 +652,7 @@ export const koMessages = {
|
|
|
652
652
|
"run.help.option.dryRun": "실행하지 않고 명령 계획을 출력합니다",
|
|
653
653
|
"run.help.option.planOnly": "--dry-run과 같은 동작입니다",
|
|
654
654
|
"run.help.option.json": "실행 결과 또는 명령 계획을 JSON으로 출력합니다",
|
|
655
|
+
"run.help.option.allowUntrustedRoot": "잠금 파일이 없거나 올바르지 않은 루트에서 수동 검토 후 이번 실행만 허용합니다",
|
|
655
656
|
"run.help.exit.ok": "명령이 허용된 종료 코드로 완료되었습니다",
|
|
656
657
|
"run.help.exit.fail": "명령이 잘못되었거나, 거부되었거나, 시간 초과되었거나, 실패했습니다",
|
|
657
658
|
"run.label.suggestedIntentSnippet": "제안 명령 계약 조각",
|
|
@@ -674,6 +675,8 @@ export const koMessages = {
|
|
|
674
675
|
"run.error.maxOutputBytes": '명령 "{intent}"의 max_output_bytes 값이 올바르지 않습니다. {detail}',
|
|
675
676
|
"run.error.maxOutputBytesDetail": "출력 상한은 허용된 최댓값 안에 있어야 합니다.",
|
|
676
677
|
"run.error.conflictingPreviewModes": "--dry-run과 --plan-only 중 하나만 사용하세요",
|
|
678
|
+
"run.error.untrustedRootMissing": "{path}이 없어 명령 실행을 거부했습니다. mf init/update로 워크플로우를 설치하거나, AGENTS.md와 .mustflow/config/commands.toml을 검토한 뒤 --allow-untrusted-root를 붙이세요.",
|
|
679
|
+
"run.error.untrustedRootInvalid": "잠금 파일이 올바르지 않아 명령 실행을 거부했습니다: {detail}. 파일을 복구하거나 다시 생성하거나, AGENTS.md와 .mustflow/config/commands.toml을 검토한 뒤 --allow-untrusted-root를 붙이세요.",
|
|
677
680
|
"run.error.timedOut": '명령 "{intent}"가 {seconds}초 뒤 시간 초과되었습니다',
|
|
678
681
|
"run.error.outputLimitExceeded": '명령 "{intent}"가 max_output_bytes 제한을 넘었습니다: {message}',
|
|
679
682
|
"run.error.startFailed": '명령 "{intent}"를 시작하지 못했습니다: {message}',
|
package/dist/cli/i18n/zh.js
CHANGED
|
@@ -652,6 +652,7 @@ export const zhMessages = {
|
|
|
652
652
|
"run.help.option.dryRun": "输出命令计划但不执行",
|
|
653
653
|
"run.help.option.planOnly": "--dry-run 的别名",
|
|
654
654
|
"run.help.option.json": "将运行记录或命令计划输出为 JSON",
|
|
655
|
+
"run.help.option.allowUntrustedRoot": "人工复核后,允许从缺失或无效清单锁的根目录执行一次命令",
|
|
655
656
|
"run.help.exit.ok": "命令已以允许的退出码完成",
|
|
656
657
|
"run.help.exit.fail": "命令无效、被拒绝、超时或失败",
|
|
657
658
|
"run.label.suggestedIntentSnippet": "建议的命令契约片段",
|
|
@@ -674,6 +675,8 @@ export const zhMessages = {
|
|
|
674
675
|
"run.error.maxOutputBytes": '命令 "{intent}" 的 max_output_bytes 无效。{detail}',
|
|
675
676
|
"run.error.maxOutputBytesDetail": "输出限制必须保持在允许的最大值内。",
|
|
676
677
|
"run.error.conflictingPreviewModes": "只能使用 --dry-run 或 --plan-only,不能同时使用",
|
|
678
|
+
"run.error.untrustedRootMissing": "已拒绝执行命令,因为缺少 {path}。请运行 mf init/update 安装工作流,或在检查 AGENTS.md 和 .mustflow/config/commands.toml 后传入 --allow-untrusted-root。",
|
|
679
|
+
"run.error.untrustedRootInvalid": "已拒绝执行命令,因为清单锁无效:{detail}。请恢复或重新生成它,或在检查 AGENTS.md 和 .mustflow/config/commands.toml 后传入 --allow-untrusted-root。",
|
|
677
680
|
"run.error.timedOut": '命令 "{intent}" 在 {seconds} 秒后超时',
|
|
678
681
|
"run.error.outputLimitExceeded": '命令 "{intent}" 超过 max_output_bytes:{message}',
|
|
679
682
|
"run.error.startFailed": '命令 "{intent}" 启动失败:{message}',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { createDashboardCompletionVerdict } from '../../core/completion-verdict.js';
|
|
4
|
+
import { createCorrelationId } from '../../core/correlation-id.js';
|
|
4
5
|
import { createDashboardEvidenceModel } from '../../core/verification-evidence.js';
|
|
5
6
|
import { redactSecretLikeText } from '../../core/secret-redaction.js';
|
|
6
7
|
import { ensureFileTargetInsideWithoutSymlinks, ensureInside, toPosixPath, writeUtf8FileInsideWithoutSymlinks, } from './filesystem.js';
|
|
@@ -487,6 +488,7 @@ export function createDashboardExportSnapshot(input) {
|
|
|
487
488
|
const snapshot = {
|
|
488
489
|
schema_version: '1',
|
|
489
490
|
command: 'dashboard export',
|
|
491
|
+
correlation_id: createCorrelationId('dashboard'),
|
|
490
492
|
format: input.format,
|
|
491
493
|
generated_at: new Date().toISOString(),
|
|
492
494
|
mustflow_root: input.projectRoot,
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { openPathInFileManager } from './browser-open.js';
|
|
4
|
+
import { updateDashboardPreferences, } from './dashboard-preferences.js';
|
|
5
|
+
import { isReviewerKind, markDocReviewEntry, } from './doc-review-ledger.js';
|
|
6
|
+
const DOC_REVIEW_BULK_PAYLOAD_FIELDS = ['paths', 'documents', 'entries'];
|
|
7
|
+
function readPreferenceUpdatePayload(value) {
|
|
8
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
9
|
+
throw new Error('Request body must be a JSON object.');
|
|
10
|
+
}
|
|
11
|
+
const updates = value.updates;
|
|
12
|
+
if (!Array.isArray(updates)) {
|
|
13
|
+
throw new Error('Request body must include an updates array.');
|
|
14
|
+
}
|
|
15
|
+
return updates.map((entry) => {
|
|
16
|
+
if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {
|
|
17
|
+
throw new Error('Each update must be a JSON object.');
|
|
18
|
+
}
|
|
19
|
+
const update = entry;
|
|
20
|
+
if (typeof update.id !== 'string' || update.id.trim().length === 0) {
|
|
21
|
+
throw new Error('Each update must include an id.');
|
|
22
|
+
}
|
|
23
|
+
return { id: update.id, value: update.value };
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function readOptionalStringField(value, key) {
|
|
27
|
+
const field = value[key];
|
|
28
|
+
return typeof field === 'string' && field.trim().length > 0 ? field.trim() : undefined;
|
|
29
|
+
}
|
|
30
|
+
function readRequiredStringField(value, key) {
|
|
31
|
+
const field = readOptionalStringField(value, key);
|
|
32
|
+
if (!field) {
|
|
33
|
+
throw new Error(`${key} is required.`);
|
|
34
|
+
}
|
|
35
|
+
return field;
|
|
36
|
+
}
|
|
37
|
+
function readDocReviewPayload(value) {
|
|
38
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
39
|
+
throw new Error('Request body must be a JSON object.');
|
|
40
|
+
}
|
|
41
|
+
const payload = value;
|
|
42
|
+
for (const field of DOC_REVIEW_BULK_PAYLOAD_FIELDS) {
|
|
43
|
+
if (field in payload) {
|
|
44
|
+
throw new Error('Bulk documentation review updates require a separate confirmed flow.');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const status = readRequiredStringField(payload, 'status');
|
|
48
|
+
if (status !== 'approved' && status !== 'needs_human' && status !== 'ignored') {
|
|
49
|
+
throw new Error('status must be approved, needs_human, or ignored.');
|
|
50
|
+
}
|
|
51
|
+
const reviewerKind = readRequiredStringField(payload, 'reviewerKind');
|
|
52
|
+
if (!isReviewerKind(reviewerKind)) {
|
|
53
|
+
throw new Error('reviewerKind must be human, llm, tool, or external.');
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
path: readRequiredStringField(payload, 'path'),
|
|
57
|
+
status,
|
|
58
|
+
reviewerKind,
|
|
59
|
+
reviewerId: readRequiredStringField(payload, 'reviewerId'),
|
|
60
|
+
reviewerLabel: readOptionalStringField(payload, 'reviewerLabel'),
|
|
61
|
+
reviewerProvider: readOptionalStringField(payload, 'reviewerProvider'),
|
|
62
|
+
reviewerModel: readOptionalStringField(payload, 'reviewerModel'),
|
|
63
|
+
reviewerCommandIntent: readOptionalStringField(payload, 'reviewerCommandIntent'),
|
|
64
|
+
summary: readOptionalStringField(payload, 'summary'),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function updateDashboardPreferencesFromPayload(projectRoot, payload) {
|
|
68
|
+
return updateDashboardPreferences(projectRoot, readPreferenceUpdatePayload(payload));
|
|
69
|
+
}
|
|
70
|
+
export function markDashboardDocReviewFromPayload(projectRoot, payload) {
|
|
71
|
+
markDocReviewEntry(projectRoot, readDocReviewPayload(payload));
|
|
72
|
+
}
|
|
73
|
+
export function openDashboardMustflowFolder(projectRoot) {
|
|
74
|
+
const mustflowPath = path.join(projectRoot, '.mustflow');
|
|
75
|
+
if (!existsSync(mustflowPath)) {
|
|
76
|
+
return 'missing';
|
|
77
|
+
}
|
|
78
|
+
return openPathInFileManager(mustflowPath) ? 'opened' : 'unavailable';
|
|
79
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isRecord, readCommandContract, readString } from '../command-contract.js';
|
|
4
|
+
import { normalizeCommandEffects } from '../../../core/command-effects.js';
|
|
5
|
+
export function collectCommandIntents(projectRoot) {
|
|
6
|
+
if (!existsSync(path.join(projectRoot, '.mustflow', 'config', 'commands.toml'))) {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
const contract = readCommandContract(projectRoot);
|
|
10
|
+
const intents = [];
|
|
11
|
+
for (const [name, intent] of Object.entries(contract.intents).sort(([left], [right]) => left.localeCompare(right))) {
|
|
12
|
+
if (!isRecord(intent)) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
intents.push({
|
|
16
|
+
name,
|
|
17
|
+
status: readString(intent, 'status') ?? 'unknown',
|
|
18
|
+
lifecycle: readString(intent, 'lifecycle') ?? null,
|
|
19
|
+
runPolicy: readString(intent, 'run_policy') ?? null,
|
|
20
|
+
description: readString(intent, 'description') ?? null,
|
|
21
|
+
effects: normalizeCommandEffects(projectRoot, contract, name),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return intents;
|
|
25
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
export function sha256Text(content) {
|
|
3
|
+
return `sha256:${createHash('sha256').update(content).digest('hex')}`;
|
|
4
|
+
}
|
|
5
|
+
export function sha256Bytes(content) {
|
|
6
|
+
return `sha256:${createHash('sha256').update(content).digest('hex')}`;
|
|
7
|
+
}
|