@mcoda/core 0.1.34 → 0.1.36
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/api/AgentsApi.d.ts +4 -1
- package/dist/api/AgentsApi.d.ts.map +1 -1
- package/dist/api/AgentsApi.js +4 -1
- package/dist/prompts/PdrPrompts.js +1 -1
- package/dist/services/docs/DocsService.d.ts +37 -0
- package/dist/services/docs/DocsService.d.ts.map +1 -1
- package/dist/services/docs/DocsService.js +537 -2
- package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts.map +1 -1
- package/dist/services/docs/review/gates/OpenQuestionsGate.js +13 -2
- package/dist/services/docs/review/gates/SdsNoUnresolvedItemsGate.d.ts.map +1 -1
- package/dist/services/docs/review/gates/SdsNoUnresolvedItemsGate.js +12 -1
- package/dist/services/planning/CreateTasksService.d.ts +57 -0
- package/dist/services/planning/CreateTasksService.d.ts.map +1 -1
- package/dist/services/planning/CreateTasksService.js +2491 -291
- package/dist/services/planning/SdsCoverageModel.d.ts +27 -0
- package/dist/services/planning/SdsCoverageModel.d.ts.map +1 -0
- package/dist/services/planning/SdsCoverageModel.js +138 -0
- package/dist/services/planning/SdsPreflightService.d.ts +2 -0
- package/dist/services/planning/SdsPreflightService.d.ts.map +1 -1
- package/dist/services/planning/SdsPreflightService.js +131 -37
- package/dist/services/planning/SdsStructureSignals.d.ts +24 -0
- package/dist/services/planning/SdsStructureSignals.d.ts.map +1 -0
- package/dist/services/planning/SdsStructureSignals.js +402 -0
- package/dist/services/planning/TaskSufficiencyService.d.ts +17 -0
- package/dist/services/planning/TaskSufficiencyService.d.ts.map +1 -1
- package/dist/services/planning/TaskSufficiencyService.js +409 -278
- package/package.json +6 -6
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface SdsCoverageSignalSet {
|
|
2
|
+
rawSectionHeadings: string[];
|
|
3
|
+
rawFolderEntries: string[];
|
|
4
|
+
sectionHeadings: string[];
|
|
5
|
+
folderEntries: string[];
|
|
6
|
+
skippedHeadingSignals: number;
|
|
7
|
+
skippedFolderSignals: number;
|
|
8
|
+
}
|
|
9
|
+
export interface SdsCoverageSummary {
|
|
10
|
+
coverageRatio: number;
|
|
11
|
+
totalSignals: number;
|
|
12
|
+
missingSectionHeadings: string[];
|
|
13
|
+
missingFolderEntries: string[];
|
|
14
|
+
}
|
|
15
|
+
export declare const normalizeCoverageText: (value: string) => string;
|
|
16
|
+
export declare const normalizeCoverageAnchor: (kind: "section" | "folder", value: string) => string;
|
|
17
|
+
export declare const collectSdsCoverageSignalsFromDocs: (docs: Array<{
|
|
18
|
+
content?: string | null;
|
|
19
|
+
}>, options: {
|
|
20
|
+
headingLimit: number;
|
|
21
|
+
folderLimit: number;
|
|
22
|
+
}) => SdsCoverageSignalSet;
|
|
23
|
+
export declare const evaluateSdsCoverage: (corpus: string, signals: {
|
|
24
|
+
sectionHeadings: string[];
|
|
25
|
+
folderEntries: string[];
|
|
26
|
+
}, existingAnchors?: Set<string>) => SdsCoverageSummary;
|
|
27
|
+
//# sourceMappingURL=SdsCoverageModel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SdsCoverageModel.d.ts","sourceRoot":"","sources":["../../../src/services/planning/SdsCoverageModel.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,oBAAoB;IACnC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB,EAAE,MAAM,EAAE,CAAC;IACjC,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC;AAED,eAAO,MAAM,qBAAqB,GAAI,OAAO,MAAM,KAAG,MAM3C,CAAC;AAEZ,eAAO,MAAM,uBAAuB,GAAI,MAAM,SAAS,GAAG,QAAQ,EAAE,OAAO,MAAM,KAAG,MACb,CAAC;AA6ExE,eAAO,MAAM,iCAAiC,GAC5C,MAAM,KAAK,CAAC;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,EACxC,SAAS;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,KACrD,oBAmBF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,MAAM,EACd,SAAS;IAAE,eAAe,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAE,EAC/D,kBAAiB,GAAG,CAAC,MAAM,CAAa,KACvC,kBAoBF,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { collectSdsImplementationSignals, normalizeFolderEntry, normalizeHeadingCandidate, } from "./SdsStructureSignals.js";
|
|
2
|
+
const coverageStopTokens = new Set([
|
|
3
|
+
"about",
|
|
4
|
+
"across",
|
|
5
|
+
"after",
|
|
6
|
+
"before",
|
|
7
|
+
"between",
|
|
8
|
+
"from",
|
|
9
|
+
"into",
|
|
10
|
+
"over",
|
|
11
|
+
"under",
|
|
12
|
+
"using",
|
|
13
|
+
"with",
|
|
14
|
+
"without",
|
|
15
|
+
"onto",
|
|
16
|
+
"the",
|
|
17
|
+
"and",
|
|
18
|
+
"for",
|
|
19
|
+
"of",
|
|
20
|
+
"to",
|
|
21
|
+
]);
|
|
22
|
+
const unique = (items) => Array.from(new Set(items.filter(Boolean)));
|
|
23
|
+
export const normalizeCoverageText = (value) => value
|
|
24
|
+
.toLowerCase()
|
|
25
|
+
.replace(/[`*_]/g, " ")
|
|
26
|
+
.replace(/[^a-z0-9/\s.-]+/g, " ")
|
|
27
|
+
.replace(/\s+/g, " ")
|
|
28
|
+
.trim();
|
|
29
|
+
export const normalizeCoverageAnchor = (kind, value) => `${kind}:${normalizeCoverageText(value).replace(/\s+/g, " ").trim()}`;
|
|
30
|
+
const tokenizeCoverageSignal = (value) => unique(value
|
|
31
|
+
.split(/\s+/)
|
|
32
|
+
.map((token) => token.replace(/[^a-z0-9._-]+/g, ""))
|
|
33
|
+
.filter((token) => token.length >= 3 && !coverageStopTokens.has(token)));
|
|
34
|
+
const buildBigrams = (tokens) => {
|
|
35
|
+
const bigrams = [];
|
|
36
|
+
for (let index = 0; index < tokens.length - 1; index += 1) {
|
|
37
|
+
const left = tokens[index];
|
|
38
|
+
const right = tokens[index + 1];
|
|
39
|
+
if (!left || !right)
|
|
40
|
+
continue;
|
|
41
|
+
bigrams.push(`${left} ${right}`);
|
|
42
|
+
}
|
|
43
|
+
return unique(bigrams);
|
|
44
|
+
};
|
|
45
|
+
const headingCovered = (corpus, heading) => {
|
|
46
|
+
const normalized = normalizeCoverageText(normalizeHeadingCandidate(heading));
|
|
47
|
+
if (!normalized)
|
|
48
|
+
return true;
|
|
49
|
+
if (corpus.includes(normalized))
|
|
50
|
+
return true;
|
|
51
|
+
const tokens = tokenizeCoverageSignal(normalized).slice(0, 10);
|
|
52
|
+
if (tokens.length === 0)
|
|
53
|
+
return true;
|
|
54
|
+
const hitCount = tokens.filter((token) => corpus.includes(token)).length;
|
|
55
|
+
const requiredHits = tokens.length <= 2
|
|
56
|
+
? tokens.length
|
|
57
|
+
: tokens.length <= 4
|
|
58
|
+
? 2
|
|
59
|
+
: Math.min(4, Math.ceil(tokens.length * 0.6));
|
|
60
|
+
if (hitCount < requiredHits)
|
|
61
|
+
return false;
|
|
62
|
+
if (tokens.length >= 3) {
|
|
63
|
+
const longestToken = tokens.reduce((longest, token) => (token.length > longest.length ? token : longest), "");
|
|
64
|
+
if (longestToken.length >= 6 && !corpus.includes(longestToken))
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const bigrams = buildBigrams(tokens);
|
|
68
|
+
if (tokens.length >= 3 && bigrams.length > 0 && !bigrams.some((bigram) => corpus.includes(bigram))) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
};
|
|
73
|
+
const folderEntryCovered = (corpus, entry) => {
|
|
74
|
+
const normalizedEntry = normalizeFolderEntry(entry)?.toLowerCase().replace(/\/+/g, "/");
|
|
75
|
+
if (!normalizedEntry)
|
|
76
|
+
return true;
|
|
77
|
+
const corpusTight = corpus.replace(/\s+/g, "");
|
|
78
|
+
if (corpusTight.includes(normalizedEntry.replace(/\s+/g, "")))
|
|
79
|
+
return true;
|
|
80
|
+
const segments = normalizedEntry
|
|
81
|
+
.split("/")
|
|
82
|
+
.map((segment) => segment.trim().replace(/[^a-z0-9._-]+/g, ""))
|
|
83
|
+
.filter(Boolean);
|
|
84
|
+
if (segments.length === 0)
|
|
85
|
+
return true;
|
|
86
|
+
const tailSegments = unique(segments.slice(Math.max(0, segments.length - 3)));
|
|
87
|
+
const hitCount = tailSegments.filter((segment) => corpus.includes(segment)).length;
|
|
88
|
+
const requiredHits = tailSegments.length <= 1 ? 1 : Math.min(2, tailSegments.length);
|
|
89
|
+
if (hitCount < requiredHits)
|
|
90
|
+
return false;
|
|
91
|
+
if (tailSegments.length >= 2) {
|
|
92
|
+
const hasStrongTokenMatch = tailSegments.some((segment) => segment.length >= 5 && corpus.includes(segment));
|
|
93
|
+
if (!hasStrongTokenMatch)
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
};
|
|
98
|
+
export const collectSdsCoverageSignalsFromDocs = (docs, options) => {
|
|
99
|
+
const docSignals = docs.map((doc) => collectSdsImplementationSignals(doc.content ?? "", {
|
|
100
|
+
headingLimit: options.headingLimit,
|
|
101
|
+
folderLimit: options.folderLimit,
|
|
102
|
+
}));
|
|
103
|
+
const rawSectionHeadings = unique(docSignals.flatMap((signals) => signals.rawSectionHeadings));
|
|
104
|
+
const rawFolderEntries = unique(docSignals.flatMap((signals) => signals.rawFolderEntries));
|
|
105
|
+
const sectionHeadings = unique(docSignals.flatMap((signals) => signals.sectionHeadings)).slice(0, options.headingLimit);
|
|
106
|
+
const folderEntries = unique(docSignals.flatMap((signals) => signals.folderEntries)).slice(0, options.folderLimit);
|
|
107
|
+
return {
|
|
108
|
+
rawSectionHeadings,
|
|
109
|
+
rawFolderEntries,
|
|
110
|
+
sectionHeadings,
|
|
111
|
+
folderEntries,
|
|
112
|
+
skippedHeadingSignals: Math.max(0, rawSectionHeadings.length - sectionHeadings.length),
|
|
113
|
+
skippedFolderSignals: Math.max(0, rawFolderEntries.length - folderEntries.length),
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
export const evaluateSdsCoverage = (corpus, signals, existingAnchors = new Set()) => {
|
|
117
|
+
const missingSectionHeadings = signals.sectionHeadings.filter((heading) => {
|
|
118
|
+
const anchor = normalizeCoverageAnchor("section", heading);
|
|
119
|
+
if (existingAnchors.has(anchor))
|
|
120
|
+
return false;
|
|
121
|
+
return !headingCovered(corpus, heading);
|
|
122
|
+
});
|
|
123
|
+
const missingFolderEntries = signals.folderEntries.filter((entry) => {
|
|
124
|
+
const anchor = normalizeCoverageAnchor("folder", entry);
|
|
125
|
+
if (existingAnchors.has(anchor))
|
|
126
|
+
return false;
|
|
127
|
+
return !folderEntryCovered(corpus, entry);
|
|
128
|
+
});
|
|
129
|
+
const totalSignals = signals.sectionHeadings.length + signals.folderEntries.length;
|
|
130
|
+
const coveredSignals = totalSignals - missingSectionHeadings.length - missingFolderEntries.length;
|
|
131
|
+
const coverageRatio = totalSignals === 0 ? 1 : coveredSignals / totalSignals;
|
|
132
|
+
return {
|
|
133
|
+
coverageRatio: Number(coverageRatio.toFixed(4)),
|
|
134
|
+
totalSignals,
|
|
135
|
+
missingSectionHeadings,
|
|
136
|
+
missingFolderEntries,
|
|
137
|
+
};
|
|
138
|
+
};
|
|
@@ -59,7 +59,9 @@ export declare class SdsPreflightService {
|
|
|
59
59
|
private walkCandidates;
|
|
60
60
|
private collectPathCandidates;
|
|
61
61
|
private discoverSdsPaths;
|
|
62
|
+
private countSdsSectionSignals;
|
|
62
63
|
private isLikelySdsPath;
|
|
64
|
+
private selectLikelySdsPaths;
|
|
63
65
|
private resolveSdsPaths;
|
|
64
66
|
private buildArtifacts;
|
|
65
67
|
private getGateRunners;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SdsPreflightService.d.ts","sourceRoot":"","sources":["../../../src/services/planning/SdsPreflightService.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAM1E,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"SdsPreflightService.d.ts","sourceRoot":"","sources":["../../../src/services/planning/SdsPreflightService.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,8 +32,24 @@ const ignoredDirs = new Set([
|
|
|
32
32
|
"tmp",
|
|
33
33
|
"temp",
|
|
34
34
|
]);
|
|
35
|
-
const
|
|
36
|
-
const
|
|
35
|
+
const strongSdsFilenamePattern = /(sds|software[-_ ]design|system[-_ ]design|design[-_ ]spec)/i;
|
|
36
|
+
const strongSdsDirectoryPattern = /(?:^|[/\\])sds(?:[/\\]|$)/i;
|
|
37
|
+
const weakSdsFilenamePattern = /architecture/i;
|
|
38
|
+
const sdsTitlePattern = /^#\s*(?:software design specification|system design specification|sds)\b/im;
|
|
39
|
+
const nonSdsTitlePattern = /^#\s*(?:product design review|pdr|request for proposal|rfp)\b/im;
|
|
40
|
+
const sdsSectionPatterns = [
|
|
41
|
+
/^#{1,6}\s+open questions\b/im,
|
|
42
|
+
/^#{1,6}\s+folder tree\b/im,
|
|
43
|
+
/^#{1,6}\s+technology stack\b/im,
|
|
44
|
+
/^#{1,6}\s+policy(?: and cache consent)?\b/im,
|
|
45
|
+
/^#{1,6}\s+telemetry\b/im,
|
|
46
|
+
/^#{1,6}\s+(?:metering and usage|metering|usage)\b/im,
|
|
47
|
+
/^#{1,6}\s+(?:operations and deployment|operations|deployment)\b/im,
|
|
48
|
+
/^#{1,6}\s+observability\b/im,
|
|
49
|
+
/^#{1,6}\s+testing gates\b/im,
|
|
50
|
+
/^#{1,6}\s+(?:failure recovery and rollback|failure modes(?:, recovery, and rollback)?)\b/im,
|
|
51
|
+
/^#{1,6}\s+external integrations and adapter contracts\b/im,
|
|
52
|
+
];
|
|
37
53
|
const markdownPattern = /\.(md|markdown|txt|rst)$/i;
|
|
38
54
|
const unresolvedTokenPattern = /\b(TBD|TBC|TODO|FIXME|to be determined|to be decided|unknown|unresolved)\b/gi;
|
|
39
55
|
const sdsHeadingLinePattern = /^#{1,6}\s+(.+)$/;
|
|
@@ -78,6 +94,14 @@ const environmentMatchers = [
|
|
|
78
94
|
{ label: "staging", pattern: /\bstaging\b|\bpre-?prod\b/i },
|
|
79
95
|
{ label: "production", pattern: /\bprod(uction)?\b/i },
|
|
80
96
|
];
|
|
97
|
+
const documentationSegmentPattern = /^(docs?|design|specs?|runbooks?|adr|architecture)$/i;
|
|
98
|
+
const implementationSegmentPattern = /^(src|app|apps|service|services|worker|workers|module|modules|package|packages|lib|libs|engine|engines|console|consoles|runtime|runtimes)$/i;
|
|
99
|
+
const interfaceSegmentPattern = /^(api|apis|openapi|swagger|graphql|proto|schema|schemas|contract|contracts|interface|interfaces)$/i;
|
|
100
|
+
const storageSegmentPattern = /^(db|data|storage|schema|schemas|migration|migrations|sql|seed|seeds)$/i;
|
|
101
|
+
const automationSegmentPattern = /^(script|scripts|tool|tools|bin|cmd|cli|automation)$/i;
|
|
102
|
+
const operationsSegmentPattern = /^(ops|deploy|deployment|deployments|infra|infrastructure|terraform|helm|k8s|kubernetes|systemd)$/i;
|
|
103
|
+
const validationSegmentPattern = /^(test|tests|testing|spec|specs|e2e|qa|fixtures)$/i;
|
|
104
|
+
const staticAssetSegmentPattern = /^(public|static|assets)$/i;
|
|
81
105
|
const moduleNoiseTokens = new Set([
|
|
82
106
|
"and",
|
|
83
107
|
"for",
|
|
@@ -101,6 +125,47 @@ const moduleNoiseTokens = new Set([
|
|
|
101
125
|
]);
|
|
102
126
|
const execFileAsync = promisify(execFile);
|
|
103
127
|
const uniqueStrings = (values) => Array.from(new Set(values.filter(Boolean)));
|
|
128
|
+
const stripManagedPreflightBlocks = (content) => {
|
|
129
|
+
let updated = content;
|
|
130
|
+
while (true) {
|
|
131
|
+
const startIndex = updated.indexOf(MANAGED_SDS_BLOCK_START);
|
|
132
|
+
if (startIndex < 0)
|
|
133
|
+
break;
|
|
134
|
+
const endIndex = updated.indexOf(MANAGED_SDS_BLOCK_END, startIndex);
|
|
135
|
+
if (endIndex < 0)
|
|
136
|
+
break;
|
|
137
|
+
updated = `${updated.slice(0, startIndex)}\n${updated.slice(endIndex + MANAGED_SDS_BLOCK_END.length)}`;
|
|
138
|
+
}
|
|
139
|
+
return updated;
|
|
140
|
+
};
|
|
141
|
+
const describeFolderEntry = (entry) => {
|
|
142
|
+
if (/\s+#/.test(entry))
|
|
143
|
+
return "";
|
|
144
|
+
const segments = entry
|
|
145
|
+
.replace(/^\.?\//, "")
|
|
146
|
+
.split("/")
|
|
147
|
+
.map((segment) => segment.trim().toLowerCase())
|
|
148
|
+
.filter(Boolean);
|
|
149
|
+
if (segments.length === 0)
|
|
150
|
+
return "implementation surface";
|
|
151
|
+
if (segments.some((segment) => documentationSegmentPattern.test(segment)))
|
|
152
|
+
return "documentation and planning inputs";
|
|
153
|
+
if (segments.some((segment) => validationSegmentPattern.test(segment)))
|
|
154
|
+
return "automated validation surfaces";
|
|
155
|
+
if (segments.some((segment) => automationSegmentPattern.test(segment)))
|
|
156
|
+
return "automation and command entrypoints";
|
|
157
|
+
if (segments.some((segment) => operationsSegmentPattern.test(segment)))
|
|
158
|
+
return "deployment and operations assets";
|
|
159
|
+
if (segments.some((segment) => storageSegmentPattern.test(segment)))
|
|
160
|
+
return "storage and schema assets";
|
|
161
|
+
if (segments.some((segment) => interfaceSegmentPattern.test(segment)))
|
|
162
|
+
return "interface definitions and compatibility surfaces";
|
|
163
|
+
if (segments.some((segment) => staticAssetSegmentPattern.test(segment)))
|
|
164
|
+
return "runtime assets";
|
|
165
|
+
if (segments.some((segment) => implementationSegmentPattern.test(segment)))
|
|
166
|
+
return "implementation surfaces";
|
|
167
|
+
return segments.length >= 2 ? "implementation surface" : "top-level workspace surface";
|
|
168
|
+
};
|
|
104
169
|
const normalizeQuestion = (value) => value
|
|
105
170
|
.toLowerCase()
|
|
106
171
|
.replace(/[^a-z0-9]+/g, " ")
|
|
@@ -213,25 +278,34 @@ export class SdsPreflightService {
|
|
|
213
278
|
});
|
|
214
279
|
return uniqueStrings(discovered).slice(0, SDS_SCAN_MAX_FILES);
|
|
215
280
|
}
|
|
281
|
+
countSdsSectionSignals(sample) {
|
|
282
|
+
const effectiveSample = stripManagedPreflightBlocks(sample);
|
|
283
|
+
return sdsSectionPatterns.reduce((count, pattern) => count + (pattern.test(effectiveSample) ? 1 : 0), 0);
|
|
284
|
+
}
|
|
216
285
|
async isLikelySdsPath(filePath) {
|
|
217
286
|
const baseName = path.basename(filePath);
|
|
218
|
-
|
|
219
|
-
return true;
|
|
287
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
220
288
|
try {
|
|
221
|
-
const
|
|
222
|
-
|
|
289
|
+
const rawSample = (await fs.readFile(filePath, "utf8")).slice(0, 35000);
|
|
290
|
+
const sample = stripManagedPreflightBlocks(rawSample);
|
|
291
|
+
if (nonSdsTitlePattern.test(sample))
|
|
292
|
+
return false;
|
|
293
|
+
if (sdsTitlePattern.test(sample))
|
|
294
|
+
return true;
|
|
295
|
+
if (strongSdsFilenamePattern.test(baseName) || strongSdsDirectoryPattern.test(normalizedPath)) {
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
if (!weakSdsFilenamePattern.test(baseName))
|
|
299
|
+
return false;
|
|
300
|
+
return this.countSdsSectionSignals(sample) >= 3;
|
|
223
301
|
}
|
|
224
302
|
catch {
|
|
225
303
|
return false;
|
|
226
304
|
}
|
|
227
305
|
}
|
|
228
|
-
async
|
|
229
|
-
const explicit = await this.collectPathCandidates(options.sdsPaths);
|
|
230
|
-
const fromInputs = await this.collectPathCandidates(options.inputPaths);
|
|
231
|
-
const discovered = await this.discoverSdsPaths();
|
|
232
|
-
const candidatePaths = uniqueStrings([...explicit, ...fromInputs, ...discovered]).slice(0, SDS_SCAN_MAX_FILES);
|
|
306
|
+
async selectLikelySdsPaths(candidatePaths) {
|
|
233
307
|
const selected = [];
|
|
234
|
-
for (const candidate of candidatePaths) {
|
|
308
|
+
for (const candidate of uniqueStrings(candidatePaths).slice(0, SDS_SCAN_MAX_FILES)) {
|
|
235
309
|
if (await this.isLikelySdsPath(candidate)) {
|
|
236
310
|
selected.push(path.resolve(candidate));
|
|
237
311
|
}
|
|
@@ -240,6 +314,19 @@ export class SdsPreflightService {
|
|
|
240
314
|
}
|
|
241
315
|
return uniqueStrings(selected);
|
|
242
316
|
}
|
|
317
|
+
async resolveSdsPaths(options) {
|
|
318
|
+
const explicit = await this.collectPathCandidates(options.sdsPaths);
|
|
319
|
+
if (explicit.length > 0) {
|
|
320
|
+
return this.selectLikelySdsPaths(explicit);
|
|
321
|
+
}
|
|
322
|
+
const fromInputs = await this.collectPathCandidates(options.inputPaths);
|
|
323
|
+
const selectedFromInputs = await this.selectLikelySdsPaths(fromInputs);
|
|
324
|
+
if (selectedFromInputs.length > 0) {
|
|
325
|
+
return selectedFromInputs;
|
|
326
|
+
}
|
|
327
|
+
const discovered = await this.discoverSdsPaths();
|
|
328
|
+
return this.selectLikelySdsPaths(discovered);
|
|
329
|
+
}
|
|
243
330
|
buildArtifacts(sdsPath) {
|
|
244
331
|
const artifacts = createEmptyArtifacts();
|
|
245
332
|
artifacts.sds = {
|
|
@@ -286,7 +373,7 @@ export class SdsPreflightService {
|
|
|
286
373
|
return path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(this.workspace.workspaceRoot, filePath);
|
|
287
374
|
}
|
|
288
375
|
collectSignalsFromContent(content) {
|
|
289
|
-
const lines = content.split(/\r?\n/);
|
|
376
|
+
const lines = stripManagedPreflightBlocks(content).split(/\r?\n/);
|
|
290
377
|
const headings = [];
|
|
291
378
|
const folderEntries = [];
|
|
292
379
|
for (const line of lines) {
|
|
@@ -445,12 +532,17 @@ export class SdsPreflightService {
|
|
|
445
532
|
}
|
|
446
533
|
managedFolderTreeSection(signals) {
|
|
447
534
|
const entries = signals?.folderEntries?.slice(0, 10) ?? [];
|
|
535
|
+
const annotateEntry = (entry, isLast) => {
|
|
536
|
+
const hint = describeFolderEntry(entry);
|
|
537
|
+
const prefix = isLast ? "└──" : "├──";
|
|
538
|
+
return hint ? `${prefix} ${entry} # ${hint}` : `${prefix} ${entry}`;
|
|
539
|
+
};
|
|
448
540
|
if (entries.length > 0) {
|
|
449
541
|
return [
|
|
450
542
|
"## Folder Tree",
|
|
451
543
|
"```text",
|
|
452
544
|
".",
|
|
453
|
-
...entries.map((entry, index) =>
|
|
545
|
+
...entries.map((entry, index) => annotateEntry(entry, index === entries.length - 1)),
|
|
454
546
|
"```",
|
|
455
547
|
"",
|
|
456
548
|
];
|
|
@@ -459,14 +551,12 @@ export class SdsPreflightService {
|
|
|
459
551
|
"## Folder Tree",
|
|
460
552
|
"```text",
|
|
461
553
|
".",
|
|
462
|
-
"├── docs/",
|
|
463
|
-
"├──
|
|
464
|
-
"├──
|
|
465
|
-
"├──
|
|
466
|
-
"├──
|
|
467
|
-
"
|
|
468
|
-
"├── tests/",
|
|
469
|
-
"└── scripts/",
|
|
554
|
+
"├── docs/architecture/ # documentation and planning inputs",
|
|
555
|
+
"├── modules/core/ # implementation surfaces",
|
|
556
|
+
"├── interfaces/public/ # interface definitions and compatibility surfaces",
|
|
557
|
+
"├── data/migrations/ # storage and schema assets",
|
|
558
|
+
"├── tests/integration/ # automated validation surfaces",
|
|
559
|
+
"└── tools/release/ # automation and command entrypoints",
|
|
470
560
|
"```",
|
|
471
561
|
"",
|
|
472
562
|
];
|
|
@@ -476,17 +566,17 @@ export class SdsPreflightService {
|
|
|
476
566
|
if (technologies.length > 0) {
|
|
477
567
|
return [
|
|
478
568
|
"## Technology Stack",
|
|
479
|
-
`-
|
|
480
|
-
"-
|
|
481
|
-
"-
|
|
569
|
+
`- Observed source-backed technology signals: ${technologies.join(", ")}.`,
|
|
570
|
+
"- Keep the chosen stack explicit in the source docs for runtime, language, persistence, interface, and tooling layers.",
|
|
571
|
+
"- Record alternatives only when the source docs name them; do not invent default stack choices during preflight.",
|
|
482
572
|
"",
|
|
483
573
|
];
|
|
484
574
|
}
|
|
485
575
|
return [
|
|
486
576
|
"## Technology Stack",
|
|
487
|
-
"-
|
|
488
|
-
"-
|
|
489
|
-
"-
|
|
577
|
+
"- Source docs do not yet make the technology stack explicit.",
|
|
578
|
+
"- Record runtime, language, persistence, interface, and tooling decisions explicitly in the source docs without assuming defaults.",
|
|
579
|
+
"- Preflight must not invent a chosen stack baseline when the source is silent.",
|
|
490
580
|
"",
|
|
491
581
|
];
|
|
492
582
|
}
|
|
@@ -878,24 +968,24 @@ export class SdsPreflightService {
|
|
|
878
968
|
const scopedIssues = issues.filter((issue) => this.issueMatchesPath(issue, sdsPath));
|
|
879
969
|
const lines = [
|
|
880
970
|
MANAGED_SDS_BLOCK_START,
|
|
881
|
-
"##
|
|
971
|
+
"## Planning Decisions (mcoda preflight)",
|
|
882
972
|
"",
|
|
883
973
|
];
|
|
884
974
|
if (scopedQuestions.length === 0) {
|
|
885
|
-
lines.push("-
|
|
975
|
+
lines.push("- Decision coverage baseline recorded for this SDS file in this preflight run.");
|
|
886
976
|
lines.push("");
|
|
887
977
|
}
|
|
888
978
|
else {
|
|
889
979
|
scopedQuestions.forEach((question, index) => {
|
|
890
980
|
const summary = this.normalizeResolvedText(question.answer);
|
|
891
|
-
const prefix = summary || "Explicit decision recorded in managed preflight output.";
|
|
892
|
-
lines.push(`-
|
|
981
|
+
const prefix = summary || "Explicit implementation decision recorded in managed preflight output.";
|
|
982
|
+
lines.push(`- Decision ${index + 1}: ${prefix}`);
|
|
893
983
|
});
|
|
894
984
|
lines.push("");
|
|
895
985
|
}
|
|
896
|
-
lines.push("##
|
|
897
|
-
lines.push("- Decision baseline:
|
|
898
|
-
lines.push("- Planning rule: each
|
|
986
|
+
lines.push("## Decision Summary (mcoda preflight)");
|
|
987
|
+
lines.push("- Decision baseline: preflight converts planning ambiguities into explicit implementation guidance.");
|
|
988
|
+
lines.push("- Planning rule: each captured decision maps to implementation and QA verification work.");
|
|
899
989
|
if (signals?.moduleDomains && signals.moduleDomains.length > 0) {
|
|
900
990
|
lines.push(`- Module scope detected for this SDS file: ${signals.moduleDomains.slice(0, 6).join(", ")}.`);
|
|
901
991
|
}
|
|
@@ -908,12 +998,13 @@ export class SdsPreflightService {
|
|
|
908
998
|
lines.push("## Gap Remediation Summary (mcoda preflight)");
|
|
909
999
|
lines.push("");
|
|
910
1000
|
if (scopedIssues.length === 0) {
|
|
911
|
-
lines.push("- No
|
|
1001
|
+
lines.push("- No remaining SDS quality gaps were detected for this SDS file in this preflight run.");
|
|
912
1002
|
lines.push("");
|
|
913
1003
|
}
|
|
914
1004
|
else {
|
|
915
1005
|
scopedIssues.forEach((issue, index) => {
|
|
916
|
-
|
|
1006
|
+
const gapSummary = this.normalizeResolvedText(issue.message) || issue.message;
|
|
1007
|
+
lines.push(`### Gap ${index + 1}: ${gapSummary}`);
|
|
917
1008
|
lines.push(`- Gate: ${issue.gateId}`);
|
|
918
1009
|
lines.push(`- Source: ${formatIssueLocation(issue)}`);
|
|
919
1010
|
lines.push("- Remediation:");
|
|
@@ -1022,6 +1113,9 @@ export class SdsPreflightService {
|
|
|
1022
1113
|
let issues = this.dedupeIssues(outcome.issues);
|
|
1023
1114
|
let questions = this.extractQuestionAnswers(issues, signalsByPath);
|
|
1024
1115
|
const applyToSds = options.applyToSds === true;
|
|
1116
|
+
if (options.commitAppliedChanges && !applyToSds) {
|
|
1117
|
+
warnings.push("SDS preflight commit was requested without applyToSds; skipping commit because source SDS writeback is disabled.");
|
|
1118
|
+
}
|
|
1025
1119
|
let appliedSdsPaths = [];
|
|
1026
1120
|
if (applyToSds) {
|
|
1027
1121
|
const applyResult = await this.applyPreflightRemediationsToSds({
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const isStructuredFilePath: (value: string) => boolean;
|
|
2
|
+
export declare const stripManagedSdsPreflightBlock: (value: string | undefined) => string | undefined;
|
|
3
|
+
export declare const normalizeHeadingCandidate: (value: string) => string;
|
|
4
|
+
export declare const headingLooksImplementationRelevant: (heading: string) => boolean;
|
|
5
|
+
export declare const pruneParentImplementationHeadings: (headings: string[]) => string[];
|
|
6
|
+
export declare const normalizeStructuredPathToken: (value: string) => string | undefined;
|
|
7
|
+
export declare const normalizeFolderEntry: (entry: string) => string | undefined;
|
|
8
|
+
export declare const extractStructuredPaths: (content: string, limit: number) => string[];
|
|
9
|
+
export declare const extractMarkdownHeadings: (content: string, limit: number) => string[];
|
|
10
|
+
export declare const folderEntryLooksRepoRelevant: (entry: string) => boolean;
|
|
11
|
+
export declare const filterImplementationStructuredPaths: (paths: string[]) => string[];
|
|
12
|
+
export interface SdsImplementationSignals {
|
|
13
|
+
rawSectionHeadings: string[];
|
|
14
|
+
rawFolderEntries: string[];
|
|
15
|
+
sectionHeadings: string[];
|
|
16
|
+
folderEntries: string[];
|
|
17
|
+
skippedHeadingSignals: number;
|
|
18
|
+
skippedFolderSignals: number;
|
|
19
|
+
}
|
|
20
|
+
export declare const collectSdsImplementationSignals: (content: string, options: {
|
|
21
|
+
headingLimit: number;
|
|
22
|
+
folderLimit: number;
|
|
23
|
+
}) => SdsImplementationSignals;
|
|
24
|
+
//# sourceMappingURL=SdsStructureSignals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SdsStructureSignals.d.ts","sourceRoot":"","sources":["../../../src/services/planning/SdsStructureSignals.ts"],"names":[],"mappings":"AA4GA,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,OAA6C,CAAC;AAEnG,eAAO,MAAM,6BAA6B,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAIlF,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,OAAO,MAAM,KAAG,MAGzD,CAAC;AAEF,eAAO,MAAM,kCAAkC,GAAI,SAAS,MAAM,KAAG,OAgBpE,CAAC;AAEF,eAAO,MAAM,iCAAiC,GAAI,UAAU,MAAM,EAAE,KAAG,MAAM,EAc5E,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,SA4BrE,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,SACiC,CAAC;AA8DhG,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,EAAE,OAAO,MAAM,KAAG,MAAM,EA0B7E,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,SAAS,MAAM,EAAE,OAAO,MAAM,KAAG,MAAM,EAsC9E,CAAC;AAaF,eAAO,MAAM,4BAA4B,GAAI,OAAO,MAAM,KAAG,OAiB5D,CAAC;AAEF,eAAO,MAAM,mCAAmC,GAAI,OAAO,MAAM,EAAE,KAAG,MAAM,EAsB3E,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACvC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,+BAA+B,GAC1C,SAAS,MAAM,EACf,SAAS;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,KACrD,wBA2BF,CAAC"}
|