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