mustflow 1.18.0 → 1.18.14
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 +16 -6
- package/dist/cli/commands/context.js +2 -2
- package/dist/cli/commands/dashboard.js +61 -7
- package/dist/cli/commands/explain.js +47 -7
- package/dist/cli/commands/index.js +9 -2
- package/dist/cli/commands/run.js +7 -15
- package/dist/cli/commands/verify.js +44 -9
- package/dist/cli/i18n/en.js +3 -0
- package/dist/cli/i18n/es.js +3 -0
- package/dist/cli/i18n/fr.js +3 -0
- package/dist/cli/i18n/hi.js +3 -0
- package/dist/cli/i18n/ko.js +3 -0
- package/dist/cli/i18n/zh.js +3 -0
- package/dist/cli/lib/agent-context.js +19 -4
- package/dist/cli/lib/dashboard-html.js +41 -0
- package/dist/cli/lib/dashboard-locale.js +2 -0
- package/dist/cli/lib/local-index.js +910 -32
- package/dist/core/change-classification.js +33 -60
- package/dist/core/command-classification.js +0 -2
- package/dist/core/source-anchor-status.js +4 -4
- package/dist/core/source-anchor-validation.js +2 -6
- package/dist/core/source-anchors.js +81 -3
- package/package.json +1 -1
- package/schemas/change-verification-report.schema.json +194 -0
- package/schemas/context-report.schema.json +30 -2
- package/schemas/explain-report.schema.json +191 -0
- package/templates/default/i18n.toml +16 -6
- package/templates/default/locales/en/.mustflow/skills/INDEX.md +2 -1
- package/templates/default/locales/en/.mustflow/skills/database-change-safety/SKILL.md +155 -0
- package/templates/default/locales/en/AGENTS.md +5 -5
- package/templates/default/locales/es/.mustflow/skills/INDEX.md +2 -1
- package/templates/default/locales/es/.mustflow/skills/database-change-safety/SKILL.md +155 -0
- package/templates/default/locales/fr/.mustflow/skills/INDEX.md +2 -1
- package/templates/default/locales/fr/.mustflow/skills/database-change-safety/SKILL.md +155 -0
- package/templates/default/locales/hi/.mustflow/skills/INDEX.md +2 -1
- package/templates/default/locales/hi/.mustflow/skills/database-change-safety/SKILL.md +155 -0
- package/templates/default/locales/ko/.mustflow/skills/INDEX.md +2 -1
- package/templates/default/locales/ko/.mustflow/skills/database-change-safety/SKILL.md +155 -0
- package/templates/default/locales/zh/.mustflow/skills/INDEX.md +2 -1
- package/templates/default/locales/zh/.mustflow/skills/database-change-safety/SKILL.md +155 -0
- package/templates/default/manifest.toml +7 -1
|
@@ -10,67 +10,30 @@ function surface(kind, category, isPublicSurface, validationReasons, affectedCon
|
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
const UNKNOWN_SURFACE = surface('unclassified_path', 'unknown', false, [], [], 'not_applicable', []);
|
|
13
|
+
function rule(id, match, changeKinds, surfaceContract) {
|
|
14
|
+
return {
|
|
15
|
+
id,
|
|
16
|
+
patternKind: 'regexp',
|
|
17
|
+
pattern: match.source,
|
|
18
|
+
patternFlags: match.flags,
|
|
19
|
+
match,
|
|
20
|
+
changeKinds,
|
|
21
|
+
surface: surfaceContract,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
13
24
|
const CHANGE_CLASSIFICATION_RULES = [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
changeKinds: ['documentation'],
|
|
27
|
-
surface: surface('docs_site_page', 'documentation', true, ['docs_change'], ['documentation site', 'navigation links', 'localized content'], 'update', ['navigation links', 'localized copies', 'command examples']),
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
match: /^templates\/[^/]+\/locales\/[^/]+\//u,
|
|
31
|
-
changeKinds: ['installed_template', 'translation'],
|
|
32
|
-
surface: surface('installed_template_translation', 'installed-template', true, ['i18n_change', 'template_version_change'], ['installed template files', 'localized workflow documents', 'template i18n metadata'], 'update_or_mark_stale', ['template i18n metadata', 'localized frontmatter', 'source revision']),
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
match: /^templates\/[^/]+\//u,
|
|
36
|
-
changeKinds: ['installed_template'],
|
|
37
|
-
surface: surface('installed_template', 'installed-template', true, ['template_version_change', 'packaging_change'], ['installed template files', 'package contents', 'template manifest'], 'update', ['template manifest', 'package inventory', 'localized copies']),
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
match: /^(AGENTS\.md|\.mustflow\/(?:docs|context|skills|config)\/)/u,
|
|
41
|
-
changeKinds: ['workflow'],
|
|
42
|
-
surface: surface('workflow_root', 'workflow', true, ['mustflow_docs_change', 'mustflow_config_change'], ['agent workflow contract', 'command contract', 'installed workflow files'], 'update', ['strict workflow validation', 'installed template parity', 'skill route alignment']),
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
match: /^examples\//u,
|
|
46
|
-
changeKinds: ['example'],
|
|
47
|
-
surface: surface('example', 'example', true, ['docs_change', 'public_api_change'], ['generated examples', 'human-readable examples'], 'update', ['example commands', 'linked docs', 'public behavior claims']),
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
match: /^schemas\//u,
|
|
51
|
-
changeKinds: ['schema'],
|
|
52
|
-
surface: surface('schema_contract', 'contract', true, ['public_api_change', 'release_risk'], ['JSON schema', 'machine-readable output contract'], 'update', ['schema tests', 'documented JSON fields', 'package inventory']),
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
match: /^package\.json$/u,
|
|
56
|
-
changeKinds: ['package_metadata'],
|
|
57
|
-
surface: surface('package_metadata', 'release', true, ['package_metadata_change', 'release_risk'], ['npm package metadata', 'published package contents'], 'update', ['package metadata tests', 'version source discovery', 'published file inventory']),
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
match: /^tests\/fixtures\//u,
|
|
61
|
-
changeKinds: ['test_fixture'],
|
|
62
|
-
surface: surface('test_fixture', 'test', false, ['test_change'], ['regression fixture inputs'], 'not_applicable', ['fixture safety', 'test route coverage']),
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
match: /^tests\//u,
|
|
66
|
-
changeKinds: ['test'],
|
|
67
|
-
surface: surface('test_contract', 'test', false, ['test_change'], ['test behavior contract'], 'not_applicable', ['related test selection']),
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
match: /^(src|scripts)\//u,
|
|
71
|
-
changeKinds: ['implementation'],
|
|
72
|
-
surface: surface('implementation', 'code', false, ['code_change'], ['runtime behavior when exported through CLI or package output'], 'not_applicable', ['related tests', 'build output']),
|
|
73
|
-
},
|
|
25
|
+
rule('readme_page', /^README\.md$/u, ['documentation'], surface('readme_page', 'documentation', true, ['docs_change', 'copy_change'], ['public documentation', 'command examples'], 'update', ['link targets', 'command examples', 'package metadata references'])),
|
|
26
|
+
rule('docs_site_translation', /^docs-site\/src\/content\/docs\/(?!en\/)[^/]+\//u, ['documentation', 'translation'], surface('docs_site_translation', 'documentation', true, ['docs_change', 'i18n_change'], ['documentation site', 'localized content', 'navigation links'], 'update_or_mark_stale', ['source page parity', 'navigation links', 'localized examples'])),
|
|
27
|
+
rule('docs_site_page', /^docs-site\/src\/content\/docs\//u, ['documentation'], surface('docs_site_page', 'documentation', true, ['docs_change'], ['documentation site', 'navigation links', 'localized content'], 'update', ['navigation links', 'localized copies', 'command examples'])),
|
|
28
|
+
rule('installed_template_translation', /^templates\/[^/]+\/locales\/[^/]+\//u, ['installed_template', 'translation'], surface('installed_template_translation', 'installed-template', true, ['i18n_change', 'template_version_change'], ['installed template files', 'localized workflow documents', 'template i18n metadata'], 'update_or_mark_stale', ['template i18n metadata', 'localized frontmatter', 'source revision'])),
|
|
29
|
+
rule('installed_template', /^templates\/[^/]+\//u, ['installed_template'], surface('installed_template', 'installed-template', true, ['template_version_change', 'packaging_change'], ['installed template files', 'package contents', 'template manifest'], 'update', ['template manifest', 'package inventory', 'localized copies'])),
|
|
30
|
+
rule('workflow_root', /^(AGENTS\.md|\.mustflow\/(?:docs|context|skills|config)\/)/u, ['workflow'], surface('workflow_root', 'workflow', true, ['mustflow_docs_change', 'mustflow_config_change'], ['agent workflow contract', 'command contract', 'installed workflow files'], 'update', ['strict workflow validation', 'installed template parity', 'skill route alignment'])),
|
|
31
|
+
rule('example', /^examples\//u, ['example'], surface('example', 'example', true, ['docs_change', 'public_api_change'], ['generated examples', 'human-readable examples'], 'update', ['example commands', 'linked docs', 'public behavior claims'])),
|
|
32
|
+
rule('schema_contract', /^schemas\//u, ['schema'], surface('schema_contract', 'contract', true, ['public_api_change', 'release_risk'], ['JSON schema', 'machine-readable output contract'], 'update', ['schema tests', 'documented JSON fields', 'package inventory'])),
|
|
33
|
+
rule('package_metadata', /^package\.json$/u, ['package_metadata'], surface('package_metadata', 'release', true, ['package_metadata_change', 'release_risk'], ['npm package metadata', 'published package contents'], 'update', ['package metadata tests', 'version source discovery', 'published file inventory'])),
|
|
34
|
+
rule('test_fixture', /^tests\/fixtures\//u, ['test_fixture'], surface('test_fixture', 'test', false, ['test_change'], ['regression fixture inputs'], 'not_applicable', ['fixture safety', 'test route coverage'])),
|
|
35
|
+
rule('test_contract', /^tests\//u, ['test'], surface('test_contract', 'test', false, ['test_change'], ['test behavior contract'], 'not_applicable', ['related test selection'])),
|
|
36
|
+
rule('implementation', /^(src|scripts)\//u, ['implementation'], surface('implementation', 'code', false, ['code_change'], ['runtime behavior when exported through CLI or package output'], 'not_applicable', ['related tests', 'build output'])),
|
|
74
37
|
];
|
|
75
38
|
function uniqueSorted(values) {
|
|
76
39
|
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
@@ -100,6 +63,16 @@ export function classifyChangePath(relativePath) {
|
|
|
100
63
|
surface: rule?.surface ?? UNKNOWN_SURFACE,
|
|
101
64
|
};
|
|
102
65
|
}
|
|
66
|
+
export function listChangeClassificationRuleDescriptors() {
|
|
67
|
+
return CHANGE_CLASSIFICATION_RULES.map((classificationRule) => ({
|
|
68
|
+
id: classificationRule.id,
|
|
69
|
+
patternKind: classificationRule.patternKind,
|
|
70
|
+
pattern: classificationRule.pattern,
|
|
71
|
+
patternFlags: classificationRule.patternFlags,
|
|
72
|
+
changeKinds: classificationRule.changeKinds,
|
|
73
|
+
surface: classificationRule.surface,
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
103
76
|
export function createChangeClassificationReport(source, relativePaths) {
|
|
104
77
|
const files = uniqueSorted(relativePaths.map(normalizeStatusPath).filter((filePath) => filePath.length > 0));
|
|
105
78
|
const classifications = files.map(classifyChangePath);
|
|
@@ -4,7 +4,6 @@ const IN_PROCESS_MUSTFLOW_BUILTIN_COMMANDS = new Set([
|
|
|
4
4
|
'classify',
|
|
5
5
|
'context',
|
|
6
6
|
'doctor',
|
|
7
|
-
'explain',
|
|
8
7
|
'help',
|
|
9
8
|
'impact',
|
|
10
9
|
'line-endings',
|
|
@@ -12,7 +11,6 @@ const IN_PROCESS_MUSTFLOW_BUILTIN_COMMANDS = new Set([
|
|
|
12
11
|
'status',
|
|
13
12
|
'update',
|
|
14
13
|
'version-sources',
|
|
15
|
-
'verify',
|
|
16
14
|
]);
|
|
17
15
|
export function isMustflowBinName(command) {
|
|
18
16
|
return MUSTFLOW_BIN_NAMES.has(command.toLowerCase());
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { listSourceAnchorFiles, parseSourceAnchorsInContent, splitSourceAnchorList, } from './source-anchors.js';
|
|
4
|
+
import { listSourceAnchorFiles, parseSourceAnchorsInContent, sourceAnchorTextContainsSecretLike, splitSourceAnchorList, } from './source-anchors.js';
|
|
5
5
|
import { extractSourceAnchorSymbol, } from './source-anchor-symbols.js';
|
|
6
6
|
const HIGH_RISK_SOURCE_ANCHOR_TAGS = new Set([
|
|
7
7
|
'authn',
|
|
@@ -210,16 +210,16 @@ function findUniqueSymbolCandidate(previous, currentRecords) {
|
|
|
210
210
|
* invariant: Status records are derived search metadata and do not grant command or verification authority.
|
|
211
211
|
* risk: cache, config
|
|
212
212
|
*/
|
|
213
|
-
export function collectSourceAnchorIndexRecords(projectRoot, previousSnapshots = []) {
|
|
213
|
+
export function collectSourceAnchorIndexRecords(projectRoot, previousSnapshots = [], fileOptions = {}) {
|
|
214
214
|
const currentRecords = [];
|
|
215
|
-
for (const relativePath of listSourceAnchorFiles(projectRoot)) {
|
|
215
|
+
for (const relativePath of listSourceAnchorFiles(projectRoot, fileOptions)) {
|
|
216
216
|
const filePath = path.join(projectRoot, ...relativePath.split('/'));
|
|
217
217
|
if (!existsSync(filePath) || !statSync(filePath).isFile()) {
|
|
218
218
|
continue;
|
|
219
219
|
}
|
|
220
220
|
const content = readFileSync(filePath, 'utf8');
|
|
221
221
|
for (const anchor of parseSourceAnchorsInContent(relativePath, content)) {
|
|
222
|
-
if (!anchor.idValid) {
|
|
222
|
+
if (!anchor.idValid || sourceAnchorTextContainsSecretLike(anchor.rawText)) {
|
|
223
223
|
continue;
|
|
224
224
|
}
|
|
225
225
|
const search = splitSourceAnchorList(anchor.fields.get('search'));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { SOURCE_ANCHOR_ALLOWED_RISKS, listSourceAnchorFiles, parseSourceAnchorsInContent, sourceAnchorPathIsGeneratedOrVendor, splitSourceAnchorList, } from './source-anchors.js';
|
|
3
|
+
import { SOURCE_ANCHOR_ALLOWED_RISKS, listSourceAnchorFiles, parseSourceAnchorsInContent, sourceAnchorPathIsGeneratedOrVendor, sourceAnchorTextContainsSecretLike, splitSourceAnchorList, } from './source-anchors.js';
|
|
4
4
|
export const SOURCE_ANCHOR_IGNORED_DIRECTORIES = new Set([
|
|
5
5
|
'.git',
|
|
6
6
|
'.mustflow',
|
|
@@ -38,10 +38,6 @@ const SOURCE_ANCHOR_FORBIDDEN_INSTRUCTION_PATTERNS = [
|
|
|
38
38
|
/\bthis\s+anchor\s+(?:authorizes|grants|allows)\b.*\b(?:agents?|commands?|validation|verification)\b/iu,
|
|
39
39
|
/\b(?:command_intents?|required_after|run_policy|argv|cmd|permissions?|allowed_edits|skip_validation|agent_action)\s*[:=]/iu,
|
|
40
40
|
];
|
|
41
|
-
const SOURCE_ANCHOR_SECRET_LIKE_PATTERNS = [
|
|
42
|
-
/\b(?:api[_-]?key|api[_-]?token|access[_-]?token|auth[_-]?token|secret|password|passwd|private[_-]?key)\b\s*[:=]\s*["']?[A-Za-z0-9_./+=:-]{8,}/iu,
|
|
43
|
-
/\b(?:sk-[A-Za-z0-9]{16,}|ghp_[A-Za-z0-9]{20,}|xox[baprs]-[A-Za-z0-9-]{20,}|AKIA[0-9A-Z]{16})\b/u,
|
|
44
|
-
];
|
|
45
41
|
function sourceAnchorIssue(message) {
|
|
46
42
|
return { severity: 'error', message };
|
|
47
43
|
}
|
|
@@ -65,7 +61,7 @@ function validateSourceAnchor(anchor) {
|
|
|
65
61
|
if (SOURCE_ANCHOR_FORBIDDEN_INSTRUCTION_PATTERNS.some((pattern) => pattern.test(anchor.rawText))) {
|
|
66
62
|
issues.push(sourceAnchorIssue(`source anchor ${label} contains agent command or policy instructions`));
|
|
67
63
|
}
|
|
68
|
-
if (
|
|
64
|
+
if (sourceAnchorTextContainsSecretLike(anchor.rawText)) {
|
|
69
65
|
issues.push(sourceAnchorIssue(`source anchor ${label} contains secret-like text`));
|
|
70
66
|
}
|
|
71
67
|
for (const field of anchor.unsupportedFields) {
|
|
@@ -44,6 +44,10 @@ export const SOURCE_ANCHOR_ALLOWED_RISKS = new Set([
|
|
|
44
44
|
'xss',
|
|
45
45
|
]);
|
|
46
46
|
export const SOURCE_ANCHOR_ID_PATTERN = /^[a-z0-9][a-z0-9.-]{0,95}$/u;
|
|
47
|
+
export const SOURCE_ANCHOR_SECRET_LIKE_PATTERNS = [
|
|
48
|
+
/\b(?:api[_-]?key|api[_-]?token|access[_-]?token|auth[_-]?token|secret|password|passwd|private[_-]?key)\b\s*[:=]\s*["']?[A-Za-z0-9_./+=:-]{8,}/iu,
|
|
49
|
+
/\b(?:sk-[A-Za-z0-9]{16,}|ghp_[A-Za-z0-9]{20,}|xox[baprs]-[A-Za-z0-9-]{20,}|AKIA[0-9A-Z]{16})\b/u,
|
|
50
|
+
];
|
|
47
51
|
function toPosixPath(value) {
|
|
48
52
|
return value.split(path.sep).join('/');
|
|
49
53
|
}
|
|
@@ -68,11 +72,82 @@ function listFilesRecursive(root, ignoredDirectoryNames, current = root) {
|
|
|
68
72
|
}
|
|
69
73
|
return files.sort((left, right) => left.localeCompare(right));
|
|
70
74
|
}
|
|
75
|
+
function escapeRegExp(value) {
|
|
76
|
+
return value.replace(/[\\^$.*+?()[\]{}|]/gu, '\\$&');
|
|
77
|
+
}
|
|
78
|
+
function globToRegExp(pattern) {
|
|
79
|
+
const normalized = toPosixPath(pattern).replace(/^\/+/u, '');
|
|
80
|
+
let source = '^';
|
|
81
|
+
for (let index = 0; index < normalized.length;) {
|
|
82
|
+
const current = normalized[index];
|
|
83
|
+
const next = normalized[index + 1];
|
|
84
|
+
const afterNext = normalized[index + 2];
|
|
85
|
+
if (current === '*' && next === '*') {
|
|
86
|
+
if (afterNext === '/') {
|
|
87
|
+
source += '(?:.*/)?';
|
|
88
|
+
index += 3;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
source += '.*';
|
|
92
|
+
index += 2;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (current === '*') {
|
|
96
|
+
source += '[^/]*';
|
|
97
|
+
index += 1;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (current === '?') {
|
|
101
|
+
source += '[^/]';
|
|
102
|
+
index += 1;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
source += escapeRegExp(current ?? '');
|
|
106
|
+
index += 1;
|
|
107
|
+
}
|
|
108
|
+
return new RegExp(`${source}$`, 'u');
|
|
109
|
+
}
|
|
110
|
+
function matchesAnyGlob(relativePath, patterns) {
|
|
111
|
+
return patterns.some((pattern) => pattern.test(relativePath));
|
|
112
|
+
}
|
|
113
|
+
function normalizeSourceAnchorExtension(value) {
|
|
114
|
+
const normalized = value.trim().toLowerCase();
|
|
115
|
+
if (normalized.length === 0) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
return normalized.startsWith('.') ? normalized : `.${normalized}`;
|
|
119
|
+
}
|
|
120
|
+
function normalizeAllowedExtensions(allowedExtensions) {
|
|
121
|
+
if (!allowedExtensions) {
|
|
122
|
+
return SOURCE_ANCHOR_EXTENSIONS;
|
|
123
|
+
}
|
|
124
|
+
const normalized = [...allowedExtensions]
|
|
125
|
+
.map((extension) => normalizeSourceAnchorExtension(extension))
|
|
126
|
+
.filter((extension) => Boolean(extension));
|
|
127
|
+
return normalized.length > 0 ? new Set(normalized) : SOURCE_ANCHOR_EXTENSIONS;
|
|
128
|
+
}
|
|
129
|
+
function mergeIgnoredDirectoryNames(ignoredDirectoryNames) {
|
|
130
|
+
return new Set([...(ignoredDirectoryNames ?? []), ...SOURCE_ANCHOR_DEFAULT_EXCLUDED_PATH_PARTS]);
|
|
131
|
+
}
|
|
132
|
+
function fileIsWithinSizeLimit(root, relativePath, maxFileBytes) {
|
|
133
|
+
if (typeof maxFileBytes !== 'number' || !Number.isFinite(maxFileBytes) || maxFileBytes <= 0) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
const filePath = path.join(root, ...relativePath.split('/'));
|
|
137
|
+
return statSync(filePath).size <= maxFileBytes;
|
|
138
|
+
}
|
|
71
139
|
export function listSourceAnchorFiles(root, options = {}) {
|
|
72
|
-
const ignoredDirectoryNames = options.ignoredDirectoryNames
|
|
140
|
+
const ignoredDirectoryNames = mergeIgnoredDirectoryNames(options.ignoredDirectoryNames);
|
|
141
|
+
const allowedExtensions = normalizeAllowedExtensions(options.allowedExtensions);
|
|
142
|
+
const include = (options.include ?? []).map((pattern) => globToRegExp(pattern));
|
|
143
|
+
const exclude = (options.exclude ?? []).map((pattern) => globToRegExp(pattern));
|
|
73
144
|
return listFilesRecursive(root, ignoredDirectoryNames)
|
|
74
145
|
.map((relativePath) => toPosixPath(relativePath))
|
|
75
|
-
.filter((relativePath) =>
|
|
146
|
+
.filter((relativePath) => allowedExtensions.has(path.posix.extname(relativePath)))
|
|
147
|
+
.filter((relativePath) => options.excludeGeneratedOrVendor !== true || !sourceAnchorPathIsGeneratedOrVendor(relativePath))
|
|
148
|
+
.filter((relativePath) => include.length === 0 || matchesAnyGlob(relativePath, include))
|
|
149
|
+
.filter((relativePath) => exclude.length === 0 || !matchesAnyGlob(relativePath, exclude))
|
|
150
|
+
.filter((relativePath) => fileIsWithinSizeLimit(root, relativePath, options.maxFileBytes));
|
|
76
151
|
}
|
|
77
152
|
export function stripSourceAnchorCommentPrefix(line) {
|
|
78
153
|
return line
|
|
@@ -113,6 +188,9 @@ export function sourceAnchorPathIsGeneratedOrVendor(relativePath) {
|
|
|
113
188
|
}
|
|
114
189
|
return parts.some((part) => SOURCE_ANCHOR_GENERATED_PATH_PARTS.has(part));
|
|
115
190
|
}
|
|
191
|
+
export function sourceAnchorTextContainsSecretLike(value) {
|
|
192
|
+
return SOURCE_ANCHOR_SECRET_LIKE_PATTERNS.some((pattern) => pattern.test(value));
|
|
193
|
+
}
|
|
116
194
|
export function parseSourceAnchorsInContent(relativePath, content) {
|
|
117
195
|
const lines = content.split(/\r?\n/);
|
|
118
196
|
const anchors = [];
|
|
@@ -174,7 +252,7 @@ export function collectSourceAnchorSummaries(projectRoot) {
|
|
|
174
252
|
}
|
|
175
253
|
const content = readFileSync(filePath, 'utf8');
|
|
176
254
|
for (const anchor of parseSourceAnchorsInContent(relativePath, content)) {
|
|
177
|
-
if (!anchor.idValid) {
|
|
255
|
+
if (!anchor.idValid || sourceAnchorTextContainsSecretLike(anchor.rawText)) {
|
|
178
256
|
continue;
|
|
179
257
|
}
|
|
180
258
|
anchors.push({
|
package/package.json
CHANGED
|
@@ -134,6 +134,97 @@
|
|
|
134
134
|
},
|
|
135
135
|
"source": {
|
|
136
136
|
"const": "change_classification"
|
|
137
|
+
},
|
|
138
|
+
"surfaceReadModels": {
|
|
139
|
+
"type": "array",
|
|
140
|
+
"items": {
|
|
141
|
+
"$ref": "#/$defs/localPathSurfaceReadModel"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
"localPathSurfaceReadModel": {
|
|
147
|
+
"type": "object",
|
|
148
|
+
"additionalProperties": false,
|
|
149
|
+
"required": [
|
|
150
|
+
"source",
|
|
151
|
+
"status",
|
|
152
|
+
"databasePath",
|
|
153
|
+
"indexFresh",
|
|
154
|
+
"stalePaths",
|
|
155
|
+
"inputPath",
|
|
156
|
+
"match",
|
|
157
|
+
"refreshHint"
|
|
158
|
+
],
|
|
159
|
+
"properties": {
|
|
160
|
+
"source": { "const": "local_index" },
|
|
161
|
+
"status": { "enum": ["fresh", "missing", "stale", "unreadable"] },
|
|
162
|
+
"databasePath": { "type": "string" },
|
|
163
|
+
"indexFresh": { "type": "boolean" },
|
|
164
|
+
"stalePaths": {
|
|
165
|
+
"type": "array",
|
|
166
|
+
"items": { "type": "string" }
|
|
167
|
+
},
|
|
168
|
+
"inputPath": { "type": ["string", "null"] },
|
|
169
|
+
"match": {
|
|
170
|
+
"anyOf": [
|
|
171
|
+
{ "type": "null" },
|
|
172
|
+
{ "$ref": "#/$defs/localPathSurfaceRuleMatch" }
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
"refreshHint": { "type": ["string", "null"] }
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"localPathSurfaceRuleMatch": {
|
|
179
|
+
"type": "object",
|
|
180
|
+
"additionalProperties": false,
|
|
181
|
+
"required": [
|
|
182
|
+
"ruleId",
|
|
183
|
+
"patternKind",
|
|
184
|
+
"pattern",
|
|
185
|
+
"patternFlags",
|
|
186
|
+
"changeKinds",
|
|
187
|
+
"surface"
|
|
188
|
+
],
|
|
189
|
+
"properties": {
|
|
190
|
+
"ruleId": { "type": "string" },
|
|
191
|
+
"patternKind": { "type": "string" },
|
|
192
|
+
"pattern": { "type": "string" },
|
|
193
|
+
"patternFlags": { "type": "string" },
|
|
194
|
+
"changeKinds": {
|
|
195
|
+
"type": "array",
|
|
196
|
+
"items": { "type": "string" }
|
|
197
|
+
},
|
|
198
|
+
"surface": {
|
|
199
|
+
"type": "object",
|
|
200
|
+
"additionalProperties": false,
|
|
201
|
+
"required": [
|
|
202
|
+
"kind",
|
|
203
|
+
"category",
|
|
204
|
+
"isPublicSurface",
|
|
205
|
+
"validationReasons",
|
|
206
|
+
"affectedContracts",
|
|
207
|
+
"updatePolicy",
|
|
208
|
+
"driftChecks"
|
|
209
|
+
],
|
|
210
|
+
"properties": {
|
|
211
|
+
"kind": { "type": "string" },
|
|
212
|
+
"category": { "type": "string" },
|
|
213
|
+
"isPublicSurface": { "type": "boolean" },
|
|
214
|
+
"validationReasons": {
|
|
215
|
+
"type": "array",
|
|
216
|
+
"items": { "type": "string" }
|
|
217
|
+
},
|
|
218
|
+
"affectedContracts": {
|
|
219
|
+
"type": "array",
|
|
220
|
+
"items": { "type": "string" }
|
|
221
|
+
},
|
|
222
|
+
"updatePolicy": { "enum": ["update", "update_or_mark_stale", "not_applicable"] },
|
|
223
|
+
"driftChecks": {
|
|
224
|
+
"type": "array",
|
|
225
|
+
"items": { "type": "string" }
|
|
226
|
+
}
|
|
227
|
+
}
|
|
137
228
|
}
|
|
138
229
|
}
|
|
139
230
|
},
|
|
@@ -271,6 +362,109 @@
|
|
|
271
362
|
"items": {
|
|
272
363
|
"$ref": "#/$defs/verificationScheduleConflict"
|
|
273
364
|
}
|
|
365
|
+
},
|
|
366
|
+
"effectGraph": {
|
|
367
|
+
"$ref": "#/$defs/commandEffectGraph"
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
"commandEffectGraph": {
|
|
372
|
+
"type": "object",
|
|
373
|
+
"additionalProperties": false,
|
|
374
|
+
"required": [
|
|
375
|
+
"source",
|
|
376
|
+
"status",
|
|
377
|
+
"databasePath",
|
|
378
|
+
"indexFresh",
|
|
379
|
+
"stalePaths",
|
|
380
|
+
"writeLocks",
|
|
381
|
+
"lockConflicts",
|
|
382
|
+
"refreshHint"
|
|
383
|
+
],
|
|
384
|
+
"properties": {
|
|
385
|
+
"source": { "const": "local_index" },
|
|
386
|
+
"status": { "enum": ["fresh", "missing", "stale", "unreadable"] },
|
|
387
|
+
"databasePath": { "type": "string" },
|
|
388
|
+
"indexFresh": { "type": "boolean" },
|
|
389
|
+
"stalePaths": {
|
|
390
|
+
"type": "array",
|
|
391
|
+
"items": { "type": "string" }
|
|
392
|
+
},
|
|
393
|
+
"writeLocks": {
|
|
394
|
+
"type": "array",
|
|
395
|
+
"items": { "$ref": "#/$defs/commandWriteLock" }
|
|
396
|
+
},
|
|
397
|
+
"lockConflicts": {
|
|
398
|
+
"type": "array",
|
|
399
|
+
"items": { "$ref": "#/$defs/commandLockConflict" }
|
|
400
|
+
},
|
|
401
|
+
"refreshHint": { "type": ["string", "null"] }
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
"commandWriteLock": {
|
|
405
|
+
"type": "object",
|
|
406
|
+
"additionalProperties": false,
|
|
407
|
+
"required": ["lock", "paths", "modes", "sources", "concurrencies", "effectCount"],
|
|
408
|
+
"properties": {
|
|
409
|
+
"lock": { "type": "string" },
|
|
410
|
+
"paths": {
|
|
411
|
+
"type": "array",
|
|
412
|
+
"items": { "type": "string" }
|
|
413
|
+
},
|
|
414
|
+
"modes": {
|
|
415
|
+
"type": "array",
|
|
416
|
+
"items": { "type": "string" }
|
|
417
|
+
},
|
|
418
|
+
"sources": {
|
|
419
|
+
"type": "array",
|
|
420
|
+
"items": { "type": "string" }
|
|
421
|
+
},
|
|
422
|
+
"concurrencies": {
|
|
423
|
+
"type": "array",
|
|
424
|
+
"items": { "type": "string" }
|
|
425
|
+
},
|
|
426
|
+
"effectCount": { "type": "integer" }
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
"commandLockConflict": {
|
|
430
|
+
"type": "object",
|
|
431
|
+
"additionalProperties": false,
|
|
432
|
+
"required": [
|
|
433
|
+
"intent",
|
|
434
|
+
"lock",
|
|
435
|
+
"paths",
|
|
436
|
+
"modes",
|
|
437
|
+
"concurrencies",
|
|
438
|
+
"conflictingPaths",
|
|
439
|
+
"conflictingModes",
|
|
440
|
+
"conflictingConcurrencies"
|
|
441
|
+
],
|
|
442
|
+
"properties": {
|
|
443
|
+
"intent": { "type": "string" },
|
|
444
|
+
"lock": { "type": "string" },
|
|
445
|
+
"paths": {
|
|
446
|
+
"type": "array",
|
|
447
|
+
"items": { "type": "string" }
|
|
448
|
+
},
|
|
449
|
+
"modes": {
|
|
450
|
+
"type": "array",
|
|
451
|
+
"items": { "type": "string" }
|
|
452
|
+
},
|
|
453
|
+
"concurrencies": {
|
|
454
|
+
"type": "array",
|
|
455
|
+
"items": { "type": "string" }
|
|
456
|
+
},
|
|
457
|
+
"conflictingPaths": {
|
|
458
|
+
"type": "array",
|
|
459
|
+
"items": { "type": "string" }
|
|
460
|
+
},
|
|
461
|
+
"conflictingModes": {
|
|
462
|
+
"type": "array",
|
|
463
|
+
"items": { "type": "string" }
|
|
464
|
+
},
|
|
465
|
+
"conflictingConcurrencies": {
|
|
466
|
+
"type": "array",
|
|
467
|
+
"items": { "type": "string" }
|
|
274
468
|
}
|
|
275
469
|
}
|
|
276
470
|
},
|
|
@@ -306,14 +306,42 @@
|
|
|
306
306
|
"taskContextLayer": {
|
|
307
307
|
"type": "object",
|
|
308
308
|
"additionalProperties": false,
|
|
309
|
-
"required": ["cache_layer", "read_policy", "sources"],
|
|
309
|
+
"required": ["cache_layer", "read_policy", "sources", "local_index"],
|
|
310
310
|
"properties": {
|
|
311
311
|
"cache_layer": { "const": "task" },
|
|
312
312
|
"read_policy": { "type": ["string", "null"] },
|
|
313
313
|
"sources": {
|
|
314
314
|
"type": "array",
|
|
315
315
|
"items": { "type": "string" }
|
|
316
|
-
}
|
|
316
|
+
},
|
|
317
|
+
"local_index": { "$ref": "#/$defs/promptCacheLocalIndex" }
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
"promptCacheLocalIndex": {
|
|
321
|
+
"type": "object",
|
|
322
|
+
"additionalProperties": false,
|
|
323
|
+
"required": [
|
|
324
|
+
"source",
|
|
325
|
+
"status",
|
|
326
|
+
"database_path",
|
|
327
|
+
"index_fresh",
|
|
328
|
+
"stale_paths",
|
|
329
|
+
"search_backend",
|
|
330
|
+
"search_fts5_available",
|
|
331
|
+
"refresh_hint"
|
|
332
|
+
],
|
|
333
|
+
"properties": {
|
|
334
|
+
"source": { "const": "local_index" },
|
|
335
|
+
"status": { "enum": ["fresh", "missing", "stale", "unreadable"] },
|
|
336
|
+
"database_path": { "type": "string" },
|
|
337
|
+
"index_fresh": { "type": "boolean" },
|
|
338
|
+
"stale_paths": {
|
|
339
|
+
"type": "array",
|
|
340
|
+
"items": { "type": "string" }
|
|
341
|
+
},
|
|
342
|
+
"search_backend": { "type": ["string", "null"], "enum": ["fts5", "table_scan", null] },
|
|
343
|
+
"search_fts5_available": { "type": ["boolean", "null"] },
|
|
344
|
+
"refresh_hint": { "type": ["string", "null"] }
|
|
317
345
|
}
|
|
318
346
|
},
|
|
319
347
|
"volatileSuffixLayer": {
|