mustflow 2.18.21 → 2.21.1
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/classify.js +2 -3
- package/dist/cli/commands/doctor.js +46 -6
- package/dist/cli/commands/run/output.js +1 -1
- package/dist/cli/commands/run/receipt.js +1 -0
- package/dist/cli/commands/verify.js +7 -8
- package/dist/cli/i18n/en.js +1 -0
- package/dist/cli/i18n/es.js +1 -0
- package/dist/cli/i18n/fr.js +1 -0
- package/dist/cli/i18n/hi.js +1 -0
- package/dist/cli/i18n/ko.js +1 -0
- package/dist/cli/i18n/zh.js +1 -0
- package/dist/cli/lib/local-index/index.js +3 -3
- package/dist/cli/lib/repo-map.js +3 -2
- package/dist/cli/lib/run-plan.js +8 -4
- package/dist/core/check-issues.js +1 -1
- package/dist/core/command-contract-validation.js +24 -10
- package/dist/core/command-output-limits.js +2 -1
- package/dist/core/line-endings.js +12 -4
- package/dist/core/repeated-failure.js +3 -3
- package/dist/core/run-performance-history.js +4 -4
- package/dist/core/run-profile.js +2 -3
- package/dist/core/run-receipt.js +11 -3
- package/dist/core/run-write-drift.js +60 -12
- package/dist/core/safe-filesystem.js +155 -0
- package/package.json +1 -1
- package/schemas/commands.schema.json +1 -0
- package/schemas/doctor-report.schema.json +23 -1
- package/schemas/run-receipt.schema.json +6 -2
- package/templates/default/i18n.toml +13 -13
- package/templates/default/locales/en/.mustflow/skills/INDEX.md +13 -13
- package/templates/default/locales/en/.mustflow/skills/adapter-boundary/SKILL.md +72 -4
- package/templates/default/locales/en/.mustflow/skills/command-contract-authoring/SKILL.md +16 -10
- package/templates/default/locales/en/.mustflow/skills/command-pattern/SKILL.md +64 -7
- package/templates/default/locales/en/.mustflow/skills/database-change-safety/SKILL.md +249 -16
- package/templates/default/locales/en/.mustflow/skills/dependency-reality-check/SKILL.md +37 -7
- package/templates/default/locales/en/.mustflow/skills/migration-safety-check/SKILL.md +74 -10
- package/templates/default/locales/en/.mustflow/skills/performance-budget-check/SKILL.md +132 -5
- package/templates/default/locales/en/.mustflow/skills/pure-core-imperative-shell/SKILL.md +12 -5
- package/templates/default/locales/en/.mustflow/skills/result-option/SKILL.md +4 -2
- package/templates/default/locales/en/.mustflow/skills/security-privacy-review/SKILL.md +112 -29
- package/templates/default/locales/en/.mustflow/skills/state-machine-pattern/SKILL.md +17 -4
- package/templates/default/locales/en/.mustflow/skills/structure-discovery-gate/SKILL.md +193 -2
- package/templates/default/manifest.toml +1 -1
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
-
import {
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { existsSync, lstatSync, readFileSync, readlinkSync, readdirSync } from 'node:fs';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import { normalizeCommandEffects } from './command-effects.js';
|
|
5
6
|
const MAX_SNAPSHOT_FILES = 20_000;
|
|
6
7
|
const MAX_REPORTED_PATHS = 200;
|
|
8
|
+
const GIT_STATUS_TIMEOUT_MS = 10_000;
|
|
9
|
+
const GIT_STATUS_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
10
|
+
const GIT_STATUS_UNTRACKED_MODE = 'normal';
|
|
11
|
+
const MAX_HASH_BYTES = 5 * 1024 * 1024;
|
|
7
12
|
const RECURSIVE_SNAPSHOT_ENV = 'MUSTFLOW_WRITE_DRIFT_SNAPSHOT';
|
|
8
13
|
const EXCLUDED_DIRECTORY_NAMES = new Set(['.git', 'node_modules']);
|
|
9
14
|
const EXCLUDED_RELATIVE_DIRECTORY_PATHS = new Set(['.mustflow/state/runs']);
|
|
@@ -33,6 +38,24 @@ function signatureForPath(fullPath) {
|
|
|
33
38
|
const type = stat.isDirectory() ? 'directory' : stat.isFile() ? 'file' : 'other';
|
|
34
39
|
return `${type}:${stat.size}:${stat.mtimeMs}`;
|
|
35
40
|
}
|
|
41
|
+
function signatureForGitStatusPath(projectRoot, relativePath, status) {
|
|
42
|
+
const fullPath = path.join(projectRoot, ...relativePath.split('/'));
|
|
43
|
+
if (!existsSync(fullPath)) {
|
|
44
|
+
return `git:${status}:missing`;
|
|
45
|
+
}
|
|
46
|
+
const stat = lstatSync(fullPath);
|
|
47
|
+
if (stat.isSymbolicLink()) {
|
|
48
|
+
return `git:${status}:symlink:${readlinkSync(fullPath)}`;
|
|
49
|
+
}
|
|
50
|
+
if (!stat.isFile()) {
|
|
51
|
+
return `git:${status}:${stat.isDirectory() ? 'directory' : 'other'}:${stat.size}:${stat.mtimeMs}`;
|
|
52
|
+
}
|
|
53
|
+
if (stat.size > MAX_HASH_BYTES) {
|
|
54
|
+
return `git:${status}:file:${stat.size}:${stat.mtimeMs}:unhashed`;
|
|
55
|
+
}
|
|
56
|
+
const digest = createHash('sha256').update(readFileSync(fullPath)).digest('hex');
|
|
57
|
+
return `git:${status}:file:${stat.size}:${digest}`;
|
|
58
|
+
}
|
|
36
59
|
function collectSnapshotEntries(projectRoot, currentPath, entries) {
|
|
37
60
|
const names = readdirSync(currentPath).sort((left, right) => left.localeCompare(right));
|
|
38
61
|
for (const name of names) {
|
|
@@ -59,7 +82,7 @@ function captureSnapshot(projectRoot) {
|
|
|
59
82
|
}
|
|
60
83
|
if (!isRecursiveSnapshotEnabled()) {
|
|
61
84
|
return {
|
|
62
|
-
|
|
85
|
+
status: 'unavailable',
|
|
63
86
|
entries: new Map(),
|
|
64
87
|
reason: 'git_status_unavailable_recursive_snapshot_disabled',
|
|
65
88
|
source: 'unavailable',
|
|
@@ -68,11 +91,11 @@ function captureSnapshot(projectRoot) {
|
|
|
68
91
|
try {
|
|
69
92
|
const entries = new Map();
|
|
70
93
|
collectSnapshotEntries(projectRoot, projectRoot, entries);
|
|
71
|
-
return {
|
|
94
|
+
return { status: 'checked', entries, reason: null, source: 'recursive_snapshot' };
|
|
72
95
|
}
|
|
73
96
|
catch (error) {
|
|
74
97
|
return {
|
|
75
|
-
|
|
98
|
+
status: 'unavailable',
|
|
76
99
|
entries: new Map(),
|
|
77
100
|
reason: error instanceof Error && error.message.length > 0 ? error.message : 'snapshot_unavailable',
|
|
78
101
|
source: 'unavailable',
|
|
@@ -80,12 +103,33 @@ function captureSnapshot(projectRoot) {
|
|
|
80
103
|
}
|
|
81
104
|
}
|
|
82
105
|
function captureGitStatusSnapshot(projectRoot) {
|
|
83
|
-
const result = spawnSync('git', ['-C', projectRoot, 'status', '--porcelain=v1', '-z',
|
|
106
|
+
const result = spawnSync('git', ['-C', projectRoot, 'status', '--porcelain=v1', '-z', `--untracked-files=${GIT_STATUS_UNTRACKED_MODE}`], {
|
|
84
107
|
encoding: 'utf8',
|
|
85
108
|
input: '',
|
|
109
|
+
maxBuffer: GIT_STATUS_MAX_BUFFER_BYTES,
|
|
86
110
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
111
|
+
timeout: GIT_STATUS_TIMEOUT_MS,
|
|
87
112
|
windowsHide: true,
|
|
88
113
|
});
|
|
114
|
+
const errorCode = typeof result.error === 'object' && result.error && 'code' in result.error
|
|
115
|
+
? String(result.error.code)
|
|
116
|
+
: null;
|
|
117
|
+
if (errorCode === 'ETIMEDOUT') {
|
|
118
|
+
return {
|
|
119
|
+
status: 'unavailable',
|
|
120
|
+
entries: new Map(),
|
|
121
|
+
reason: 'git_status_timeout',
|
|
122
|
+
source: 'unavailable',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (errorCode === 'ENOBUFS') {
|
|
126
|
+
return {
|
|
127
|
+
status: 'unavailable',
|
|
128
|
+
entries: new Map(),
|
|
129
|
+
reason: 'git_status_output_limit_exceeded',
|
|
130
|
+
source: 'unavailable',
|
|
131
|
+
};
|
|
132
|
+
}
|
|
89
133
|
if (result.error || result.status !== 0) {
|
|
90
134
|
return null;
|
|
91
135
|
}
|
|
@@ -98,15 +142,15 @@ function captureGitStatusSnapshot(projectRoot) {
|
|
|
98
142
|
if (filePath.length === 0) {
|
|
99
143
|
continue;
|
|
100
144
|
}
|
|
101
|
-
entries.set(filePath,
|
|
145
|
+
entries.set(filePath, signatureForGitStatusPath(projectRoot, filePath, status));
|
|
102
146
|
if (status.includes('R') || status.includes('C')) {
|
|
103
147
|
index += 1;
|
|
104
148
|
}
|
|
105
149
|
}
|
|
106
150
|
return {
|
|
107
|
-
|
|
151
|
+
status: 'partial',
|
|
108
152
|
entries,
|
|
109
|
-
reason:
|
|
153
|
+
reason: 'git_status_untracked_files_normal',
|
|
110
154
|
source: 'git_status',
|
|
111
155
|
};
|
|
112
156
|
}
|
|
@@ -150,7 +194,7 @@ export function startRunWriteTracking(projectRoot, contract, intentName) {
|
|
|
150
194
|
};
|
|
151
195
|
}
|
|
152
196
|
export function finishRunWriteTracking(tracker) {
|
|
153
|
-
if (
|
|
197
|
+
if (tracker.before.status === 'unavailable') {
|
|
154
198
|
return {
|
|
155
199
|
status: 'unavailable',
|
|
156
200
|
declared_paths: tracker.declaredPaths,
|
|
@@ -165,7 +209,7 @@ export function finishRunWriteTracking(tracker) {
|
|
|
165
209
|
};
|
|
166
210
|
}
|
|
167
211
|
const after = captureSnapshot(tracker.projectRoot);
|
|
168
|
-
if (
|
|
212
|
+
if (after.status === 'unavailable') {
|
|
169
213
|
return {
|
|
170
214
|
status: 'unavailable',
|
|
171
215
|
declared_paths: tracker.declaredPaths,
|
|
@@ -185,8 +229,12 @@ export function finishRunWriteTracking(tracker) {
|
|
|
185
229
|
const observed = truncatePaths(observedPaths);
|
|
186
230
|
const declaredObserved = truncatePaths(declaredObservedPaths);
|
|
187
231
|
const undeclared = truncatePaths(undeclaredPaths);
|
|
232
|
+
const status = tracker.before.status === 'partial' || after.status === 'partial' ? 'partial' : 'checked';
|
|
233
|
+
const reason = status === 'partial'
|
|
234
|
+
? tracker.before.reason ?? after.reason ?? 'partial_snapshot'
|
|
235
|
+
: null;
|
|
188
236
|
return {
|
|
189
|
-
status
|
|
237
|
+
status,
|
|
190
238
|
declared_paths: tracker.declaredPaths,
|
|
191
239
|
observed_paths: observed.paths,
|
|
192
240
|
declared_observed_paths: declaredObserved.paths,
|
|
@@ -195,6 +243,6 @@ export function finishRunWriteTracking(tracker) {
|
|
|
195
243
|
undeclared_count: undeclaredPaths.length,
|
|
196
244
|
has_undeclared_changes: undeclaredPaths.length > 0,
|
|
197
245
|
truncated: observed.truncated || declaredObserved.truncated || undeclared.truncated,
|
|
198
|
-
reason
|
|
246
|
+
reason,
|
|
199
247
|
};
|
|
200
248
|
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { closeSync, constants, lstatSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { randomBytes } from 'node:crypto';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
const NOFOLLOW_FLAG = typeof constants.O_NOFOLLOW === 'number' ? constants.O_NOFOLLOW : 0;
|
|
5
|
+
function isMissingPathError(error) {
|
|
6
|
+
return error instanceof Error && 'code' in error && error.code === 'ENOENT';
|
|
7
|
+
}
|
|
8
|
+
function tempFilePath(targetPath) {
|
|
9
|
+
const suffix = `${process.pid}-${Date.now()}-${randomBytes(6).toString('hex')}`;
|
|
10
|
+
return path.join(path.dirname(targetPath), `.${path.basename(targetPath)}.${suffix}.tmp`);
|
|
11
|
+
}
|
|
12
|
+
export function ensureInside(parentPath, childPath) {
|
|
13
|
+
const parent = path.resolve(parentPath);
|
|
14
|
+
const child = path.resolve(childPath);
|
|
15
|
+
const relative = path.relative(parent, child);
|
|
16
|
+
if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
throw new Error(`Path escapes allowed directory: ${childPath}`);
|
|
20
|
+
}
|
|
21
|
+
export function ensureInsideWithoutSymlinks(parentPath, childPath, options = {}) {
|
|
22
|
+
ensureInside(parentPath, childPath);
|
|
23
|
+
const parent = path.resolve(parentPath);
|
|
24
|
+
const child = path.resolve(childPath);
|
|
25
|
+
const relative = path.relative(parent, child);
|
|
26
|
+
const segments = relative === '' ? [] : relative.split(path.sep).filter((segment) => segment.length > 0);
|
|
27
|
+
let currentPath = parent;
|
|
28
|
+
const parentStats = lstatSync(parent);
|
|
29
|
+
if (parentStats.isSymbolicLink()) {
|
|
30
|
+
throw new Error(`Path must not contain symlinks: ${childPath}`);
|
|
31
|
+
}
|
|
32
|
+
for (const [index, segment] of segments.entries()) {
|
|
33
|
+
currentPath = path.join(currentPath, segment);
|
|
34
|
+
const isLeaf = index === segments.length - 1;
|
|
35
|
+
try {
|
|
36
|
+
const stats = lstatSync(currentPath);
|
|
37
|
+
if (stats.isSymbolicLink()) {
|
|
38
|
+
throw new Error(`Path must not contain symlinks: ${childPath}`);
|
|
39
|
+
}
|
|
40
|
+
if (!isLeaf && !stats.isDirectory()) {
|
|
41
|
+
throw new Error(`Path component is not a directory: ${currentPath}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (isMissingPathError(error) && options.allowMissingLeaf) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function ensureDirectoryInsideWithoutSymlinks(parentPath, directoryPath) {
|
|
53
|
+
ensureInside(parentPath, directoryPath);
|
|
54
|
+
const parent = path.resolve(parentPath);
|
|
55
|
+
const directory = path.resolve(directoryPath);
|
|
56
|
+
const relative = path.relative(parent, directory);
|
|
57
|
+
const segments = relative === '' ? [] : relative.split(path.sep).filter((segment) => segment.length > 0);
|
|
58
|
+
let currentPath = parent;
|
|
59
|
+
const parentStats = lstatSync(parent);
|
|
60
|
+
if (parentStats.isSymbolicLink()) {
|
|
61
|
+
throw new Error(`Path must not contain symlinks: ${directoryPath}`);
|
|
62
|
+
}
|
|
63
|
+
for (const segment of segments) {
|
|
64
|
+
currentPath = path.join(currentPath, segment);
|
|
65
|
+
try {
|
|
66
|
+
const stats = lstatSync(currentPath);
|
|
67
|
+
if (stats.isSymbolicLink()) {
|
|
68
|
+
throw new Error(`Path must not contain symlinks: ${directoryPath}`);
|
|
69
|
+
}
|
|
70
|
+
if (!stats.isDirectory()) {
|
|
71
|
+
throw new Error(`Path component is not a directory: ${currentPath}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (!isMissingPathError(error)) {
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
mkdirSync(currentPath);
|
|
79
|
+
const stats = lstatSync(currentPath);
|
|
80
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
81
|
+
throw new Error(`Path component is not a directory: ${currentPath}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function ensureFileTargetInsideWithoutSymlinks(parentPath, childPath, options = {}) {
|
|
87
|
+
const absoluteChildPath = path.resolve(childPath);
|
|
88
|
+
ensureInside(parentPath, absoluteChildPath);
|
|
89
|
+
ensureInsideWithoutSymlinks(parentPath, path.dirname(absoluteChildPath), { allowMissingLeaf: true });
|
|
90
|
+
try {
|
|
91
|
+
const stats = lstatSync(absoluteChildPath);
|
|
92
|
+
if (stats.isSymbolicLink()) {
|
|
93
|
+
throw new Error(`Path must not contain symlinks: ${childPath}`);
|
|
94
|
+
}
|
|
95
|
+
if (!stats.isFile()) {
|
|
96
|
+
throw new Error(`Path must be a regular file: ${childPath}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (isMissingPathError(error) && options.allowMissingLeaf) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function readFileInsideWithoutSymlinks(parentPath, childPath) {
|
|
107
|
+
const absoluteChildPath = path.resolve(childPath);
|
|
108
|
+
ensureInsideWithoutSymlinks(parentPath, absoluteChildPath);
|
|
109
|
+
const fileDescriptor = openSync(absoluteChildPath, constants.O_RDONLY | NOFOLLOW_FLAG);
|
|
110
|
+
try {
|
|
111
|
+
return readFileSync(fileDescriptor);
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
closeSync(fileDescriptor);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export function writeFileInsideWithoutSymlinks(parentPath, childPath, content) {
|
|
118
|
+
const absoluteChildPath = path.resolve(childPath);
|
|
119
|
+
const directoryPath = path.dirname(absoluteChildPath);
|
|
120
|
+
ensureDirectoryInsideWithoutSymlinks(parentPath, directoryPath);
|
|
121
|
+
ensureFileTargetInsideWithoutSymlinks(parentPath, absoluteChildPath, { allowMissingLeaf: true });
|
|
122
|
+
const temporaryPath = tempFilePath(absoluteChildPath);
|
|
123
|
+
let fileDescriptor = null;
|
|
124
|
+
try {
|
|
125
|
+
fileDescriptor = openSync(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | NOFOLLOW_FLAG);
|
|
126
|
+
writeFileSync(fileDescriptor, content);
|
|
127
|
+
closeSync(fileDescriptor);
|
|
128
|
+
fileDescriptor = null;
|
|
129
|
+
ensureFileTargetInsideWithoutSymlinks(parentPath, absoluteChildPath, { allowMissingLeaf: true });
|
|
130
|
+
renameSync(temporaryPath, absoluteChildPath);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (fileDescriptor !== null) {
|
|
134
|
+
try {
|
|
135
|
+
closeSync(fileDescriptor);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// Best-effort cleanup before removing the temporary file.
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
unlinkSync(temporaryPath);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Best-effort cleanup for a temporary file that may not have been created.
|
|
146
|
+
}
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
export function writeUtf8FileInsideWithoutSymlinks(parentPath, childPath, content) {
|
|
151
|
+
writeFileInsideWithoutSymlinks(parentPath, childPath, content);
|
|
152
|
+
}
|
|
153
|
+
export function writeJsonFileInsideWithoutSymlinks(parentPath, childPath, value) {
|
|
154
|
+
writeUtf8FileInsideWithoutSymlinks(parentPath, childPath, `${JSON.stringify(value, null, 2)}\n`);
|
|
155
|
+
}
|
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"ok",
|
|
14
14
|
"check",
|
|
15
15
|
"context",
|
|
16
|
+
"command_environment",
|
|
16
17
|
"effective_policy",
|
|
17
18
|
"state_policy",
|
|
18
19
|
"blocked_actions",
|
|
@@ -29,13 +30,18 @@
|
|
|
29
30
|
"check": {
|
|
30
31
|
"type": "object",
|
|
31
32
|
"additionalProperties": false,
|
|
32
|
-
"required": ["ok", "issue_count", "issues"],
|
|
33
|
+
"required": ["ok", "issue_count", "issues", "warning_count", "warnings"],
|
|
33
34
|
"properties": {
|
|
34
35
|
"ok": { "type": "boolean" },
|
|
35
36
|
"issue_count": { "type": "integer" },
|
|
36
37
|
"issues": {
|
|
37
38
|
"type": "array",
|
|
38
39
|
"items": { "type": "string" }
|
|
40
|
+
},
|
|
41
|
+
"warning_count": { "type": "integer" },
|
|
42
|
+
"warnings": {
|
|
43
|
+
"type": "array",
|
|
44
|
+
"items": { "type": "string" }
|
|
39
45
|
}
|
|
40
46
|
}
|
|
41
47
|
},
|
|
@@ -83,6 +89,21 @@
|
|
|
83
89
|
"latest_run_exists": { "type": "boolean" }
|
|
84
90
|
}
|
|
85
91
|
},
|
|
92
|
+
"command_environment": {
|
|
93
|
+
"type": "object",
|
|
94
|
+
"additionalProperties": false,
|
|
95
|
+
"required": ["inherited_intents", "inherited_network_intents"],
|
|
96
|
+
"properties": {
|
|
97
|
+
"inherited_intents": {
|
|
98
|
+
"type": "array",
|
|
99
|
+
"items": { "type": "string" }
|
|
100
|
+
},
|
|
101
|
+
"inherited_network_intents": {
|
|
102
|
+
"type": "array",
|
|
103
|
+
"items": { "type": "string" }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
86
107
|
"effective_policy": { "$ref": "#/$defs/effectivePolicy" },
|
|
87
108
|
"state_policy": { "$ref": "#/$defs/statePolicy" },
|
|
88
109
|
"blocked_actions": {
|
|
@@ -102,6 +123,7 @@
|
|
|
102
123
|
"validation",
|
|
103
124
|
"skill_routes",
|
|
104
125
|
"commands",
|
|
126
|
+
"environment",
|
|
105
127
|
"read_order",
|
|
106
128
|
"optional_read_order",
|
|
107
129
|
"repo_map",
|
|
@@ -55,7 +55,9 @@
|
|
|
55
55
|
},
|
|
56
56
|
"cmd": { "type": "string" },
|
|
57
57
|
"timeout_seconds": { "type": "integer" },
|
|
58
|
+
"kill_after_seconds": { "type": "integer" },
|
|
58
59
|
"max_output_bytes": { "type": "integer" },
|
|
60
|
+
"max_output_bytes_scope": { "const": "per_stream" },
|
|
59
61
|
"success_exit_codes": {
|
|
60
62
|
"type": "array",
|
|
61
63
|
"items": { "type": "integer" }
|
|
@@ -174,8 +176,10 @@
|
|
|
174
176
|
"properties": {
|
|
175
177
|
"stdout_bytes": { "type": "integer", "minimum": 0 },
|
|
176
178
|
"stderr_bytes": { "type": "integer", "minimum": 0 },
|
|
179
|
+
"total_bytes": { "type": "integer", "minimum": 0 },
|
|
177
180
|
"stdout_truncated": { "type": "boolean" },
|
|
178
|
-
"stderr_truncated": { "type": "boolean" }
|
|
181
|
+
"stderr_truncated": { "type": "boolean" },
|
|
182
|
+
"max_output_bytes_scope": { "const": "per_stream" }
|
|
179
183
|
}
|
|
180
184
|
},
|
|
181
185
|
"result_summary": {
|
|
@@ -256,7 +260,7 @@
|
|
|
256
260
|
"reason"
|
|
257
261
|
],
|
|
258
262
|
"properties": {
|
|
259
|
-
"status": { "enum": ["checked", "unavailable"] },
|
|
263
|
+
"status": { "enum": ["checked", "partial", "unavailable"] },
|
|
260
264
|
"declared_paths": {
|
|
261
265
|
"type": "array",
|
|
262
266
|
"items": { "type": "string" }
|
|
@@ -56,13 +56,13 @@ translations = {}
|
|
|
56
56
|
[documents."skills.index"]
|
|
57
57
|
source = "locales/en/.mustflow/skills/INDEX.md"
|
|
58
58
|
source_locale = "en"
|
|
59
|
-
revision =
|
|
59
|
+
revision = 73
|
|
60
60
|
translations = {}
|
|
61
61
|
|
|
62
62
|
[documents."skill.adapter-boundary"]
|
|
63
63
|
source = "locales/en/.mustflow/skills/adapter-boundary/SKILL.md"
|
|
64
64
|
source_locale = "en"
|
|
65
|
-
revision =
|
|
65
|
+
revision = 11
|
|
66
66
|
translations = {}
|
|
67
67
|
|
|
68
68
|
[documents."skill.artifact-integrity-check"]
|
|
@@ -104,7 +104,7 @@ translations = {}
|
|
|
104
104
|
[documents."skill.database-change-safety"]
|
|
105
105
|
source = "locales/en/.mustflow/skills/database-change-safety/SKILL.md"
|
|
106
106
|
source_locale = "en"
|
|
107
|
-
revision =
|
|
107
|
+
revision = 16
|
|
108
108
|
translations = {}
|
|
109
109
|
|
|
110
110
|
[documents."skill.dependency-injection"]
|
|
@@ -116,7 +116,7 @@ translations = {}
|
|
|
116
116
|
[documents."skill.dependency-reality-check"]
|
|
117
117
|
source = "locales/en/.mustflow/skills/dependency-reality-check/SKILL.md"
|
|
118
118
|
source_locale = "en"
|
|
119
|
-
revision =
|
|
119
|
+
revision = 6
|
|
120
120
|
translations = {}
|
|
121
121
|
|
|
122
122
|
[documents."skill.line-ending-hygiene"]
|
|
@@ -152,13 +152,13 @@ translations = {}
|
|
|
152
152
|
[documents."skill.command-pattern"]
|
|
153
153
|
source = "locales/en/.mustflow/skills/command-pattern/SKILL.md"
|
|
154
154
|
source_locale = "en"
|
|
155
|
-
revision =
|
|
155
|
+
revision = 13
|
|
156
156
|
translations = {}
|
|
157
157
|
|
|
158
158
|
[documents."skill.command-contract-authoring"]
|
|
159
159
|
source = "locales/en/.mustflow/skills/command-contract-authoring/SKILL.md"
|
|
160
160
|
source_locale = "en"
|
|
161
|
-
revision =
|
|
161
|
+
revision = 2
|
|
162
162
|
translations = {}
|
|
163
163
|
|
|
164
164
|
[documents."skill.cross-platform-filesystem-safety"]
|
|
@@ -170,13 +170,13 @@ translations = {}
|
|
|
170
170
|
[documents."skill.pure-core-imperative-shell"]
|
|
171
171
|
source = "locales/en/.mustflow/skills/pure-core-imperative-shell/SKILL.md"
|
|
172
172
|
source_locale = "en"
|
|
173
|
-
revision =
|
|
173
|
+
revision = 7
|
|
174
174
|
translations = {}
|
|
175
175
|
|
|
176
176
|
[documents."skill.result-option"]
|
|
177
177
|
source = "locales/en/.mustflow/skills/result-option/SKILL.md"
|
|
178
178
|
source_locale = "en"
|
|
179
|
-
revision =
|
|
179
|
+
revision = 3
|
|
180
180
|
translations = {}
|
|
181
181
|
|
|
182
182
|
[documents."skill.docs-update"]
|
|
@@ -223,7 +223,7 @@ translations = {}
|
|
|
223
223
|
[documents."skill.migration-safety-check"]
|
|
224
224
|
source = "locales/en/.mustflow/skills/migration-safety-check/SKILL.md"
|
|
225
225
|
source_locale = "en"
|
|
226
|
-
revision =
|
|
226
|
+
revision = 8
|
|
227
227
|
translations = {}
|
|
228
228
|
|
|
229
229
|
[documents."skill.multi-agent-work-coordination"]
|
|
@@ -241,7 +241,7 @@ translations = {}
|
|
|
241
241
|
[documents."skill.performance-budget-check"]
|
|
242
242
|
source = "locales/en/.mustflow/skills/performance-budget-check/SKILL.md"
|
|
243
243
|
source_locale = "en"
|
|
244
|
-
revision =
|
|
244
|
+
revision = 12
|
|
245
245
|
translations = {}
|
|
246
246
|
|
|
247
247
|
[documents."skill.pattern-scout"]
|
|
@@ -271,13 +271,13 @@ translations = {}
|
|
|
271
271
|
[documents."skill.structure-discovery-gate"]
|
|
272
272
|
source = "locales/en/.mustflow/skills/structure-discovery-gate/SKILL.md"
|
|
273
273
|
source_locale = "en"
|
|
274
|
-
revision =
|
|
274
|
+
revision = 26
|
|
275
275
|
translations = {}
|
|
276
276
|
|
|
277
277
|
[documents."skill.state-machine-pattern"]
|
|
278
278
|
source = "locales/en/.mustflow/skills/state-machine-pattern/SKILL.md"
|
|
279
279
|
source_locale = "en"
|
|
280
|
-
revision =
|
|
280
|
+
revision = 4
|
|
281
281
|
translations = {}
|
|
282
282
|
|
|
283
283
|
[documents."skill.strategy-pattern"]
|
|
@@ -325,7 +325,7 @@ translations = {}
|
|
|
325
325
|
[documents."skill.security-privacy-review"]
|
|
326
326
|
source = "locales/en/.mustflow/skills/security-privacy-review/SKILL.md"
|
|
327
327
|
source_locale = "en"
|
|
328
|
-
revision =
|
|
328
|
+
revision = 16
|
|
329
329
|
translations = {}
|
|
330
330
|
|
|
331
331
|
[documents."skill.security-regression-tests"]
|