mustflow 2.106.1 → 2.107.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.
@@ -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.map((metadata) => hashIndexedFileMetadataRecord(projectRoot, metadata));
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
- records.set(anchorPath, readIndexedFileRecord(projectRoot, anchorPath, 'source_anchor'));
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
- records.set(LATEST_RUN_STATE_RELATIVE_PATH, readIndexedFileRecord(projectRoot, LATEST_RUN_STATE_RELATIVE_PATH, 'state'));
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
- if (!existsSync(filePath) || !statSync(filePath).isFile()) {
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;
@@ -13,6 +13,8 @@ export const SOURCE_ANCHOR_EXTENSIONS = new Set([
13
13
  '.svelte',
14
14
  '.ts',
15
15
  '.tsx',
16
+ '.yaml',
17
+ '.yml',
16
18
  ]);
17
19
  export const SOURCE_ANCHOR_DEFAULT_EXCLUDED_PATH_PARTS = new Set([
18
20
  '.cache',
@@ -35,6 +37,7 @@ export const SOURCE_ANCHOR_DEFAULT_EXCLUDED_PATH_PARTS = new Set([
35
37
  'tmp',
36
38
  'vendor',
37
39
  ]);
40
+ export const SOURCE_ANCHOR_DEFAULT_EXCLUDED_PATH_PREFIXES = ['.tmp-agent-', 'tmp-agent-'];
38
41
  export const SOURCE_ANCHOR_GENERATED_PATH_PARTS = new Set([
39
42
  '.astro',
40
43
  '.next',
@@ -109,6 +112,10 @@ function fileIsWithinSizeLimit(filePath, maxFileBytes) {
109
112
  return false;
110
113
  }
111
114
  }
115
+ function sourceAnchorPathPartIsIgnored(part, ignoredDirectoryNames) {
116
+ return (ignoredDirectoryNames.has(part) ||
117
+ SOURCE_ANCHOR_DEFAULT_EXCLUDED_PATH_PREFIXES.some((prefix) => part.startsWith(prefix)));
118
+ }
112
119
  function listFilesRecursive(root, options, current = root, depth = 0) {
113
120
  if (!existsSync(current)) {
114
121
  return [];
@@ -116,16 +123,29 @@ function listFilesRecursive(root, options, current = root, depth = 0) {
116
123
  if (depth > MAX_SOURCE_ANCHOR_DIRECTORY_DEPTH) {
117
124
  return [];
118
125
  }
119
- const currentRealPath = realpathSync(current);
126
+ let currentRealPath;
127
+ try {
128
+ currentRealPath = realpathSync(current);
129
+ }
130
+ catch {
131
+ return [];
132
+ }
120
133
  if (!pathIsInsideRoot(options.rootRealPath, currentRealPath) || options.visitedRealDirectories.has(currentRealPath)) {
121
134
  return [];
122
135
  }
123
136
  options.visitedRealDirectories.add(currentRealPath);
124
137
  const files = [];
125
- const entries = readdirSync(current, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
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));
126
146
  for (const entry of entries) {
127
147
  const entryPath = path.join(current, entry.name);
128
- if (options.ignoredDirectoryNames.has(entry.name)) {
148
+ if (sourceAnchorPathPartIsIgnored(entry.name, options.ignoredDirectoryNames)) {
129
149
  continue;
130
150
  }
131
151
  if (entry.isDirectory()) {
@@ -294,7 +314,8 @@ export function sourceAnchorPathIsGeneratedOrVendor(relativePath) {
294
314
  if (normalized.endsWith('.min.js') || normalized.endsWith('.min.css')) {
295
315
  return true;
296
316
  }
297
- 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)));
298
319
  }
299
320
  export function sourceAnchorTextContainsSecretLike(value) {
300
321
  return textContainsSecretLike(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mustflow",
3
- "version": "2.106.1",
3
+ "version": "2.107.1",
4
4
  "description": "Agent workflow documents and CLI for mustflow repository roots.",
5
5
  "type": "module",
6
6
  "license": "MIT-0",
@@ -1,6 +1,6 @@
1
1
  id = "default"
2
2
  name = "default"
3
- version = "2.106.1"
3
+ version = "2.107.1"
4
4
  description = "Minimal workflow for LLM agents to read, edit, and verify their work in a repository."
5
5
  common_root = "common"
6
6
  locales_root = "locales"