@danmoisan/drm-copilot-mcp 1.0.21 → 1.0.23
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 +1730 -139
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/MEMORY.md +5 -1
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_commit_push_memory_before_pr.md +48 -2
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_no_sendmessage_tool.md +35 -0
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_worktree_isolation_branches_from_main.md +45 -0
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +257 -0
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +183 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +23 -11
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +259 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +499 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate-helpers.ps1 +302 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +359 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +244 -0
- package/resources/claude-customizations/.claude/lib/bash/compute-cohorts.sh +143 -0
- package/resources/claude-customizations/.claude/lib/bash/compute-concurrency-batches.sh +122 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +330 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-common.sh +238 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-items-validate.sh +244 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-manifest-validate.sh +187 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-yaml-emit.sh +340 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-yaml-scan.sh +335 -0
- package/resources/claude-customizations/.claude/lib/bash/validate-parallel-manifest.sh +134 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +379 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +491 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +490 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusGlob.psm1 +429 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +366 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +184 -0
- package/resources/claude-customizations/.claude/rules/shell.md +7 -2
- package/resources/claude-customizations/.claude/settings.json +28 -0
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +152 -0
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +93 -0
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +971 -0
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +461 -0
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +176 -0
- package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +56 -0
- package/resources/claude-customizations/config/blast-radius.json +16 -0
- package/resources/claude-customizations/config/orchestration-routing.json +355 -0
- package/resources/claude-customizations/pack-manifests/core.json +32 -1
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/config/orchestration-routing.json +22 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +29 -0
package/out/mcp-server.js
CHANGED
|
@@ -1796,13 +1796,13 @@ var require_code2 = __commonJS({
|
|
|
1796
1796
|
const valid = gen.name("valid");
|
|
1797
1797
|
if (it.allErrors) {
|
|
1798
1798
|
const validArr = gen.let("valid", true);
|
|
1799
|
-
|
|
1799
|
+
validateItems2(() => gen.assign(validArr, false));
|
|
1800
1800
|
return validArr;
|
|
1801
1801
|
}
|
|
1802
1802
|
gen.var(valid, true);
|
|
1803
|
-
|
|
1803
|
+
validateItems2(() => gen.break());
|
|
1804
1804
|
return valid;
|
|
1805
|
-
function
|
|
1805
|
+
function validateItems2(notValid) {
|
|
1806
1806
|
const len = gen.const("len", (0, codegen_1._)`${data}.length`);
|
|
1807
1807
|
gen.forRange("i", 0, len, (i) => {
|
|
1808
1808
|
cxt.subschema({
|
|
@@ -5246,10 +5246,10 @@ var require_additionalItems = __commonJS({
|
|
|
5246
5246
|
cxt.pass((0, codegen_1._)`${len} <= ${items.length}`);
|
|
5247
5247
|
} else if (typeof schema == "object" && !(0, util_1.alwaysValidSchema)(it, schema)) {
|
|
5248
5248
|
const valid = gen.var("valid", (0, codegen_1._)`${len} <= ${items.length}`);
|
|
5249
|
-
gen.if((0, codegen_1.not)(valid), () =>
|
|
5249
|
+
gen.if((0, codegen_1.not)(valid), () => validateItems2(valid));
|
|
5250
5250
|
cxt.ok(valid);
|
|
5251
5251
|
}
|
|
5252
|
-
function
|
|
5252
|
+
function validateItems2(valid) {
|
|
5253
5253
|
gen.forRange("i", items.length, len, (i) => {
|
|
5254
5254
|
cxt.subschema({ keyword, dataProp: i, dataPropType: util_1.Type.Num }, valid);
|
|
5255
5255
|
if (!it.allErrors)
|
|
@@ -5421,7 +5421,7 @@ var require_contains = __commonJS({
|
|
|
5421
5421
|
it.items = true;
|
|
5422
5422
|
const valid = gen.name("valid");
|
|
5423
5423
|
if (max === void 0 && min === 1) {
|
|
5424
|
-
|
|
5424
|
+
validateItems2(valid, () => gen.if(valid, () => gen.break()));
|
|
5425
5425
|
} else if (min === 0) {
|
|
5426
5426
|
gen.let(valid, true);
|
|
5427
5427
|
if (max !== void 0)
|
|
@@ -5434,9 +5434,9 @@ var require_contains = __commonJS({
|
|
|
5434
5434
|
function validateItemsWithCount() {
|
|
5435
5435
|
const schValid = gen.name("_valid");
|
|
5436
5436
|
const count = gen.let("count", 0);
|
|
5437
|
-
|
|
5437
|
+
validateItems2(schValid, () => gen.if(schValid, () => checkLimits(count)));
|
|
5438
5438
|
}
|
|
5439
|
-
function
|
|
5439
|
+
function validateItems2(_valid, block) {
|
|
5440
5440
|
gen.forRange("i", 0, len, (i) => {
|
|
5441
5441
|
cxt.subschema({
|
|
5442
5442
|
keyword: "contains",
|
|
@@ -8990,13 +8990,13 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
8990
8990
|
}
|
|
8991
8991
|
return propValues;
|
|
8992
8992
|
});
|
|
8993
|
-
const
|
|
8993
|
+
const isObject15 = isObject;
|
|
8994
8994
|
const catchall = def.catchall;
|
|
8995
8995
|
let value;
|
|
8996
8996
|
inst._zod.parse = (payload, ctx) => {
|
|
8997
8997
|
value ?? (value = _normalized.value);
|
|
8998
8998
|
const input = payload.value;
|
|
8999
|
-
if (!
|
|
8999
|
+
if (!isObject15(input)) {
|
|
9000
9000
|
payload.issues.push({
|
|
9001
9001
|
expected: "object",
|
|
9002
9002
|
code: "invalid_type",
|
|
@@ -9123,7 +9123,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
9123
9123
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
9124
9124
|
};
|
|
9125
9125
|
let fastpass;
|
|
9126
|
-
const
|
|
9126
|
+
const isObject15 = isObject;
|
|
9127
9127
|
const jit = !globalConfig.jitless;
|
|
9128
9128
|
const allowsEval2 = allowsEval;
|
|
9129
9129
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -9132,7 +9132,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
9132
9132
|
inst._zod.parse = (payload, ctx) => {
|
|
9133
9133
|
value ?? (value = _normalized.value);
|
|
9134
9134
|
const input = payload.value;
|
|
9135
|
-
if (!
|
|
9135
|
+
if (!isObject15(input)) {
|
|
9136
9136
|
payload.issues.push({
|
|
9137
9137
|
expected: "object",
|
|
9138
9138
|
code: "invalid_type",
|
|
@@ -15089,16 +15089,7 @@ var Server = class extends Protocol {
|
|
|
15089
15089
|
if (!methodSchema) {
|
|
15090
15090
|
throw new Error("Schema is missing a method literal");
|
|
15091
15091
|
}
|
|
15092
|
-
|
|
15093
|
-
if (isZ4Schema(methodSchema)) {
|
|
15094
|
-
const v4Schema = methodSchema;
|
|
15095
|
-
const v4Def = v4Schema._zod?.def;
|
|
15096
|
-
methodValue = v4Def?.value ?? v4Schema.value;
|
|
15097
|
-
} else {
|
|
15098
|
-
const v3Schema = methodSchema;
|
|
15099
|
-
const legacyDef = v3Schema._def;
|
|
15100
|
-
methodValue = legacyDef?.value ?? v3Schema.value;
|
|
15101
|
-
}
|
|
15092
|
+
const methodValue = getLiteralValue(methodSchema);
|
|
15102
15093
|
if (typeof methodValue !== "string") {
|
|
15103
15094
|
throw new Error("Schema method literal must be a string");
|
|
15104
15095
|
}
|
|
@@ -15407,8 +15398,17 @@ var Server = class extends Protocol {
|
|
|
15407
15398
|
var import_node_process = __toESM(require("node:process"), 1);
|
|
15408
15399
|
|
|
15409
15400
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
15401
|
+
var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
15410
15402
|
var ReadBuffer = class {
|
|
15403
|
+
constructor(options) {
|
|
15404
|
+
this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
|
|
15405
|
+
}
|
|
15411
15406
|
append(chunk) {
|
|
15407
|
+
const newSize = (this._buffer?.length ?? 0) + chunk.length;
|
|
15408
|
+
if (newSize > this._maxBufferSize) {
|
|
15409
|
+
this.clear();
|
|
15410
|
+
throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
|
|
15411
|
+
}
|
|
15412
15412
|
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
15413
15413
|
}
|
|
15414
15414
|
readMessage() {
|
|
@@ -15436,18 +15436,24 @@ function serializeMessage(message) {
|
|
|
15436
15436
|
|
|
15437
15437
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
15438
15438
|
var StdioServerTransport = class {
|
|
15439
|
-
constructor(_stdin = import_node_process.default.stdin, _stdout = import_node_process.default.stdout) {
|
|
15439
|
+
constructor(_stdin = import_node_process.default.stdin, _stdout = import_node_process.default.stdout, options) {
|
|
15440
15440
|
this._stdin = _stdin;
|
|
15441
15441
|
this._stdout = _stdout;
|
|
15442
|
-
this._readBuffer = new ReadBuffer();
|
|
15443
15442
|
this._started = false;
|
|
15444
15443
|
this._ondata = (chunk) => {
|
|
15445
|
-
|
|
15446
|
-
|
|
15444
|
+
try {
|
|
15445
|
+
this._readBuffer.append(chunk);
|
|
15446
|
+
this.processReadBuffer();
|
|
15447
|
+
} catch (error2) {
|
|
15448
|
+
this.onerror?.(error2);
|
|
15449
|
+
this.close().catch(() => {
|
|
15450
|
+
});
|
|
15451
|
+
}
|
|
15447
15452
|
};
|
|
15448
15453
|
this._onerror = (error2) => {
|
|
15449
15454
|
this.onerror?.(error2);
|
|
15450
15455
|
};
|
|
15456
|
+
this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
|
|
15451
15457
|
}
|
|
15452
15458
|
/**
|
|
15453
15459
|
* Starts listening for messages on stdin.
|
|
@@ -16262,7 +16268,10 @@ var VALID_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
|
|
|
16262
16268
|
"orchestrator-state",
|
|
16263
16269
|
"epic-orchestrator-state",
|
|
16264
16270
|
"epic-planner-state",
|
|
16265
|
-
"epic-kickoff"
|
|
16271
|
+
"epic-kickoff",
|
|
16272
|
+
"parallel-orchestrator-state",
|
|
16273
|
+
"parallel-planner-state",
|
|
16274
|
+
"parallel-kickoff"
|
|
16266
16275
|
]);
|
|
16267
16276
|
function resolveValidateOrchestrationArtifactsToolInput(rawInput, fallbackWorkspaceRoot) {
|
|
16268
16277
|
const args = asToolArgumentObject(rawInput);
|
|
@@ -17007,7 +17016,10 @@ var REPO_AUTOMATION_TOOL_DEFINITIONS = [
|
|
|
17007
17016
|
"orchestrator-state",
|
|
17008
17017
|
"epic-orchestrator-state",
|
|
17009
17018
|
"epic-planner-state",
|
|
17010
|
-
"epic-kickoff"
|
|
17019
|
+
"epic-kickoff",
|
|
17020
|
+
"parallel-orchestrator-state",
|
|
17021
|
+
"parallel-planner-state",
|
|
17022
|
+
"parallel-kickoff"
|
|
17011
17023
|
],
|
|
17012
17024
|
description: "The type of orchestration artifact to validate."
|
|
17013
17025
|
},
|
|
@@ -17017,7 +17029,7 @@ var REPO_AUTOMATION_TOOL_DEFINITIONS = [
|
|
|
17017
17029
|
},
|
|
17018
17030
|
require_complete: {
|
|
17019
17031
|
type: "boolean",
|
|
17020
|
-
description: "When true and artifact_type is 'orchestrator-state' or '
|
|
17032
|
+
description: "When true and artifact_type is 'orchestrator-state', 'epic-orchestrator-state', or 'parallel-orchestrator-state', require all phases to be complete."
|
|
17021
17033
|
},
|
|
17022
17034
|
require_model_routing: {
|
|
17023
17035
|
type: "boolean",
|
|
@@ -17033,7 +17045,7 @@ var REPO_AUTOMATION_TOOL_DEFINITIONS = [
|
|
|
17033
17045
|
},
|
|
17034
17046
|
require_ready_for_execution: {
|
|
17035
17047
|
type: "boolean",
|
|
17036
|
-
description: "When true and artifact_type is 'epic-planner-state', require every child to be prepared and preflight-cleared."
|
|
17048
|
+
description: "When true and artifact_type is 'epic-planner-state' or 'parallel-planner-state', require every child to be prepared and preflight-cleared."
|
|
17037
17049
|
}
|
|
17038
17050
|
},
|
|
17039
17051
|
required: ["workspace_root", "artifact_type", "artifact_path"],
|
|
@@ -18799,9 +18811,161 @@ var ExcludingFileSystem = class {
|
|
|
18799
18811
|
}
|
|
18800
18812
|
};
|
|
18801
18813
|
|
|
18814
|
+
// ../../extensions/drm-copilot/src/lib/push-down/claude-routing-merge.ts
|
|
18815
|
+
var ROUTES_KEY = "routes";
|
|
18816
|
+
var AUTHORITATIVE_ROUTE = "parallel";
|
|
18817
|
+
var RoutingMergeError = class extends Error {
|
|
18818
|
+
/** Destination path whose current content could not be parsed. */
|
|
18819
|
+
path;
|
|
18820
|
+
/**
|
|
18821
|
+
* @param path Destination path that failed to parse.
|
|
18822
|
+
* @param detail Parser detail appended to the message.
|
|
18823
|
+
*/
|
|
18824
|
+
constructor(path11, detail) {
|
|
18825
|
+
super(
|
|
18826
|
+
`Destination routing document is not valid JSON and was not written: ${path11} (${detail})`
|
|
18827
|
+
);
|
|
18828
|
+
this.name = "RoutingMergeError";
|
|
18829
|
+
this.path = path11;
|
|
18830
|
+
}
|
|
18831
|
+
};
|
|
18832
|
+
function normalizePosix4(value) {
|
|
18833
|
+
return value.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
18834
|
+
}
|
|
18835
|
+
function relativeToPosix4(path11, root) {
|
|
18836
|
+
const normalizedPath = normalizePosix4(path11);
|
|
18837
|
+
const normalizedRoot = normalizePosix4(root);
|
|
18838
|
+
if (normalizedPath === normalizedRoot) {
|
|
18839
|
+
return "";
|
|
18840
|
+
}
|
|
18841
|
+
const prefix = `${normalizedRoot}/`;
|
|
18842
|
+
return normalizedPath.startsWith(prefix) ? normalizedPath.slice(prefix.length) : null;
|
|
18843
|
+
}
|
|
18844
|
+
function parseRoutingObject(text, path11) {
|
|
18845
|
+
let parsed;
|
|
18846
|
+
try {
|
|
18847
|
+
parsed = JSON.parse(text);
|
|
18848
|
+
} catch (error2) {
|
|
18849
|
+
const detail = error2 instanceof Error ? error2.message : String(error2);
|
|
18850
|
+
throw new RoutingMergeError(path11, detail);
|
|
18851
|
+
}
|
|
18852
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
18853
|
+
throw new RoutingMergeError(path11, "document root is not a JSON object");
|
|
18854
|
+
}
|
|
18855
|
+
return parsed;
|
|
18856
|
+
}
|
|
18857
|
+
function asObject(value) {
|
|
18858
|
+
if (value === void 0 || value === null || typeof value !== "object") {
|
|
18859
|
+
return null;
|
|
18860
|
+
}
|
|
18861
|
+
return Array.isArray(value) ? null : value;
|
|
18862
|
+
}
|
|
18863
|
+
function mergeRoutes(destinationRoutes, sourceRoutes) {
|
|
18864
|
+
const merged = {};
|
|
18865
|
+
if (destinationRoutes !== null) {
|
|
18866
|
+
for (const [name, definition] of Object.entries(destinationRoutes)) {
|
|
18867
|
+
const sourceDefinition = sourceRoutes?.[name];
|
|
18868
|
+
merged[name] = name === AUTHORITATIVE_ROUTE && sourceDefinition !== void 0 ? sourceDefinition : definition;
|
|
18869
|
+
}
|
|
18870
|
+
}
|
|
18871
|
+
if (sourceRoutes !== null) {
|
|
18872
|
+
for (const [name, definition] of Object.entries(sourceRoutes)) {
|
|
18873
|
+
if (!(name in merged)) {
|
|
18874
|
+
merged[name] = definition;
|
|
18875
|
+
}
|
|
18876
|
+
}
|
|
18877
|
+
}
|
|
18878
|
+
return merged;
|
|
18879
|
+
}
|
|
18880
|
+
function mergeRoutingDocuments(destinationText, sourceText, path11) {
|
|
18881
|
+
const destination = parseRoutingObject(destinationText, path11);
|
|
18882
|
+
const source = parseRoutingObject(sourceText, path11);
|
|
18883
|
+
const merged = {};
|
|
18884
|
+
for (const [key, value] of Object.entries(destination)) {
|
|
18885
|
+
merged[key] = key === ROUTES_KEY ? mergeRoutes(asObject(value), asObject(source[ROUTES_KEY])) : value;
|
|
18886
|
+
}
|
|
18887
|
+
for (const [key, value] of Object.entries(source)) {
|
|
18888
|
+
if (key in merged) {
|
|
18889
|
+
continue;
|
|
18890
|
+
}
|
|
18891
|
+
merged[key] = key === ROUTES_KEY ? mergeRoutes(null, asObject(value)) : value;
|
|
18892
|
+
}
|
|
18893
|
+
return `${JSON.stringify(merged, null, 2)}
|
|
18894
|
+
`;
|
|
18895
|
+
}
|
|
18896
|
+
var RoutingMergeFileSystem = class {
|
|
18897
|
+
inner;
|
|
18898
|
+
destinationRoot;
|
|
18899
|
+
mergeRelativePath;
|
|
18900
|
+
/**
|
|
18901
|
+
* @param inner The wrapped adapter performing real I/O.
|
|
18902
|
+
* @param destinationRoot Destination workspace root (POSIX path).
|
|
18903
|
+
* @param mergeRelativePath Destination-relative path to merge.
|
|
18904
|
+
*/
|
|
18905
|
+
constructor(inner, destinationRoot, mergeRelativePath) {
|
|
18906
|
+
this.inner = inner;
|
|
18907
|
+
this.destinationRoot = normalizePosix4(destinationRoot);
|
|
18908
|
+
this.mergeRelativePath = mergeRelativePath;
|
|
18909
|
+
}
|
|
18910
|
+
/** @inheritdoc */
|
|
18911
|
+
listFiles(root) {
|
|
18912
|
+
return this.inner.listFiles(root);
|
|
18913
|
+
}
|
|
18914
|
+
/** @inheritdoc */
|
|
18915
|
+
isDir(path11) {
|
|
18916
|
+
return this.inner.isDir(path11);
|
|
18917
|
+
}
|
|
18918
|
+
/** @inheritdoc */
|
|
18919
|
+
isFile(path11) {
|
|
18920
|
+
return this.inner.isFile(path11);
|
|
18921
|
+
}
|
|
18922
|
+
/** @inheritdoc */
|
|
18923
|
+
readTextFile(path11) {
|
|
18924
|
+
return this.inner.readTextFile(path11);
|
|
18925
|
+
}
|
|
18926
|
+
/** @inheritdoc */
|
|
18927
|
+
ensureDir(path11) {
|
|
18928
|
+
this.inner.ensureDir(path11);
|
|
18929
|
+
}
|
|
18930
|
+
/**
|
|
18931
|
+
* Write a file, merging the one configured routing path when it exists.
|
|
18932
|
+
*
|
|
18933
|
+
* @param path Absolute destination POSIX path.
|
|
18934
|
+
* @param content Source content the engine wants to publish.
|
|
18935
|
+
* @throws RoutingMergeError When the destination routing document is not
|
|
18936
|
+
* parseable; the destination bytes are left untouched.
|
|
18937
|
+
*/
|
|
18938
|
+
writeTextFile(path11, content) {
|
|
18939
|
+
if (!this.isMergeTarget(path11)) {
|
|
18940
|
+
this.inner.writeTextFile(path11, content);
|
|
18941
|
+
return;
|
|
18942
|
+
}
|
|
18943
|
+
if (!this.inner.isFile(path11)) {
|
|
18944
|
+
this.inner.writeTextFile(path11, content);
|
|
18945
|
+
return;
|
|
18946
|
+
}
|
|
18947
|
+
const merged = mergeRoutingDocuments(
|
|
18948
|
+
this.inner.readTextFile(path11),
|
|
18949
|
+
content,
|
|
18950
|
+
path11
|
|
18951
|
+
);
|
|
18952
|
+
this.inner.writeTextFile(path11, merged);
|
|
18953
|
+
}
|
|
18954
|
+
/**
|
|
18955
|
+
* Return whether a destination path is the configured merge target.
|
|
18956
|
+
*
|
|
18957
|
+
* @param path Absolute destination POSIX path.
|
|
18958
|
+
* @returns True when the path resolves to the merge-target relative path.
|
|
18959
|
+
*/
|
|
18960
|
+
isMergeTarget(path11) {
|
|
18961
|
+
return relativeToPosix4(path11, this.destinationRoot) === this.mergeRelativePath;
|
|
18962
|
+
}
|
|
18963
|
+
};
|
|
18964
|
+
|
|
18802
18965
|
// ../../extensions/drm-copilot/src/lib/push-down/claude-customizations.ts
|
|
18803
18966
|
var ARTIFACT_DIRECTORY4 = "artifacts/claude-customizations";
|
|
18804
|
-
var ROOT_FOLDERS2 = [".claude"];
|
|
18967
|
+
var ROOT_FOLDERS2 = [".claude", "config"];
|
|
18968
|
+
var ROUTING_MERGE_RELATIVE_PATH = "config/orchestration-routing.json";
|
|
18805
18969
|
var EXCLUDED_RELATIVE_PATHS = [
|
|
18806
18970
|
".claude/settings.local.json"
|
|
18807
18971
|
];
|
|
@@ -18850,8 +19014,13 @@ function pushDownCustomizations4(options) {
|
|
|
18850
19014
|
effectiveBundle,
|
|
18851
19015
|
fs9
|
|
18852
19016
|
);
|
|
18853
|
-
const
|
|
19017
|
+
const mergingFs = new RoutingMergeFileSystem(
|
|
18854
19018
|
fs9,
|
|
19019
|
+
destinationRoot,
|
|
19020
|
+
ROUTING_MERGE_RELATIVE_PATH
|
|
19021
|
+
);
|
|
19022
|
+
const excludingFs = new ExcludingFileSystem(
|
|
19023
|
+
mergingFs,
|
|
18855
19024
|
repoRoot,
|
|
18856
19025
|
EXCLUDED_RELATIVE_PATHS,
|
|
18857
19026
|
{
|
|
@@ -26088,121 +26257,1529 @@ function validateOrchestratorStateText(text, options = {}) {
|
|
|
26088
26257
|
return errors;
|
|
26089
26258
|
}
|
|
26090
26259
|
|
|
26091
|
-
// ../../extensions/drm-copilot/src/lib/validate/
|
|
26092
|
-
var
|
|
26093
|
-
var
|
|
26094
|
-
|
|
26095
|
-
|
|
26096
|
-
|
|
26097
|
-
|
|
26098
|
-
|
|
26099
|
-
|
|
26100
|
-
"
|
|
26101
|
-
"
|
|
26102
|
-
"
|
|
26103
|
-
"
|
|
26104
|
-
"
|
|
26105
|
-
"
|
|
26106
|
-
"## Appendix B: Toolchain Commands Reference"
|
|
26107
|
-
];
|
|
26108
|
-
var POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = [
|
|
26109
|
-
"TypeScript baseline coverage artifact:",
|
|
26110
|
-
"TypeScript post-change coverage artifact:",
|
|
26111
|
-
"PowerShell baseline coverage artifact:",
|
|
26112
|
-
"PowerShell post-change coverage artifact:",
|
|
26113
|
-
"Per-language comparison summary:"
|
|
26114
|
-
];
|
|
26115
|
-
var POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison";
|
|
26116
|
-
var PLACEHOLDER_MARKERS = [
|
|
26117
|
-
"[n]",
|
|
26118
|
-
"[path",
|
|
26119
|
-
"[artifact",
|
|
26120
|
-
"[section reference",
|
|
26121
|
-
"[language]",
|
|
26122
|
-
"tbd",
|
|
26123
|
-
"unverified",
|
|
26124
|
-
"missing"
|
|
26125
|
-
];
|
|
26126
|
-
var TEMPLATE_RESOLVER_TOOL = "resolve_policy_audit_template_asset";
|
|
26127
|
-
var TEMPLATE_RESOLVER_MISSING_MARKERS = [
|
|
26128
|
-
"not exposed",
|
|
26129
|
-
"was not exposed",
|
|
26130
|
-
"missing resolver exposure",
|
|
26131
|
-
"fallback template",
|
|
26132
|
-
"fallback-template"
|
|
26260
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-kickoff-artifact.ts
|
|
26261
|
+
var KICKOFF_HEADING_RE2 = /^# Parallel Kickoff: (?<slug>[a-z0-9][a-z0-9-]*)$/;
|
|
26262
|
+
var PARALLEL_RUN_RE = /Run `\/parallel-run (?<slug>[a-z0-9][a-z0-9-]*)`/;
|
|
26263
|
+
var MANIFEST_RE2 = /docs\/features\/parallel\/[a-z0-9][a-z0-9-]*\/parallel\.md/;
|
|
26264
|
+
var PLAN_BRANCH_RE = /parallel\/[a-z0-9][a-z0-9-]*-plan/;
|
|
26265
|
+
var RESUME_RE2 = /(?:Every item|Each item|items)\s+resumes?\s+at atomic execution\s+from\s+(?:its|their)\s+committed plan-path\s+on\s+(?:its|their)\s+own\s+(?:pushed\s+)?feature branch/i;
|
|
26266
|
+
var INTEGRITY_COMMIT_RE2 = /^(?:-\s*)?planning_commit:\s*`?(?<commit>[0-9a-fA-F]{7,64})`?\s*$/;
|
|
26267
|
+
var LINE_SPLIT_RE = /\r\n|\r|\n/u;
|
|
26268
|
+
var ITEM_HEADERS = [
|
|
26269
|
+
"issue_num",
|
|
26270
|
+
"feature_folder",
|
|
26271
|
+
"cohort",
|
|
26272
|
+
"complexity",
|
|
26273
|
+
"branch",
|
|
26274
|
+
"plan-path"
|
|
26133
26275
|
];
|
|
26134
|
-
|
|
26135
|
-
|
|
26276
|
+
var HASH_HEADERS2 = /* @__PURE__ */ new Set([
|
|
26277
|
+
"plan-hash",
|
|
26278
|
+
"plan_hash",
|
|
26279
|
+
"git-blob-sha",
|
|
26280
|
+
"git_blob_sha"
|
|
26281
|
+
]);
|
|
26282
|
+
var COMPLEXITY_BANDS2 = /* @__PURE__ */ new Set(["C1", "C2", "C3", "C4"]);
|
|
26283
|
+
function splitSections3(text) {
|
|
26284
|
+
const sections = /* @__PURE__ */ new Map();
|
|
26285
|
+
const errors = [];
|
|
26286
|
+
let current;
|
|
26287
|
+
for (const line of text.split(LINE_SPLIT_RE).slice(1)) {
|
|
26288
|
+
if (line.startsWith("## ")) {
|
|
26289
|
+
current = line.slice(3).trim();
|
|
26290
|
+
if (sections.has(current)) {
|
|
26291
|
+
errors.push(
|
|
26292
|
+
`Parallel kickoff contains duplicate section: ## ${current}`
|
|
26293
|
+
);
|
|
26294
|
+
} else {
|
|
26295
|
+
sections.set(current, []);
|
|
26296
|
+
}
|
|
26297
|
+
continue;
|
|
26298
|
+
}
|
|
26299
|
+
if (current !== void 0) {
|
|
26300
|
+
sections.get(current)?.push(line);
|
|
26301
|
+
}
|
|
26302
|
+
}
|
|
26303
|
+
for (const required2 of ["Invocation Prompt", "Item Summary"]) {
|
|
26304
|
+
if (!sections.has(required2)) {
|
|
26305
|
+
errors.push(
|
|
26306
|
+
`Parallel kickoff is missing required section: ## ${required2}`
|
|
26307
|
+
);
|
|
26308
|
+
}
|
|
26309
|
+
}
|
|
26310
|
+
return { sections, errors };
|
|
26136
26311
|
}
|
|
26137
|
-
function
|
|
26138
|
-
|
|
26312
|
+
function parseCells2(line) {
|
|
26313
|
+
const stripped = line.trim();
|
|
26314
|
+
if (!stripped.startsWith("|") || !stripped.endsWith("|")) {
|
|
26315
|
+
return void 0;
|
|
26316
|
+
}
|
|
26317
|
+
return stripped.slice(1, -1).split("|").map((cell) => cell.trim().replace(/^`|`$/g, ""));
|
|
26139
26318
|
}
|
|
26140
|
-
function
|
|
26141
|
-
|
|
26142
|
-
return PLACEHOLDER_MARKERS.some((marker) => lowered.includes(marker));
|
|
26319
|
+
function isSeparator2(cells) {
|
|
26320
|
+
return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
|
|
26143
26321
|
}
|
|
26144
|
-
function
|
|
26145
|
-
const
|
|
26146
|
-
if (
|
|
26147
|
-
return
|
|
26322
|
+
function tableRows2(lines, expectedHeaders) {
|
|
26323
|
+
const nonempty = lines.filter((line) => line.trim().length > 0);
|
|
26324
|
+
if (nonempty.length < 2) {
|
|
26325
|
+
return {
|
|
26326
|
+
rows: [],
|
|
26327
|
+
errors: [
|
|
26328
|
+
"Parallel kickoff table is missing its header or separator row."
|
|
26329
|
+
]
|
|
26330
|
+
};
|
|
26148
26331
|
}
|
|
26149
|
-
|
|
26150
|
-
|
|
26332
|
+
const headers = parseCells2(nonempty[0] ?? "");
|
|
26333
|
+
const separator = parseCells2(nonempty[1] ?? "");
|
|
26334
|
+
const errors = [];
|
|
26335
|
+
if (headers === void 0 || headers.length !== expectedHeaders.length || headers.some((value, index) => value !== expectedHeaders[index])) {
|
|
26336
|
+
errors.push(
|
|
26337
|
+
`Parallel kickoff item table headers must be: ${expectedHeaders.join(" | ")}`
|
|
26338
|
+
);
|
|
26339
|
+
}
|
|
26340
|
+
if (separator === void 0 || separator.length !== expectedHeaders.length || !isSeparator2(separator)) {
|
|
26341
|
+
errors.push("Parallel kickoff table separator row is invalid.");
|
|
26151
26342
|
}
|
|
26152
|
-
return /\b(pass|ready|readiness)\b/.test(lowered);
|
|
26153
|
-
}
|
|
26154
|
-
function extractPolicyAuditCoverageRows(text) {
|
|
26155
26343
|
const rows = [];
|
|
26156
|
-
for (const line of
|
|
26157
|
-
|
|
26158
|
-
|
|
26159
|
-
|
|
26160
|
-
|
|
26161
|
-
|
|
26162
|
-
if (cells.length !== 7) {
|
|
26163
|
-
continue;
|
|
26164
|
-
}
|
|
26165
|
-
const language = cells[0] ?? "";
|
|
26166
|
-
if (language === "Language" || language === "----------" || !language) {
|
|
26167
|
-
continue;
|
|
26168
|
-
}
|
|
26169
|
-
if (language.length > 0 && /^-+$/.test(language)) {
|
|
26170
|
-
continue;
|
|
26344
|
+
for (const line of nonempty.slice(2)) {
|
|
26345
|
+
const cells = parseCells2(line);
|
|
26346
|
+
if (cells === void 0 || cells.length !== expectedHeaders.length) {
|
|
26347
|
+
errors.push(`Parallel kickoff table row is invalid: ${line}`);
|
|
26348
|
+
} else {
|
|
26349
|
+
rows.push(cells);
|
|
26171
26350
|
}
|
|
26172
|
-
rows.push({
|
|
26173
|
-
Language: language,
|
|
26174
|
-
"Files Changed": cells[1] ?? "",
|
|
26175
|
-
Tests: cells[2] ?? "",
|
|
26176
|
-
"Test Result": cells[3] ?? "",
|
|
26177
|
-
"Baseline Coverage": cells[4] ?? "",
|
|
26178
|
-
"Post-Change Coverage": cells[5] ?? "",
|
|
26179
|
-
"New Code Coverage": cells[6] ?? ""
|
|
26180
|
-
});
|
|
26181
26351
|
}
|
|
26182
|
-
|
|
26183
|
-
|
|
26184
|
-
|
|
26185
|
-
|
|
26186
|
-
const stripped = line.trim();
|
|
26187
|
-
if (stripped.startsWith("- ") && stripped.includes(label)) {
|
|
26188
|
-
return stripped;
|
|
26189
|
-
}
|
|
26352
|
+
if (rows.length === 0) {
|
|
26353
|
+
errors.push(
|
|
26354
|
+
"Parallel kickoff item table must contain at least one item row."
|
|
26355
|
+
);
|
|
26190
26356
|
}
|
|
26191
|
-
return
|
|
26357
|
+
return { rows, errors };
|
|
26192
26358
|
}
|
|
26193
|
-
function
|
|
26194
|
-
|
|
26195
|
-
const
|
|
26196
|
-
|
|
26197
|
-
const
|
|
26198
|
-
if (
|
|
26199
|
-
|
|
26200
|
-
|
|
26359
|
+
function parseItems(lines) {
|
|
26360
|
+
const table = tableRows2(lines, ITEM_HEADERS);
|
|
26361
|
+
const items = [];
|
|
26362
|
+
table.rows.forEach((row, index) => {
|
|
26363
|
+
const issueNum = Number(row[0]);
|
|
26364
|
+
if (!Number.isInteger(issueNum)) {
|
|
26365
|
+
table.errors.push(
|
|
26366
|
+
`Parallel kickoff item row ${String(index)} issue_num must be an integer.`
|
|
26367
|
+
);
|
|
26368
|
+
return;
|
|
26201
26369
|
}
|
|
26202
|
-
|
|
26203
|
-
|
|
26370
|
+
const cohort = Number(row[2]);
|
|
26371
|
+
if (!Number.isInteger(cohort)) {
|
|
26372
|
+
table.errors.push(
|
|
26373
|
+
`Parallel kickoff item row ${String(index)} cohort must be an integer.`
|
|
26374
|
+
);
|
|
26375
|
+
return;
|
|
26204
26376
|
}
|
|
26205
|
-
|
|
26377
|
+
const complexity = row[3] ?? "";
|
|
26378
|
+
if (!COMPLEXITY_BANDS2.has(complexity)) {
|
|
26379
|
+
table.errors.push(
|
|
26380
|
+
`Parallel kickoff item row ${String(index)} complexity must be C1-C4.`
|
|
26381
|
+
);
|
|
26382
|
+
}
|
|
26383
|
+
items.push({
|
|
26384
|
+
issueNum,
|
|
26385
|
+
featureFolder: row[1] ?? "",
|
|
26386
|
+
cohort,
|
|
26387
|
+
complexity,
|
|
26388
|
+
branch: row[4] ?? "",
|
|
26389
|
+
planPath: row[5] ?? ""
|
|
26390
|
+
});
|
|
26391
|
+
});
|
|
26392
|
+
return { items, errors: table.errors };
|
|
26393
|
+
}
|
|
26394
|
+
function parseIntegrityTable(tableLines) {
|
|
26395
|
+
const planHashes = {};
|
|
26396
|
+
const errors = [];
|
|
26397
|
+
const header = parseCells2(tableLines[0] ?? "");
|
|
26398
|
+
if (header === void 0 || header.length !== 2 || header[0] !== "plan-path" || !HASH_HEADERS2.has(header[1] ?? "")) {
|
|
26399
|
+
errors.push(
|
|
26400
|
+
"Parallel kickoff integrity table headers must be plan-path and plan-hash."
|
|
26401
|
+
);
|
|
26402
|
+
} else if (tableLines.length < 2) {
|
|
26403
|
+
errors.push(
|
|
26404
|
+
"Parallel kickoff integrity table is missing its separator row."
|
|
26405
|
+
);
|
|
26406
|
+
} else {
|
|
26407
|
+
const separator = parseCells2(tableLines[1] ?? "");
|
|
26408
|
+
if (separator === void 0 || separator.length !== 2 || !isSeparator2(separator)) {
|
|
26409
|
+
errors.push("Parallel kickoff integrity table separator row is invalid.");
|
|
26410
|
+
}
|
|
26411
|
+
for (const line of tableLines.slice(2)) {
|
|
26412
|
+
const cells = parseCells2(line);
|
|
26413
|
+
if (cells === void 0 || cells.length !== 2 || !/^[0-9a-fA-F]{40,64}$/.test(cells[1] ?? "")) {
|
|
26414
|
+
errors.push(`Parallel kickoff integrity table row is invalid: ${line}`);
|
|
26415
|
+
continue;
|
|
26416
|
+
}
|
|
26417
|
+
const planPath = cells[0] ?? "";
|
|
26418
|
+
if (planHashes[planPath] !== void 0) {
|
|
26419
|
+
errors.push(
|
|
26420
|
+
`Parallel kickoff integrity repeats plan path: '${planPath}'.`
|
|
26421
|
+
);
|
|
26422
|
+
}
|
|
26423
|
+
planHashes[planPath] = (cells[1] ?? "").toLowerCase();
|
|
26424
|
+
}
|
|
26425
|
+
}
|
|
26426
|
+
return { planHashes, errors };
|
|
26427
|
+
}
|
|
26428
|
+
function parseIntegrity2(lines) {
|
|
26429
|
+
let planningCommit;
|
|
26430
|
+
const errors = [];
|
|
26431
|
+
const tableLines = [];
|
|
26432
|
+
for (const line of lines) {
|
|
26433
|
+
if (line.trim().length === 0) {
|
|
26434
|
+
continue;
|
|
26435
|
+
}
|
|
26436
|
+
const match = INTEGRITY_COMMIT_RE2.exec(line.trim());
|
|
26437
|
+
if (match?.groups?.["commit"] !== void 0) {
|
|
26438
|
+
if (planningCommit !== void 0) {
|
|
26439
|
+
errors.push(
|
|
26440
|
+
"Parallel kickoff integrity has duplicate planning_commit fields."
|
|
26441
|
+
);
|
|
26442
|
+
}
|
|
26443
|
+
planningCommit = match.groups["commit"].toLowerCase();
|
|
26444
|
+
} else if (line.trim().startsWith("|")) {
|
|
26445
|
+
tableLines.push(line);
|
|
26446
|
+
} else {
|
|
26447
|
+
errors.push(`Parallel kickoff integrity line is invalid: ${line}`);
|
|
26448
|
+
}
|
|
26449
|
+
}
|
|
26450
|
+
let planHashes = {};
|
|
26451
|
+
if (tableLines.length > 0) {
|
|
26452
|
+
const table = parseIntegrityTable(tableLines);
|
|
26453
|
+
planHashes = table.planHashes;
|
|
26454
|
+
errors.push(...table.errors);
|
|
26455
|
+
}
|
|
26456
|
+
return {
|
|
26457
|
+
...planningCommit === void 0 ? {} : { planningCommit },
|
|
26458
|
+
planHashes,
|
|
26459
|
+
errors
|
|
26460
|
+
};
|
|
26461
|
+
}
|
|
26462
|
+
function parseParallelKickoff(text) {
|
|
26463
|
+
const lines = text.split(LINE_SPLIT_RE);
|
|
26464
|
+
if (text.length === 0) {
|
|
26465
|
+
return { errors: ["Parallel kickoff is empty."] };
|
|
26466
|
+
}
|
|
26467
|
+
const heading = KICKOFF_HEADING_RE2.exec(lines[0] ?? "");
|
|
26468
|
+
if (heading?.groups?.["slug"] === void 0) {
|
|
26469
|
+
return {
|
|
26470
|
+
errors: [
|
|
26471
|
+
"Parallel kickoff first line must match '# Parallel Kickoff: <slug>'."
|
|
26472
|
+
]
|
|
26473
|
+
};
|
|
26474
|
+
}
|
|
26475
|
+
const sectionResult = splitSections3(text);
|
|
26476
|
+
const invocation = (sectionResult.sections.get("Invocation Prompt") ?? []).join("\n");
|
|
26477
|
+
const invocationSlug = PARALLEL_RUN_RE.exec(invocation)?.groups?.["slug"];
|
|
26478
|
+
const manifestMatch = MANIFEST_RE2.exec(invocation);
|
|
26479
|
+
const branchMatch = PLAN_BRANCH_RE.exec(invocation);
|
|
26480
|
+
const resumeMatch = RESUME_RE2.exec(invocation);
|
|
26481
|
+
if (invocationSlug === void 0) {
|
|
26482
|
+
sectionResult.errors.push(
|
|
26483
|
+
"Parallel kickoff invocation must contain `Run /parallel-run <slug>`."
|
|
26484
|
+
);
|
|
26485
|
+
}
|
|
26486
|
+
if (manifestMatch?.[0] === void 0 || branchMatch?.[0] === void 0 || resumeMatch === null) {
|
|
26487
|
+
sectionResult.errors.push(
|
|
26488
|
+
"Parallel kickoff invocation must structurally name the manifest, plan-home branch, and atomic-execution resume boundary."
|
|
26489
|
+
);
|
|
26490
|
+
}
|
|
26491
|
+
const itemResult = parseItems(
|
|
26492
|
+
sectionResult.sections.get("Item Summary") ?? []
|
|
26493
|
+
);
|
|
26494
|
+
sectionResult.errors.push(...itemResult.errors);
|
|
26495
|
+
const integrity = parseIntegrity2(
|
|
26496
|
+
sectionResult.sections.get("Integrity") ?? []
|
|
26497
|
+
);
|
|
26498
|
+
sectionResult.errors.push(...integrity.errors);
|
|
26499
|
+
if (sectionResult.errors.length > 0 || invocationSlug === void 0 || manifestMatch?.[0] === void 0 || branchMatch?.[0] === void 0 || resumeMatch === null) {
|
|
26500
|
+
return { errors: sectionResult.errors };
|
|
26501
|
+
}
|
|
26502
|
+
return {
|
|
26503
|
+
parsed: {
|
|
26504
|
+
slug: heading.groups["slug"],
|
|
26505
|
+
invocationSlug,
|
|
26506
|
+
manifestPath: manifestMatch[0],
|
|
26507
|
+
planHomeBranch: branchMatch[0],
|
|
26508
|
+
items: itemResult.items,
|
|
26509
|
+
...integrity.planningCommit === void 0 ? {} : { planningCommit: integrity.planningCommit },
|
|
26510
|
+
planHashes: integrity.planHashes
|
|
26511
|
+
},
|
|
26512
|
+
errors: []
|
|
26513
|
+
};
|
|
26514
|
+
}
|
|
26515
|
+
function validateParallelKickoffText(text) {
|
|
26516
|
+
return parseParallelKickoff(text).errors;
|
|
26517
|
+
}
|
|
26518
|
+
|
|
26519
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-state-shared.ts
|
|
26520
|
+
function words(text) {
|
|
26521
|
+
return text.split(" ");
|
|
26522
|
+
}
|
|
26523
|
+
var VALID_ITEM_STATES = words(
|
|
26524
|
+
"proposed admitted prepared scheduled in_flight merged withdrawn blocked"
|
|
26525
|
+
);
|
|
26526
|
+
var VALID_MERGE_STATUS2 = words(
|
|
26527
|
+
"not_started worktree_created pr_open ci_green merged worktree_removed blocked_drift blocked_ci_loop_limit"
|
|
26528
|
+
);
|
|
26529
|
+
var VALID_SOURCES = words("derived declared observed");
|
|
26530
|
+
var VALID_KINDS = words("feature bug");
|
|
26531
|
+
var VALID_MODES = words("closed open");
|
|
26532
|
+
var VALID_MUTATION_OPS = words("add remove close requeue");
|
|
26533
|
+
var VALID_DISPOSITIONS = words("detach abandon");
|
|
26534
|
+
var VALID_EDGE_REASONS = words(
|
|
26535
|
+
"path_overlap module_overlap shared_surface_overlap contract_dependency"
|
|
26536
|
+
);
|
|
26537
|
+
var VALID_DRIFT_ACTIONS = words(
|
|
26538
|
+
"raised_blocking_finding halted_later_started_item"
|
|
26539
|
+
);
|
|
26540
|
+
var MERGED_MERGE_STATUSES = words("merged worktree_removed");
|
|
26541
|
+
var BLOCKED_MERGE_STATUSES = words(
|
|
26542
|
+
"blocked_drift blocked_ci_loop_limit"
|
|
26543
|
+
);
|
|
26544
|
+
var BLAST_RADIUS_LIST_FIELDS = words(
|
|
26545
|
+
"paths modules shared_surfaces contracts"
|
|
26546
|
+
);
|
|
26547
|
+
var PROHIBITED_ANY_LEVEL_KEYS = words(
|
|
26548
|
+
"depends_on integration_branch epic_merge_pr"
|
|
26549
|
+
);
|
|
26550
|
+
var ROOT_PATH = "<root>";
|
|
26551
|
+
function isObject14(value) {
|
|
26552
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26553
|
+
}
|
|
26554
|
+
function pythonRepr9(value) {
|
|
26555
|
+
if (value === null || value === void 0) {
|
|
26556
|
+
return "None";
|
|
26557
|
+
}
|
|
26558
|
+
if (typeof value === "boolean") {
|
|
26559
|
+
return value ? "True" : "False";
|
|
26560
|
+
}
|
|
26561
|
+
if (typeof value === "string") {
|
|
26562
|
+
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
26563
|
+
}
|
|
26564
|
+
if (Array.isArray(value)) {
|
|
26565
|
+
return `[${value.map(pythonRepr9).join(", ")}]`;
|
|
26566
|
+
}
|
|
26567
|
+
if (isObject14(value)) {
|
|
26568
|
+
const pairs = Object.entries(value).map(
|
|
26569
|
+
([key, item]) => `${pythonRepr9(key)}: ${pythonRepr9(item)}`
|
|
26570
|
+
);
|
|
26571
|
+
return `{${pairs.join(", ")}}`;
|
|
26572
|
+
}
|
|
26573
|
+
return String(value);
|
|
26574
|
+
}
|
|
26575
|
+
function pythonStr2(value) {
|
|
26576
|
+
return typeof value === "string" ? value : pythonRepr9(value);
|
|
26577
|
+
}
|
|
26578
|
+
function isEnumMember(members, value) {
|
|
26579
|
+
return typeof value === "string" && members.includes(value);
|
|
26580
|
+
}
|
|
26581
|
+
function isNonEmptyString2(value) {
|
|
26582
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
26583
|
+
}
|
|
26584
|
+
function isIntegral(value) {
|
|
26585
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
26586
|
+
}
|
|
26587
|
+
function isPositiveInteger(value) {
|
|
26588
|
+
return isIntegral(value) && value > 0;
|
|
26589
|
+
}
|
|
26590
|
+
function isNonNegativeInteger(value) {
|
|
26591
|
+
return isIntegral(value) && value >= 0;
|
|
26592
|
+
}
|
|
26593
|
+
function isStringList(value) {
|
|
26594
|
+
return Array.isArray(value) && value.every(isNonEmptyString2);
|
|
26595
|
+
}
|
|
26596
|
+
function inBoundedRange(value, minimum, maximum) {
|
|
26597
|
+
return isIntegral(value) && value >= minimum && value <= maximum;
|
|
26598
|
+
}
|
|
26599
|
+
function enumError(context, field, members, value) {
|
|
26600
|
+
return `${context} ${field} must be one of ${members.join(", ")}; found: ${pythonRepr9(value)}.`;
|
|
26601
|
+
}
|
|
26602
|
+
function itemContext(context, index) {
|
|
26603
|
+
return `${context} items[${index}]`;
|
|
26604
|
+
}
|
|
26605
|
+
function validateBlastRadiusBlock(radius, context) {
|
|
26606
|
+
if (!isObject14(radius)) {
|
|
26607
|
+
return [`${context} blast_radius must be an object.`];
|
|
26608
|
+
}
|
|
26609
|
+
const errors = [];
|
|
26610
|
+
for (const field of BLAST_RADIUS_LIST_FIELDS) {
|
|
26611
|
+
if (!isStringList(radius[field])) {
|
|
26612
|
+
errors.push(
|
|
26613
|
+
`${context} blast_radius.${field} must be a list of non-empty strings.`
|
|
26614
|
+
);
|
|
26615
|
+
}
|
|
26616
|
+
}
|
|
26617
|
+
const source = radius["source"];
|
|
26618
|
+
if (!isEnumMember(VALID_SOURCES, source)) {
|
|
26619
|
+
errors.push(
|
|
26620
|
+
enumError(context, "blast_radius.source", VALID_SOURCES, source)
|
|
26621
|
+
);
|
|
26622
|
+
}
|
|
26623
|
+
if (!isNonEmptyString2(radius["computed_at"])) {
|
|
26624
|
+
errors.push(
|
|
26625
|
+
`${context} blast_radius.computed_at must be a non-empty string.`
|
|
26626
|
+
);
|
|
26627
|
+
}
|
|
26628
|
+
return errors;
|
|
26629
|
+
}
|
|
26630
|
+
function validateMergeStatus(record2, context, state) {
|
|
26631
|
+
if (!("merge_status" in record2)) {
|
|
26632
|
+
return [];
|
|
26633
|
+
}
|
|
26634
|
+
const mergeStatus = record2["merge_status"];
|
|
26635
|
+
if (!isEnumMember(VALID_MERGE_STATUS2, mergeStatus)) {
|
|
26636
|
+
return [
|
|
26637
|
+
enumError(context, "merge_status", VALID_MERGE_STATUS2, mergeStatus)
|
|
26638
|
+
];
|
|
26639
|
+
}
|
|
26640
|
+
if (isEnumMember(MERGED_MERGE_STATUSES, mergeStatus) && state !== "merged") {
|
|
26641
|
+
return [
|
|
26642
|
+
`${context} merge_status ${pythonRepr9(mergeStatus)} requires state 'merged'; found: ${pythonRepr9(state)}.`
|
|
26643
|
+
];
|
|
26644
|
+
}
|
|
26645
|
+
if (isEnumMember(BLOCKED_MERGE_STATUSES, mergeStatus) && state !== "blocked") {
|
|
26646
|
+
return [
|
|
26647
|
+
`${context} merge_status ${pythonRepr9(mergeStatus)} requires state 'blocked'; found: ${pythonRepr9(state)}.`
|
|
26648
|
+
];
|
|
26649
|
+
}
|
|
26650
|
+
return [];
|
|
26651
|
+
}
|
|
26652
|
+
function validateItemRecord(item, context, requireKind = false) {
|
|
26653
|
+
if (!isObject14(item)) {
|
|
26654
|
+
return [`${context} must be an object.`];
|
|
26655
|
+
}
|
|
26656
|
+
const errors = [];
|
|
26657
|
+
const issueNum = item["issue_num"];
|
|
26658
|
+
if (!isPositiveInteger(issueNum)) {
|
|
26659
|
+
errors.push(
|
|
26660
|
+
`${context} issue_num must be a positive integer; found: ${pythonRepr9(issueNum)}.`
|
|
26661
|
+
);
|
|
26662
|
+
}
|
|
26663
|
+
if (!isNonEmptyString2(item["feature_folder"])) {
|
|
26664
|
+
errors.push(`${context} feature_folder must be a non-empty string.`);
|
|
26665
|
+
}
|
|
26666
|
+
const state = item["state"];
|
|
26667
|
+
if (!isEnumMember(VALID_ITEM_STATES, state)) {
|
|
26668
|
+
errors.push(enumError(context, "state", VALID_ITEM_STATES, state));
|
|
26669
|
+
}
|
|
26670
|
+
if (requireKind) {
|
|
26671
|
+
const kind = item["kind"];
|
|
26672
|
+
if (!isEnumMember(VALID_KINDS, kind)) {
|
|
26673
|
+
errors.push(enumError(context, "kind", VALID_KINDS, kind));
|
|
26674
|
+
}
|
|
26675
|
+
}
|
|
26676
|
+
errors.push(...validateMergeStatus(item, context, state));
|
|
26677
|
+
errors.push(...validateBlastRadiusBlock(item["blast_radius"], context));
|
|
26678
|
+
return errors;
|
|
26679
|
+
}
|
|
26680
|
+
function validateItems(items, context, requireKind = false) {
|
|
26681
|
+
if (!Array.isArray(items)) {
|
|
26682
|
+
return [`${context} items must be a list.`];
|
|
26683
|
+
}
|
|
26684
|
+
const errors = [];
|
|
26685
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26686
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
26687
|
+
items.forEach((entry, index) => {
|
|
26688
|
+
errors.push(
|
|
26689
|
+
...validateItemRecord(entry, itemContext(context, index), requireKind)
|
|
26690
|
+
);
|
|
26691
|
+
if (!isObject14(entry)) {
|
|
26692
|
+
return;
|
|
26693
|
+
}
|
|
26694
|
+
const issueNum = entry["issue_num"];
|
|
26695
|
+
if (typeof issueNum !== "number" || !Number.isInteger(issueNum)) {
|
|
26696
|
+
return;
|
|
26697
|
+
}
|
|
26698
|
+
if (seen.has(issueNum)) {
|
|
26699
|
+
duplicates.add(issueNum);
|
|
26700
|
+
}
|
|
26701
|
+
seen.add(issueNum);
|
|
26702
|
+
});
|
|
26703
|
+
for (const issueNum of [...duplicates].sort((left, right) => left - right)) {
|
|
26704
|
+
errors.push(`${context} has duplicate items[].issue_num: ${issueNum}.`);
|
|
26705
|
+
}
|
|
26706
|
+
return errors;
|
|
26707
|
+
}
|
|
26708
|
+
function prohibitedKeyErrors(value, path11, context, keys) {
|
|
26709
|
+
const errors = [];
|
|
26710
|
+
if (isObject14(value)) {
|
|
26711
|
+
for (const [key, child] of Object.entries(value)) {
|
|
26712
|
+
if (keys.includes(key)) {
|
|
26713
|
+
errors.push(`${context} carries prohibited key '${key}' at ${path11}.`);
|
|
26714
|
+
}
|
|
26715
|
+
const childPath = path11 === ROOT_PATH ? key : `${path11}.${key}`;
|
|
26716
|
+
errors.push(...prohibitedKeyErrors(child, childPath, context, keys));
|
|
26717
|
+
}
|
|
26718
|
+
} else if (Array.isArray(value)) {
|
|
26719
|
+
value.forEach((entry, index) => {
|
|
26720
|
+
errors.push(
|
|
26721
|
+
...prohibitedKeyErrors(entry, `${path11}[${index}]`, context, keys)
|
|
26722
|
+
);
|
|
26723
|
+
});
|
|
26724
|
+
}
|
|
26725
|
+
return errors;
|
|
26726
|
+
}
|
|
26727
|
+
function scanProhibitedKeys(root, context, deepKeys = PROHIBITED_ANY_LEVEL_KEYS, topLevelKeys = []) {
|
|
26728
|
+
const errors = prohibitedKeyErrors(root, ROOT_PATH, context, deepKeys);
|
|
26729
|
+
if (isObject14(root) && topLevelKeys.length > 0) {
|
|
26730
|
+
for (const key of topLevelKeys) {
|
|
26731
|
+
if (key in root) {
|
|
26732
|
+
errors.push(
|
|
26733
|
+
`${context} carries prohibited key '${key}' at ${ROOT_PATH}.`
|
|
26734
|
+
);
|
|
26735
|
+
}
|
|
26736
|
+
}
|
|
26737
|
+
}
|
|
26738
|
+
return errors;
|
|
26739
|
+
}
|
|
26740
|
+
|
|
26741
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-orchestrator-state-cohort-barrier.ts
|
|
26742
|
+
var VIOLATION_PREFIX = "PARALLEL_COHORT_BARRIER_VIOLATION";
|
|
26743
|
+
var ITEM_START_TIMESTAMP_FIELD = "worktree_created_at";
|
|
26744
|
+
var MERGE_CONFIRMATION_TIMESTAMP_FIELD = "merged_at";
|
|
26745
|
+
var NOT_STARTED_MERGE_STATUS = "not_started";
|
|
26746
|
+
var GATING_KEYS = ["conflict_edges", "cohorts"];
|
|
26747
|
+
var FOLDER_HINT_PREFIXES = [
|
|
26748
|
+
"docs/features/active/",
|
|
26749
|
+
"docs/features/completed/",
|
|
26750
|
+
"active/",
|
|
26751
|
+
"completed/"
|
|
26752
|
+
];
|
|
26753
|
+
function normalizeFolderHint2(value) {
|
|
26754
|
+
for (const prefix of FOLDER_HINT_PREFIXES) {
|
|
26755
|
+
if (value.startsWith(prefix)) {
|
|
26756
|
+
return value.slice(prefix.length);
|
|
26757
|
+
}
|
|
26758
|
+
}
|
|
26759
|
+
return value;
|
|
26760
|
+
}
|
|
26761
|
+
function buildReferenceIndex(items) {
|
|
26762
|
+
const records = /* @__PURE__ */ new Map();
|
|
26763
|
+
const byFolderHint = /* @__PURE__ */ new Map();
|
|
26764
|
+
if (!Array.isArray(items)) {
|
|
26765
|
+
return { records, byFolderHint };
|
|
26766
|
+
}
|
|
26767
|
+
for (const entry of items) {
|
|
26768
|
+
if (!isObject14(entry)) {
|
|
26769
|
+
continue;
|
|
26770
|
+
}
|
|
26771
|
+
const issueNum = entry["issue_num"];
|
|
26772
|
+
if (typeof issueNum !== "number" || !isPositiveInteger(issueNum)) {
|
|
26773
|
+
continue;
|
|
26774
|
+
}
|
|
26775
|
+
if (!records.has(issueNum)) {
|
|
26776
|
+
records.set(issueNum, entry);
|
|
26777
|
+
}
|
|
26778
|
+
const folder = entry["feature_folder"];
|
|
26779
|
+
if (typeof folder === "string" && folder.trim().length > 0) {
|
|
26780
|
+
const hint = normalizeFolderHint2(folder);
|
|
26781
|
+
if (!byFolderHint.has(hint)) {
|
|
26782
|
+
byFolderHint.set(hint, issueNum);
|
|
26783
|
+
}
|
|
26784
|
+
}
|
|
26785
|
+
}
|
|
26786
|
+
return { records, byFolderHint };
|
|
26787
|
+
}
|
|
26788
|
+
function resolveReference(reference, references) {
|
|
26789
|
+
if (typeof reference === "string") {
|
|
26790
|
+
return references.byFolderHint.get(normalizeFolderHint2(reference)) ?? null;
|
|
26791
|
+
}
|
|
26792
|
+
if (typeof reference === "number" && isPositiveInteger(reference) && references.records.has(reference)) {
|
|
26793
|
+
return reference;
|
|
26794
|
+
}
|
|
26795
|
+
return null;
|
|
26796
|
+
}
|
|
26797
|
+
function cohortIndexByItem(cohorts, recolorGeneration, references) {
|
|
26798
|
+
const assignments = /* @__PURE__ */ new Map();
|
|
26799
|
+
if (!Array.isArray(cohorts) || !isNonNegativeInteger(recolorGeneration)) {
|
|
26800
|
+
return assignments;
|
|
26801
|
+
}
|
|
26802
|
+
for (const entry of cohorts) {
|
|
26803
|
+
if (!isObject14(entry) || entry["generation"] !== recolorGeneration) {
|
|
26804
|
+
continue;
|
|
26805
|
+
}
|
|
26806
|
+
const cohortIndex = entry["index"];
|
|
26807
|
+
const itemKeys = entry["item_keys"];
|
|
26808
|
+
if (typeof cohortIndex !== "number" || !isNonNegativeInteger(cohortIndex) || !Array.isArray(itemKeys)) {
|
|
26809
|
+
continue;
|
|
26810
|
+
}
|
|
26811
|
+
for (const reference of itemKeys) {
|
|
26812
|
+
const key = resolveReference(reference, references);
|
|
26813
|
+
if (key !== null && !assignments.has(key)) {
|
|
26814
|
+
assignments.set(key, cohortIndex);
|
|
26815
|
+
}
|
|
26816
|
+
}
|
|
26817
|
+
}
|
|
26818
|
+
return assignments;
|
|
26819
|
+
}
|
|
26820
|
+
function hasStarted(record2) {
|
|
26821
|
+
const start = record2[ITEM_START_TIMESTAMP_FIELD];
|
|
26822
|
+
if (typeof start === "string" && start.trim().length > 0) {
|
|
26823
|
+
return true;
|
|
26824
|
+
}
|
|
26825
|
+
const mergeStatus = record2["merge_status"];
|
|
26826
|
+
return typeof mergeStatus === "string" && mergeStatus !== NOT_STARTED_MERGE_STATUS;
|
|
26827
|
+
}
|
|
26828
|
+
function satisfiesBarrier(record2) {
|
|
26829
|
+
return isEnumMember(MERGED_MERGE_STATUSES, record2["merge_status"]);
|
|
26830
|
+
}
|
|
26831
|
+
function mergeConfirmedAfterStart(earlier, later) {
|
|
26832
|
+
const confirmed = earlier[MERGE_CONFIRMATION_TIMESTAMP_FIELD];
|
|
26833
|
+
const started = later[ITEM_START_TIMESTAMP_FIELD];
|
|
26834
|
+
if (typeof confirmed !== "string" || typeof started !== "string") {
|
|
26835
|
+
return false;
|
|
26836
|
+
}
|
|
26837
|
+
return confirmed > started;
|
|
26838
|
+
}
|
|
26839
|
+
function violationEndpoints(first, second, assignments, records) {
|
|
26840
|
+
const firstIndex = assignments.get(first);
|
|
26841
|
+
const secondIndex = assignments.get(second);
|
|
26842
|
+
if (firstIndex !== void 0 && firstIndex === secondIndex) {
|
|
26843
|
+
return [first, second];
|
|
26844
|
+
}
|
|
26845
|
+
if (firstIndex === void 0 || secondIndex === void 0) {
|
|
26846
|
+
return null;
|
|
26847
|
+
}
|
|
26848
|
+
const [earlierKey, laterKey] = firstIndex < secondIndex ? [first, second] : [second, first];
|
|
26849
|
+
const earlier = records.get(earlierKey);
|
|
26850
|
+
const later = records.get(laterKey);
|
|
26851
|
+
if (earlier === void 0 || later === void 0) {
|
|
26852
|
+
return null;
|
|
26853
|
+
}
|
|
26854
|
+
const statusViolation = hasStarted(later) && !satisfiesBarrier(earlier);
|
|
26855
|
+
if (statusViolation || mergeConfirmedAfterStart(earlier, later)) {
|
|
26856
|
+
return [earlierKey, laterKey];
|
|
26857
|
+
}
|
|
26858
|
+
return null;
|
|
26859
|
+
}
|
|
26860
|
+
function validateCohortBarrierOrdering(state) {
|
|
26861
|
+
if (GATING_KEYS.some((key) => !(key in state))) {
|
|
26862
|
+
return [];
|
|
26863
|
+
}
|
|
26864
|
+
const edges = state["conflict_edges"];
|
|
26865
|
+
if (!Array.isArray(edges)) {
|
|
26866
|
+
return [];
|
|
26867
|
+
}
|
|
26868
|
+
const references = buildReferenceIndex(state["items"]);
|
|
26869
|
+
const assignments = cohortIndexByItem(
|
|
26870
|
+
state["cohorts"],
|
|
26871
|
+
state["recolor_generation"],
|
|
26872
|
+
references
|
|
26873
|
+
);
|
|
26874
|
+
const errors = [];
|
|
26875
|
+
for (const entry of edges) {
|
|
26876
|
+
if (!isObject14(entry)) {
|
|
26877
|
+
continue;
|
|
26878
|
+
}
|
|
26879
|
+
const first = resolveReference(entry["a"], references);
|
|
26880
|
+
const second = resolveReference(entry["b"], references);
|
|
26881
|
+
if (first === null || second === null || first === second) {
|
|
26882
|
+
continue;
|
|
26883
|
+
}
|
|
26884
|
+
const endpoints = violationEndpoints(
|
|
26885
|
+
first,
|
|
26886
|
+
second,
|
|
26887
|
+
assignments,
|
|
26888
|
+
references.records
|
|
26889
|
+
);
|
|
26890
|
+
if (endpoints !== null) {
|
|
26891
|
+
errors.push(
|
|
26892
|
+
`${VIOLATION_PREFIX}: ${endpoints[0]} ran concurrently with conflicting ${endpoints[1]}`
|
|
26893
|
+
);
|
|
26894
|
+
}
|
|
26895
|
+
}
|
|
26896
|
+
return errors;
|
|
26897
|
+
}
|
|
26898
|
+
|
|
26899
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-state-records.ts
|
|
26900
|
+
var OPS_REQUIRING_ITEM_KEY = ["add", "remove", "requeue"];
|
|
26901
|
+
var OPS_REQUIRING_NULL_PRIOR_STATE = ["add", "close"];
|
|
26902
|
+
var OPS_REQUIRING_NULL_NEW_STATE = ["close"];
|
|
26903
|
+
function isNone(value) {
|
|
26904
|
+
return value === null || value === void 0;
|
|
26905
|
+
}
|
|
26906
|
+
function resolves(value, issueNums) {
|
|
26907
|
+
return typeof value === "number" && Number.isInteger(value) && issueNums.has(value);
|
|
26908
|
+
}
|
|
26909
|
+
function validateMutationItemKey(entry, entryContext, op, issueNums) {
|
|
26910
|
+
const itemKey = entry["item_key"];
|
|
26911
|
+
if (op === "close") {
|
|
26912
|
+
if (!isNone(itemKey)) {
|
|
26913
|
+
return [
|
|
26914
|
+
`${entryContext} item_key must be null for op 'close'; found: ${pythonRepr9(itemKey)}.`
|
|
26915
|
+
];
|
|
26916
|
+
}
|
|
26917
|
+
return [];
|
|
26918
|
+
}
|
|
26919
|
+
if (isEnumMember(OPS_REQUIRING_ITEM_KEY, op) && !resolves(itemKey, issueNums)) {
|
|
26920
|
+
return [
|
|
26921
|
+
`${entryContext} item_key ${pythonRepr9(itemKey)} does not resolve to an items[].issue_num.`
|
|
26922
|
+
];
|
|
26923
|
+
}
|
|
26924
|
+
return [];
|
|
26925
|
+
}
|
|
26926
|
+
function validateMutationStateField(entry, entryContext, field, op, nullOps) {
|
|
26927
|
+
const value = entry[field];
|
|
26928
|
+
if (isNone(value)) {
|
|
26929
|
+
return [];
|
|
26930
|
+
}
|
|
26931
|
+
if (isEnumMember(nullOps, op)) {
|
|
26932
|
+
return [
|
|
26933
|
+
`${entryContext} ${field} must be null for op ${pythonRepr9(op)}; found: ${pythonRepr9(value)}.`
|
|
26934
|
+
];
|
|
26935
|
+
}
|
|
26936
|
+
if (!isEnumMember(VALID_ITEM_STATES, value)) {
|
|
26937
|
+
return [
|
|
26938
|
+
`${entryContext} ${field} must be null or one of ${VALID_ITEM_STATES.join(", ")}; found: ${pythonRepr9(value)}.`
|
|
26939
|
+
];
|
|
26940
|
+
}
|
|
26941
|
+
return [];
|
|
26942
|
+
}
|
|
26943
|
+
function validateMutationDisposition(entry, entryContext, op) {
|
|
26944
|
+
const disposition = entry["disposition"];
|
|
26945
|
+
if (op === "remove" && entry["prior_state"] === "in_flight") {
|
|
26946
|
+
if (!isEnumMember(VALID_DISPOSITIONS, disposition)) {
|
|
26947
|
+
return [
|
|
26948
|
+
`${entryContext} disposition must be one of ${VALID_DISPOSITIONS.join(", ")} for an in-flight removal; found: ${pythonRepr9(disposition)}.`
|
|
26949
|
+
];
|
|
26950
|
+
}
|
|
26951
|
+
return [];
|
|
26952
|
+
}
|
|
26953
|
+
if (!isNone(disposition)) {
|
|
26954
|
+
return [
|
|
26955
|
+
`${entryContext} disposition must be null unless op is 'remove' with prior_state 'in_flight'; found: ${pythonRepr9(disposition)}.`
|
|
26956
|
+
];
|
|
26957
|
+
}
|
|
26958
|
+
return [];
|
|
26959
|
+
}
|
|
26960
|
+
function validateMutationGeneration(entry, entryContext, recolorGeneration) {
|
|
26961
|
+
const generation = entry["recolor_generation"];
|
|
26962
|
+
if (!isNonNegativeInteger(generation)) {
|
|
26963
|
+
return [
|
|
26964
|
+
`${entryContext} recolor_generation must be a non-negative integer; found: ${pythonRepr9(generation)}.`
|
|
26965
|
+
];
|
|
26966
|
+
}
|
|
26967
|
+
if (isNonNegativeInteger(recolorGeneration) && typeof generation === "number" && typeof recolorGeneration === "number" && generation > recolorGeneration) {
|
|
26968
|
+
return [
|
|
26969
|
+
`${entryContext} recolor_generation ${generation} must not exceed recolor_generation ${recolorGeneration}.`
|
|
26970
|
+
];
|
|
26971
|
+
}
|
|
26972
|
+
return [];
|
|
26973
|
+
}
|
|
26974
|
+
function validateMutations(mutations, issueNums, recolorGeneration, context) {
|
|
26975
|
+
if (!Array.isArray(mutations)) {
|
|
26976
|
+
return [`${context} mutations must be a list.`];
|
|
26977
|
+
}
|
|
26978
|
+
const errors = [];
|
|
26979
|
+
mutations.forEach((entry, position) => {
|
|
26980
|
+
const entryContext = `${context} mutations[${position}]`;
|
|
26981
|
+
if (!isObject14(entry)) {
|
|
26982
|
+
errors.push(`${entryContext} must be an object.`);
|
|
26983
|
+
return;
|
|
26984
|
+
}
|
|
26985
|
+
const op = entry["op"];
|
|
26986
|
+
if (!isEnumMember(VALID_MUTATION_OPS, op)) {
|
|
26987
|
+
errors.push(enumError(entryContext, "op", VALID_MUTATION_OPS, op));
|
|
26988
|
+
}
|
|
26989
|
+
errors.push(...validateMutationItemKey(entry, entryContext, op, issueNums));
|
|
26990
|
+
if (!isNonEmptyString2(entry["at"])) {
|
|
26991
|
+
errors.push(`${entryContext} at must be a non-empty string.`);
|
|
26992
|
+
}
|
|
26993
|
+
errors.push(
|
|
26994
|
+
...validateMutationStateField(
|
|
26995
|
+
entry,
|
|
26996
|
+
entryContext,
|
|
26997
|
+
"prior_state",
|
|
26998
|
+
op,
|
|
26999
|
+
OPS_REQUIRING_NULL_PRIOR_STATE
|
|
27000
|
+
)
|
|
27001
|
+
);
|
|
27002
|
+
errors.push(
|
|
27003
|
+
...validateMutationStateField(
|
|
27004
|
+
entry,
|
|
27005
|
+
entryContext,
|
|
27006
|
+
"new_state",
|
|
27007
|
+
op,
|
|
27008
|
+
OPS_REQUIRING_NULL_NEW_STATE
|
|
27009
|
+
)
|
|
27010
|
+
);
|
|
27011
|
+
errors.push(...validateMutationDisposition(entry, entryContext, op));
|
|
27012
|
+
errors.push(
|
|
27013
|
+
...validateMutationGeneration(entry, entryContext, recolorGeneration)
|
|
27014
|
+
);
|
|
27015
|
+
});
|
|
27016
|
+
return errors;
|
|
27017
|
+
}
|
|
27018
|
+
function validateDriftEvents(events, issueNums, context) {
|
|
27019
|
+
if (!Array.isArray(events)) {
|
|
27020
|
+
return [`${context} drift_events must be a list.`];
|
|
27021
|
+
}
|
|
27022
|
+
const errors = [];
|
|
27023
|
+
events.forEach((entry, position) => {
|
|
27024
|
+
const entryContext = `${context} drift_events[${position}]`;
|
|
27025
|
+
if (!isObject14(entry)) {
|
|
27026
|
+
errors.push(`${entryContext} must be an object.`);
|
|
27027
|
+
return;
|
|
27028
|
+
}
|
|
27029
|
+
const itemKey = entry["item_key"];
|
|
27030
|
+
if (!resolves(itemKey, issueNums)) {
|
|
27031
|
+
errors.push(
|
|
27032
|
+
`${entryContext} item_key ${pythonRepr9(itemKey)} does not resolve to an items[].issue_num.`
|
|
27033
|
+
);
|
|
27034
|
+
}
|
|
27035
|
+
for (const field of ["declared", "observed"]) {
|
|
27036
|
+
if (!isStringList(entry[field])) {
|
|
27037
|
+
errors.push(
|
|
27038
|
+
`${entryContext} ${field} must be a list of non-empty strings.`
|
|
27039
|
+
);
|
|
27040
|
+
}
|
|
27041
|
+
}
|
|
27042
|
+
const escapedPaths = entry["escaped_paths"];
|
|
27043
|
+
if (!isStringList(escapedPaths) || !Array.isArray(escapedPaths) || escapedPaths.length === 0) {
|
|
27044
|
+
errors.push(
|
|
27045
|
+
`${entryContext} escaped_paths must be a non-empty list of non-empty strings.`
|
|
27046
|
+
);
|
|
27047
|
+
}
|
|
27048
|
+
if (!isNonEmptyString2(entry["at"])) {
|
|
27049
|
+
errors.push(`${entryContext} at must be a non-empty string.`);
|
|
27050
|
+
}
|
|
27051
|
+
const action = entry["action"];
|
|
27052
|
+
if (!isEnumMember(VALID_DRIFT_ACTIONS, action)) {
|
|
27053
|
+
errors.push(
|
|
27054
|
+
enumError(entryContext, "action", VALID_DRIFT_ACTIONS, action)
|
|
27055
|
+
);
|
|
27056
|
+
}
|
|
27057
|
+
});
|
|
27058
|
+
return errors;
|
|
27059
|
+
}
|
|
27060
|
+
|
|
27061
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-state-structures.ts
|
|
27062
|
+
var COHORT_COVERAGE_EXEMPT_STATES = "withdrawn merged blocked".split(" ");
|
|
27063
|
+
var RECEIPT_ARRAY_KEYS = "delegation_receipts skill_receipts mcp_call_receipts".split(" ");
|
|
27064
|
+
function collectItemKeysAndStates(items) {
|
|
27065
|
+
const pairs = [];
|
|
27066
|
+
if (!Array.isArray(items)) {
|
|
27067
|
+
return pairs;
|
|
27068
|
+
}
|
|
27069
|
+
for (const entry of items) {
|
|
27070
|
+
if (!isObject14(entry)) {
|
|
27071
|
+
continue;
|
|
27072
|
+
}
|
|
27073
|
+
const issueNum = entry["issue_num"];
|
|
27074
|
+
if (typeof issueNum === "number" && Number.isInteger(issueNum) && issueNum > 0) {
|
|
27075
|
+
pairs.push({ issueNum, state: entry["state"] });
|
|
27076
|
+
}
|
|
27077
|
+
}
|
|
27078
|
+
return pairs;
|
|
27079
|
+
}
|
|
27080
|
+
function collectIssueNumbers(items) {
|
|
27081
|
+
return new Set(collectItemKeysAndStates(items).map((pair) => pair.issueNum));
|
|
27082
|
+
}
|
|
27083
|
+
function validateCohortEntry(entry, entryContext, issueNums, recolorGeneration) {
|
|
27084
|
+
const errors = [];
|
|
27085
|
+
const index = entry["index"];
|
|
27086
|
+
if (!isNonNegativeInteger(index)) {
|
|
27087
|
+
errors.push(
|
|
27088
|
+
`${entryContext} index must be a non-negative integer; found: ${pythonRepr9(index)}.`
|
|
27089
|
+
);
|
|
27090
|
+
}
|
|
27091
|
+
const generation = entry["generation"];
|
|
27092
|
+
if (!isNonNegativeInteger(generation)) {
|
|
27093
|
+
errors.push(
|
|
27094
|
+
`${entryContext} generation must be a non-negative integer; found: ${pythonRepr9(generation)}.`
|
|
27095
|
+
);
|
|
27096
|
+
} else if (recolorGeneration !== null && typeof generation === "number" && generation > recolorGeneration) {
|
|
27097
|
+
errors.push(
|
|
27098
|
+
`${entryContext} generation ${generation} must not exceed recolor_generation ${recolorGeneration}.`
|
|
27099
|
+
);
|
|
27100
|
+
}
|
|
27101
|
+
const itemKeys = entry["item_keys"];
|
|
27102
|
+
if (!Array.isArray(itemKeys)) {
|
|
27103
|
+
errors.push(`${entryContext} item_keys must be a list.`);
|
|
27104
|
+
return errors;
|
|
27105
|
+
}
|
|
27106
|
+
for (const key of itemKeys) {
|
|
27107
|
+
if (typeof key !== "number" || !Number.isInteger(key) || !issueNums.has(key)) {
|
|
27108
|
+
errors.push(
|
|
27109
|
+
`${entryContext} item_keys entry ${pythonRepr9(key)} does not resolve to an items[].issue_num.`
|
|
27110
|
+
);
|
|
27111
|
+
}
|
|
27112
|
+
}
|
|
27113
|
+
return errors;
|
|
27114
|
+
}
|
|
27115
|
+
function validateCohortShapes(cohorts, issueNums, recolorGeneration, context) {
|
|
27116
|
+
const errors = [];
|
|
27117
|
+
const generationOk = isNonNegativeInteger(recolorGeneration);
|
|
27118
|
+
if (!generationOk) {
|
|
27119
|
+
errors.push(
|
|
27120
|
+
`${context} recolor_generation must be a non-negative integer; found: ${pythonRepr9(recolorGeneration)}.`
|
|
27121
|
+
);
|
|
27122
|
+
}
|
|
27123
|
+
if (!Array.isArray(cohorts)) {
|
|
27124
|
+
errors.push(`${context} cohorts must be a list.`);
|
|
27125
|
+
return errors;
|
|
27126
|
+
}
|
|
27127
|
+
const bound = generationOk && typeof recolorGeneration === "number" ? recolorGeneration : null;
|
|
27128
|
+
cohorts.forEach((entry, position) => {
|
|
27129
|
+
const entryContext = `${context} cohorts[${position}]`;
|
|
27130
|
+
if (!isObject14(entry)) {
|
|
27131
|
+
errors.push(`${entryContext} must be an object.`);
|
|
27132
|
+
return;
|
|
27133
|
+
}
|
|
27134
|
+
errors.push(...validateCohortEntry(entry, entryContext, issueNums, bound));
|
|
27135
|
+
});
|
|
27136
|
+
return errors;
|
|
27137
|
+
}
|
|
27138
|
+
function currentGenerationCohorts(cohorts, recolorGeneration) {
|
|
27139
|
+
if (!isNonNegativeInteger(recolorGeneration) || !Array.isArray(cohorts)) {
|
|
27140
|
+
return [];
|
|
27141
|
+
}
|
|
27142
|
+
return cohorts.filter(isObject14).filter((entry) => entry["generation"] === recolorGeneration);
|
|
27143
|
+
}
|
|
27144
|
+
function validateCurrentGenerationCohorts(cohorts, items, recolorGeneration, context) {
|
|
27145
|
+
const current = currentGenerationCohorts(cohorts, recolorGeneration);
|
|
27146
|
+
const errors = [];
|
|
27147
|
+
const seenIndices = /* @__PURE__ */ new Set();
|
|
27148
|
+
const duplicateIndices = /* @__PURE__ */ new Set();
|
|
27149
|
+
const membershipCounts = /* @__PURE__ */ new Map();
|
|
27150
|
+
for (const entry of current) {
|
|
27151
|
+
const index = entry["index"];
|
|
27152
|
+
if (isNonNegativeInteger(index) && typeof index === "number") {
|
|
27153
|
+
if (seenIndices.has(index)) {
|
|
27154
|
+
duplicateIndices.add(index);
|
|
27155
|
+
}
|
|
27156
|
+
seenIndices.add(index);
|
|
27157
|
+
}
|
|
27158
|
+
const itemKeys = entry["item_keys"];
|
|
27159
|
+
if (!Array.isArray(itemKeys)) {
|
|
27160
|
+
continue;
|
|
27161
|
+
}
|
|
27162
|
+
for (const key of itemKeys) {
|
|
27163
|
+
if (typeof key === "number" && Number.isInteger(key)) {
|
|
27164
|
+
membershipCounts.set(key, (membershipCounts.get(key) ?? 0) + 1);
|
|
27165
|
+
}
|
|
27166
|
+
}
|
|
27167
|
+
}
|
|
27168
|
+
for (const index of [...duplicateIndices].sort(
|
|
27169
|
+
(left, right) => left - right
|
|
27170
|
+
)) {
|
|
27171
|
+
errors.push(
|
|
27172
|
+
`${context} has duplicate current-generation cohorts[].index: ${index}.`
|
|
27173
|
+
);
|
|
27174
|
+
}
|
|
27175
|
+
const pairs = [...collectItemKeysAndStates(items)].sort(
|
|
27176
|
+
(left, right) => left.issueNum - right.issueNum
|
|
27177
|
+
);
|
|
27178
|
+
for (const { issueNum, state } of pairs) {
|
|
27179
|
+
const count = membershipCounts.get(issueNum) ?? 0;
|
|
27180
|
+
if (count === 1) {
|
|
27181
|
+
continue;
|
|
27182
|
+
}
|
|
27183
|
+
if (count === 0 && isEnumMember(COHORT_COVERAGE_EXEMPT_STATES, state)) {
|
|
27184
|
+
continue;
|
|
27185
|
+
}
|
|
27186
|
+
errors.push(
|
|
27187
|
+
`${context} item ${issueNum} in state ${pythonRepr9(state)} must appear in exactly one current-generation cohort; found ${count}.`
|
|
27188
|
+
);
|
|
27189
|
+
}
|
|
27190
|
+
return errors;
|
|
27191
|
+
}
|
|
27192
|
+
function validateCurrentCohortBound(currentCohort, cohorts, recolorGeneration, context) {
|
|
27193
|
+
if (!isNonNegativeInteger(currentCohort) || typeof currentCohort !== "number") {
|
|
27194
|
+
return [
|
|
27195
|
+
`${context} current_cohort must be a non-negative integer; found: ${pythonRepr9(currentCohort)}.`
|
|
27196
|
+
];
|
|
27197
|
+
}
|
|
27198
|
+
const indices = [];
|
|
27199
|
+
for (const entry of currentGenerationCohorts(cohorts, recolorGeneration)) {
|
|
27200
|
+
const index = entry["index"];
|
|
27201
|
+
if (isNonNegativeInteger(index) && typeof index === "number") {
|
|
27202
|
+
indices.push(index);
|
|
27203
|
+
}
|
|
27204
|
+
}
|
|
27205
|
+
if (indices.length === 0) {
|
|
27206
|
+
return [];
|
|
27207
|
+
}
|
|
27208
|
+
const highest = Math.max(...indices);
|
|
27209
|
+
if (currentCohort > highest) {
|
|
27210
|
+
return [
|
|
27211
|
+
`${context} current_cohort ${currentCohort} must not exceed the maximum current-generation cohorts[].index ${highest}.`
|
|
27212
|
+
];
|
|
27213
|
+
}
|
|
27214
|
+
return [];
|
|
27215
|
+
}
|
|
27216
|
+
function validateEdgeEndpoints(entry, entryContext, issueNums) {
|
|
27217
|
+
const errors = [];
|
|
27218
|
+
const endpoints = /* @__PURE__ */ new Map();
|
|
27219
|
+
for (const field of ["a", "b"]) {
|
|
27220
|
+
const value = entry[field];
|
|
27221
|
+
if (typeof value === "number" && Number.isInteger(value) && issueNums.has(value)) {
|
|
27222
|
+
endpoints.set(field, value);
|
|
27223
|
+
} else {
|
|
27224
|
+
errors.push(
|
|
27225
|
+
`${entryContext} ${field} ${pythonRepr9(value)} does not resolve to an items[].issue_num.`
|
|
27226
|
+
);
|
|
27227
|
+
}
|
|
27228
|
+
}
|
|
27229
|
+
if (endpoints.size !== 2) {
|
|
27230
|
+
return { errors, pair: null };
|
|
27231
|
+
}
|
|
27232
|
+
const first = endpoints.get("a") ?? 0;
|
|
27233
|
+
const second = endpoints.get("b") ?? 0;
|
|
27234
|
+
if (first === second) {
|
|
27235
|
+
errors.push(`${entryContext} endpoints must be distinct; found: ${first}.`);
|
|
27236
|
+
return { errors, pair: null };
|
|
27237
|
+
}
|
|
27238
|
+
if (first > second) {
|
|
27239
|
+
errors.push(
|
|
27240
|
+
`${entryContext} must be normalized with a < b; found: (${first}, ${second}).`
|
|
27241
|
+
);
|
|
27242
|
+
return { errors, pair: null };
|
|
27243
|
+
}
|
|
27244
|
+
return { errors, pair: [first, second] };
|
|
27245
|
+
}
|
|
27246
|
+
function validateConflictEdges(edges, issueNums, context) {
|
|
27247
|
+
if (!Array.isArray(edges)) {
|
|
27248
|
+
return [`${context} conflict_edges must be a list.`];
|
|
27249
|
+
}
|
|
27250
|
+
const errors = [];
|
|
27251
|
+
const seen = /* @__PURE__ */ new Set();
|
|
27252
|
+
const duplicates = /* @__PURE__ */ new Map();
|
|
27253
|
+
edges.forEach((entry, position) => {
|
|
27254
|
+
const entryContext = `${context} conflict_edges[${position}]`;
|
|
27255
|
+
if (!isObject14(entry)) {
|
|
27256
|
+
errors.push(`${entryContext} must be an object.`);
|
|
27257
|
+
return;
|
|
27258
|
+
}
|
|
27259
|
+
const { errors: endpointErrors, pair } = validateEdgeEndpoints(
|
|
27260
|
+
entry,
|
|
27261
|
+
entryContext,
|
|
27262
|
+
issueNums
|
|
27263
|
+
);
|
|
27264
|
+
errors.push(...endpointErrors);
|
|
27265
|
+
const reason = entry["reason"];
|
|
27266
|
+
if (!isEnumMember(VALID_EDGE_REASONS, reason)) {
|
|
27267
|
+
errors.push(
|
|
27268
|
+
enumError(entryContext, "reason", VALID_EDGE_REASONS, reason)
|
|
27269
|
+
);
|
|
27270
|
+
}
|
|
27271
|
+
if (pair === null) {
|
|
27272
|
+
return;
|
|
27273
|
+
}
|
|
27274
|
+
const key = `${pair[0]},${pair[1]}`;
|
|
27275
|
+
if (seen.has(key)) {
|
|
27276
|
+
duplicates.set(key, pair);
|
|
27277
|
+
}
|
|
27278
|
+
seen.add(key);
|
|
27279
|
+
});
|
|
27280
|
+
const ordered = [...duplicates.values()].sort(
|
|
27281
|
+
(left, right) => left[0] - right[0] || left[1] - right[1]
|
|
27282
|
+
);
|
|
27283
|
+
for (const pair of ordered) {
|
|
27284
|
+
errors.push(
|
|
27285
|
+
`${context} has duplicate conflict_edges[] pair: (${pair[0]}, ${pair[1]}).`
|
|
27286
|
+
);
|
|
27287
|
+
}
|
|
27288
|
+
return errors;
|
|
27289
|
+
}
|
|
27290
|
+
function validateReceiptArrays(state, context) {
|
|
27291
|
+
const errors = [];
|
|
27292
|
+
for (const key of RECEIPT_ARRAY_KEYS) {
|
|
27293
|
+
if (key in state && !Array.isArray(state[key])) {
|
|
27294
|
+
errors.push(`${context} ${key} must be a list when present.`);
|
|
27295
|
+
}
|
|
27296
|
+
}
|
|
27297
|
+
return errors;
|
|
27298
|
+
}
|
|
27299
|
+
|
|
27300
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-orchestrator-state-core.ts
|
|
27301
|
+
var CONTEXT = "Parallel checkpoint";
|
|
27302
|
+
var EXPECTED_ROUTE_ID2 = "parallel";
|
|
27303
|
+
var MIN_CONCURRENCY = 1;
|
|
27304
|
+
var MAX_CONCURRENCY = 8;
|
|
27305
|
+
var REQUIRED_KEYS4 = [
|
|
27306
|
+
"objective",
|
|
27307
|
+
"completed_steps",
|
|
27308
|
+
"next_step",
|
|
27309
|
+
"last_updated",
|
|
27310
|
+
"route_id",
|
|
27311
|
+
"parallel_slug",
|
|
27312
|
+
"parallel_manifest_path",
|
|
27313
|
+
"parallel_status_doc_path",
|
|
27314
|
+
"mode",
|
|
27315
|
+
"max_concurrency",
|
|
27316
|
+
"current_cohort",
|
|
27317
|
+
"recolor_generation",
|
|
27318
|
+
"cohorts",
|
|
27319
|
+
"items",
|
|
27320
|
+
"conflict_edges",
|
|
27321
|
+
"mutations",
|
|
27322
|
+
"drift_events"
|
|
27323
|
+
];
|
|
27324
|
+
function missingRequiredKeys(state) {
|
|
27325
|
+
return REQUIRED_KEYS4.filter((key) => !(key in state)).map(
|
|
27326
|
+
(key) => `${CONTEXT} missing required key: ${key}.`
|
|
27327
|
+
);
|
|
27328
|
+
}
|
|
27329
|
+
function validateIdentity(state) {
|
|
27330
|
+
const errors = [];
|
|
27331
|
+
const routeId = state["route_id"];
|
|
27332
|
+
if ("route_id" in state && routeId !== EXPECTED_ROUTE_ID2) {
|
|
27333
|
+
errors.push(
|
|
27334
|
+
`${CONTEXT} route_id must be '${EXPECTED_ROUTE_ID2}'; found: ${pythonRepr9(routeId)}.`
|
|
27335
|
+
);
|
|
27336
|
+
}
|
|
27337
|
+
const mode = state["mode"];
|
|
27338
|
+
if ("mode" in state && !isEnumMember(VALID_MODES, mode)) {
|
|
27339
|
+
errors.push(enumError(CONTEXT, "mode", VALID_MODES, mode));
|
|
27340
|
+
}
|
|
27341
|
+
const concurrency = state["max_concurrency"];
|
|
27342
|
+
if ("max_concurrency" in state && !inBoundedRange(concurrency, MIN_CONCURRENCY, MAX_CONCURRENCY)) {
|
|
27343
|
+
errors.push(
|
|
27344
|
+
`${CONTEXT} max_concurrency must be an integer from ${MIN_CONCURRENCY} through ${MAX_CONCURRENCY}; found: ${pythonRepr9(concurrency)}.`
|
|
27345
|
+
);
|
|
27346
|
+
}
|
|
27347
|
+
return errors;
|
|
27348
|
+
}
|
|
27349
|
+
function validateCollections(state) {
|
|
27350
|
+
const items = state["items"];
|
|
27351
|
+
const issueNums = collectIssueNumbers(items);
|
|
27352
|
+
const generation = state["recolor_generation"];
|
|
27353
|
+
const cohorts = state["cohorts"];
|
|
27354
|
+
const errors = [];
|
|
27355
|
+
if ("items" in state) {
|
|
27356
|
+
errors.push(...validateItems(items, CONTEXT));
|
|
27357
|
+
}
|
|
27358
|
+
if ("cohorts" in state) {
|
|
27359
|
+
errors.push(
|
|
27360
|
+
...validateCohortShapes(cohorts, issueNums, generation, CONTEXT)
|
|
27361
|
+
);
|
|
27362
|
+
errors.push(
|
|
27363
|
+
...validateCurrentGenerationCohorts(cohorts, items, generation, CONTEXT)
|
|
27364
|
+
);
|
|
27365
|
+
}
|
|
27366
|
+
if ("current_cohort" in state) {
|
|
27367
|
+
errors.push(
|
|
27368
|
+
...validateCurrentCohortBound(
|
|
27369
|
+
state["current_cohort"],
|
|
27370
|
+
cohorts,
|
|
27371
|
+
generation,
|
|
27372
|
+
CONTEXT
|
|
27373
|
+
)
|
|
27374
|
+
);
|
|
27375
|
+
}
|
|
27376
|
+
if ("conflict_edges" in state) {
|
|
27377
|
+
errors.push(
|
|
27378
|
+
...validateConflictEdges(state["conflict_edges"], issueNums, CONTEXT)
|
|
27379
|
+
);
|
|
27380
|
+
}
|
|
27381
|
+
if ("mutations" in state) {
|
|
27382
|
+
errors.push(
|
|
27383
|
+
...validateMutations(state["mutations"], issueNums, generation, CONTEXT)
|
|
27384
|
+
);
|
|
27385
|
+
}
|
|
27386
|
+
if ("drift_events" in state) {
|
|
27387
|
+
errors.push(
|
|
27388
|
+
...validateDriftEvents(state["drift_events"], issueNums, CONTEXT)
|
|
27389
|
+
);
|
|
27390
|
+
}
|
|
27391
|
+
errors.push(...validateReceiptArrays(state, CONTEXT));
|
|
27392
|
+
return errors;
|
|
27393
|
+
}
|
|
27394
|
+
function recordsCloseMutation(state) {
|
|
27395
|
+
const mutations = state["mutations"];
|
|
27396
|
+
if (!Array.isArray(mutations)) {
|
|
27397
|
+
return false;
|
|
27398
|
+
}
|
|
27399
|
+
return mutations.some(
|
|
27400
|
+
(entry) => isObject14(entry) && entry["op"] === "close"
|
|
27401
|
+
);
|
|
27402
|
+
}
|
|
27403
|
+
function validateCompletion2(state) {
|
|
27404
|
+
const errors = [];
|
|
27405
|
+
const items = state["items"];
|
|
27406
|
+
const entries = Array.isArray(items) ? items : [];
|
|
27407
|
+
entries.forEach((entry, index) => {
|
|
27408
|
+
if (!isObject14(entry)) {
|
|
27409
|
+
return;
|
|
27410
|
+
}
|
|
27411
|
+
if (entry["state"] === "withdrawn") {
|
|
27412
|
+
return;
|
|
27413
|
+
}
|
|
27414
|
+
const mergeStatus = entry["merge_status"];
|
|
27415
|
+
if (!isEnumMember(MERGED_MERGE_STATUSES, mergeStatus)) {
|
|
27416
|
+
errors.push(
|
|
27417
|
+
`${itemContext(CONTEXT, index)} completion validation failed: merge_status is not merged or worktree_removed; found: ${pythonRepr9(mergeStatus)}.`
|
|
27418
|
+
);
|
|
27419
|
+
}
|
|
27420
|
+
});
|
|
27421
|
+
if (state["mode"] === "open" && !recordsCloseMutation(state)) {
|
|
27422
|
+
errors.push(
|
|
27423
|
+
`${CONTEXT} completion validation failed: open mode requires a mutations[] entry with op 'close'.`
|
|
27424
|
+
);
|
|
27425
|
+
}
|
|
27426
|
+
return errors;
|
|
27427
|
+
}
|
|
27428
|
+
function validateParallelOrchestratorStateText(text, options = {}) {
|
|
27429
|
+
let state;
|
|
27430
|
+
try {
|
|
27431
|
+
state = JSON.parse(text);
|
|
27432
|
+
} catch (error2) {
|
|
27433
|
+
const detail = error2 instanceof Error ? error2.message : String(error2);
|
|
27434
|
+
return [`${CONTEXT} is not valid JSON: ${detail}.`];
|
|
27435
|
+
}
|
|
27436
|
+
if (!isObject14(state)) {
|
|
27437
|
+
return [`${CONTEXT} root must be a JSON object.`];
|
|
27438
|
+
}
|
|
27439
|
+
const errors = [];
|
|
27440
|
+
errors.push(...missingRequiredKeys(state));
|
|
27441
|
+
errors.push(...validateIdentity(state));
|
|
27442
|
+
errors.push(...scanProhibitedKeys(state, CONTEXT));
|
|
27443
|
+
errors.push(...validateCollections(state));
|
|
27444
|
+
errors.push(...validateCohortBarrierOrdering(state));
|
|
27445
|
+
if (options.requireComplete === true) {
|
|
27446
|
+
errors.push(...validateCompletion2(state));
|
|
27447
|
+
}
|
|
27448
|
+
return errors;
|
|
27449
|
+
}
|
|
27450
|
+
|
|
27451
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-planner-state-core.ts
|
|
27452
|
+
var CONTEXT2 = "Parallel planner checkpoint";
|
|
27453
|
+
var MIN_CONCURRENCY2 = 1;
|
|
27454
|
+
var MAX_CONCURRENCY2 = 8;
|
|
27455
|
+
var REQUIRED_KEYS5 = [
|
|
27456
|
+
"objective",
|
|
27457
|
+
"parallel_slug",
|
|
27458
|
+
"parallel_manifest_path",
|
|
27459
|
+
"mode",
|
|
27460
|
+
"max_concurrency",
|
|
27461
|
+
"items",
|
|
27462
|
+
"cohorts",
|
|
27463
|
+
"conflict_edges",
|
|
27464
|
+
"recolor_generation",
|
|
27465
|
+
"completed_steps",
|
|
27466
|
+
"next_step",
|
|
27467
|
+
"last_updated"
|
|
27468
|
+
];
|
|
27469
|
+
var REQUIRED_ITEM_KEYS = [
|
|
27470
|
+
"issue_num",
|
|
27471
|
+
"feature_folder",
|
|
27472
|
+
"kind",
|
|
27473
|
+
"state",
|
|
27474
|
+
"blast_radius",
|
|
27475
|
+
"preparation_status",
|
|
27476
|
+
"research_path",
|
|
27477
|
+
"plan_path",
|
|
27478
|
+
"preflight_status"
|
|
27479
|
+
];
|
|
27480
|
+
var VALID_COMPLEXITY_BANDS = [
|
|
27481
|
+
"C1",
|
|
27482
|
+
"C2",
|
|
27483
|
+
"C3",
|
|
27484
|
+
"C4"
|
|
27485
|
+
];
|
|
27486
|
+
var READY_NEXT_STEP2 = "PARALLEL_EXECUTION_READY";
|
|
27487
|
+
var READY_PREPARATION_STATUS = "prepared";
|
|
27488
|
+
var READY_PREFLIGHT_STATUS = "PREFLIGHT: ALL CLEAR";
|
|
27489
|
+
var READY_RADIUS_SOURCE = "declared";
|
|
27490
|
+
var MINIMUM_READY_ITEMS = 2;
|
|
27491
|
+
var READY_ITEM_PATH_KEYS = ["research_path", "plan_path"];
|
|
27492
|
+
function kickoffPathFor(slug) {
|
|
27493
|
+
return `artifacts/orchestration/parallel-kickoff-${pythonStr2(slug)}.md`;
|
|
27494
|
+
}
|
|
27495
|
+
function missingRequiredKeys2(state) {
|
|
27496
|
+
return REQUIRED_KEYS5.filter((key) => !(key in state)).map(
|
|
27497
|
+
(key) => `${CONTEXT2} missing required key: ${key}.`
|
|
27498
|
+
);
|
|
27499
|
+
}
|
|
27500
|
+
function validateIdentity2(state) {
|
|
27501
|
+
const errors = [];
|
|
27502
|
+
for (const key of ["parallel_slug", "parallel_manifest_path"]) {
|
|
27503
|
+
if (key in state && !isNonEmptyString2(state[key])) {
|
|
27504
|
+
errors.push(`${CONTEXT2} ${key} must be a non-empty string.`);
|
|
27505
|
+
}
|
|
27506
|
+
}
|
|
27507
|
+
const mode = state["mode"];
|
|
27508
|
+
if ("mode" in state && !isEnumMember(VALID_MODES, mode)) {
|
|
27509
|
+
errors.push(enumError(CONTEXT2, "mode", VALID_MODES, mode));
|
|
27510
|
+
}
|
|
27511
|
+
const concurrency = state["max_concurrency"];
|
|
27512
|
+
if ("max_concurrency" in state && !inBoundedRange(concurrency, MIN_CONCURRENCY2, MAX_CONCURRENCY2)) {
|
|
27513
|
+
errors.push(
|
|
27514
|
+
`${CONTEXT2} max_concurrency must be an integer from ${MIN_CONCURRENCY2} through ${MAX_CONCURRENCY2}; found: ${pythonRepr9(concurrency)}.`
|
|
27515
|
+
);
|
|
27516
|
+
}
|
|
27517
|
+
return errors;
|
|
27518
|
+
}
|
|
27519
|
+
function itemRecords(items) {
|
|
27520
|
+
if (!Array.isArray(items)) {
|
|
27521
|
+
return [];
|
|
27522
|
+
}
|
|
27523
|
+
const records = [];
|
|
27524
|
+
items.forEach((entry, index) => {
|
|
27525
|
+
if (isObject14(entry)) {
|
|
27526
|
+
records.push({ index, record: entry });
|
|
27527
|
+
}
|
|
27528
|
+
});
|
|
27529
|
+
return records;
|
|
27530
|
+
}
|
|
27531
|
+
function validateItemContract(items) {
|
|
27532
|
+
const errors = [];
|
|
27533
|
+
for (const { index, record: record2 } of itemRecords(items)) {
|
|
27534
|
+
const entryContext = itemContext(CONTEXT2, index);
|
|
27535
|
+
for (const key of REQUIRED_ITEM_KEYS) {
|
|
27536
|
+
if (!(key in record2)) {
|
|
27537
|
+
errors.push(`${entryContext} missing required key: ${key}.`);
|
|
27538
|
+
}
|
|
27539
|
+
}
|
|
27540
|
+
const band = record2["complexity_band"];
|
|
27541
|
+
if ("complexity_band" in record2 && !isEnumMember(VALID_COMPLEXITY_BANDS, band)) {
|
|
27542
|
+
errors.push(
|
|
27543
|
+
enumError(
|
|
27544
|
+
entryContext,
|
|
27545
|
+
"complexity_band",
|
|
27546
|
+
VALID_COMPLEXITY_BANDS,
|
|
27547
|
+
band
|
|
27548
|
+
)
|
|
27549
|
+
);
|
|
27550
|
+
}
|
|
27551
|
+
}
|
|
27552
|
+
return errors;
|
|
27553
|
+
}
|
|
27554
|
+
function validateCollections2(state) {
|
|
27555
|
+
const items = state["items"];
|
|
27556
|
+
const issueNums = collectIssueNumbers(items);
|
|
27557
|
+
const generation = state["recolor_generation"];
|
|
27558
|
+
const cohorts = state["cohorts"];
|
|
27559
|
+
const errors = [];
|
|
27560
|
+
if ("items" in state) {
|
|
27561
|
+
errors.push(...validateItems(items, CONTEXT2, true));
|
|
27562
|
+
errors.push(...validateItemContract(items));
|
|
27563
|
+
}
|
|
27564
|
+
if ("cohorts" in state) {
|
|
27565
|
+
errors.push(
|
|
27566
|
+
...validateCohortShapes(cohorts, issueNums, generation, CONTEXT2)
|
|
27567
|
+
);
|
|
27568
|
+
errors.push(
|
|
27569
|
+
...validateCurrentGenerationCohorts(cohorts, items, generation, CONTEXT2)
|
|
27570
|
+
);
|
|
27571
|
+
}
|
|
27572
|
+
if ("current_cohort" in state) {
|
|
27573
|
+
errors.push(
|
|
27574
|
+
...validateCurrentCohortBound(
|
|
27575
|
+
state["current_cohort"],
|
|
27576
|
+
cohorts,
|
|
27577
|
+
generation,
|
|
27578
|
+
CONTEXT2
|
|
27579
|
+
)
|
|
27580
|
+
);
|
|
27581
|
+
}
|
|
27582
|
+
if ("conflict_edges" in state) {
|
|
27583
|
+
errors.push(
|
|
27584
|
+
...validateConflictEdges(state["conflict_edges"], issueNums, CONTEXT2)
|
|
27585
|
+
);
|
|
27586
|
+
}
|
|
27587
|
+
return errors;
|
|
27588
|
+
}
|
|
27589
|
+
function validateReadyItem(record2, entryContext) {
|
|
27590
|
+
const errors = [];
|
|
27591
|
+
const preparationStatus = record2["preparation_status"];
|
|
27592
|
+
if (preparationStatus !== READY_PREPARATION_STATUS) {
|
|
27593
|
+
errors.push(
|
|
27594
|
+
`${entryContext} preparation_status must be ${pythonRepr9(READY_PREPARATION_STATUS)}; found: ${pythonRepr9(preparationStatus)}.`
|
|
27595
|
+
);
|
|
27596
|
+
}
|
|
27597
|
+
const preflightStatus = record2["preflight_status"];
|
|
27598
|
+
if (preflightStatus !== READY_PREFLIGHT_STATUS) {
|
|
27599
|
+
errors.push(
|
|
27600
|
+
`${entryContext} preflight_status must be ${pythonRepr9(READY_PREFLIGHT_STATUS)}; found: ${pythonRepr9(preflightStatus)}.`
|
|
27601
|
+
);
|
|
27602
|
+
}
|
|
27603
|
+
for (const key of READY_ITEM_PATH_KEYS) {
|
|
27604
|
+
if (!isNonEmptyString2(record2[key])) {
|
|
27605
|
+
errors.push(`${entryContext} ${key} must be a non-empty string.`);
|
|
27606
|
+
}
|
|
27607
|
+
}
|
|
27608
|
+
const radius = record2["blast_radius"];
|
|
27609
|
+
const source = isObject14(radius) ? radius["source"] : null;
|
|
27610
|
+
if (source !== READY_RADIUS_SOURCE) {
|
|
27611
|
+
errors.push(
|
|
27612
|
+
`${entryContext} blast_radius.source must be ${pythonRepr9(READY_RADIUS_SOURCE)} for execution readiness; found: ${pythonRepr9(source)}.`
|
|
27613
|
+
);
|
|
27614
|
+
}
|
|
27615
|
+
return errors;
|
|
27616
|
+
}
|
|
27617
|
+
function validateReadyGate(state) {
|
|
27618
|
+
const errors = [];
|
|
27619
|
+
const items = state["items"];
|
|
27620
|
+
if (Array.isArray(items)) {
|
|
27621
|
+
const count = items.length;
|
|
27622
|
+
if (count < MINIMUM_READY_ITEMS) {
|
|
27623
|
+
errors.push(
|
|
27624
|
+
`${CONTEXT2} requires at least ${MINIMUM_READY_ITEMS} items for execution readiness; found: ${count}.`
|
|
27625
|
+
);
|
|
27626
|
+
}
|
|
27627
|
+
for (const { index, record: record2 } of itemRecords(items)) {
|
|
27628
|
+
errors.push(...validateReadyItem(record2, itemContext(CONTEXT2, index)));
|
|
27629
|
+
}
|
|
27630
|
+
}
|
|
27631
|
+
const nextStep = state["next_step"];
|
|
27632
|
+
if (nextStep !== READY_NEXT_STEP2) {
|
|
27633
|
+
errors.push(
|
|
27634
|
+
`${CONTEXT2} next_step must be ${pythonRepr9(READY_NEXT_STEP2)}; found: ${pythonRepr9(nextStep)}.`
|
|
27635
|
+
);
|
|
27636
|
+
}
|
|
27637
|
+
const expectedKickoff = kickoffPathFor(state["parallel_slug"]);
|
|
27638
|
+
const kickoffPromptPath = state["kickoff_prompt_path"];
|
|
27639
|
+
if (kickoffPromptPath !== expectedKickoff) {
|
|
27640
|
+
errors.push(
|
|
27641
|
+
`${CONTEXT2} kickoff_prompt_path must be ${pythonRepr9(expectedKickoff)}; found: ${pythonRepr9(kickoffPromptPath)}.`
|
|
27642
|
+
);
|
|
27643
|
+
}
|
|
27644
|
+
return errors;
|
|
27645
|
+
}
|
|
27646
|
+
function validateParallelPlannerStateText(text, options = {}) {
|
|
27647
|
+
let state;
|
|
27648
|
+
try {
|
|
27649
|
+
state = JSON.parse(text);
|
|
27650
|
+
} catch (error2) {
|
|
27651
|
+
const detail = error2 instanceof Error ? error2.message : String(error2);
|
|
27652
|
+
return [`${CONTEXT2} is not valid JSON: ${detail}.`];
|
|
27653
|
+
}
|
|
27654
|
+
if (!isObject14(state)) {
|
|
27655
|
+
return [`${CONTEXT2} root must be a JSON object.`];
|
|
27656
|
+
}
|
|
27657
|
+
const errors = [];
|
|
27658
|
+
errors.push(...missingRequiredKeys2(state));
|
|
27659
|
+
errors.push(...validateIdentity2(state));
|
|
27660
|
+
errors.push(...scanProhibitedKeys(state, CONTEXT2));
|
|
27661
|
+
errors.push(...validateCollections2(state));
|
|
27662
|
+
if (options.requireReadyForExecution === true) {
|
|
27663
|
+
errors.push(...validateReadyGate(state));
|
|
27664
|
+
}
|
|
27665
|
+
return errors;
|
|
27666
|
+
}
|
|
27667
|
+
|
|
27668
|
+
// ../../extensions/drm-copilot/src/lib/validate/policy-audit-artifact.ts
|
|
27669
|
+
var COVERAGE_PERCENT_RE = /\b\d+(?:\.\d+)?%/;
|
|
27670
|
+
var POLICY_AUDIT_REQUIRED_HEADINGS = [
|
|
27671
|
+
"## Executive Summary",
|
|
27672
|
+
"## 1. General Unit Test Policy Compliance",
|
|
27673
|
+
"## 2. General Code Change Policy Compliance",
|
|
27674
|
+
"## 3. Language-Specific Code Change Policy Compliance",
|
|
27675
|
+
"## 4. Language-Specific Unit Test Policy Compliance",
|
|
27676
|
+
"## 5. Test Coverage Detail",
|
|
27677
|
+
"## 6. Test Execution Metrics",
|
|
27678
|
+
"## 7. Code Quality Checks",
|
|
27679
|
+
"## 8. Gaps and Exceptions",
|
|
27680
|
+
"## 9. Summary of Changes",
|
|
27681
|
+
"## 10. Compliance Verdict",
|
|
27682
|
+
"## Appendix A: Test Inventory",
|
|
27683
|
+
"## Appendix B: Toolchain Commands Reference"
|
|
27684
|
+
];
|
|
27685
|
+
var POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = [
|
|
27686
|
+
"TypeScript baseline coverage artifact:",
|
|
27687
|
+
"TypeScript post-change coverage artifact:",
|
|
27688
|
+
"PowerShell baseline coverage artifact:",
|
|
27689
|
+
"PowerShell post-change coverage artifact:",
|
|
27690
|
+
"Per-language comparison summary:"
|
|
27691
|
+
];
|
|
27692
|
+
var POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison";
|
|
27693
|
+
var PLACEHOLDER_MARKERS = [
|
|
27694
|
+
"[n]",
|
|
27695
|
+
"[path",
|
|
27696
|
+
"[artifact",
|
|
27697
|
+
"[section reference",
|
|
27698
|
+
"[language]",
|
|
27699
|
+
"tbd",
|
|
27700
|
+
"unverified",
|
|
27701
|
+
"missing"
|
|
27702
|
+
];
|
|
27703
|
+
var TEMPLATE_RESOLVER_TOOL = "resolve_policy_audit_template_asset";
|
|
27704
|
+
var TEMPLATE_RESOLVER_MISSING_MARKERS = [
|
|
27705
|
+
"not exposed",
|
|
27706
|
+
"was not exposed",
|
|
27707
|
+
"missing resolver exposure",
|
|
27708
|
+
"fallback template",
|
|
27709
|
+
"fallback-template"
|
|
27710
|
+
];
|
|
27711
|
+
function hasNumericCoverage(value) {
|
|
27712
|
+
return COVERAGE_PERCENT_RE.test(value);
|
|
27713
|
+
}
|
|
27714
|
+
function isNaValue(value) {
|
|
27715
|
+
return value.trim().toLowerCase().startsWith("n/a");
|
|
27716
|
+
}
|
|
27717
|
+
function hasPlaceholderMarker(value) {
|
|
27718
|
+
const lowered = value.toLowerCase();
|
|
27719
|
+
return PLACEHOLDER_MARKERS.some((marker) => lowered.includes(marker));
|
|
27720
|
+
}
|
|
27721
|
+
function reportsMissingTemplateResolverSuccess(text) {
|
|
27722
|
+
const lowered = text.toLowerCase();
|
|
27723
|
+
if (!lowered.includes(TEMPLATE_RESOLVER_TOOL)) {
|
|
27724
|
+
return false;
|
|
27725
|
+
}
|
|
27726
|
+
if (!TEMPLATE_RESOLVER_MISSING_MARKERS.some((m) => lowered.includes(m))) {
|
|
27727
|
+
return false;
|
|
27728
|
+
}
|
|
27729
|
+
return /\b(pass|ready|readiness)\b/.test(lowered);
|
|
27730
|
+
}
|
|
27731
|
+
function extractPolicyAuditCoverageRows(text) {
|
|
27732
|
+
const rows = [];
|
|
27733
|
+
for (const line of text.split("\n")) {
|
|
27734
|
+
if (!line.startsWith("|")) {
|
|
27735
|
+
continue;
|
|
27736
|
+
}
|
|
27737
|
+
const segments = line.split("|");
|
|
27738
|
+
const cells = segments.slice(1, -1).map((cell) => cell.trim());
|
|
27739
|
+
if (cells.length !== 7) {
|
|
27740
|
+
continue;
|
|
27741
|
+
}
|
|
27742
|
+
const language = cells[0] ?? "";
|
|
27743
|
+
if (language === "Language" || language === "----------" || !language) {
|
|
27744
|
+
continue;
|
|
27745
|
+
}
|
|
27746
|
+
if (language.length > 0 && /^-+$/.test(language)) {
|
|
27747
|
+
continue;
|
|
27748
|
+
}
|
|
27749
|
+
rows.push({
|
|
27750
|
+
Language: language,
|
|
27751
|
+
"Files Changed": cells[1] ?? "",
|
|
27752
|
+
Tests: cells[2] ?? "",
|
|
27753
|
+
"Test Result": cells[3] ?? "",
|
|
27754
|
+
"Baseline Coverage": cells[4] ?? "",
|
|
27755
|
+
"Post-Change Coverage": cells[5] ?? "",
|
|
27756
|
+
"New Code Coverage": cells[6] ?? ""
|
|
27757
|
+
});
|
|
27758
|
+
}
|
|
27759
|
+
return rows;
|
|
27760
|
+
}
|
|
27761
|
+
function findPolicyAuditChecklistLine(text, label) {
|
|
27762
|
+
for (const line of text.split("\n")) {
|
|
27763
|
+
const stripped = line.trim();
|
|
27764
|
+
if (stripped.startsWith("- ") && stripped.includes(label)) {
|
|
27765
|
+
return stripped;
|
|
27766
|
+
}
|
|
27767
|
+
}
|
|
27768
|
+
return null;
|
|
27769
|
+
}
|
|
27770
|
+
function extractPolicyAuditComparisonLines(text) {
|
|
27771
|
+
let inSection = false;
|
|
27772
|
+
const comparisonLines = /* @__PURE__ */ new Map();
|
|
27773
|
+
for (const line of text.split("\n")) {
|
|
27774
|
+
const stripped = line.trim();
|
|
27775
|
+
if (stripped === POLICY_AUDIT_COMPARISON_HEADING) {
|
|
27776
|
+
inSection = true;
|
|
27777
|
+
continue;
|
|
27778
|
+
}
|
|
27779
|
+
if (inSection && stripped.startsWith("### ")) {
|
|
27780
|
+
break;
|
|
27781
|
+
}
|
|
27782
|
+
if (!inSection || !stripped.startsWith("- ")) {
|
|
26206
27783
|
continue;
|
|
26207
27784
|
}
|
|
26208
27785
|
const body = stripped.slice(2);
|
|
@@ -26492,6 +28069,20 @@ function validateArtifact(input) {
|
|
|
26492
28069
|
}
|
|
26493
28070
|
case "epic-kickoff":
|
|
26494
28071
|
return validateEpicKickoffText(input.text);
|
|
28072
|
+
case "parallel-orchestrator-state": {
|
|
28073
|
+
const options = {
|
|
28074
|
+
...input.requireComplete === void 0 ? {} : { requireComplete: input.requireComplete }
|
|
28075
|
+
};
|
|
28076
|
+
return validateParallelOrchestratorStateText(input.text, options);
|
|
28077
|
+
}
|
|
28078
|
+
case "parallel-planner-state": {
|
|
28079
|
+
const options = {
|
|
28080
|
+
...input.requireReadyForExecution === void 0 ? {} : { requireReadyForExecution: input.requireReadyForExecution }
|
|
28081
|
+
};
|
|
28082
|
+
return validateParallelPlannerStateText(input.text, options);
|
|
28083
|
+
}
|
|
28084
|
+
case "parallel-kickoff":
|
|
28085
|
+
return validateParallelKickoffText(input.text);
|
|
26495
28086
|
default:
|
|
26496
28087
|
return [`Unsupported artifact type: ${input.artifactType}`];
|
|
26497
28088
|
}
|
|
@@ -28065,7 +29656,7 @@ function resolveReadinessSignal(fs9, featureDir) {
|
|
|
28065
29656
|
}
|
|
28066
29657
|
return [null, null];
|
|
28067
29658
|
}
|
|
28068
|
-
function
|
|
29659
|
+
function relativeToPosix5(root, path11) {
|
|
28069
29660
|
const normalizedRoot = toPosixPath2(root).replace(/\/+$/u, "");
|
|
28070
29661
|
const normalized = toPosixPath2(path11);
|
|
28071
29662
|
if (normalized.startsWith(`${normalizedRoot}/`)) {
|
|
@@ -28103,7 +29694,7 @@ function discoverCanonicalEvidenceFiles(fs9, root, feature) {
|
|
|
28103
29694
|
for (const pattern of CANONICAL_GLOBS) {
|
|
28104
29695
|
for (const candidate of fs9.glob(featureRoot, pattern)) {
|
|
28105
29696
|
if (fs9.isFile(candidate)) {
|
|
28106
|
-
discovered.add(
|
|
29697
|
+
discovered.add(relativeToPosix6(normalizedRoot, candidate));
|
|
28107
29698
|
}
|
|
28108
29699
|
}
|
|
28109
29700
|
}
|
|
@@ -28174,7 +29765,7 @@ function parseIntegerStrict(value) {
|
|
|
28174
29765
|
}
|
|
28175
29766
|
return Number.parseInt(value, 10);
|
|
28176
29767
|
}
|
|
28177
|
-
function
|
|
29768
|
+
function relativeToPosix6(root, absolute) {
|
|
28178
29769
|
const normalized = toPosixPath2(absolute);
|
|
28179
29770
|
if (normalized.startsWith(`${root}/`)) {
|
|
28180
29771
|
return normalized.slice(root.length + 1);
|
|
@@ -28371,11 +29962,11 @@ function buildContextFiles(params) {
|
|
|
28371
29962
|
const contextFiles = [];
|
|
28372
29963
|
for (const path11 of candidatePaths) {
|
|
28373
29964
|
if (fs9.exists(path11)) {
|
|
28374
|
-
contextFiles.push(
|
|
29965
|
+
contextFiles.push(relativeToPosix5(root, path11));
|
|
28375
29966
|
}
|
|
28376
29967
|
}
|
|
28377
29968
|
if (readinessSource !== null) {
|
|
28378
|
-
contextFiles.push(
|
|
29969
|
+
contextFiles.push(relativeToPosix5(root, readinessSource));
|
|
28379
29970
|
}
|
|
28380
29971
|
const evidenceContextFiles = discoverCanonicalEvidenceFiles(
|
|
28381
29972
|
fs9,
|