mustflow 2.107.0 → 2.107.3
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 -1
- package/dist/cli/lib/local-index/source-index.js +27 -3
- package/dist/core/source-anchor-status.js +8 -2
- package/dist/core/source-anchors.js +23 -4
- package/package.json +1 -1
- package/templates/default/i18n.toml +1 -1
- package/templates/default/locales/en/.mustflow/docs/agent-workflow.md +4 -3
- package/templates/default/manifest.toml +1 -1
package/README.md
CHANGED
|
@@ -369,6 +369,9 @@ commands when a repository uses another runner or has a faster related-test entr
|
|
|
369
369
|
- `lifecycle = "oneshot"`
|
|
370
370
|
- `run_policy = "agent_allowed"`
|
|
371
371
|
- `stdin = "closed"`
|
|
372
|
+
- `timeout_seconds` is a positive integer
|
|
373
|
+
- a command is declared with `argv`, or with `mode = "shell"` plus `cmd` and `allow_shell = true`
|
|
374
|
+
- `cwd` resolves inside the current mustflow root
|
|
372
375
|
|
|
373
376
|
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. If a bounded one-shot command has a name that matches a common long-running pattern, the intent can explicitly acknowledge that with `allow_long_running_command_patterns = true`; background shell patterns remain blocked.
|
|
374
377
|
|
|
@@ -468,6 +471,7 @@ mf run docs_validate_fast
|
|
|
468
471
|
mf run docs_validate
|
|
469
472
|
mf run mustflow_check
|
|
470
473
|
mf run release_npm_version_available
|
|
474
|
+
mf run release_npm_publish
|
|
471
475
|
mf run release_npm_published_verify
|
|
472
476
|
```
|
|
473
477
|
|
|
@@ -481,7 +485,7 @@ Run the full release check before publishing:
|
|
|
481
485
|
bun run release:check
|
|
482
486
|
```
|
|
483
487
|
|
|
484
|
-
`release:check` validates the CLI, builds the documentation site, packs the npm tarball, installs it into a temporary project, and runs the public `mf` workflow. Maintainer npm publishing uses the `Publish npm package` GitHub Actions workflow from a
|
|
488
|
+
`release:check` validates the CLI, builds the documentation site, packs the npm tarball, installs it into a temporary project, and runs the public `mf` workflow. Maintainer npm publishing uses the `Publish npm package` GitHub Actions workflow from a release tag. The release tag must match the `package.json` version, with an optional leading `v`. Run `mf run release_npm_version_available` before creating the tag, `mf run release_npm_publish` to push the release tag that triggers trusted publishing and GitHub Release creation, and `mf run release_npm_published_verify` after the publish workflow completes. npm Trusted Publishing must be configured for the workflow before maintainers publish through it.
|
|
485
489
|
|
|
486
490
|
## Documentation site
|
|
487
491
|
|
|
@@ -78,8 +78,18 @@ function hashIndexedFileMetadataRecord(projectRoot, metadata) {
|
|
|
78
78
|
contentHash: sha256Bytes(readFileSync(path.join(projectRoot, ...metadata.path.split('/')))),
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
|
+
function tryHashIndexedFileMetadataRecord(projectRoot, metadata) {
|
|
82
|
+
try {
|
|
83
|
+
return hashIndexedFileMetadataRecord(projectRoot, metadata);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
81
89
|
export function hashIndexedFileMetadataRecords(projectRoot, metadataRecords) {
|
|
82
|
-
return metadataRecords
|
|
90
|
+
return metadataRecords
|
|
91
|
+
.map((metadata) => tryHashIndexedFileMetadataRecord(projectRoot, metadata))
|
|
92
|
+
.filter((record) => Boolean(record));
|
|
83
93
|
}
|
|
84
94
|
export function readIndexedFileMetadataRecord(projectRoot, relativePath, sourceScope) {
|
|
85
95
|
const fullPath = path.join(projectRoot, ...relativePath.split('/'));
|
|
@@ -91,6 +101,14 @@ export function readIndexedFileMetadataRecord(projectRoot, relativePath, sourceS
|
|
|
91
101
|
mtimeMs: Math.round(stats.mtimeMs),
|
|
92
102
|
};
|
|
93
103
|
}
|
|
104
|
+
function tryReadIndexedFileRecord(projectRoot, relativePath, sourceScope, contentHash = null) {
|
|
105
|
+
try {
|
|
106
|
+
return readIndexedFileRecord(projectRoot, relativePath, sourceScope, contentHash);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
94
112
|
export function collectIndexedFileRecords(projectRoot, documents, sourceAnchors, sourceAnchorCandidatePaths = []) {
|
|
95
113
|
const records = new Map();
|
|
96
114
|
for (const document of documents) {
|
|
@@ -99,11 +117,17 @@ export function collectIndexedFileRecords(projectRoot, documents, sourceAnchors,
|
|
|
99
117
|
const sourcePaths = new Set([...sourceAnchorCandidatePaths, ...sourceAnchors.map((anchor) => anchor.path)]);
|
|
100
118
|
for (const anchorPath of [...sourcePaths].sort((left, right) => left.localeCompare(right))) {
|
|
101
119
|
if (!records.has(anchorPath)) {
|
|
102
|
-
|
|
120
|
+
const record = tryReadIndexedFileRecord(projectRoot, anchorPath, 'source_anchor');
|
|
121
|
+
if (record) {
|
|
122
|
+
records.set(anchorPath, record);
|
|
123
|
+
}
|
|
103
124
|
}
|
|
104
125
|
}
|
|
105
126
|
if (existsSync(path.join(projectRoot, ...LATEST_RUN_STATE_RELATIVE_PATH.split('/')))) {
|
|
106
|
-
|
|
127
|
+
const record = tryReadIndexedFileRecord(projectRoot, LATEST_RUN_STATE_RELATIVE_PATH, 'state');
|
|
128
|
+
if (record) {
|
|
129
|
+
records.set(LATEST_RUN_STATE_RELATIVE_PATH, record);
|
|
130
|
+
}
|
|
107
131
|
}
|
|
108
132
|
return [...records.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
109
133
|
}
|
|
@@ -217,10 +217,16 @@ export function collectSourceAnchorIndexRecords(projectRoot, previousSnapshots =
|
|
|
217
217
|
const currentRecords = [];
|
|
218
218
|
for (const relativePath of listSourceAnchorFiles(projectRoot, fileOptions)) {
|
|
219
219
|
const filePath = path.join(projectRoot, ...relativePath.split('/'));
|
|
220
|
-
|
|
220
|
+
let content;
|
|
221
|
+
try {
|
|
222
|
+
if (!existsSync(filePath) || !statSync(filePath).isFile()) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
content = readFileSync(filePath, 'utf8');
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
221
228
|
continue;
|
|
222
229
|
}
|
|
223
|
-
const content = readFileSync(filePath, 'utf8');
|
|
224
230
|
for (const anchor of parseSourceAnchorsInContent(relativePath, content)) {
|
|
225
231
|
if (!anchor.idValid || sourceAnchorTextContainsSecretLike(anchor.rawText)) {
|
|
226
232
|
continue;
|
|
@@ -37,6 +37,7 @@ export const SOURCE_ANCHOR_DEFAULT_EXCLUDED_PATH_PARTS = new Set([
|
|
|
37
37
|
'tmp',
|
|
38
38
|
'vendor',
|
|
39
39
|
]);
|
|
40
|
+
export const SOURCE_ANCHOR_DEFAULT_EXCLUDED_PATH_PREFIXES = ['.tmp-agent-', 'tmp-agent-'];
|
|
40
41
|
export const SOURCE_ANCHOR_GENERATED_PATH_PARTS = new Set([
|
|
41
42
|
'.astro',
|
|
42
43
|
'.next',
|
|
@@ -111,6 +112,10 @@ function fileIsWithinSizeLimit(filePath, maxFileBytes) {
|
|
|
111
112
|
return false;
|
|
112
113
|
}
|
|
113
114
|
}
|
|
115
|
+
function sourceAnchorPathPartIsIgnored(part, ignoredDirectoryNames) {
|
|
116
|
+
return (ignoredDirectoryNames.has(part) ||
|
|
117
|
+
SOURCE_ANCHOR_DEFAULT_EXCLUDED_PATH_PREFIXES.some((prefix) => part.startsWith(prefix)));
|
|
118
|
+
}
|
|
114
119
|
function listFilesRecursive(root, options, current = root, depth = 0) {
|
|
115
120
|
if (!existsSync(current)) {
|
|
116
121
|
return [];
|
|
@@ -118,16 +123,29 @@ function listFilesRecursive(root, options, current = root, depth = 0) {
|
|
|
118
123
|
if (depth > MAX_SOURCE_ANCHOR_DIRECTORY_DEPTH) {
|
|
119
124
|
return [];
|
|
120
125
|
}
|
|
121
|
-
|
|
126
|
+
let currentRealPath;
|
|
127
|
+
try {
|
|
128
|
+
currentRealPath = realpathSync(current);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
122
133
|
if (!pathIsInsideRoot(options.rootRealPath, currentRealPath) || options.visitedRealDirectories.has(currentRealPath)) {
|
|
123
134
|
return [];
|
|
124
135
|
}
|
|
125
136
|
options.visitedRealDirectories.add(currentRealPath);
|
|
126
137
|
const files = [];
|
|
127
|
-
|
|
138
|
+
let entries;
|
|
139
|
+
try {
|
|
140
|
+
entries = readdirSync(current, { withFileTypes: true });
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
128
146
|
for (const entry of entries) {
|
|
129
147
|
const entryPath = path.join(current, entry.name);
|
|
130
|
-
if (
|
|
148
|
+
if (sourceAnchorPathPartIsIgnored(entry.name, options.ignoredDirectoryNames)) {
|
|
131
149
|
continue;
|
|
132
150
|
}
|
|
133
151
|
if (entry.isDirectory()) {
|
|
@@ -296,7 +314,8 @@ export function sourceAnchorPathIsGeneratedOrVendor(relativePath) {
|
|
|
296
314
|
if (normalized.endsWith('.min.js') || normalized.endsWith('.min.css')) {
|
|
297
315
|
return true;
|
|
298
316
|
}
|
|
299
|
-
return parts.some((part) => SOURCE_ANCHOR_GENERATED_PATH_PARTS.has(part)
|
|
317
|
+
return parts.some((part) => SOURCE_ANCHOR_GENERATED_PATH_PARTS.has(part) ||
|
|
318
|
+
SOURCE_ANCHOR_DEFAULT_EXCLUDED_PATH_PREFIXES.some((prefix) => part.startsWith(prefix)));
|
|
300
319
|
}
|
|
301
320
|
export function sourceAnchorTextContainsSecretLike(value) {
|
|
302
321
|
return textContainsSecretLike(value);
|
package/package.json
CHANGED
|
@@ -40,7 +40,7 @@ translations.hi = { path = "locales/hi/.mustflow/context/PROJECT.md", source_rev
|
|
|
40
40
|
[documents."docs.agent-workflow"]
|
|
41
41
|
source = "locales/en/.mustflow/docs/agent-workflow.md"
|
|
42
42
|
source_locale = "en"
|
|
43
|
-
revision =
|
|
43
|
+
revision = 27
|
|
44
44
|
translations.ko = { path = "locales/ko/.mustflow/docs/agent-workflow.md", source_revision = 23, status = "needs_review" }
|
|
45
45
|
translations.zh = { path = "locales/zh/.mustflow/docs/agent-workflow.md", source_revision = 18, status = "needs_review" }
|
|
46
46
|
translations.es = { path = "locales/es/.mustflow/docs/agent-workflow.md", source_revision = 18, status = "needs_review" }
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: docs.agent-workflow
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 27
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: workflow-policy
|
|
8
8
|
---
|
|
@@ -233,12 +233,12 @@ A command intent is eligible for agent use only when all of these are true:
|
|
|
233
233
|
- `run_policy = "agent_allowed"`
|
|
234
234
|
- `stdin = "closed"`
|
|
235
235
|
- `timeout_seconds` is a positive integer
|
|
236
|
-
- A command is declared with `argv`, or with `mode = "shell"` and `
|
|
236
|
+
- A command is declared with `argv`, or with `mode = "shell"`, `cmd`, and `allow_shell = true`
|
|
237
237
|
- `cwd` remains inside the current mustflow root
|
|
238
238
|
|
|
239
239
|
`manual_only` is a status for new configurations. `run_policy = "manual_only"` may be read for older configs, but new templates should use `status = "manual_only"` instead.
|
|
240
240
|
|
|
241
|
-
Prefer `mf run <intent>` so the project receives a concise run record in `.mustflow/state/runs/latest.json`.
|
|
241
|
+
Prefer `mf run <intent>` so the project receives a concise run record in `.mustflow/state/runs/latest.json` and a retained run index in `.mustflow/state/runs/latest.index.json`.
|
|
242
242
|
|
|
243
243
|
Run `mf run` command intents serially. Do not start a second `mf run` while another configured intent is still running. Intents that declare non-empty `writes` are exclusive verification phases; wait for them to finish before running any other `mf run`. This is especially important when an intent rewrites package output such as `dist/`, because the local `mf` executable may load from that output.
|
|
244
244
|
|
|
@@ -268,6 +268,7 @@ Generated files should be refreshed by tools:
|
|
|
268
268
|
- `REPO_MAP.md` through `mf map --write`
|
|
269
269
|
- `.mustflow/cache/mustflow.sqlite` through `mf index`
|
|
270
270
|
- `.mustflow/state/runs/latest.json` through `mf run <intent>`
|
|
271
|
+
- `.mustflow/state/runs/latest.index.json` through `mf run <intent>`
|
|
271
272
|
|
|
272
273
|
## Verification
|
|
273
274
|
|