mustflow 2.103.31 → 2.103.32

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.
@@ -3,7 +3,7 @@ import { acquireActiveCommandLock, GENERATED_SURFACE_READ_EFFECTS, reportActiveC
3
3
  import { t } from '../lib/i18n.js';
4
4
  import { formatCliOptionParseError, hasCliOptionToken, hasParsedCliOption, parseCliOptions, } from '../lib/option-parser.js';
5
5
  import { resolveMustflowRoot } from '../lib/project-root.js';
6
- import { checkMustflowProjectReport } from '../lib/validation.js';
6
+ import { checkMustflowProjectReportWithGeneratedState } from '../lib/validation.js';
7
7
  const CHECK_OPTIONS = [
8
8
  { name: '--json', kind: 'boolean' },
9
9
  { name: '--strict', kind: 'boolean' },
@@ -33,7 +33,7 @@ export function getCheckHelp(lang = 'en') {
33
33
  ],
34
34
  }, lang);
35
35
  }
36
- export function runCheck(args, reporter, lang = 'en') {
36
+ export async function runCheck(args, reporter, lang = 'en') {
37
37
  if (hasCliOptionToken(args, '--help', ['-h'])) {
38
38
  reporter.stdout(getCheckHelp(lang));
39
39
  return 0;
@@ -51,7 +51,7 @@ export function runCheck(args, reporter, lang = 'en') {
51
51
  return 1;
52
52
  }
53
53
  try {
54
- const report = checkMustflowProjectReport(projectRoot, { strict });
54
+ const report = await checkMustflowProjectReportWithGeneratedState(projectRoot, { strict });
55
55
  const issues = report.issues;
56
56
  const warnings = report.warnings;
57
57
  const ok = issues.length === 0;
@@ -670,3 +670,73 @@ ORDER BY source_anchors.id
670
670
  database.close();
671
671
  }
672
672
  }
673
+ /**
674
+ * mf:anchor cli.index.source-anchor-check-warnings
675
+ * purpose: Surface generated source-anchor registry drift through mf check without making the registry authoritative.
676
+ * search: mf check, source anchor index, stale anchor, generated registry
677
+ * invariant: Local index warnings are review hints only and never grant command or verification authority.
678
+ * risk: cache, config
679
+ */
680
+ export async function readLocalSourceAnchorCheckWarnings(projectRoot) {
681
+ const databasePath = getLocalIndexDatabasePath(projectRoot);
682
+ if (!existsSync(databasePath)) {
683
+ return [];
684
+ }
685
+ let SQL;
686
+ try {
687
+ SQL = await loadSqlJs();
688
+ }
689
+ catch (error) {
690
+ const message = error instanceof Error ? error.message : String(error);
691
+ return [`source anchor local index could not be loaded (${message}); refresh with mf index --source`];
692
+ }
693
+ let database;
694
+ try {
695
+ database = new SQL.Database(readFileSync(databasePath));
696
+ }
697
+ catch (error) {
698
+ const message = error instanceof Error ? error.message : String(error);
699
+ return [`source anchor local index could not be read (${message}); refresh with mf index --source`];
700
+ }
701
+ try {
702
+ if (readMetadataValue(database, 'source_index_enabled') !== 'true') {
703
+ return [];
704
+ }
705
+ if (!hasTable(database, 'indexed_files') || !hasTable(database, 'source_anchors') || !hasTable(database, 'source_anchor_status')) {
706
+ return ['source anchor local index is missing source-anchor tables; refresh with mf index --source'];
707
+ }
708
+ const indexedSourcePaths = new Set(queryRows(database, 'SELECT path FROM indexed_files WHERE source_scope = "source_anchor"')
709
+ .map((row) => toSearchString(row.path))
710
+ .filter(Boolean));
711
+ const staleSourcePaths = getStalePaths(projectRoot, database, { includeState: false }).filter((stalePath) => indexedSourcePaths.has(stalePath));
712
+ if (staleSourcePaths.length > 0) {
713
+ return [
714
+ `source anchor local index is stale for source paths: ${staleSourcePaths.join(', ')}; refresh with mf index --source`,
715
+ ];
716
+ }
717
+ return queryRows(database, `
718
+ SELECT
719
+ source_anchors.id,
720
+ source_anchors.path,
721
+ source_anchors.line_start,
722
+ source_anchor_status.status
723
+ FROM source_anchors
724
+ JOIN source_anchor_status ON source_anchor_status.anchor_id = source_anchors.id
725
+ WHERE source_anchor_status.status IN ('changed', 'review', 'stale')
726
+ ORDER BY source_anchors.id
727
+ `).map((row) => {
728
+ const anchorId = toSearchString(row.id);
729
+ const anchorPath = toSearchString(row.path);
730
+ const lineStart = toNullableNumber(row.line_start) ?? 0;
731
+ const status = toSearchString(row.status);
732
+ return `source anchor local index marks anchor "${anchorId}" as ${status} at ${anchorPath}:${lineStart}; review the anchor, then refresh with mf index --source if the current snapshot is accepted`;
733
+ });
734
+ }
735
+ catch (error) {
736
+ const message = error instanceof Error ? error.message : String(error);
737
+ return [`source anchor local index could not be checked (${message}); refresh with mf index --source`];
738
+ }
739
+ finally {
740
+ database.close();
741
+ }
742
+ }
@@ -8,6 +8,7 @@ import { formatManagedMarkdownLabel, getManagedMarkdownExpectation, } from '../.
8
8
  import { SKILL_INDEX_ROUTE_COLUMN_COUNT, SKILL_INDEX_ROUTE_COLUMNS, SKILL_INDEX_SKILL_PATH_COLUMN_INDEX, findSkillRouteConflictWarnings, findSkillIndexRoutePathColumn, parseSkillIndexRoutes, readBacktickValues, } from '../../../core/skill-route-alignment.js';
9
9
  import { validateTemplateVersionSync } from '../../../core/release-version-validation.js';
10
10
  import { validateSourceAnchorsInProject } from '../../../core/source-anchor-validation.js';
11
+ import { readLocalSourceAnchorCheckWarnings } from '../local-index/index.js';
11
12
  import { listFilesRecursive, toPosixPath } from '../filesystem.js';
12
13
  import { readGitChangedFiles } from '../git-changes.js';
13
14
  import { inspectManifestLock } from '../manifest-lock.js';
@@ -1667,6 +1668,9 @@ function collectCheckIssues(projectRoot, options = {}) {
1667
1668
  }
1668
1669
  export function checkMustflowProjectReport(projectRoot, options = {}) {
1669
1670
  const issues = collectCheckIssues(projectRoot, options);
1671
+ return checkProjectReportFromIssues(issues);
1672
+ }
1673
+ function checkProjectReportFromIssues(issues) {
1670
1674
  const errorIssues = issues.filter((issue) => issue.severity !== 'warning');
1671
1675
  const warningIssues = issues.filter((issue) => issue.severity === 'warning');
1672
1676
  const errors = errorIssues.map((issue) => issue.message);
@@ -1678,6 +1682,21 @@ export function checkMustflowProjectReport(projectRoot, options = {}) {
1678
1682
  issueDetails: describeCheckIssues([...errorIssues, ...warningIssues]),
1679
1683
  };
1680
1684
  }
1685
+ async function collectGeneratedSourceAnchorIndexWarnings(projectRoot, options) {
1686
+ if (!options.strict) {
1687
+ return [];
1688
+ }
1689
+ const warnings = await readLocalSourceAnchorCheckWarnings(projectRoot);
1690
+ return warnings.map((message) => ({
1691
+ message: `Strict warning: ${message}`,
1692
+ severity: 'warning',
1693
+ }));
1694
+ }
1695
+ export async function checkMustflowProjectReportWithGeneratedState(projectRoot, options = {}) {
1696
+ const issues = collectCheckIssues(projectRoot, options);
1697
+ issues.push(...(await collectGeneratedSourceAnchorIndexWarnings(projectRoot, options)));
1698
+ return checkProjectReportFromIssues(issues);
1699
+ }
1681
1700
  export function checkMustflowProject(projectRoot, options = {}) {
1682
1701
  return checkMustflowProjectReport(projectRoot, options).issues;
1683
1702
  }
@@ -78,6 +78,8 @@ const CHECK_ISSUE_ID_RULES = [
78
78
  ['mustflow.source_anchor.too_many_search_terms', /^Strict warning: source anchor [^ ]+ in .+ has too many search terms/u],
79
79
  ['mustflow.source_anchor.high_density', /^Strict warning: .+ has high source anchor density/u],
80
80
  ['mustflow.source_anchor.high_risk_review', /^Strict warning: source anchor [^ ]+ in .+ uses high-risk tags and needs review:/u],
81
+ ['mustflow.source_anchor.index_stale', /^Strict warning: source anchor local index (?:is stale|could not be|is missing)/u],
82
+ ['mustflow.source_anchor.index_status', /^Strict warning: source anchor local index marks anchor "[^"]+" as (?:changed|review|stale) at /u],
81
83
  ['mustflow.run_receipt.invalid_json', /^Strict: \.mustflow\/state\/runs\/latest\.json is not valid JSON:/u],
82
84
  ['mustflow.run_receipt.invalid_shape', /^Strict: \.mustflow\/state\/runs\/latest\.json must contain a JSON object$/u],
83
85
  ['mustflow.retention.run_receipt_size_limit', /^Strict: \.mustflow\/state\/runs\/latest\.json exceeds \[retention\.run_receipts\]\.max_file_kb/u],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mustflow",
3
- "version": "2.103.31",
3
+ "version": "2.103.32",
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.103.31"
3
+ version = "2.103.32"
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"