@danmoisan/drm-copilot-mcp 1.0.26 → 1.0.27
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/out/mcp-server.js +542 -41
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +109 -5
- package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +390 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +105 -2
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +32 -52
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +107 -99
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +295 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +9 -3
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidGrammar.psm1 +491 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidLineScanner.psm1 +488 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidMarkdownFences.psm1 +298 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidValidation.psm1 +496 -0
- package/resources/claude-customizations/.claude/rules/mermaid.md +142 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +61 -1
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +116 -0
- package/resources/claude-customizations/.claude/settings.json +5 -0
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +15 -0
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +6 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/SKILL.md +184 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/c4.md +50 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/class.md +63 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/er.md +56 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/flowchart.md +68 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/gantt.md +51 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/other-types.md +82 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/pie.md +32 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/sequence.md +63 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/state.md +49 -0
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +8 -7
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +24 -4
- package/resources/claude-customizations/config/blast-radius.json +8 -0
- package/resources/claude-customizations/pack-manifests/core.json +19 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +16 -1
package/out/mcp-server.js
CHANGED
|
@@ -17260,7 +17260,8 @@ function toMcpToolResult(result) {
|
|
|
17260
17260
|
...result.assetId === void 0 ? {} : { asset_id: result.assetId },
|
|
17261
17261
|
...result.bundledSourcePath === void 0 ? {} : { bundled_source_path: result.bundledSourcePath },
|
|
17262
17262
|
...result.destinationPath === void 0 ? {} : { destination_path: result.destinationPath },
|
|
17263
|
-
...result.renderedTree === void 0 ? {} : { rendered_tree: result.renderedTree }
|
|
17263
|
+
...result.renderedTree === void 0 ? {} : { rendered_tree: result.renderedTree },
|
|
17264
|
+
...result.warnings === void 0 ? {} : { warnings: result.warnings }
|
|
17264
17265
|
};
|
|
17265
17266
|
}
|
|
17266
17267
|
function toFailureToolResult(tool, workspaceRoot, error2) {
|
|
@@ -19015,7 +19016,8 @@ var CARRIED_KEYS = [
|
|
|
19015
19016
|
"version",
|
|
19016
19017
|
"shared_surfaces",
|
|
19017
19018
|
"shared_surface_globs",
|
|
19018
|
-
"over_breadth_fraction"
|
|
19019
|
+
"over_breadth_fraction",
|
|
19020
|
+
"mandate_reads"
|
|
19019
19021
|
];
|
|
19020
19022
|
var BlastRadiusDeriveError = class extends Error {
|
|
19021
19023
|
/** Destination-relative path of the document that failed to parse. */
|
|
@@ -19143,6 +19145,7 @@ function deriveDestinationModuleMap(observations, sourceDocumentText) {
|
|
|
19143
19145
|
version: source[CARRIED_KEYS[0]],
|
|
19144
19146
|
shared_surfaces: source[CARRIED_KEYS[1]],
|
|
19145
19147
|
shared_surface_globs: source[CARRIED_KEYS[2]],
|
|
19148
|
+
mandate_reads: source[CARRIED_KEYS[4]],
|
|
19146
19149
|
modules,
|
|
19147
19150
|
over_breadth_fraction: source[CARRIED_KEYS[3]]
|
|
19148
19151
|
};
|
|
@@ -26846,6 +26849,417 @@ function validateParallelKickoffText(text) {
|
|
|
26846
26849
|
return parseParallelKickoff(text).errors;
|
|
26847
26850
|
}
|
|
26848
26851
|
|
|
26852
|
+
// ../../extensions/drm-copilot/src/lib/validate/plan-gate-commands.ts
|
|
26853
|
+
var SHELL_WHITESPACE = /* @__PURE__ */ new Set([" ", " ", "\r", "\n"]);
|
|
26854
|
+
var ESCAPE = "\\";
|
|
26855
|
+
var COV_FLAG = "--cov";
|
|
26856
|
+
var COV_FLAG_PREFIX = "--cov=";
|
|
26857
|
+
var GREP_EXECUTABLES = /* @__PURE__ */ new Set(["grep", "egrep", "fgrep", "rg"]);
|
|
26858
|
+
var EXECUTABLE_SCAN_LIMIT = 4;
|
|
26859
|
+
var PLAN_GATE_TASK_PATTERN = /^- \[(?<state>[ xX])\] \[P(?<phase>\d+)-T(?<task>\d+)\] (?<title>.+)$/;
|
|
26860
|
+
var PLAN_GATE_HEADING_PATTERN = /^#{1,6} /;
|
|
26861
|
+
var INLINE_SPAN_RE = /`([^`]+)`/g;
|
|
26862
|
+
var FENCE_RE = /^\s*```/;
|
|
26863
|
+
var MINIMUM_ARGV_LENGTH = 2;
|
|
26864
|
+
function splitShellWords(span) {
|
|
26865
|
+
const words2 = [];
|
|
26866
|
+
let token = null;
|
|
26867
|
+
let quote = null;
|
|
26868
|
+
let index = 0;
|
|
26869
|
+
while (index < span.length) {
|
|
26870
|
+
const char = span[index] ?? "";
|
|
26871
|
+
index += 1;
|
|
26872
|
+
if (quote === null) {
|
|
26873
|
+
if (SHELL_WHITESPACE.has(char)) {
|
|
26874
|
+
if (token !== null) {
|
|
26875
|
+
words2.push(token);
|
|
26876
|
+
token = null;
|
|
26877
|
+
}
|
|
26878
|
+
continue;
|
|
26879
|
+
}
|
|
26880
|
+
if (char === ESCAPE) {
|
|
26881
|
+
const next = span[index];
|
|
26882
|
+
if (next === void 0) {
|
|
26883
|
+
return null;
|
|
26884
|
+
}
|
|
26885
|
+
index += 1;
|
|
26886
|
+
token = (token ?? "") + next;
|
|
26887
|
+
continue;
|
|
26888
|
+
}
|
|
26889
|
+
if (char === '"' || char === "'") {
|
|
26890
|
+
quote = char;
|
|
26891
|
+
token = token ?? "";
|
|
26892
|
+
continue;
|
|
26893
|
+
}
|
|
26894
|
+
token = (token ?? "") + char;
|
|
26895
|
+
continue;
|
|
26896
|
+
}
|
|
26897
|
+
if (char === quote) {
|
|
26898
|
+
quote = null;
|
|
26899
|
+
continue;
|
|
26900
|
+
}
|
|
26901
|
+
if (quote === '"' && char === ESCAPE) {
|
|
26902
|
+
const next = span[index];
|
|
26903
|
+
if (next === void 0) {
|
|
26904
|
+
return null;
|
|
26905
|
+
}
|
|
26906
|
+
index += 1;
|
|
26907
|
+
if (next !== quote && next !== ESCAPE) {
|
|
26908
|
+
token = (token ?? "") + ESCAPE;
|
|
26909
|
+
}
|
|
26910
|
+
token = (token ?? "") + next;
|
|
26911
|
+
continue;
|
|
26912
|
+
}
|
|
26913
|
+
token = (token ?? "") + char;
|
|
26914
|
+
}
|
|
26915
|
+
if (quote !== null) {
|
|
26916
|
+
return null;
|
|
26917
|
+
}
|
|
26918
|
+
if (token !== null) {
|
|
26919
|
+
words2.push(token);
|
|
26920
|
+
}
|
|
26921
|
+
return words2;
|
|
26922
|
+
}
|
|
26923
|
+
function isCovFlagToken(token) {
|
|
26924
|
+
return token === COV_FLAG || token.startsWith(COV_FLAG_PREFIX);
|
|
26925
|
+
}
|
|
26926
|
+
function grepExecutableIndex(argv) {
|
|
26927
|
+
const limit = Math.min(argv.length, EXECUTABLE_SCAN_LIMIT);
|
|
26928
|
+
for (let index = 0; index < limit; index += 1) {
|
|
26929
|
+
const word = argv[index];
|
|
26930
|
+
if (word === void 0) {
|
|
26931
|
+
continue;
|
|
26932
|
+
}
|
|
26933
|
+
if (GREP_EXECUTABLES.has(word)) {
|
|
26934
|
+
return index;
|
|
26935
|
+
}
|
|
26936
|
+
if (word === "git" && argv[index + 1] === "grep") {
|
|
26937
|
+
return index + 1;
|
|
26938
|
+
}
|
|
26939
|
+
}
|
|
26940
|
+
return null;
|
|
26941
|
+
}
|
|
26942
|
+
function classifyKind(argv) {
|
|
26943
|
+
if (grepExecutableIndex(argv) !== null) {
|
|
26944
|
+
return "grep";
|
|
26945
|
+
}
|
|
26946
|
+
if (argv.some((word) => isCovFlagToken(word))) {
|
|
26947
|
+
return "pytest_cov";
|
|
26948
|
+
}
|
|
26949
|
+
return "other";
|
|
26950
|
+
}
|
|
26951
|
+
function splitLines2(text) {
|
|
26952
|
+
return text.split(/\r\n|\n|\r/);
|
|
26953
|
+
}
|
|
26954
|
+
function inlineSpans(line) {
|
|
26955
|
+
const spans = [];
|
|
26956
|
+
for (const match of line.matchAll(INLINE_SPAN_RE)) {
|
|
26957
|
+
const body = match[1];
|
|
26958
|
+
if (body !== void 0) {
|
|
26959
|
+
spans.push(body);
|
|
26960
|
+
}
|
|
26961
|
+
}
|
|
26962
|
+
return spans;
|
|
26963
|
+
}
|
|
26964
|
+
function appendCommand(commands, taskId, sourceLine, rawSpan) {
|
|
26965
|
+
const argv = splitShellWords(rawSpan);
|
|
26966
|
+
if (argv === null || argv.length < MINIMUM_ARGV_LENGTH) {
|
|
26967
|
+
return;
|
|
26968
|
+
}
|
|
26969
|
+
commands.push({
|
|
26970
|
+
taskId,
|
|
26971
|
+
sourceLine,
|
|
26972
|
+
rawSpan,
|
|
26973
|
+
argv,
|
|
26974
|
+
kind: classifyKind(argv)
|
|
26975
|
+
});
|
|
26976
|
+
}
|
|
26977
|
+
function extractPlanCommands(text) {
|
|
26978
|
+
const commands = [];
|
|
26979
|
+
let currentTask = null;
|
|
26980
|
+
let inFence = false;
|
|
26981
|
+
const lines = splitLines2(text);
|
|
26982
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
26983
|
+
const line = lines[index] ?? "";
|
|
26984
|
+
const lineNumber = index + 1;
|
|
26985
|
+
if (FENCE_RE.test(line)) {
|
|
26986
|
+
inFence = !inFence;
|
|
26987
|
+
continue;
|
|
26988
|
+
}
|
|
26989
|
+
if (inFence) {
|
|
26990
|
+
const fenced = line.trim();
|
|
26991
|
+
if (currentTask !== null && fenced !== "") {
|
|
26992
|
+
appendCommand(commands, currentTask, lineNumber, fenced);
|
|
26993
|
+
}
|
|
26994
|
+
continue;
|
|
26995
|
+
}
|
|
26996
|
+
if (PLAN_GATE_HEADING_PATTERN.test(line)) {
|
|
26997
|
+
currentTask = null;
|
|
26998
|
+
continue;
|
|
26999
|
+
}
|
|
27000
|
+
const taskMatch = PLAN_GATE_TASK_PATTERN.exec(line);
|
|
27001
|
+
if (taskMatch !== null) {
|
|
27002
|
+
const phase = taskMatch.groups?.["phase"] ?? "";
|
|
27003
|
+
const task = taskMatch.groups?.["task"] ?? "";
|
|
27004
|
+
currentTask = `P${phase}-T${task}`;
|
|
27005
|
+
}
|
|
27006
|
+
if (currentTask === null) {
|
|
27007
|
+
continue;
|
|
27008
|
+
}
|
|
27009
|
+
for (const span of inlineSpans(line)) {
|
|
27010
|
+
appendCommand(commands, currentTask, lineNumber, span);
|
|
27011
|
+
}
|
|
27012
|
+
}
|
|
27013
|
+
return commands;
|
|
27014
|
+
}
|
|
27015
|
+
|
|
27016
|
+
// ../../extensions/drm-copilot/src/lib/validate/plan-gate-rules.ts
|
|
27017
|
+
function emptyPlanGateReport() {
|
|
27018
|
+
return { blocking: [], warnings: [] };
|
|
27019
|
+
}
|
|
27020
|
+
var BLOCKING_CHANNEL = "blocking";
|
|
27021
|
+
var PLACEHOLDER_MARKERS = ["<", ">", "${", "$(", "%"];
|
|
27022
|
+
var PATH_SEPARATORS = ["/", "\\"];
|
|
27023
|
+
var PYTHON_SUFFIX = ".py";
|
|
27024
|
+
var PYTEST_NODE_SEPARATOR = "::";
|
|
27025
|
+
var REGEX_METACHARACTERS = /* @__PURE__ */ new Set([...".*[]^$\\(){}|+?"]);
|
|
27026
|
+
var FIXED_STRING_FLAG = "-F";
|
|
27027
|
+
var WINDOW_SIZE = 4;
|
|
27028
|
+
function isPlaceholder(value) {
|
|
27029
|
+
return PLACEHOLDER_MARKERS.some((marker) => value.includes(marker));
|
|
27030
|
+
}
|
|
27031
|
+
function dottedRemedy(value) {
|
|
27032
|
+
const stem2 = value.endsWith(PYTHON_SUFFIX) ? value.slice(0, value.length - PYTHON_SUFFIX.length) : value;
|
|
27033
|
+
return stem2.split("/").join(".").split("\\").join(".");
|
|
27034
|
+
}
|
|
27035
|
+
function covValues(command) {
|
|
27036
|
+
const values = [];
|
|
27037
|
+
const argv = command.argv;
|
|
27038
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
27039
|
+
const word = argv[index];
|
|
27040
|
+
if (word === void 0) {
|
|
27041
|
+
continue;
|
|
27042
|
+
}
|
|
27043
|
+
if (word === COV_FLAG) {
|
|
27044
|
+
const next = argv[index + 1];
|
|
27045
|
+
if (next !== void 0) {
|
|
27046
|
+
values.push({ value: next, spaceSeparated: true });
|
|
27047
|
+
}
|
|
27048
|
+
continue;
|
|
27049
|
+
}
|
|
27050
|
+
if (word.startsWith(COV_FLAG_PREFIX)) {
|
|
27051
|
+
values.push({
|
|
27052
|
+
value: word.slice(COV_FLAG_PREFIX.length),
|
|
27053
|
+
spaceSeparated: false
|
|
27054
|
+
});
|
|
27055
|
+
}
|
|
27056
|
+
}
|
|
27057
|
+
return values;
|
|
27058
|
+
}
|
|
27059
|
+
function evaluateCovValue(report, command, cov, context) {
|
|
27060
|
+
const task = command.taskId;
|
|
27061
|
+
if (cov.spaceSeparated) {
|
|
27062
|
+
report.warnings.push(
|
|
27063
|
+
`[${task}] --cov argument value \`${cov.value}\` is supplied space-separated; the ambiguous form can bind the following positional argument. Use the --cov=<module> form.`
|
|
27064
|
+
);
|
|
27065
|
+
}
|
|
27066
|
+
if (isPlaceholder(cov.value)) {
|
|
27067
|
+
return;
|
|
27068
|
+
}
|
|
27069
|
+
const truncated = cov.value.split(PYTEST_NODE_SEPARATOR)[0] ?? "";
|
|
27070
|
+
if (truncated.endsWith(PYTHON_SUFFIX)) {
|
|
27071
|
+
report.blocking.push(
|
|
27072
|
+
`[${task}] --cov argument \`${cov.value}\` names a filesystem path; coverage.py accepts only directories or importable names. Use --cov=${dottedRemedy(truncated)}.`
|
|
27073
|
+
);
|
|
27074
|
+
return;
|
|
27075
|
+
}
|
|
27076
|
+
if (!PATH_SEPARATORS.some((separator) => cov.value.includes(separator))) {
|
|
27077
|
+
return;
|
|
27078
|
+
}
|
|
27079
|
+
if (context === void 0) {
|
|
27080
|
+
return;
|
|
27081
|
+
}
|
|
27082
|
+
try {
|
|
27083
|
+
evaluateTrackedCovValue(report, task, cov, truncated, context);
|
|
27084
|
+
} catch {
|
|
27085
|
+
}
|
|
27086
|
+
}
|
|
27087
|
+
function evaluateTrackedCovValue(report, task, cov, truncated, context) {
|
|
27088
|
+
if (context.git.isTrackedFile(truncated + PYTHON_SUFFIX)) {
|
|
27089
|
+
report.blocking.push(
|
|
27090
|
+
`[${task}] --cov argument \`${cov.value}\` names a tracked module file path; coverage.py accepts only directories or importable names. Use --cov=${dottedRemedy(truncated)}.`
|
|
27091
|
+
);
|
|
27092
|
+
return;
|
|
27093
|
+
}
|
|
27094
|
+
if (context.git.isTrackedDirectory(truncated)) {
|
|
27095
|
+
return;
|
|
27096
|
+
}
|
|
27097
|
+
report.warnings.push(
|
|
27098
|
+
`[${task}] --cov argument \`${cov.value}\` contains a path separator but resolves to neither a tracked file nor a tracked directory; coverage may collect no data. Use the importable dotted form or a tracked directory.`
|
|
27099
|
+
);
|
|
27100
|
+
}
|
|
27101
|
+
function patternOperand(argv) {
|
|
27102
|
+
const executable = grepExecutableIndex(argv);
|
|
27103
|
+
if (executable === null) {
|
|
27104
|
+
return null;
|
|
27105
|
+
}
|
|
27106
|
+
for (let index = executable + 1; index < argv.length; index += 1) {
|
|
27107
|
+
const word = argv[index];
|
|
27108
|
+
if (word === void 0 || word.startsWith("-")) {
|
|
27109
|
+
continue;
|
|
27110
|
+
}
|
|
27111
|
+
return word;
|
|
27112
|
+
}
|
|
27113
|
+
return null;
|
|
27114
|
+
}
|
|
27115
|
+
function isCheckableLiteral(argv, pattern) {
|
|
27116
|
+
if (isPlaceholder(pattern)) {
|
|
27117
|
+
return false;
|
|
27118
|
+
}
|
|
27119
|
+
if (argv.includes(FIXED_STRING_FLAG)) {
|
|
27120
|
+
return true;
|
|
27121
|
+
}
|
|
27122
|
+
return ![...pattern].some((character) => REGEX_METACHARACTERS.has(character));
|
|
27123
|
+
}
|
|
27124
|
+
function normalizeWhitespace(value) {
|
|
27125
|
+
return value.split(/\s+/).filter((word) => word !== "").join(" ");
|
|
27126
|
+
}
|
|
27127
|
+
function planQuotesLiteral(text, literal2, excludeSpan) {
|
|
27128
|
+
const remainder = text.split(excludeSpan).join(" ");
|
|
27129
|
+
const needle = normalizeWhitespace(literal2);
|
|
27130
|
+
if (needle === "") {
|
|
27131
|
+
return false;
|
|
27132
|
+
}
|
|
27133
|
+
return normalizeWhitespace(remainder).includes(needle);
|
|
27134
|
+
}
|
|
27135
|
+
function windowJoin(lines, size = WINDOW_SIZE) {
|
|
27136
|
+
const dense = lines.filter((line) => line.trim() !== "").map((line) => normalizeWhitespace(line));
|
|
27137
|
+
const windows = [];
|
|
27138
|
+
for (let index = 0; index < dense.length; index += 1) {
|
|
27139
|
+
windows.push(dense.slice(index, index + size).join(" "));
|
|
27140
|
+
}
|
|
27141
|
+
return windows;
|
|
27142
|
+
}
|
|
27143
|
+
function hasCrossLinePresence(context, literal2) {
|
|
27144
|
+
const words2 = literal2.split(/\s+/).filter((word) => word !== "");
|
|
27145
|
+
if (words2.length < 2) {
|
|
27146
|
+
return false;
|
|
27147
|
+
}
|
|
27148
|
+
const needle = words2.join(" ");
|
|
27149
|
+
const firstWord = words2[0] ?? "";
|
|
27150
|
+
for (const path11 of context.git.filesContaining(firstWord)) {
|
|
27151
|
+
const lines = context.git.readTrackedText(path11).split(/\r\n|\n|\r/);
|
|
27152
|
+
if (lines.some((line) => normalizeWhitespace(line).includes(needle))) {
|
|
27153
|
+
continue;
|
|
27154
|
+
}
|
|
27155
|
+
if (windowJoin(lines).some((window2) => window2.includes(needle))) {
|
|
27156
|
+
return true;
|
|
27157
|
+
}
|
|
27158
|
+
}
|
|
27159
|
+
return false;
|
|
27160
|
+
}
|
|
27161
|
+
|
|
27162
|
+
// ../../extensions/drm-copilot/src/lib/validate/plan-gate-discrimination.ts
|
|
27163
|
+
var G5_SEVERITY = "warning";
|
|
27164
|
+
var CommandRunnerPlanGateRepository = class {
|
|
27165
|
+
constructor(workspaceRoot, runner) {
|
|
27166
|
+
this.workspaceRoot = workspaceRoot;
|
|
27167
|
+
this.runner = runner;
|
|
27168
|
+
}
|
|
27169
|
+
workspaceRoot;
|
|
27170
|
+
runner;
|
|
27171
|
+
/** Run one `git` invocation and return its exit code and trimmed stdout. */
|
|
27172
|
+
run(arguments_) {
|
|
27173
|
+
const result = this.runner.run(["git", ...arguments_], {
|
|
27174
|
+
cwd: this.workspaceRoot,
|
|
27175
|
+
allowError: true
|
|
27176
|
+
});
|
|
27177
|
+
return { code: result.code, stdout: result.stdout.trim() };
|
|
27178
|
+
}
|
|
27179
|
+
/** Return tracked paths carrying the literal on a single line. */
|
|
27180
|
+
filesContaining(literal2) {
|
|
27181
|
+
const result = this.run(["grep", "-F", "-l", "--", literal2]);
|
|
27182
|
+
if (result.code !== 0 || result.stdout === "") {
|
|
27183
|
+
return [];
|
|
27184
|
+
}
|
|
27185
|
+
return result.stdout.split(/\r\n|\n|\r/).map((line) => line.trim()).filter((line) => line !== "");
|
|
27186
|
+
}
|
|
27187
|
+
/** Return whether `git ls-files` lists the path itself. */
|
|
27188
|
+
isTrackedFile(path11) {
|
|
27189
|
+
const normalized = path11.split("\\").join("/");
|
|
27190
|
+
const result = this.run(["ls-files", "--", normalized]);
|
|
27191
|
+
if (result.code !== 0 || result.stdout === "") {
|
|
27192
|
+
return false;
|
|
27193
|
+
}
|
|
27194
|
+
return result.stdout.split(/\r\n|\n|\r/).some((line) => line.trim() === normalized);
|
|
27195
|
+
}
|
|
27196
|
+
/** Return whether entries exist beneath the path but none equals it. */
|
|
27197
|
+
isTrackedDirectory(path11) {
|
|
27198
|
+
const normalized = path11.split("\\").join("/").replace(/\/+$/, "");
|
|
27199
|
+
const result = this.run(["ls-files", "--", normalized]);
|
|
27200
|
+
if (result.code !== 0 || result.stdout === "") {
|
|
27201
|
+
return false;
|
|
27202
|
+
}
|
|
27203
|
+
const listed = result.stdout.split(/\r\n|\n|\r/).map((line) => line.trim()).filter((line) => line !== "");
|
|
27204
|
+
return listed.length > 0 && listed.every((entry) => entry !== normalized);
|
|
27205
|
+
}
|
|
27206
|
+
/** Return the committed text of the path at `HEAD`, or an empty string. */
|
|
27207
|
+
readTrackedText(path11) {
|
|
27208
|
+
const normalized = path11.split("\\").join("/");
|
|
27209
|
+
const result = this.run(["show", `HEAD:${normalized}`]);
|
|
27210
|
+
return result.code === 0 ? result.stdout : "";
|
|
27211
|
+
}
|
|
27212
|
+
};
|
|
27213
|
+
function evaluateLiteral(report, text, command, context) {
|
|
27214
|
+
const pattern = patternOperand(command.argv);
|
|
27215
|
+
if (pattern === null || !isCheckableLiteral(command.argv, pattern)) {
|
|
27216
|
+
return;
|
|
27217
|
+
}
|
|
27218
|
+
if (context.git.filesContaining(pattern).length > 0) {
|
|
27219
|
+
return;
|
|
27220
|
+
}
|
|
27221
|
+
if (planQuotesLiteral(text, pattern, command.rawSpan)) {
|
|
27222
|
+
return;
|
|
27223
|
+
}
|
|
27224
|
+
if (hasCrossLinePresence(context, pattern)) {
|
|
27225
|
+
report.warnings.push(
|
|
27226
|
+
`[${command.taskId}] search literal \`${pattern}\` is present only across adjacent lines of a tracked file and matches no single line; a line-oriented search returns zero matches. Search a shorter single-line token.`
|
|
27227
|
+
);
|
|
27228
|
+
return;
|
|
27229
|
+
}
|
|
27230
|
+
const finding = `[${command.taskId}] search literal \`${pattern}\` is absent from the tracked tree and is not quoted in the plan; the search returns zero matches whatever the executor does. Quote the exact literal the task will create, or assert a literal that exists.`;
|
|
27231
|
+
const channel = G5_SEVERITY === BLOCKING_CHANNEL ? report.blocking : report.warnings;
|
|
27232
|
+
channel.push(finding);
|
|
27233
|
+
}
|
|
27234
|
+
function evaluateLiteralRules(report, text, commands, context) {
|
|
27235
|
+
const literalFindings = emptyPlanGateReport();
|
|
27236
|
+
try {
|
|
27237
|
+
for (const command of commands) {
|
|
27238
|
+
if (command.kind !== "grep") {
|
|
27239
|
+
continue;
|
|
27240
|
+
}
|
|
27241
|
+
evaluateLiteral(literalFindings, text, command, context);
|
|
27242
|
+
}
|
|
27243
|
+
} catch {
|
|
27244
|
+
return;
|
|
27245
|
+
}
|
|
27246
|
+
report.blocking.push(...literalFindings.blocking);
|
|
27247
|
+
report.warnings.push(...literalFindings.warnings);
|
|
27248
|
+
}
|
|
27249
|
+
function evaluatePlanGates(text, context) {
|
|
27250
|
+
const report = emptyPlanGateReport();
|
|
27251
|
+
const commands = extractPlanCommands(text);
|
|
27252
|
+
for (const command of commands) {
|
|
27253
|
+
for (const cov of covValues(command)) {
|
|
27254
|
+
evaluateCovValue(report, command, cov, context);
|
|
27255
|
+
}
|
|
27256
|
+
}
|
|
27257
|
+
if (context !== void 0) {
|
|
27258
|
+
evaluateLiteralRules(report, text, commands, context);
|
|
27259
|
+
}
|
|
27260
|
+
return report;
|
|
27261
|
+
}
|
|
27262
|
+
|
|
26849
27263
|
// ../../extensions/drm-copilot/src/lib/validate/parallel-state-shared.ts
|
|
26850
27264
|
function words(text) {
|
|
26851
27265
|
return text.split(" ");
|
|
@@ -28020,7 +28434,7 @@ var POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = [
|
|
|
28020
28434
|
"Per-language comparison summary:"
|
|
28021
28435
|
];
|
|
28022
28436
|
var POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison";
|
|
28023
|
-
var
|
|
28437
|
+
var PLACEHOLDER_MARKERS2 = [
|
|
28024
28438
|
"[n]",
|
|
28025
28439
|
"[path",
|
|
28026
28440
|
"[artifact",
|
|
@@ -28046,7 +28460,7 @@ function isNaValue(value) {
|
|
|
28046
28460
|
}
|
|
28047
28461
|
function hasPlaceholderMarker(value) {
|
|
28048
28462
|
const lowered = value.toLowerCase();
|
|
28049
|
-
return
|
|
28463
|
+
return PLACEHOLDER_MARKERS2.some((marker) => lowered.includes(marker));
|
|
28050
28464
|
}
|
|
28051
28465
|
function reportsMissingTemplateResolverSuccess(text) {
|
|
28052
28466
|
const lowered = text.toLowerCase();
|
|
@@ -28353,10 +28767,28 @@ function validatePlanText(text) {
|
|
|
28353
28767
|
}
|
|
28354
28768
|
return errors;
|
|
28355
28769
|
}
|
|
28356
|
-
function
|
|
28770
|
+
function buildPlanGateContext(input) {
|
|
28771
|
+
if (input.fs === void 0 || input.root === void 0 || input.artifactPath === void 0 || input.runner === void 0) {
|
|
28772
|
+
return void 0;
|
|
28773
|
+
}
|
|
28774
|
+
return {
|
|
28775
|
+
workspaceRoot: input.root,
|
|
28776
|
+
fileSystem: input.fs,
|
|
28777
|
+
git: new CommandRunnerPlanGateRepository(input.root, input.runner)
|
|
28778
|
+
};
|
|
28779
|
+
}
|
|
28780
|
+
function validateArtifactWithWarnings(input) {
|
|
28781
|
+
if (input.artifactType === "plan") {
|
|
28782
|
+
const report = evaluatePlanGates(input.text, buildPlanGateContext(input));
|
|
28783
|
+
return {
|
|
28784
|
+
errors: [...validatePlanText(input.text), ...report.blocking],
|
|
28785
|
+
warnings: report.warnings
|
|
28786
|
+
};
|
|
28787
|
+
}
|
|
28788
|
+
return { errors: dispatchValidatorErrors(input), warnings: [] };
|
|
28789
|
+
}
|
|
28790
|
+
function dispatchValidatorErrors(input) {
|
|
28357
28791
|
switch (input.artifactType) {
|
|
28358
|
-
case "plan":
|
|
28359
|
-
return validatePlanText(input.text);
|
|
28360
28792
|
case "policy-audit":
|
|
28361
28793
|
return validatePolicyAuditText(input.text);
|
|
28362
28794
|
case "code-review":
|
|
@@ -28419,12 +28851,13 @@ function validateArtifact(input) {
|
|
|
28419
28851
|
}
|
|
28420
28852
|
|
|
28421
28853
|
// ../../extensions/drm-copilot/src/lib/validate/validate-orchestration-service-call.ts
|
|
28854
|
+
var PLAN_GATE_WARNING_PREFIX = "PLAN GATE WARNING: ";
|
|
28422
28855
|
function validateOrchestrationServiceCall(input) {
|
|
28423
28856
|
const artifactFullPath = toPosixPath2(
|
|
28424
28857
|
path9.join(input.workspaceRoot, input.artifactPath)
|
|
28425
28858
|
);
|
|
28426
28859
|
const text = input.fileSystem.readTextFile(artifactFullPath);
|
|
28427
|
-
const errors =
|
|
28860
|
+
const { errors, warnings } = validateArtifactWithWarnings({
|
|
28428
28861
|
artifactType: input.artifactType,
|
|
28429
28862
|
text,
|
|
28430
28863
|
...input.requireComplete === void 0 ? {} : { requireComplete: input.requireComplete },
|
|
@@ -28438,15 +28871,17 @@ function validateOrchestrationServiceCall(input) {
|
|
|
28438
28871
|
root: input.workspaceRoot
|
|
28439
28872
|
});
|
|
28440
28873
|
if (errors.length > 0) {
|
|
28874
|
+
const warningBlock = warnings.length === 0 ? "" : "\n" + warnings.map((warning) => `${PLAN_GATE_WARNING_PREFIX}${warning}`).join("\n");
|
|
28441
28875
|
throw new Error(
|
|
28442
28876
|
`Validation failed for ${input.artifactType} artifact at '${input.artifactPath}':
|
|
28443
|
-
${errors.join("\n")}`
|
|
28877
|
+
${errors.join("\n")}${warningBlock}`
|
|
28444
28878
|
);
|
|
28445
28879
|
}
|
|
28446
28880
|
return {
|
|
28447
28881
|
tool: "validate_orchestration_artifacts",
|
|
28448
28882
|
workspaceRoot: input.workspaceRoot,
|
|
28449
|
-
summary: `Validated ${input.artifactType} artifact at '${input.artifactPath}'
|
|
28883
|
+
summary: `Validated ${input.artifactType} artifact at '${input.artifactPath}'.`,
|
|
28884
|
+
...warnings.length === 0 ? {} : { warnings }
|
|
28450
28885
|
};
|
|
28451
28886
|
}
|
|
28452
28887
|
|
|
@@ -28669,7 +29104,7 @@ function truncate(text, limit = 800) {
|
|
|
28669
29104
|
}
|
|
28670
29105
|
return rstrip3(text.slice(0, limit - 3)) + "...";
|
|
28671
29106
|
}
|
|
28672
|
-
function
|
|
29107
|
+
function splitLines3(value) {
|
|
28673
29108
|
if (value === "") {
|
|
28674
29109
|
return [];
|
|
28675
29110
|
}
|
|
@@ -28680,7 +29115,7 @@ function splitLines2(value) {
|
|
|
28680
29115
|
return lines;
|
|
28681
29116
|
}
|
|
28682
29117
|
function truncateLines(text, limit) {
|
|
28683
|
-
const lines =
|
|
29118
|
+
const lines = splitLines3(text);
|
|
28684
29119
|
if (lines.length <= limit) {
|
|
28685
29120
|
return text;
|
|
28686
29121
|
}
|
|
@@ -29444,7 +29879,7 @@ function convertNumstat(numstatText) {
|
|
|
29444
29879
|
let adds = 0;
|
|
29445
29880
|
let dels = 0;
|
|
29446
29881
|
const files = [];
|
|
29447
|
-
for (const rawLine of
|
|
29882
|
+
for (const rawLine of splitLines4(numstatText)) {
|
|
29448
29883
|
if (!rawLine.trim()) {
|
|
29449
29884
|
continue;
|
|
29450
29885
|
}
|
|
@@ -29507,7 +29942,7 @@ function summarizeConventionalCommits(subjects) {
|
|
|
29507
29942
|
}
|
|
29508
29943
|
counts.set("other", 0);
|
|
29509
29944
|
const typePattern = /^(feat|fix|refactor|perf|docs|test|chore|build|ci|style)(\(|!|:)/u;
|
|
29510
|
-
for (const rawLine of
|
|
29945
|
+
for (const rawLine of splitLines4(subjects)) {
|
|
29511
29946
|
const line = rawLine.trim();
|
|
29512
29947
|
if (!line) {
|
|
29513
29948
|
continue;
|
|
@@ -29562,7 +29997,7 @@ function buildIssuesToAutocloseSection(params) {
|
|
|
29562
29997
|
function extractChangedPaths(contextText) {
|
|
29563
29998
|
const paths = [];
|
|
29564
29999
|
let capture = false;
|
|
29565
|
-
for (const line of
|
|
30000
|
+
for (const line of splitLines4(contextText)) {
|
|
29566
30001
|
if (line.startsWith("===== Changed files")) {
|
|
29567
30002
|
capture = true;
|
|
29568
30003
|
continue;
|
|
@@ -29608,7 +30043,7 @@ function compareCodePoint2(left, right) {
|
|
|
29608
30043
|
}
|
|
29609
30044
|
return 0;
|
|
29610
30045
|
}
|
|
29611
|
-
function
|
|
30046
|
+
function splitLines4(value) {
|
|
29612
30047
|
if (value === "") {
|
|
29613
30048
|
return [];
|
|
29614
30049
|
}
|
|
@@ -29678,7 +30113,7 @@ function buildPrContext(options) {
|
|
|
29678
30113
|
const subjects = git.log("--pretty=%s", revRange);
|
|
29679
30114
|
const authors = git.log("--format=%an <%ae>", revRange);
|
|
29680
30115
|
const authorsList = sortedSet2(
|
|
29681
|
-
|
|
30116
|
+
splitLines5(authors).map((line) => line.trim()).filter((line) => line)
|
|
29682
30117
|
);
|
|
29683
30118
|
const nameStatus = git.diffRange(["--name-status", mergeBase, headSha]);
|
|
29684
30119
|
const numstat = git.diffRange(["--numstat", mergeBase, headSha]);
|
|
@@ -29686,7 +30121,7 @@ function buildPrContext(options) {
|
|
|
29686
30121
|
const stat = git.diffRange(["--stat", mergeBase, headSha]);
|
|
29687
30122
|
const [additions, deletions, files] = convertNumstat(numstat);
|
|
29688
30123
|
const extSummary = extensionSummary(files);
|
|
29689
|
-
const mergePrs = extractMergePrNumbers(
|
|
30124
|
+
const mergePrs = extractMergePrNumbers(splitLines5(oneline));
|
|
29690
30125
|
const issueCandidates = extractIssueReferences(
|
|
29691
30126
|
oneline + "\n" + subjects
|
|
29692
30127
|
).filter((ref) => !mergePrs.includes(ref));
|
|
@@ -29845,7 +30280,7 @@ function compareCodePoint3(left, right) {
|
|
|
29845
30280
|
}
|
|
29846
30281
|
return 0;
|
|
29847
30282
|
}
|
|
29848
|
-
function
|
|
30283
|
+
function splitLines5(value) {
|
|
29849
30284
|
if (value === "") {
|
|
29850
30285
|
return [];
|
|
29851
30286
|
}
|
|
@@ -29871,7 +30306,7 @@ function parseSection2(markdown, heading) {
|
|
|
29871
30306
|
}
|
|
29872
30307
|
function completedPlanTasks2(markdown, limit = 10) {
|
|
29873
30308
|
const tasks = [];
|
|
29874
|
-
for (const line of
|
|
30309
|
+
for (const line of splitLines3(markdown)) {
|
|
29875
30310
|
if (/\[x\]/iu.test(line)) {
|
|
29876
30311
|
const cleaned = line.replace(/^[-*]\s*\[[xX]\]\s*/u, "").trim();
|
|
29877
30312
|
tasks.push(cleaned);
|
|
@@ -29950,7 +30385,7 @@ function parsePrimaryIssueFromMetadata(params) {
|
|
|
29950
30385
|
params.storyText,
|
|
29951
30386
|
params.issueText
|
|
29952
30387
|
]) {
|
|
29953
|
-
for (const line of
|
|
30388
|
+
for (const line of splitLines3(sourceText)) {
|
|
29954
30389
|
const match = pattern.exec(line);
|
|
29955
30390
|
if (match) {
|
|
29956
30391
|
return match[1];
|
|
@@ -30009,11 +30444,15 @@ function escapeRegExp4(value) {
|
|
|
30009
30444
|
|
|
30010
30445
|
// ../../extensions/drm-copilot/src/lib/pr-context/verification-evidence.ts
|
|
30011
30446
|
var REQUIRED_FIELDS = ["Timestamp", "Command", "EXIT_CODE"];
|
|
30447
|
+
var EXPECTED_EXIT_CODE_FIELD = "ExpectedExitCode";
|
|
30012
30448
|
var CANONICAL_GLOBS = [
|
|
30013
30449
|
"evidence/qa-gates/**/*.md",
|
|
30014
30450
|
"evidence/regression-testing/**/*.md",
|
|
30015
30451
|
"evidence/other/**/*.md"
|
|
30016
30452
|
];
|
|
30453
|
+
function normalizeResult(exitCode, expectedExitCode) {
|
|
30454
|
+
return exitCode === expectedExitCode ? "pass" : "fail";
|
|
30455
|
+
}
|
|
30017
30456
|
function discoverCanonicalEvidenceFiles(fs10, root, feature) {
|
|
30018
30457
|
const normalizedRoot = toPosixPath2(root).replace(/\/+$/u, "");
|
|
30019
30458
|
const featureRoot = `${normalizedRoot}/docs/features/active/${feature}`;
|
|
@@ -30033,7 +30472,7 @@ function discoverCanonicalEvidenceFiles(fs10, root, feature) {
|
|
|
30033
30472
|
function parseVerificationEvidenceMarkdown(params) {
|
|
30034
30473
|
const { feature, sourceFile, markdown } = params;
|
|
30035
30474
|
const parsed = /* @__PURE__ */ new Map();
|
|
30036
|
-
for (const rawLine of
|
|
30475
|
+
for (const rawLine of splitLines6(markdown)) {
|
|
30037
30476
|
const colonIndex = rawLine.indexOf(":");
|
|
30038
30477
|
if (colonIndex === -1) {
|
|
30039
30478
|
continue;
|
|
@@ -30043,10 +30482,14 @@ function parseVerificationEvidenceMarkdown(params) {
|
|
|
30043
30482
|
if (REQUIRED_FIELDS.includes(key) && !parsed.has(key)) {
|
|
30044
30483
|
parsed.set(key, value);
|
|
30045
30484
|
}
|
|
30485
|
+
if (key === EXPECTED_EXIT_CODE_FIELD && !parsed.has(key)) {
|
|
30486
|
+
parsed.set(key, value);
|
|
30487
|
+
}
|
|
30046
30488
|
}
|
|
30047
30489
|
const timestamp = parsed.get("Timestamp") ?? null;
|
|
30048
30490
|
const command = parsed.get("Command") ?? null;
|
|
30049
30491
|
const exitCodeRaw = parsed.get("EXIT_CODE");
|
|
30492
|
+
const expectedExitCodeRaw = parsed.get(EXPECTED_EXIT_CODE_FIELD);
|
|
30050
30493
|
if (!timestamp || !command || exitCodeRaw === void 0) {
|
|
30051
30494
|
return {
|
|
30052
30495
|
feature,
|
|
@@ -30054,7 +30497,8 @@ function parseVerificationEvidenceMarkdown(params) {
|
|
|
30054
30497
|
timestamp,
|
|
30055
30498
|
command,
|
|
30056
30499
|
exitCode: null,
|
|
30057
|
-
normalizedResult: "unparseable"
|
|
30500
|
+
normalizedResult: "unparseable",
|
|
30501
|
+
expectedExitCode: 0
|
|
30058
30502
|
};
|
|
30059
30503
|
}
|
|
30060
30504
|
const exitCode = parseIntegerStrict(exitCodeRaw);
|
|
@@ -30065,17 +30509,34 @@ function parseVerificationEvidenceMarkdown(params) {
|
|
|
30065
30509
|
timestamp,
|
|
30066
30510
|
command,
|
|
30067
30511
|
exitCode: null,
|
|
30068
|
-
normalizedResult: "unparseable"
|
|
30512
|
+
normalizedResult: "unparseable",
|
|
30513
|
+
expectedExitCode: 0
|
|
30069
30514
|
};
|
|
30070
30515
|
}
|
|
30071
|
-
const
|
|
30516
|
+
const expectedExitCode = expectedExitCodeRaw === void 0 ? 0 : parseIntegerStrict(expectedExitCodeRaw);
|
|
30517
|
+
if (expectedExitCode === null) {
|
|
30518
|
+
return {
|
|
30519
|
+
feature,
|
|
30520
|
+
sourceFile,
|
|
30521
|
+
timestamp,
|
|
30522
|
+
command,
|
|
30523
|
+
exitCode: null,
|
|
30524
|
+
normalizedResult: "unparseable",
|
|
30525
|
+
expectedExitCode: 0
|
|
30526
|
+
};
|
|
30527
|
+
}
|
|
30528
|
+
const normalizedResult = normalizeResult(
|
|
30529
|
+
exitCode,
|
|
30530
|
+
expectedExitCode
|
|
30531
|
+
);
|
|
30072
30532
|
return {
|
|
30073
30533
|
feature,
|
|
30074
30534
|
sourceFile,
|
|
30075
30535
|
timestamp,
|
|
30076
30536
|
command,
|
|
30077
30537
|
exitCode,
|
|
30078
|
-
normalizedResult
|
|
30538
|
+
normalizedResult,
|
|
30539
|
+
expectedExitCode
|
|
30079
30540
|
};
|
|
30080
30541
|
}
|
|
30081
30542
|
function parseVerificationEvidenceFile(params) {
|
|
@@ -30111,7 +30572,7 @@ function compareCodePoint5(left, right) {
|
|
|
30111
30572
|
}
|
|
30112
30573
|
return 0;
|
|
30113
30574
|
}
|
|
30114
|
-
function
|
|
30575
|
+
function splitLines6(value) {
|
|
30115
30576
|
if (value === "") {
|
|
30116
30577
|
return [];
|
|
30117
30578
|
}
|
|
@@ -30333,7 +30794,7 @@ function extractDigestBullets(body, headings, limit) {
|
|
|
30333
30794
|
if (!sectionText) {
|
|
30334
30795
|
continue;
|
|
30335
30796
|
}
|
|
30336
|
-
for (const line of
|
|
30797
|
+
for (const line of splitLines3(sectionText)) {
|
|
30337
30798
|
if (!line.trim()) {
|
|
30338
30799
|
continue;
|
|
30339
30800
|
}
|
|
@@ -30474,7 +30935,7 @@ function parseNumstatDetailed(numstatText) {
|
|
|
30474
30935
|
let addsTotal = 0;
|
|
30475
30936
|
let delsTotal = 0;
|
|
30476
30937
|
const perFile = /* @__PURE__ */ new Map();
|
|
30477
|
-
for (const rawLine of
|
|
30938
|
+
for (const rawLine of splitLines3(numstatText)) {
|
|
30478
30939
|
if (!rawLine.trim()) {
|
|
30479
30940
|
continue;
|
|
30480
30941
|
}
|
|
@@ -30493,7 +30954,7 @@ function parseNumstatDetailed(numstatText) {
|
|
|
30493
30954
|
}
|
|
30494
30955
|
function parseNameStatusMap(nameStatusText) {
|
|
30495
30956
|
const mapping = /* @__PURE__ */ new Map();
|
|
30496
|
-
for (const rawLine of
|
|
30957
|
+
for (const rawLine of splitLines3(nameStatusText)) {
|
|
30497
30958
|
if (!rawLine.trim()) {
|
|
30498
30959
|
continue;
|
|
30499
30960
|
}
|
|
@@ -30541,7 +31002,7 @@ function scopingDocChanges(options) {
|
|
|
30541
31002
|
path11
|
|
30542
31003
|
]);
|
|
30543
31004
|
let headingTouched = false;
|
|
30544
|
-
for (const line of
|
|
31005
|
+
for (const line of splitLines3(diffText)) {
|
|
30545
31006
|
if (!line.startsWith("+") || line.startsWith("+++")) {
|
|
30546
31007
|
continue;
|
|
30547
31008
|
}
|
|
@@ -30557,7 +31018,7 @@ function scopingDocChanges(options) {
|
|
|
30557
31018
|
material = true;
|
|
30558
31019
|
reasons.push("key section touched");
|
|
30559
31020
|
}
|
|
30560
|
-
const addedLines =
|
|
31021
|
+
const addedLines = splitLines3(diffText).filter((line) => line.startsWith("+") && !line.startsWith("+++")).map((line) => line.replace(/^\++/u, "").trim());
|
|
30561
31022
|
if (addedLines.length > 0 && addedLines.every(
|
|
30562
31023
|
(line) => !line || line.startsWith("[") || line.startsWith("http")
|
|
30563
31024
|
)) {
|
|
@@ -30957,12 +31418,15 @@ function renderVerificationEvidenceSection(fs10, resolvedRoot, featureDocs) {
|
|
|
30957
31418
|
(left, right) => left.sourceFile < right.sourceFile ? -1 : left.sourceFile > right.sourceFile ? 1 : 0
|
|
30958
31419
|
);
|
|
30959
31420
|
for (const record2 of sorted) {
|
|
31421
|
+
const expected = record2.expectedExitCode;
|
|
31422
|
+
const expectedRows = expected === 0 ? [] : [` - Expected EXIT_CODE: ${String(expected)}`];
|
|
30960
31423
|
lines.push(
|
|
30961
31424
|
`- Feature: ${record2.feature}`,
|
|
30962
31425
|
` - Source: ${record2.sourceFile}`,
|
|
30963
31426
|
` - Timestamp: ${record2.timestamp}`,
|
|
30964
31427
|
` - Command: ${record2.command}`,
|
|
30965
31428
|
` - EXIT_CODE: ${record2.exitCode}`,
|
|
31429
|
+
...expectedRows,
|
|
30966
31430
|
` - Normalized result: ${record2.normalizedResult}`
|
|
30967
31431
|
);
|
|
30968
31432
|
}
|
|
@@ -31795,12 +32259,13 @@ var CommandRunnerGhAdapter = class {
|
|
|
31795
32259
|
};
|
|
31796
32260
|
function potentialToIssueServiceCall(input) {
|
|
31797
32261
|
const ghClient = input.gh ?? new RealGhClient({ runner: new CommandRunnerGhAdapter(input.runner) });
|
|
32262
|
+
const fileSystem = input.fileSystem ?? new RealPotentialFileSystem();
|
|
31798
32263
|
const outcome = promotePotential({
|
|
31799
32264
|
potentialPath: input.potentialPath,
|
|
31800
32265
|
promotionType: input.promotionType,
|
|
31801
32266
|
workMode: input.workMode,
|
|
31802
32267
|
workspace: input.workspaceRoot,
|
|
31803
|
-
fs:
|
|
32268
|
+
fs: fileSystem,
|
|
31804
32269
|
gh: ghClient,
|
|
31805
32270
|
...input.log === void 0 ? {} : { emit: input.log }
|
|
31806
32271
|
});
|
|
@@ -31811,6 +32276,11 @@ ${outcome.messages.join("\n")}` : "";
|
|
|
31811
32276
|
}
|
|
31812
32277
|
const summary = `Promoted '${input.potentialPath}' as a ${input.promotionType} workflow in ${input.workMode} mode.`;
|
|
31813
32278
|
const [issueUrl] = parseIssueReference(outcome.messages);
|
|
32279
|
+
if (outcome.destination !== void 0 && !fileSystem.exists(outcome.destination)) {
|
|
32280
|
+
throw new Error(
|
|
32281
|
+
`potential_to_issue reported a path that does not exist: ${outcome.destination}`
|
|
32282
|
+
);
|
|
32283
|
+
}
|
|
31814
32284
|
return {
|
|
31815
32285
|
tool: "potential_to_issue",
|
|
31816
32286
|
workspaceRoot: input.workspaceRoot,
|
|
@@ -31997,12 +32467,12 @@ function validateFeatureName2(featureName) {
|
|
|
31997
32467
|
function escapeRegExp6(value) {
|
|
31998
32468
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31999
32469
|
}
|
|
32000
|
-
function
|
|
32470
|
+
function splitLines7(text) {
|
|
32001
32471
|
return text.split(/\r\n|\r|\n/);
|
|
32002
32472
|
}
|
|
32003
32473
|
function formatChecklist(text) {
|
|
32004
32474
|
const lines = [];
|
|
32005
|
-
for (const rawLine of
|
|
32475
|
+
for (const rawLine of splitLines7(text)) {
|
|
32006
32476
|
const trimmed = rawLine.trim();
|
|
32007
32477
|
if (!trimmed) {
|
|
32008
32478
|
continue;
|
|
@@ -32031,7 +32501,7 @@ function getSection2(content, name) {
|
|
|
32031
32501
|
function upsertWorkModeMarker(content, mode) {
|
|
32032
32502
|
const markerLine = `- Work Mode: ${mode}`;
|
|
32033
32503
|
const markerPattern = /^- Work Mode:\s*(minor-audit|full-feature|full-bug|full)\s*$/;
|
|
32034
|
-
const lines =
|
|
32504
|
+
const lines = splitLines7(content).filter((line) => !markerPattern.test(line));
|
|
32035
32505
|
for (let idx = 0; idx < lines.length; idx += 1) {
|
|
32036
32506
|
const line = lines[idx] ?? "";
|
|
32037
32507
|
if (line.replace(/^\s+/, "").startsWith("## ")) {
|
|
@@ -32723,6 +33193,7 @@ function createActiveFolder(options) {
|
|
|
32723
33193
|
filesystem
|
|
32724
33194
|
);
|
|
32725
33195
|
const potentialContent = potentialFile ? filesystem.readText(potentialFile) : "";
|
|
33196
|
+
const retainsPotentialSource = potentialFile !== null && isPromotedPotentialSource(potentialFile, workspacePath);
|
|
32726
33197
|
const selectedWorkMode = normalizeRequestedWorkMode(workMode, featureType);
|
|
32727
33198
|
const [useMinorAudit, fallbackReason] = shouldUseMinorAuditMode(
|
|
32728
33199
|
selectedWorkMode,
|
|
@@ -32810,7 +33281,11 @@ function createActiveFolder(options) {
|
|
|
32810
33281
|
if (useMinorAudit) {
|
|
32811
33282
|
if (potentialFile) {
|
|
32812
33283
|
potentialIssuePath = joinPosix13(targetDir, "issue.md");
|
|
32813
|
-
|
|
33284
|
+
if (retainsPotentialSource) {
|
|
33285
|
+
filesystem.copyFile(potentialFile, potentialIssuePath);
|
|
33286
|
+
} else {
|
|
33287
|
+
filesystem.move(potentialFile, potentialIssuePath);
|
|
33288
|
+
}
|
|
32814
33289
|
const movedContent = filesystem.readText(potentialIssuePath);
|
|
32815
33290
|
filesystem.writeText(
|
|
32816
33291
|
potentialIssuePath,
|
|
@@ -32866,17 +33341,25 @@ function createActiveFolder(options) {
|
|
|
32866
33341
|
if (potentialFile) {
|
|
32867
33342
|
if (useMinorAudit) {
|
|
32868
33343
|
if (potentialIssuePath !== null) {
|
|
32869
|
-
emit(
|
|
33344
|
+
emit(
|
|
33345
|
+
retainsPotentialSource ? `Copied potential file to ${potentialIssuePath}` : `Moved potential file to ${potentialIssuePath}`
|
|
33346
|
+
);
|
|
32870
33347
|
}
|
|
32871
33348
|
} else {
|
|
32872
33349
|
potentialIssuePath = joinPosix13(targetDir, "issue.md");
|
|
32873
|
-
|
|
33350
|
+
if (retainsPotentialSource) {
|
|
33351
|
+
filesystem.copyFile(potentialFile, potentialIssuePath);
|
|
33352
|
+
} else {
|
|
33353
|
+
filesystem.move(potentialFile, potentialIssuePath);
|
|
33354
|
+
}
|
|
32874
33355
|
const movedContent = filesystem.readText(potentialIssuePath);
|
|
32875
33356
|
filesystem.writeText(
|
|
32876
33357
|
potentialIssuePath,
|
|
32877
33358
|
upsertWorkModeMarker(movedContent, selectedWorkMode)
|
|
32878
33359
|
);
|
|
32879
|
-
emit(
|
|
33360
|
+
emit(
|
|
33361
|
+
retainsPotentialSource ? `Copied potential file to ${potentialIssuePath}` : `Moved potential file to ${potentialIssuePath}`
|
|
33362
|
+
);
|
|
32880
33363
|
}
|
|
32881
33364
|
}
|
|
32882
33365
|
if (potentialFile) {
|
|
@@ -32915,6 +33398,12 @@ function isRelativeTo(child, root) {
|
|
|
32915
33398
|
const normalizedRoot = toPosixPath2(root);
|
|
32916
33399
|
return normalizedChild === normalizedRoot || normalizedChild.startsWith(`${normalizedRoot}/`);
|
|
32917
33400
|
}
|
|
33401
|
+
function isPromotedPotentialSource(potentialPath, workspacePath) {
|
|
33402
|
+
return isRelativeTo(
|
|
33403
|
+
potentialPath,
|
|
33404
|
+
joinPosix13(workspacePath, "docs/features/potential/promoted")
|
|
33405
|
+
);
|
|
33406
|
+
}
|
|
32918
33407
|
function posixBaseName(path11) {
|
|
32919
33408
|
const normalized = toPosixPath2(path11).replace(/\/+$/, "");
|
|
32920
33409
|
const slash = normalized.lastIndexOf("/");
|
|
@@ -32927,7 +33416,15 @@ function posixStem2(path11) {
|
|
|
32927
33416
|
}
|
|
32928
33417
|
|
|
32929
33418
|
// ../../extensions/drm-copilot/src/lib/new-active-feature-folder/new-active-feature-folder-service-call.ts
|
|
33419
|
+
function requireReportedPathExists(fileSystem, path11) {
|
|
33420
|
+
if (!fileSystem.exists(path11)) {
|
|
33421
|
+
throw new Error(
|
|
33422
|
+
`new_active_feature_folder reported a path that does not exist: ${path11}`
|
|
33423
|
+
);
|
|
33424
|
+
}
|
|
33425
|
+
}
|
|
32930
33426
|
function newActiveFeatureFolderServiceCall(input) {
|
|
33427
|
+
const fileSystem = input.fileSystem ?? new RealFolderFileSystem();
|
|
32931
33428
|
const result = createActiveFolder({
|
|
32932
33429
|
featureName: input.featureName,
|
|
32933
33430
|
featureType: input.type,
|
|
@@ -32935,13 +33432,17 @@ function newActiveFeatureFolderServiceCall(input) {
|
|
|
32935
33432
|
workMode: input.workMode,
|
|
32936
33433
|
workspace: input.workspaceRoot,
|
|
32937
33434
|
templateRoot: input.templateRoot,
|
|
32938
|
-
fs:
|
|
33435
|
+
fs: fileSystem,
|
|
32939
33436
|
// Route the guarded gh issue fetch through the injected F1 runner.
|
|
32940
33437
|
issueFetcher: (issueNumber) => defaultIssueFetcher(issueNumber, input.runner),
|
|
32941
33438
|
// No-op launcher: the MCP/non-interactive path must never open an editor.
|
|
32942
33439
|
codeLauncher: () => false,
|
|
32943
33440
|
...input.log === void 0 ? {} : { emit: input.log }
|
|
32944
33441
|
});
|
|
33442
|
+
requireReportedPathExists(fileSystem, result.target);
|
|
33443
|
+
if (result.potentialIssuePath !== null) {
|
|
33444
|
+
requireReportedPathExists(fileSystem, result.potentialIssuePath);
|
|
33445
|
+
}
|
|
32945
33446
|
return {
|
|
32946
33447
|
tool: "new_active_feature_folder",
|
|
32947
33448
|
workspaceRoot: input.workspaceRoot,
|