mustflow 2.103.31 → 2.103.33
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/check.js +3 -3
- package/dist/cli/lib/local-index/index.js +70 -0
- package/dist/cli/lib/local-index/search-read-model.js +1 -1
- package/dist/cli/lib/validation/index.js +19 -0
- package/dist/core/check-issues.js +2 -0
- package/package.json +1 -1
- package/templates/default/manifest.toml +1 -1
|
@@ -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 {
|
|
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 =
|
|
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
|
+
}
|
|
@@ -391,7 +391,7 @@ export async function searchLocalIndex(projectRoot, query, options = {}) {
|
|
|
391
391
|
const results = [];
|
|
392
392
|
try {
|
|
393
393
|
const cacheLayers = readCacheLayerSets(projectRoot);
|
|
394
|
-
const stalePaths = getStalePaths(projectRoot, database);
|
|
394
|
+
const stalePaths = getStalePaths(projectRoot, database, { includeState: false });
|
|
395
395
|
capabilities = readStoredSearchCapabilities(database);
|
|
396
396
|
const indexedMatches = getIndexedSearchMatches(database, normalizedQuery);
|
|
397
397
|
const querySnippetNgrams = buildSearchNgrams([normalizedQuery]);
|
|
@@ -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