mustflow 2.75.0 → 2.75.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.
@@ -11,6 +11,7 @@ const DEFAULT_MAX_FILE_BYTES = 1024 * 1024;
11
11
  const DEFAULT_MAX_FILES = 200;
12
12
  const DEFAULT_CONTEXT_LINES = 0;
13
13
  const DEFAULT_MAX_SNIPPET_LINES = 250;
14
+ const RETURN_PREVIEW_MAX_CHARS = 120;
14
15
  const CODE_FILE_EXTENSIONS = ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs'];
15
16
  const IGNORED_DIRECTORIES = [
16
17
  '.git',
@@ -261,6 +262,169 @@ function buildSignature(lines, startLine, endLine) {
261
262
  const signature = parts.join(' ').replace(/\s+/gu, ' ');
262
263
  return signature.length > 240 ? `${signature.slice(0, 237)}...` : signature;
263
264
  }
265
+ function normalizeReturnType(value) {
266
+ return value.replace(/\s+/gu, ' ').replace(/[;{]\s*$/u, '').trim();
267
+ }
268
+ function extractExplicitReturnType(signature, match) {
269
+ if (match.kind !== 'function') {
270
+ return null;
271
+ }
272
+ const functionReturnMatch = /\bfunction(?:\s+[$A-Z_a-z][$\w]*)?\s*\([^)]*\)\s*:\s*(?<returnType>[^={;]+?)(?=\s*(?:\{|$))/u.exec(signature);
273
+ if (functionReturnMatch?.groups?.returnType) {
274
+ return normalizeReturnType(functionReturnMatch.groups.returnType);
275
+ }
276
+ const arrowReturnMatch = /\)\s*:\s*(?<returnType>[^=]+?)\s*=>/u.exec(signature);
277
+ if (arrowReturnMatch?.groups?.returnType) {
278
+ return normalizeReturnType(arrowReturnMatch.groups.returnType);
279
+ }
280
+ const arrowTypeAnnotationMatch = /:\s*(?:async\s*)?\([^)]*\)\s*=>\s*(?<returnType>[^=;]+?)\s*=/u.exec(signature);
281
+ if (arrowTypeAnnotationMatch?.groups?.returnType) {
282
+ return normalizeReturnType(arrowTypeAnnotationMatch.groups.returnType);
283
+ }
284
+ return null;
285
+ }
286
+ function truncateReturnPreview(value) {
287
+ const preview = value.replace(/\s+/gu, ' ').trim();
288
+ return preview.length > RETURN_PREVIEW_MAX_CHARS
289
+ ? `${preview.slice(0, RETURN_PREVIEW_MAX_CHARS - 3)}...`
290
+ : preview;
291
+ }
292
+ function extractArrowExpressionReturnPreview(signature) {
293
+ const arrowIndex = signature.lastIndexOf('=>');
294
+ if (arrowIndex < 0) {
295
+ return null;
296
+ }
297
+ const expression = signature.slice(arrowIndex + 2).trim().replace(/;\s*$/u, '');
298
+ if (expression.length === 0 || expression.startsWith('{')) {
299
+ return null;
300
+ }
301
+ return truncateReturnPreview(expression);
302
+ }
303
+ function isIdentifierCharacter(value) {
304
+ return typeof value === 'string' && /[$\w]/u.test(value);
305
+ }
306
+ function findReturnKeywordIndex(line) {
307
+ let quote = null;
308
+ let escaped = false;
309
+ for (let index = 0; index < line.length; index += 1) {
310
+ const character = line[index];
311
+ const nextCharacter = line[index + 1];
312
+ if (quote !== null) {
313
+ if (escaped) {
314
+ escaped = false;
315
+ continue;
316
+ }
317
+ if (character === '\\') {
318
+ escaped = true;
319
+ continue;
320
+ }
321
+ if (character === quote) {
322
+ quote = null;
323
+ }
324
+ continue;
325
+ }
326
+ if (character === '/' && nextCharacter === '/') {
327
+ return -1;
328
+ }
329
+ if (character === '"' || character === "'" || character === '`') {
330
+ quote = character;
331
+ continue;
332
+ }
333
+ if (line.startsWith('return', index) &&
334
+ !isIdentifierCharacter(line[index - 1]) &&
335
+ !isIdentifierCharacter(line[index + 'return'.length])) {
336
+ return index;
337
+ }
338
+ }
339
+ return -1;
340
+ }
341
+ function extractReturnExpressionPreview(line) {
342
+ const returnIndex = findReturnKeywordIndex(line);
343
+ if (returnIndex < 0) {
344
+ return null;
345
+ }
346
+ const expression = line
347
+ .slice(returnIndex + 'return'.length)
348
+ .replace(/\/\/.*$/u, '')
349
+ .trim()
350
+ .replace(/;\s*$/u, '')
351
+ .trim();
352
+ return expression.length === 0 ? null : truncateReturnPreview(expression);
353
+ }
354
+ function hasReturnStatement(line) {
355
+ return findReturnKeywordIndex(line) >= 0;
356
+ }
357
+ function simpleBodyThrowsOnly(lines, startLine, endLine, returnType) {
358
+ let sawThrow = false;
359
+ let sawOtherExecutableLine = false;
360
+ for (let index = startLine; index < endLine - 1; index += 1) {
361
+ const bodyLine = stripLineForBraceScan(lines[index] ?? '')
362
+ .replace(/[{};]/gu, '')
363
+ .trim();
364
+ if (bodyLine.length === 0) {
365
+ continue;
366
+ }
367
+ if (/^throw\b/u.test(bodyLine)) {
368
+ sawThrow = true;
369
+ continue;
370
+ }
371
+ sawOtherExecutableLine = true;
372
+ }
373
+ return sawThrow && (!sawOtherExecutableLine || returnType === 'never');
374
+ }
375
+ function extractReturnMetadata(lines, startLine, endLine, signature, match) {
376
+ const returnType = extractExplicitReturnType(signature, match);
377
+ if (match.kind !== 'function') {
378
+ return {
379
+ return_type: null,
380
+ return_behavior: 'unknown',
381
+ return_count: 0,
382
+ return_lines: [],
383
+ return_preview: null,
384
+ };
385
+ }
386
+ const returnLines = [];
387
+ const valueReturnPreviews = [];
388
+ let voidReturnCount = 0;
389
+ for (let index = startLine - 1; index < endLine; index += 1) {
390
+ const line = lines[index] ?? '';
391
+ if (!hasReturnStatement(line)) {
392
+ continue;
393
+ }
394
+ returnLines.push(index + 1);
395
+ const preview = extractReturnExpressionPreview(line);
396
+ if (preview === null) {
397
+ voidReturnCount += 1;
398
+ }
399
+ else {
400
+ valueReturnPreviews.push(preview);
401
+ }
402
+ }
403
+ const arrowExpressionPreview = returnLines.length === 0 ? extractArrowExpressionReturnPreview(signature) : null;
404
+ let returnBehavior;
405
+ if (valueReturnPreviews.length > 0 && voidReturnCount > 0) {
406
+ returnBehavior = 'mixed';
407
+ }
408
+ else if (valueReturnPreviews.length > 0 || arrowExpressionPreview !== null) {
409
+ returnBehavior = 'value';
410
+ }
411
+ else if (voidReturnCount > 0) {
412
+ returnBehavior = 'void';
413
+ }
414
+ else if (simpleBodyThrowsOnly(lines, startLine, endLine, returnType)) {
415
+ returnBehavior = 'throws_only';
416
+ }
417
+ else {
418
+ returnBehavior = 'implicit_undefined';
419
+ }
420
+ return {
421
+ return_type: returnType,
422
+ return_behavior: returnBehavior,
423
+ return_count: returnLines.length,
424
+ return_lines: returnLines,
425
+ return_preview: valueReturnPreviews[0] ?? arrowExpressionPreview,
426
+ };
427
+ }
264
428
  function extractSymbols(relativePath, language, contentSha256, text) {
265
429
  const lines = text.split(/\r\n|\r|\n/u);
266
430
  const symbols = [];
@@ -271,6 +435,8 @@ function extractSymbols(relativePath, language, contentSha256, text) {
271
435
  }
272
436
  const startLine = index + 1;
273
437
  const endLine = findDeclarationEndLine(lines, index);
438
+ const signature = buildSignature(lines, startLine, endLine);
439
+ const returnMetadata = extractReturnMetadata(lines, startLine, endLine, signature, match);
274
440
  symbols.push({
275
441
  id: `${relativePath}:${startLine}:${match.kind}:${match.name}`,
276
442
  path: relativePath,
@@ -279,9 +445,10 @@ function extractSymbols(relativePath, language, contentSha256, text) {
279
445
  name: match.name,
280
446
  start_line: startLine,
281
447
  end_line: endLine,
282
- signature: buildSignature(lines, startLine, endLine),
448
+ signature,
283
449
  exported: match.exported,
284
450
  async: match.async,
451
+ ...returnMetadata,
285
452
  parent: null,
286
453
  content_sha256: contentSha256,
287
454
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mustflow",
3
- "version": "2.75.0",
3
+ "version": "2.75.1",
4
4
  "description": "Agent workflow documents and CLI for mustflow repository roots.",
5
5
  "type": "module",
6
6
  "license": "MIT-0",
package/schemas/README.md CHANGED
@@ -67,11 +67,11 @@ Current schemas:
67
67
  - `code-outline-report.schema.json`: output of
68
68
  `mf script-pack run code/outline scan <path...> --json`, containing a bounded TypeScript and
69
69
  JavaScript source outline with file hashes, symbol names, declaration kinds, line ranges,
70
- signatures, export flags, and stable input-limit finding codes
70
+ signatures, export flags, static return metadata, and stable input-limit finding codes
71
71
  - `code-symbol-read-report.schema.json`: output of
72
72
  `mf script-pack run code/symbol-read read <path> --start-line <line> --json`, containing a
73
73
  focused source snippet selected by outline symbol line or explicit line range with file hash,
74
- resolved line metadata, optional symbol metadata, and stable range/read finding codes
74
+ resolved line metadata, optional symbol and static return metadata, and stable range/read finding codes
75
75
  - `text-budget-report.schema.json`: output of
76
76
  `mf script-pack run core/text-budget check <path...> --json`, containing
77
77
  exact text-budget metrics, input content hashes, policy metadata, findings, and JSON Pointer field
@@ -104,6 +104,11 @@
104
104
  "signature",
105
105
  "exported",
106
106
  "async",
107
+ "return_type",
108
+ "return_behavior",
109
+ "return_count",
110
+ "return_lines",
111
+ "return_preview",
107
112
  "parent",
108
113
  "content_sha256"
109
114
  ],
@@ -118,6 +123,16 @@
118
123
  "signature": { "type": "string" },
119
124
  "exported": { "type": "boolean" },
120
125
  "async": { "type": "boolean" },
126
+ "return_type": { "type": ["string", "null"] },
127
+ "return_behavior": {
128
+ "enum": ["value", "void", "implicit_undefined", "mixed", "throws_only", "unknown"]
129
+ },
130
+ "return_count": { "type": "integer", "minimum": 0 },
131
+ "return_lines": {
132
+ "type": "array",
133
+ "items": { "type": "integer", "minimum": 1 }
134
+ },
135
+ "return_preview": { "type": ["string", "null"] },
121
136
  "parent": { "type": ["string", "null"] },
122
137
  "content_sha256": { "$ref": "#/$defs/sha256" }
123
138
  }
@@ -91,6 +91,11 @@
91
91
  "signature",
92
92
  "exported",
93
93
  "async",
94
+ "return_type",
95
+ "return_behavior",
96
+ "return_count",
97
+ "return_lines",
98
+ "return_preview",
94
99
  "parent",
95
100
  "content_sha256"
96
101
  ],
@@ -105,6 +110,16 @@
105
110
  "signature": { "type": "string" },
106
111
  "exported": { "type": "boolean" },
107
112
  "async": { "type": "boolean" },
113
+ "return_type": { "type": ["string", "null"] },
114
+ "return_behavior": {
115
+ "enum": ["value", "void", "implicit_undefined", "mixed", "throws_only", "unknown"]
116
+ },
117
+ "return_count": { "type": "integer", "minimum": 0 },
118
+ "return_lines": {
119
+ "type": "array",
120
+ "items": { "type": "integer", "minimum": 1 }
121
+ },
122
+ "return_preview": { "type": ["string", "null"] },
108
123
  "parent": { "type": ["string", "null"] },
109
124
  "content_sha256": { "$ref": "#/$defs/sha256" }
110
125
  }
@@ -1,6 +1,6 @@
1
1
  id = "default"
2
2
  name = "default"
3
- version = "2.75.0"
3
+ version = "2.75.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"