@danmoisan/drm-copilot-mcp 1.0.11 → 1.0.13
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 +585 -123
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +4 -3
- package/resources/claude-customizations/.claude/hooks/persist-session-id.ps1 +153 -0
- package/resources/claude-customizations/.claude/settings.json +13 -0
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +51 -24
- package/resources/claude-customizations/.claude/skills/identify-session-id/SKILL.md +44 -0
- package/resources/claude-customizations/.claude/skills/show-my-agent-tree/SKILL.md +39 -0
- package/resources/claude-customizations/pack-manifests/core.json +3 -0
- package/resources/feature-templates/epic/epic-status.md +20 -0
- package/resources/feature-templates/epic/epic.md +79 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +4 -0
- package/resources/templates/new-claude-worktree-session.ps1 +58 -9
- package/resources/feature-templates/epic/initiative.md +0 -43
package/out/mcp-server.js
CHANGED
|
@@ -8964,13 +8964,13 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
8964
8964
|
}
|
|
8965
8965
|
return propValues;
|
|
8966
8966
|
});
|
|
8967
|
-
const
|
|
8967
|
+
const isObject9 = isObject;
|
|
8968
8968
|
const catchall = def.catchall;
|
|
8969
8969
|
let value;
|
|
8970
8970
|
inst._zod.parse = (payload, ctx) => {
|
|
8971
8971
|
value ?? (value = _normalized.value);
|
|
8972
8972
|
const input = payload.value;
|
|
8973
|
-
if (!
|
|
8973
|
+
if (!isObject9(input)) {
|
|
8974
8974
|
payload.issues.push({
|
|
8975
8975
|
expected: "object",
|
|
8976
8976
|
code: "invalid_type",
|
|
@@ -9097,7 +9097,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
9097
9097
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
9098
9098
|
};
|
|
9099
9099
|
let fastpass;
|
|
9100
|
-
const
|
|
9100
|
+
const isObject9 = isObject;
|
|
9101
9101
|
const jit = !globalConfig.jitless;
|
|
9102
9102
|
const allowsEval2 = allowsEval;
|
|
9103
9103
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -9106,7 +9106,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
9106
9106
|
inst._zod.parse = (payload, ctx) => {
|
|
9107
9107
|
value ?? (value = _normalized.value);
|
|
9108
9108
|
const input = payload.value;
|
|
9109
|
-
if (!
|
|
9109
|
+
if (!isObject9(input)) {
|
|
9110
9110
|
payload.issues.push({
|
|
9111
9111
|
expected: "object",
|
|
9112
9112
|
code: "invalid_type",
|
|
@@ -15561,6 +15561,19 @@ function createBufferedOutput() {
|
|
|
15561
15561
|
lines
|
|
15562
15562
|
};
|
|
15563
15563
|
}
|
|
15564
|
+
function getClaudeProjectsRoot(env = process.env) {
|
|
15565
|
+
const configDirOverride = env["CLAUDE_CONFIG_DIR"]?.trim();
|
|
15566
|
+
if (configDirOverride !== void 0 && configDirOverride.length > 0) {
|
|
15567
|
+
return path2.join(configDirOverride, "projects").replace(/\\/g, "/");
|
|
15568
|
+
}
|
|
15569
|
+
const home = env["HOME"]?.trim() || env["USERPROFILE"]?.trim();
|
|
15570
|
+
if (home === void 0 || home.length === 0) {
|
|
15571
|
+
throw new Error(
|
|
15572
|
+
"Cannot resolve the user-global Claude projects directory: none of CLAUDE_CONFIG_DIR, HOME, or USERPROFILE is set."
|
|
15573
|
+
);
|
|
15574
|
+
}
|
|
15575
|
+
return path2.join(home, ".claude", "projects").replace(/\\/g, "/");
|
|
15576
|
+
}
|
|
15564
15577
|
function resolveBundledScriptPath(extensionRoot, bundledRelativePath) {
|
|
15565
15578
|
const normalizedExtensionRoot = extensionRoot.replace(/\\/g, "/");
|
|
15566
15579
|
const normalizedBundledRelativePath = bundledRelativePath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
@@ -16222,6 +16235,22 @@ var REPO_AUTOMATION_TOOL_DEFINITIONS = [
|
|
|
16222
16235
|
required: ["artifact_type", "artifact_path"],
|
|
16223
16236
|
additionalProperties: false
|
|
16224
16237
|
}
|
|
16238
|
+
},
|
|
16239
|
+
{
|
|
16240
|
+
name: "render_subagent_tree",
|
|
16241
|
+
description: "Render the subagent call tree for a root session id. The session id is a transcript filename stem; the transcript is resolved under the user-global Claude projects directory, searching the encoded workspace directory plus its '-wt-' worktree siblings (case-insensitive) and returning the first match deterministically.",
|
|
16242
|
+
inputSchema: {
|
|
16243
|
+
type: "object",
|
|
16244
|
+
properties: {
|
|
16245
|
+
workspace_root: workspaceRootProperty,
|
|
16246
|
+
session_id: {
|
|
16247
|
+
type: "string",
|
|
16248
|
+
description: "Root session identifier (transcript filename stem under ~/.claude/projects/<encoded-workspace>/, e.g. a UUIDv4)."
|
|
16249
|
+
}
|
|
16250
|
+
},
|
|
16251
|
+
required: ["session_id"],
|
|
16252
|
+
additionalProperties: false
|
|
16253
|
+
}
|
|
16225
16254
|
}
|
|
16226
16255
|
];
|
|
16227
16256
|
|
|
@@ -16246,7 +16275,8 @@ var REPO_AUTOMATION_TOOLS = [
|
|
|
16246
16275
|
"resolve_policy_audit_template_asset",
|
|
16247
16276
|
"resolve_execute_hard_lock_prompt",
|
|
16248
16277
|
"resolve_atomic_plan_prompt",
|
|
16249
|
-
"validate_orchestration_artifacts"
|
|
16278
|
+
"validate_orchestration_artifacts",
|
|
16279
|
+
"render_subagent_tree"
|
|
16250
16280
|
];
|
|
16251
16281
|
|
|
16252
16282
|
// ../../extensions/drm-copilot/src/mcp-tool-inputs-push-down.ts
|
|
@@ -16700,6 +16730,24 @@ async function handleResolveExecuteHardLockPrompt(rawInput, service) {
|
|
|
16700
16730
|
});
|
|
16701
16731
|
}
|
|
16702
16732
|
|
|
16733
|
+
// ../../extensions/drm-copilot/src/mcp-tool-inputs-subagent-tree.ts
|
|
16734
|
+
function resolveRenderSubagentTreeToolInput(rawInput, fallbackWorkspaceRoot) {
|
|
16735
|
+
const args = asToolArgumentObject(rawInput);
|
|
16736
|
+
return {
|
|
16737
|
+
workspaceRoot: normalizeWorkspaceRoot(
|
|
16738
|
+
args["workspace_root"],
|
|
16739
|
+
fallbackWorkspaceRoot
|
|
16740
|
+
),
|
|
16741
|
+
sessionId: normalizeRequiredText(args["session_id"], "session_id")
|
|
16742
|
+
};
|
|
16743
|
+
}
|
|
16744
|
+
|
|
16745
|
+
// ../../extensions/drm-copilot/src/mcp-handlers/render-subagent-tree-handler.ts
|
|
16746
|
+
async function handleRenderSubagentTree(rawInput, service) {
|
|
16747
|
+
const input = resolveRenderSubagentTreeToolInput(rawInput);
|
|
16748
|
+
return service.renderSubagentTree(input);
|
|
16749
|
+
}
|
|
16750
|
+
|
|
16703
16751
|
// ../../extensions/drm-copilot/src/mcp-handlers/template-validation-handlers.ts
|
|
16704
16752
|
async function handleResolvePolicyAuditTemplateAsset(rawInput, service) {
|
|
16705
16753
|
const input = resolvePolicyAuditTemplateAssetToolInput(rawInput);
|
|
@@ -16727,7 +16775,8 @@ function toMcpToolResult(result) {
|
|
|
16727
16775
|
...result.artifacts === void 0 ? {} : { artifacts: result.artifacts },
|
|
16728
16776
|
...result.assetId === void 0 ? {} : { asset_id: result.assetId },
|
|
16729
16777
|
...result.bundledSourcePath === void 0 ? {} : { bundled_source_path: result.bundledSourcePath },
|
|
16730
|
-
...result.destinationPath === void 0 ? {} : { destination_path: result.destinationPath }
|
|
16778
|
+
...result.destinationPath === void 0 ? {} : { destination_path: result.destinationPath },
|
|
16779
|
+
...result.renderedTree === void 0 ? {} : { rendered_tree: result.renderedTree }
|
|
16731
16780
|
};
|
|
16732
16781
|
}
|
|
16733
16782
|
function toFailureToolResult(tool, workspaceRoot, error2) {
|
|
@@ -16833,6 +16882,11 @@ async function dispatchRepoAutomationTool(toolName, rawInput, service) {
|
|
|
16833
16882
|
await handleValidateOrchestrationArtifacts(rawInput, service)
|
|
16834
16883
|
);
|
|
16835
16884
|
}
|
|
16885
|
+
case "render_subagent_tree": {
|
|
16886
|
+
return toMcpToolResult(
|
|
16887
|
+
await handleRenderSubagentTree(rawInput, service)
|
|
16888
|
+
);
|
|
16889
|
+
}
|
|
16836
16890
|
}
|
|
16837
16891
|
} catch (error2) {
|
|
16838
16892
|
return toFailureToolResult(toolName, workspaceRoot, error2);
|
|
@@ -17039,6 +17093,26 @@ function parseFirstArtifactPath(execution, pattern) {
|
|
|
17039
17093
|
return capturedPath && capturedPath.length > 0 ? normalizeGeneratedPath(capturedPath) : void 0;
|
|
17040
17094
|
}
|
|
17041
17095
|
|
|
17096
|
+
// ../../extensions/drm-copilot/src/repo-automation-execute-script.ts
|
|
17097
|
+
async function executeScriptServiceCall(output, extensionRoot, options) {
|
|
17098
|
+
const execution = await executeBundledScriptFromExtensionRoot(output, {
|
|
17099
|
+
runtimeKind: options.runtimeKind,
|
|
17100
|
+
bundledRelativePath: options.bundledRelativePath,
|
|
17101
|
+
commandId: options.invocationId,
|
|
17102
|
+
args: options.args,
|
|
17103
|
+
extensionRoot,
|
|
17104
|
+
workspaceRoot: options.workspaceRoot
|
|
17105
|
+
});
|
|
17106
|
+
const parsedArtifactPath = options.stdoutArtifactPattern === void 0 ? void 0 : parseFirstArtifactPath(execution, options.stdoutArtifactPattern);
|
|
17107
|
+
const artifacts = options.artifactPaths ?? (parsedArtifactPath === void 0 ? void 0 : [parsedArtifactPath]);
|
|
17108
|
+
return {
|
|
17109
|
+
tool: options.tool,
|
|
17110
|
+
workspaceRoot: options.workspaceRoot,
|
|
17111
|
+
summary: options.summary,
|
|
17112
|
+
...artifacts === void 0 ? {} : { artifacts }
|
|
17113
|
+
};
|
|
17114
|
+
}
|
|
17115
|
+
|
|
17042
17116
|
// ../../extensions/drm-copilot/src/repo-automation-args.ts
|
|
17043
17117
|
function buildPoshQcWorkflowArguments(tool, input) {
|
|
17044
17118
|
const toolConfig = POSH_QC_TOOL_CONFIG[tool];
|
|
@@ -21791,6 +21865,143 @@ var SubprocessRunner = class {
|
|
|
21791
21865
|
// ../../extensions/drm-copilot/src/lib/validate/validate-orchestration-service-call.ts
|
|
21792
21866
|
var path9 = __toESM(require("node:path"));
|
|
21793
21867
|
|
|
21868
|
+
// ../../extensions/drm-copilot/src/lib/validate/epic-orchestrator-state-resolution.ts
|
|
21869
|
+
var LIFECYCLE_PREFIXES = [
|
|
21870
|
+
"docs/features/active/",
|
|
21871
|
+
"docs/features/completed/",
|
|
21872
|
+
"active/",
|
|
21873
|
+
"completed/"
|
|
21874
|
+
];
|
|
21875
|
+
var VALID_EPIC_TYPES = /* @__PURE__ */ new Set(["business", "enabler"]);
|
|
21876
|
+
function isObject2(value) {
|
|
21877
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21878
|
+
}
|
|
21879
|
+
function pythonRepr(value) {
|
|
21880
|
+
if (value === null || value === void 0) {
|
|
21881
|
+
return "None";
|
|
21882
|
+
}
|
|
21883
|
+
if (typeof value === "boolean") {
|
|
21884
|
+
return value ? "True" : "False";
|
|
21885
|
+
}
|
|
21886
|
+
if (typeof value === "string") {
|
|
21887
|
+
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
21888
|
+
}
|
|
21889
|
+
return String(value);
|
|
21890
|
+
}
|
|
21891
|
+
function normalizeFolderHint(value) {
|
|
21892
|
+
for (const prefix of LIFECYCLE_PREFIXES) {
|
|
21893
|
+
if (value.startsWith(prefix)) {
|
|
21894
|
+
return value.slice(prefix.length);
|
|
21895
|
+
}
|
|
21896
|
+
}
|
|
21897
|
+
return value;
|
|
21898
|
+
}
|
|
21899
|
+
function buildFeatureReferenceIndex(features) {
|
|
21900
|
+
const byFolderHint = /* @__PURE__ */ new Map();
|
|
21901
|
+
const byIssueNum = /* @__PURE__ */ new Map();
|
|
21902
|
+
for (const feature of features) {
|
|
21903
|
+
const folder = feature["feature_folder"];
|
|
21904
|
+
if (typeof folder === "string" && folder) {
|
|
21905
|
+
byFolderHint.set(normalizeFolderHint(folder), folder);
|
|
21906
|
+
const issueNum = feature["issue_num"];
|
|
21907
|
+
if (issueNum !== void 0 && issueNum !== null) {
|
|
21908
|
+
byIssueNum.set(issueNum, folder);
|
|
21909
|
+
}
|
|
21910
|
+
}
|
|
21911
|
+
}
|
|
21912
|
+
return { byFolderHint, byIssueNum };
|
|
21913
|
+
}
|
|
21914
|
+
function resolveFeatureReference(dependency, index) {
|
|
21915
|
+
if (typeof dependency !== "string") {
|
|
21916
|
+
return index.byIssueNum.get(dependency) ?? null;
|
|
21917
|
+
}
|
|
21918
|
+
return index.byFolderHint.get(normalizeFolderHint(dependency)) ?? null;
|
|
21919
|
+
}
|
|
21920
|
+
function detectDependencyCycle(features) {
|
|
21921
|
+
const index = buildFeatureReferenceIndex(features);
|
|
21922
|
+
const graph = /* @__PURE__ */ new Map();
|
|
21923
|
+
for (const feature of features) {
|
|
21924
|
+
const folder = feature["feature_folder"];
|
|
21925
|
+
if (typeof folder !== "string" || !folder) {
|
|
21926
|
+
continue;
|
|
21927
|
+
}
|
|
21928
|
+
const dependsOn = feature["depends_on"];
|
|
21929
|
+
if (!Array.isArray(dependsOn)) {
|
|
21930
|
+
graph.set(folder, []);
|
|
21931
|
+
continue;
|
|
21932
|
+
}
|
|
21933
|
+
const resolvedEdges = [];
|
|
21934
|
+
for (const dependency of dependsOn) {
|
|
21935
|
+
const resolved = resolveFeatureReference(dependency, index);
|
|
21936
|
+
if (resolved !== null) {
|
|
21937
|
+
resolvedEdges.push(resolved);
|
|
21938
|
+
}
|
|
21939
|
+
}
|
|
21940
|
+
graph.set(folder, resolvedEdges);
|
|
21941
|
+
}
|
|
21942
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
21943
|
+
const visited = /* @__PURE__ */ new Set();
|
|
21944
|
+
function visit(node) {
|
|
21945
|
+
if (visiting.has(node)) {
|
|
21946
|
+
return node;
|
|
21947
|
+
}
|
|
21948
|
+
if (visited.has(node) || !graph.has(node)) {
|
|
21949
|
+
return null;
|
|
21950
|
+
}
|
|
21951
|
+
visiting.add(node);
|
|
21952
|
+
for (const dependency of graph.get(node) ?? []) {
|
|
21953
|
+
const cycleNode = visit(dependency);
|
|
21954
|
+
if (cycleNode !== null) {
|
|
21955
|
+
return cycleNode;
|
|
21956
|
+
}
|
|
21957
|
+
}
|
|
21958
|
+
visiting.delete(node);
|
|
21959
|
+
visited.add(node);
|
|
21960
|
+
return null;
|
|
21961
|
+
}
|
|
21962
|
+
for (const start of graph.keys()) {
|
|
21963
|
+
const cycleNode = visit(start);
|
|
21964
|
+
if (cycleNode !== null) {
|
|
21965
|
+
return `Epic checkpoint depends_on graph contains a cycle involving feature_folder: ${cycleNode}`;
|
|
21966
|
+
}
|
|
21967
|
+
}
|
|
21968
|
+
return null;
|
|
21969
|
+
}
|
|
21970
|
+
function validateIntentBlock(state) {
|
|
21971
|
+
if (!("intent" in state)) {
|
|
21972
|
+
return [];
|
|
21973
|
+
}
|
|
21974
|
+
const intent = state["intent"];
|
|
21975
|
+
if (!isObject2(intent)) {
|
|
21976
|
+
return ["Epic checkpoint intent must be an object."];
|
|
21977
|
+
}
|
|
21978
|
+
const errors = [];
|
|
21979
|
+
const epicType = intent["epic_type"];
|
|
21980
|
+
if (typeof epicType !== "string" || !VALID_EPIC_TYPES.has(epicType)) {
|
|
21981
|
+
errors.push(
|
|
21982
|
+
`Epic checkpoint intent.epic_type must be 'business' or 'enabler', found: ${pythonRepr(epicType)}`
|
|
21983
|
+
);
|
|
21984
|
+
}
|
|
21985
|
+
const hypothesis = intent["business_outcome_hypothesis"];
|
|
21986
|
+
if (typeof hypothesis !== "string" || !hypothesis.trim()) {
|
|
21987
|
+
errors.push(
|
|
21988
|
+
"Epic checkpoint intent.business_outcome_hypothesis must be a non-empty string."
|
|
21989
|
+
);
|
|
21990
|
+
}
|
|
21991
|
+
for (const fieldName of ["leading_indicators", "nfrs"]) {
|
|
21992
|
+
if (!(fieldName in intent)) {
|
|
21993
|
+
continue;
|
|
21994
|
+
}
|
|
21995
|
+
const value = intent[fieldName];
|
|
21996
|
+
if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
|
|
21997
|
+
errors.push(
|
|
21998
|
+
`Epic checkpoint intent.${fieldName} must be a list of strings.`
|
|
21999
|
+
);
|
|
22000
|
+
}
|
|
22001
|
+
}
|
|
22002
|
+
return errors;
|
|
22003
|
+
}
|
|
22004
|
+
|
|
21794
22005
|
// ../../extensions/drm-copilot/src/lib/validate/epic-orchestrator-state-core.ts
|
|
21795
22006
|
var REQUIRED_BASELINE_KEYS = [
|
|
21796
22007
|
"objective",
|
|
@@ -21820,7 +22031,7 @@ var MERGED_STATUSES = /* @__PURE__ */ new Set([
|
|
|
21820
22031
|
"merged",
|
|
21821
22032
|
"worktree_removed"
|
|
21822
22033
|
]);
|
|
21823
|
-
function
|
|
22034
|
+
function isObject3(value) {
|
|
21824
22035
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21825
22036
|
}
|
|
21826
22037
|
function extractFeatures(state) {
|
|
@@ -21828,7 +22039,7 @@ function extractFeatures(state) {
|
|
|
21828
22039
|
if (!Array.isArray(features)) {
|
|
21829
22040
|
return [];
|
|
21830
22041
|
}
|
|
21831
|
-
return features.filter(
|
|
22042
|
+
return features.filter(isObject3);
|
|
21832
22043
|
}
|
|
21833
22044
|
function missingBaselineAndEpicKeys(state) {
|
|
21834
22045
|
const errors = [];
|
|
@@ -21851,13 +22062,7 @@ function validateFeatureFolderUniquenessAndDependencies(features) {
|
|
|
21851
22062
|
const errors = [];
|
|
21852
22063
|
const seen = /* @__PURE__ */ new Set();
|
|
21853
22064
|
const duplicates = /* @__PURE__ */ new Set();
|
|
21854
|
-
const
|
|
21855
|
-
for (const feature of features) {
|
|
21856
|
-
const folder = feature["feature_folder"];
|
|
21857
|
-
if (typeof folder === "string" && folder) {
|
|
21858
|
-
allFolders.add(folder);
|
|
21859
|
-
}
|
|
21860
|
-
}
|
|
22065
|
+
const index = buildFeatureReferenceIndex(features);
|
|
21861
22066
|
for (const feature of features) {
|
|
21862
22067
|
const folder = feature["feature_folder"];
|
|
21863
22068
|
if (typeof folder !== "string" || !folder) {
|
|
@@ -21872,7 +22077,7 @@ function validateFeatureFolderUniquenessAndDependencies(features) {
|
|
|
21872
22077
|
continue;
|
|
21873
22078
|
}
|
|
21874
22079
|
for (const dependency of dependsOn) {
|
|
21875
|
-
if (
|
|
22080
|
+
if (resolveFeatureReference(dependency, index) === null) {
|
|
21876
22081
|
errors.push(
|
|
21877
22082
|
`Epic checkpoint feature '${folder}' depends_on unresolved feature_folder: ${JSON.stringify(dependency)}`
|
|
21878
22083
|
);
|
|
@@ -21886,49 +22091,6 @@ function validateFeatureFolderUniquenessAndDependencies(features) {
|
|
|
21886
22091
|
}
|
|
21887
22092
|
return errors;
|
|
21888
22093
|
}
|
|
21889
|
-
function detectDependencyCycle(features) {
|
|
21890
|
-
const graph = /* @__PURE__ */ new Map();
|
|
21891
|
-
for (const feature of features) {
|
|
21892
|
-
const folder = feature["feature_folder"];
|
|
21893
|
-
if (typeof folder !== "string" || !folder) {
|
|
21894
|
-
continue;
|
|
21895
|
-
}
|
|
21896
|
-
const dependsOn = feature["depends_on"];
|
|
21897
|
-
graph.set(
|
|
21898
|
-
folder,
|
|
21899
|
-
Array.isArray(dependsOn) ? dependsOn.filter(
|
|
21900
|
-
(d) => typeof d === "string"
|
|
21901
|
-
) : []
|
|
21902
|
-
);
|
|
21903
|
-
}
|
|
21904
|
-
const visiting = /* @__PURE__ */ new Set();
|
|
21905
|
-
const visited = /* @__PURE__ */ new Set();
|
|
21906
|
-
function visit(node) {
|
|
21907
|
-
if (visiting.has(node)) {
|
|
21908
|
-
return node;
|
|
21909
|
-
}
|
|
21910
|
-
if (visited.has(node) || !graph.has(node)) {
|
|
21911
|
-
return null;
|
|
21912
|
-
}
|
|
21913
|
-
visiting.add(node);
|
|
21914
|
-
for (const dependency of graph.get(node) ?? []) {
|
|
21915
|
-
const cycleNode = visit(dependency);
|
|
21916
|
-
if (cycleNode !== null) {
|
|
21917
|
-
return cycleNode;
|
|
21918
|
-
}
|
|
21919
|
-
}
|
|
21920
|
-
visiting.delete(node);
|
|
21921
|
-
visited.add(node);
|
|
21922
|
-
return null;
|
|
21923
|
-
}
|
|
21924
|
-
for (const start of graph.keys()) {
|
|
21925
|
-
const cycleNode = visit(start);
|
|
21926
|
-
if (cycleNode !== null) {
|
|
21927
|
-
return `Epic checkpoint depends_on graph contains a cycle involving feature_folder: ${cycleNode}`;
|
|
21928
|
-
}
|
|
21929
|
-
}
|
|
21930
|
-
return null;
|
|
21931
|
-
}
|
|
21932
22094
|
function validateMergeStatusEnum(features) {
|
|
21933
22095
|
const errors = [];
|
|
21934
22096
|
for (const feature of features) {
|
|
@@ -21951,6 +22113,7 @@ function validateWaveBarrierOrdering(features) {
|
|
|
21951
22113
|
byFolder.set(folder, feature);
|
|
21952
22114
|
}
|
|
21953
22115
|
}
|
|
22116
|
+
const index = buildFeatureReferenceIndex(features);
|
|
21954
22117
|
for (const feature of features) {
|
|
21955
22118
|
const folder = feature["feature_folder"];
|
|
21956
22119
|
const dependsOn = feature["depends_on"];
|
|
@@ -21959,7 +22122,8 @@ function validateWaveBarrierOrdering(features) {
|
|
|
21959
22122
|
}
|
|
21960
22123
|
const worktreeCreatedAt = feature["worktree_created_at"];
|
|
21961
22124
|
for (const dependency of dependsOn) {
|
|
21962
|
-
const
|
|
22125
|
+
const resolved = resolveFeatureReference(dependency, index);
|
|
22126
|
+
const dependencyFeature = resolved !== null ? byFolder.get(resolved) : void 0;
|
|
21963
22127
|
if (dependencyFeature === void 0) {
|
|
21964
22128
|
continue;
|
|
21965
22129
|
}
|
|
@@ -21982,15 +22146,17 @@ function validateWavesConsistency(state) {
|
|
|
21982
22146
|
if (!Array.isArray(waves)) {
|
|
21983
22147
|
return errors;
|
|
21984
22148
|
}
|
|
22149
|
+
const features = extractFeatures(state);
|
|
21985
22150
|
const featuresByFolder = /* @__PURE__ */ new Map();
|
|
21986
|
-
for (const feature of
|
|
22151
|
+
for (const feature of features) {
|
|
21987
22152
|
const folder = feature["feature_folder"];
|
|
21988
22153
|
if (typeof folder === "string") {
|
|
21989
22154
|
featuresByFolder.set(folder, feature);
|
|
21990
22155
|
}
|
|
21991
22156
|
}
|
|
22157
|
+
const index = buildFeatureReferenceIndex(features);
|
|
21992
22158
|
for (const waveItem of waves) {
|
|
21993
|
-
if (!
|
|
22159
|
+
if (!isObject3(waveItem)) {
|
|
21994
22160
|
continue;
|
|
21995
22161
|
}
|
|
21996
22162
|
const waveNumber = waveItem["wave_number"];
|
|
@@ -21999,7 +22165,8 @@ function validateWavesConsistency(state) {
|
|
|
21999
22165
|
continue;
|
|
22000
22166
|
}
|
|
22001
22167
|
for (const folder of folders) {
|
|
22002
|
-
const
|
|
22168
|
+
const resolved = resolveFeatureReference(folder, index);
|
|
22169
|
+
const feature = resolved !== null ? featuresByFolder.get(resolved) : void 0;
|
|
22003
22170
|
if (feature === void 0) {
|
|
22004
22171
|
continue;
|
|
22005
22172
|
}
|
|
@@ -22024,7 +22191,7 @@ function validateCompletion(features, state) {
|
|
|
22024
22191
|
}
|
|
22025
22192
|
}
|
|
22026
22193
|
const epicMergePr = state["epic_merge_pr"];
|
|
22027
|
-
const mergeCommitSha =
|
|
22194
|
+
const mergeCommitSha = isObject3(epicMergePr) ? epicMergePr["merge_commit_sha"] : void 0;
|
|
22028
22195
|
if (typeof mergeCommitSha !== "string" || !mergeCommitSha.trim()) {
|
|
22029
22196
|
errors.push(
|
|
22030
22197
|
"Epic checkpoint completion validation failed: epic_merge_pr.merge_commit_sha is missing or empty."
|
|
@@ -22041,7 +22208,7 @@ function validateEpicOrchestratorStateText(text, options = {}) {
|
|
|
22041
22208
|
`Epic checkpoint is not valid JSON: ${exc instanceof Error ? exc.message : String(exc)}`
|
|
22042
22209
|
];
|
|
22043
22210
|
}
|
|
22044
|
-
if (!
|
|
22211
|
+
if (!isObject3(state)) {
|
|
22045
22212
|
return ["Epic checkpoint root must be a JSON object."];
|
|
22046
22213
|
}
|
|
22047
22214
|
const stateMap = state;
|
|
@@ -22057,6 +22224,7 @@ function validateEpicOrchestratorStateText(text, options = {}) {
|
|
|
22057
22224
|
errors.push(...validateMergeStatusEnum(features));
|
|
22058
22225
|
errors.push(...validateWaveBarrierOrdering(features));
|
|
22059
22226
|
errors.push(...validateWavesConsistency(stateMap));
|
|
22227
|
+
errors.push(...validateIntentBlock(stateMap));
|
|
22060
22228
|
if (options.requireComplete === true) {
|
|
22061
22229
|
errors.push(...validateCompletion(features, stateMap));
|
|
22062
22230
|
}
|
|
@@ -22079,11 +22247,11 @@ var PROMOTION_RECEIPT_KEYS = [
|
|
|
22079
22247
|
"issue",
|
|
22080
22248
|
"feature_folder"
|
|
22081
22249
|
];
|
|
22082
|
-
function
|
|
22250
|
+
function isObject4(value) {
|
|
22083
22251
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22084
22252
|
}
|
|
22085
22253
|
function missingObjectKeys(value, keys) {
|
|
22086
|
-
if (!
|
|
22254
|
+
if (!isObject4(value)) {
|
|
22087
22255
|
return [...keys];
|
|
22088
22256
|
}
|
|
22089
22257
|
const missing = [];
|
|
@@ -22098,7 +22266,7 @@ function missingObjectKeys(value, keys) {
|
|
|
22098
22266
|
function validateCompletionPrGate(state) {
|
|
22099
22267
|
const prGate = state["pr_gate"];
|
|
22100
22268
|
const missing = missingObjectKeys(prGate, PR_GATE_KEYS);
|
|
22101
|
-
if (!
|
|
22269
|
+
if (!isObject4(prGate)) {
|
|
22102
22270
|
return [
|
|
22103
22271
|
`Checkpoint completion validation failed: pr_gate must be an object with keys: ${PR_GATE_KEYS.join(", ")}.`
|
|
22104
22272
|
];
|
|
@@ -22121,7 +22289,7 @@ function validateCompletionPrGate(state) {
|
|
|
22121
22289
|
function validateCompletionCiGate(state) {
|
|
22122
22290
|
const ciGate = state["ci_gate"];
|
|
22123
22291
|
const missing = missingObjectKeys(ciGate, CI_GATE_KEYS);
|
|
22124
|
-
if (!
|
|
22292
|
+
if (!isObject4(ciGate)) {
|
|
22125
22293
|
return [
|
|
22126
22294
|
`Checkpoint completion validation failed: ci_gate must be an object with keys: ${CI_GATE_KEYS.join(", ")}.`
|
|
22127
22295
|
];
|
|
@@ -22138,7 +22306,7 @@ function validateCompletionCiGate(state) {
|
|
|
22138
22306
|
);
|
|
22139
22307
|
}
|
|
22140
22308
|
const prGate = state["pr_gate"];
|
|
22141
|
-
const prHeadSha =
|
|
22309
|
+
const prHeadSha = isObject4(prGate) ? prGate["head_sha"] : null;
|
|
22142
22310
|
if (prHeadSha !== null && prHeadSha !== void 0 && ciGate["head_sha"] !== prHeadSha) {
|
|
22143
22311
|
errors.push(
|
|
22144
22312
|
"Checkpoint completion validation failed: ci_gate.head_sha must match pr_gate.head_sha."
|
|
@@ -22153,7 +22321,7 @@ function validateIssue232PromotionReceipts(state) {
|
|
|
22153
22321
|
const receipts = state["delegation_receipts"];
|
|
22154
22322
|
let promotionSource = "promotion_receipts";
|
|
22155
22323
|
let promotion = state["promotion_receipts"];
|
|
22156
|
-
if (
|
|
22324
|
+
if (isObject4(receipts)) {
|
|
22157
22325
|
const namespacedPromotion = receipts[PROMOTION_RECEIPT_NAMESPACE_KEY];
|
|
22158
22326
|
if (namespacedPromotion !== void 0 && namespacedPromotion !== null) {
|
|
22159
22327
|
promotionSource = "delegation_receipts.promotion";
|
|
@@ -22178,10 +22346,10 @@ var HUMAN_INTERACTION_RESPONSE_ENUM = /* @__PURE__ */ new Set([
|
|
|
22178
22346
|
"halt"
|
|
22179
22347
|
]);
|
|
22180
22348
|
var HUMAN_INTERACTION_EXCEPTION_RESPONSE = "exception";
|
|
22181
|
-
function
|
|
22349
|
+
function isObject5(value) {
|
|
22182
22350
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22183
22351
|
}
|
|
22184
|
-
function
|
|
22352
|
+
function pythonRepr2(value) {
|
|
22185
22353
|
if (value === null || value === void 0) {
|
|
22186
22354
|
return "None";
|
|
22187
22355
|
}
|
|
@@ -22195,7 +22363,7 @@ function pythonRepr(value) {
|
|
|
22195
22363
|
}
|
|
22196
22364
|
function validateHumanInteraction(humanInteraction) {
|
|
22197
22365
|
const errors = [];
|
|
22198
|
-
if (!
|
|
22366
|
+
if (!isObject5(humanInteraction)) {
|
|
22199
22367
|
errors.push("Checkpoint human_interaction must be an object when present.");
|
|
22200
22368
|
return errors;
|
|
22201
22369
|
}
|
|
@@ -22205,7 +22373,7 @@ function validateHumanInteraction(humanInteraction) {
|
|
|
22205
22373
|
return errors;
|
|
22206
22374
|
}
|
|
22207
22375
|
requirements.forEach((requirement, index) => {
|
|
22208
|
-
if (!
|
|
22376
|
+
if (!isObject5(requirement)) {
|
|
22209
22377
|
errors.push(
|
|
22210
22378
|
`Checkpoint human_interaction.requirements #${index} must be an object.`
|
|
22211
22379
|
);
|
|
@@ -22214,7 +22382,7 @@ function validateHumanInteraction(humanInteraction) {
|
|
|
22214
22382
|
const response = requirement["response"];
|
|
22215
22383
|
if (typeof response !== "string" || !HUMAN_INTERACTION_RESPONSE_ENUM.has(response)) {
|
|
22216
22384
|
errors.push(
|
|
22217
|
-
`Checkpoint human_interaction.requirements #${index} response must be one of scope_change, exception, halt; got: ` +
|
|
22385
|
+
`Checkpoint human_interaction.requirements #${index} response must be one of scope_change, exception, halt; got: ` + pythonRepr2(response)
|
|
22218
22386
|
);
|
|
22219
22387
|
return;
|
|
22220
22388
|
}
|
|
@@ -22235,7 +22403,7 @@ var REMEDIATION_LOOP_KEY = "remediation_loop";
|
|
|
22235
22403
|
var REMEDIATION_CYCLES_KEY = "cycles";
|
|
22236
22404
|
var EXECUTION_STATUSES_REQUIRING_CLEAR_PREFLIGHT = /* @__PURE__ */ new Set(["in_progress", "complete", "failed"]);
|
|
22237
22405
|
var PREFLIGHT_CLEARED_STATUS = "clear";
|
|
22238
|
-
function
|
|
22406
|
+
function isObject6(value) {
|
|
22239
22407
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22240
22408
|
}
|
|
22241
22409
|
function validateRemediationCycle(index, cycle) {
|
|
@@ -22249,7 +22417,7 @@ function validateRemediationCycle(index, cycle) {
|
|
|
22249
22417
|
const executionStatus = cycle["execution_status"];
|
|
22250
22418
|
if (typeof executionStatus === "string" && EXECUTION_STATUSES_REQUIRING_CLEAR_PREFLIGHT.has(executionStatus)) {
|
|
22251
22419
|
const preflight = cycle["preflight"];
|
|
22252
|
-
const preflightStatus =
|
|
22420
|
+
const preflightStatus = isObject6(preflight) ? preflight["final_status"] : void 0;
|
|
22253
22421
|
if (preflightStatus !== PREFLIGHT_CLEARED_STATUS) {
|
|
22254
22422
|
errors.push(
|
|
22255
22423
|
`Checkpoint remediation cycle #${index} execution_status is ${executionStatus} but preflight.final_status is not 'clear'.`
|
|
@@ -22265,7 +22433,7 @@ function validateRemediationCycle(index, cycle) {
|
|
|
22265
22433
|
}
|
|
22266
22434
|
function validateRemediationLoop(remediationLoop) {
|
|
22267
22435
|
const errors = [];
|
|
22268
|
-
if (!
|
|
22436
|
+
if (!isObject6(remediationLoop)) {
|
|
22269
22437
|
return errors;
|
|
22270
22438
|
}
|
|
22271
22439
|
const cycles = remediationLoop[REMEDIATION_CYCLES_KEY];
|
|
@@ -22273,7 +22441,7 @@ function validateRemediationLoop(remediationLoop) {
|
|
|
22273
22441
|
return errors;
|
|
22274
22442
|
}
|
|
22275
22443
|
cycles.forEach((cycle, index) => {
|
|
22276
|
-
if (!
|
|
22444
|
+
if (!isObject6(cycle)) {
|
|
22277
22445
|
errors.push(`Checkpoint remediation cycle #${index} must be an object.`);
|
|
22278
22446
|
return;
|
|
22279
22447
|
}
|
|
@@ -22284,7 +22452,7 @@ function validateRemediationLoop(remediationLoop) {
|
|
|
22284
22452
|
|
|
22285
22453
|
// ../../extensions/drm-copilot/src/lib/validate/orchestrator-state-routing.ts
|
|
22286
22454
|
var ROUTING_MATRIX_RELATIVE_PATH = "config/orchestration-routing.json";
|
|
22287
|
-
function
|
|
22455
|
+
function isObject7(value) {
|
|
22288
22456
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22289
22457
|
}
|
|
22290
22458
|
function loadRoutingMatrix(fs9, root) {
|
|
@@ -22321,7 +22489,7 @@ function listReceipts(receipts) {
|
|
|
22321
22489
|
if (!Array.isArray(receipts)) {
|
|
22322
22490
|
return [];
|
|
22323
22491
|
}
|
|
22324
|
-
return receipts.filter(
|
|
22492
|
+
return receipts.filter(isObject7);
|
|
22325
22493
|
}
|
|
22326
22494
|
function receiptAgents(state) {
|
|
22327
22495
|
const agents = /* @__PURE__ */ new Set();
|
|
@@ -22340,7 +22508,7 @@ function receiptSkills(state) {
|
|
|
22340
22508
|
return skills;
|
|
22341
22509
|
}
|
|
22342
22510
|
for (const receipt of receipts) {
|
|
22343
|
-
if (!
|
|
22511
|
+
if (!isObject7(receipt)) {
|
|
22344
22512
|
continue;
|
|
22345
22513
|
}
|
|
22346
22514
|
const skill = receipt["skill"];
|
|
@@ -22359,7 +22527,7 @@ function mcpTools(state) {
|
|
|
22359
22527
|
return tools;
|
|
22360
22528
|
}
|
|
22361
22529
|
for (const receipt of receipts) {
|
|
22362
|
-
if (!
|
|
22530
|
+
if (!isObject7(receipt)) {
|
|
22363
22531
|
continue;
|
|
22364
22532
|
}
|
|
22365
22533
|
const tool = receipt["tool"];
|
|
@@ -22391,7 +22559,7 @@ function validateLifecycleOperations(state) {
|
|
|
22391
22559
|
}
|
|
22392
22560
|
const errors = [];
|
|
22393
22561
|
operations.forEach((operation, index) => {
|
|
22394
|
-
if (!
|
|
22562
|
+
if (!isObject7(operation)) {
|
|
22395
22563
|
errors.push(
|
|
22396
22564
|
`Checkpoint lifecycle_operations #${index} must be an object.`
|
|
22397
22565
|
);
|
|
@@ -22407,11 +22575,11 @@ function validateLifecycleOperations(state) {
|
|
|
22407
22575
|
}
|
|
22408
22576
|
function validateRoutingContract(state, options = {}) {
|
|
22409
22577
|
const matrix = options.routingMatrix;
|
|
22410
|
-
if (!
|
|
22578
|
+
if (!isObject7(matrix)) {
|
|
22411
22579
|
return ["Routing matrix missing routes object."];
|
|
22412
22580
|
}
|
|
22413
22581
|
const rawRoutes = matrix["routes"];
|
|
22414
|
-
if (!
|
|
22582
|
+
if (!isObject7(rawRoutes)) {
|
|
22415
22583
|
return ["Routing matrix missing routes object."];
|
|
22416
22584
|
}
|
|
22417
22585
|
const routeIdValue = state["route_id"] !== void 0 ? state["route_id"] : state["path_selected"];
|
|
@@ -22420,7 +22588,7 @@ function validateRoutingContract(state, options = {}) {
|
|
|
22420
22588
|
}
|
|
22421
22589
|
const routeId = routeIdValue;
|
|
22422
22590
|
const rawRoute = rawRoutes[routeId];
|
|
22423
|
-
if (!
|
|
22591
|
+
if (!isObject7(rawRoute)) {
|
|
22424
22592
|
return [
|
|
22425
22593
|
`Checkpoint selected route has no routing-matrix entry: ${routeId}.`
|
|
22426
22594
|
];
|
|
@@ -22538,13 +22706,13 @@ var DELEGATING_AGENTS = /* @__PURE__ */ new Set([
|
|
|
22538
22706
|
"prd-feature",
|
|
22539
22707
|
"pr-author"
|
|
22540
22708
|
]);
|
|
22541
|
-
function
|
|
22709
|
+
function isObject8(value) {
|
|
22542
22710
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22543
22711
|
}
|
|
22544
22712
|
function validateListDelegationReceipts(receipts) {
|
|
22545
22713
|
const errors = [];
|
|
22546
22714
|
receipts.forEach((receipt, index) => {
|
|
22547
|
-
if (!
|
|
22715
|
+
if (!isObject8(receipt)) {
|
|
22548
22716
|
errors.push(`Checkpoint delegation receipt #${index} must be an object.`);
|
|
22549
22717
|
return;
|
|
22550
22718
|
}
|
|
@@ -22576,7 +22744,7 @@ function validateNamespacedDelegationReceipts(receipts) {
|
|
|
22576
22744
|
if (promotionReceipts === void 0 || promotionReceipts === null) {
|
|
22577
22745
|
return errors;
|
|
22578
22746
|
}
|
|
22579
|
-
if (!
|
|
22747
|
+
if (!isObject8(promotionReceipts)) {
|
|
22580
22748
|
errors.push(
|
|
22581
22749
|
"Checkpoint delegation_receipts.promotion must be an object namespace."
|
|
22582
22750
|
);
|
|
@@ -22606,7 +22774,7 @@ function delegatedAgents(stateMap) {
|
|
|
22606
22774
|
const receipts = stateMap["delegation_receipts"];
|
|
22607
22775
|
if (Array.isArray(receipts)) {
|
|
22608
22776
|
receipts.forEach((receipt) => {
|
|
22609
|
-
if (!
|
|
22777
|
+
if (!isObject8(receipt)) {
|
|
22610
22778
|
return;
|
|
22611
22779
|
}
|
|
22612
22780
|
const agentName = receipt["agent_name"];
|
|
@@ -22631,7 +22799,7 @@ function validateModelRoutingExistence(stateMap) {
|
|
|
22631
22799
|
const receipts = stateMap["model_routing_receipts"];
|
|
22632
22800
|
if (Array.isArray(receipts)) {
|
|
22633
22801
|
receipts.forEach((receipt) => {
|
|
22634
|
-
if (!
|
|
22802
|
+
if (!isObject8(receipt)) {
|
|
22635
22803
|
return;
|
|
22636
22804
|
}
|
|
22637
22805
|
const agent = receipt["agent"];
|
|
@@ -22658,7 +22826,7 @@ function validateOrchestratorStateText(text, options = {}) {
|
|
|
22658
22826
|
`Checkpoint is not valid JSON: ${exc instanceof Error ? exc.message : String(exc)}`
|
|
22659
22827
|
];
|
|
22660
22828
|
}
|
|
22661
|
-
if (!
|
|
22829
|
+
if (!isObject8(state)) {
|
|
22662
22830
|
return ["Checkpoint root must be a JSON object."];
|
|
22663
22831
|
}
|
|
22664
22832
|
const stateMap = state;
|
|
@@ -22683,7 +22851,7 @@ function validateOrchestratorStateText(text, options = {}) {
|
|
|
22683
22851
|
if (receipts !== void 0 && receipts !== null) {
|
|
22684
22852
|
if (Array.isArray(receipts)) {
|
|
22685
22853
|
errors.push(...validateListDelegationReceipts(receipts));
|
|
22686
|
-
} else if (
|
|
22854
|
+
} else if (isObject8(receipts)) {
|
|
22687
22855
|
errors.push(...validateNamespacedDelegationReceipts(receipts));
|
|
22688
22856
|
} else {
|
|
22689
22857
|
errors.push(
|
|
@@ -27041,6 +27209,13 @@ function copyTemplate(featureType, templateDir, targetDir, fs9) {
|
|
|
27041
27209
|
}
|
|
27042
27210
|
}
|
|
27043
27211
|
}
|
|
27212
|
+
} else if (featureType === "epic") {
|
|
27213
|
+
for (const name of ["epic.md", "epic-status.md"]) {
|
|
27214
|
+
const src = joinPosix13(templateDir, name);
|
|
27215
|
+
if (fs9.exists(src)) {
|
|
27216
|
+
fs9.copyFile(src, joinPosix13(targetDir, name));
|
|
27217
|
+
}
|
|
27218
|
+
}
|
|
27044
27219
|
} else {
|
|
27045
27220
|
fs9.copyTree(templateDir, targetDir);
|
|
27046
27221
|
}
|
|
@@ -27238,9 +27413,9 @@ function updateFeatureDocs(featureType, featureName, targetDir, issueField, owne
|
|
|
27238
27413
|
);
|
|
27239
27414
|
filesToOpen.push(spec, plan);
|
|
27240
27415
|
} else if (featureType === "epic") {
|
|
27241
|
-
const
|
|
27416
|
+
const epic = joinPosix13(targetDir, "epic.md");
|
|
27242
27417
|
applyHeaderAndSections(
|
|
27243
|
-
|
|
27418
|
+
epic,
|
|
27244
27419
|
featureName,
|
|
27245
27420
|
issueField,
|
|
27246
27421
|
ownerField,
|
|
@@ -27251,7 +27426,7 @@ function updateFeatureDocs(featureType, featureName, targetDir, issueField, owne
|
|
|
27251
27426
|
fs9,
|
|
27252
27427
|
[]
|
|
27253
27428
|
);
|
|
27254
|
-
filesToOpen.push(
|
|
27429
|
+
filesToOpen.push(epic);
|
|
27255
27430
|
} else if (featureType === "bug") {
|
|
27256
27431
|
const spec = joinPosix13(targetDir, "spec.md");
|
|
27257
27432
|
const plan = planPath ?? joinPosix13(targetDir, "plan.md");
|
|
@@ -27418,15 +27593,18 @@ function createActiveFolder(options) {
|
|
|
27418
27593
|
if (!normalizedIssueNumber) {
|
|
27419
27594
|
normalizedIssueNumber = parseIssueNumber(potentialContent);
|
|
27420
27595
|
}
|
|
27421
|
-
|
|
27422
|
-
|
|
27423
|
-
|
|
27424
|
-
|
|
27425
|
-
|
|
27426
|
-
|
|
27427
|
-
|
|
27428
|
-
|
|
27429
|
-
|
|
27596
|
+
let targetDir;
|
|
27597
|
+
if (featureType === "epic") {
|
|
27598
|
+
const epicSlug = buildFolderSlug(resolvedFeatureName, null, null);
|
|
27599
|
+
targetDir = joinPosix13(workspacePath, `docs/features/epics/${epicSlug}`);
|
|
27600
|
+
} else {
|
|
27601
|
+
const folderSlug = buildFolderSlug(
|
|
27602
|
+
resolvedFeatureName,
|
|
27603
|
+
potentialFile,
|
|
27604
|
+
normalizedIssueNumber
|
|
27605
|
+
);
|
|
27606
|
+
targetDir = joinPosix13(workspacePath, `docs/features/active/${folderSlug}`);
|
|
27607
|
+
}
|
|
27430
27608
|
if (filesystem.exists(targetDir) && !force) {
|
|
27431
27609
|
throw new Error(
|
|
27432
27610
|
`Target exists: ${targetDir}. Re-run with --force to overwrite.`
|
|
@@ -27631,6 +27809,299 @@ function newActiveFeatureFolderServiceCall(input) {
|
|
|
27631
27809
|
};
|
|
27632
27810
|
}
|
|
27633
27811
|
|
|
27812
|
+
// ../../extensions/drm-copilot/src/lib/subagent-tree/tree-assembler.ts
|
|
27813
|
+
var ROOT_KEY = "__root__";
|
|
27814
|
+
function assembleTree(scanned) {
|
|
27815
|
+
const transcriptsByKey = /* @__PURE__ */ new Map();
|
|
27816
|
+
transcriptsByKey.set(ROOT_KEY, scanned.root);
|
|
27817
|
+
for (const subagent of scanned.subagents) {
|
|
27818
|
+
transcriptsByKey.set(subagent.meta.agentId, subagent.transcript);
|
|
27819
|
+
}
|
|
27820
|
+
const matchedChildrenByParentKey = /* @__PURE__ */ new Map();
|
|
27821
|
+
const orphans = [];
|
|
27822
|
+
for (const subagent of scanned.subagents) {
|
|
27823
|
+
const parentKey = findParentKey(subagent.meta.toolUseId, transcriptsByKey);
|
|
27824
|
+
if (parentKey === void 0) {
|
|
27825
|
+
orphans.push(subagent);
|
|
27826
|
+
continue;
|
|
27827
|
+
}
|
|
27828
|
+
const siblings = matchedChildrenByParentKey.get(parentKey) ?? [];
|
|
27829
|
+
siblings.push(subagent);
|
|
27830
|
+
matchedChildrenByParentKey.set(parentKey, siblings);
|
|
27831
|
+
}
|
|
27832
|
+
orphans.sort(compareByAgentId);
|
|
27833
|
+
return buildNode({
|
|
27834
|
+
key: ROOT_KEY,
|
|
27835
|
+
agentType: "root",
|
|
27836
|
+
description: "",
|
|
27837
|
+
depth: 0,
|
|
27838
|
+
models: scanned.root.models,
|
|
27839
|
+
transcriptsByKey,
|
|
27840
|
+
matchedChildrenByParentKey,
|
|
27841
|
+
orphans
|
|
27842
|
+
});
|
|
27843
|
+
}
|
|
27844
|
+
function findParentKey(toolUseId, transcriptsByKey) {
|
|
27845
|
+
for (const [key, transcript] of transcriptsByKey) {
|
|
27846
|
+
if (transcript.agentToolUseIds.includes(toolUseId)) {
|
|
27847
|
+
return key;
|
|
27848
|
+
}
|
|
27849
|
+
}
|
|
27850
|
+
return void 0;
|
|
27851
|
+
}
|
|
27852
|
+
function compareByAgentId(a, b) {
|
|
27853
|
+
if (a.meta.agentId < b.meta.agentId) {
|
|
27854
|
+
return -1;
|
|
27855
|
+
}
|
|
27856
|
+
if (a.meta.agentId > b.meta.agentId) {
|
|
27857
|
+
return 1;
|
|
27858
|
+
}
|
|
27859
|
+
return 0;
|
|
27860
|
+
}
|
|
27861
|
+
function sortBySpawnIndex(children, parentTranscript) {
|
|
27862
|
+
return [...children].sort((a, b) => {
|
|
27863
|
+
const indexA = parentTranscript.agentToolUseIds.indexOf(a.meta.toolUseId);
|
|
27864
|
+
const indexB = parentTranscript.agentToolUseIds.indexOf(b.meta.toolUseId);
|
|
27865
|
+
if (indexA !== indexB) {
|
|
27866
|
+
return indexA - indexB;
|
|
27867
|
+
}
|
|
27868
|
+
return compareByAgentId(a, b);
|
|
27869
|
+
});
|
|
27870
|
+
}
|
|
27871
|
+
function buildNode(input) {
|
|
27872
|
+
const {
|
|
27873
|
+
key,
|
|
27874
|
+
agentType,
|
|
27875
|
+
description,
|
|
27876
|
+
depth,
|
|
27877
|
+
models,
|
|
27878
|
+
transcriptsByKey,
|
|
27879
|
+
matchedChildrenByParentKey,
|
|
27880
|
+
orphans
|
|
27881
|
+
} = input;
|
|
27882
|
+
const transcript = transcriptsByKey.get(key);
|
|
27883
|
+
const matchedChildren = matchedChildrenByParentKey.get(key) ?? [];
|
|
27884
|
+
const orderedMatched = transcript ? sortBySpawnIndex(matchedChildren, transcript) : matchedChildren;
|
|
27885
|
+
const isRoot = key === ROOT_KEY;
|
|
27886
|
+
const orderedChildren = isRoot ? [...orderedMatched, ...orphans] : orderedMatched;
|
|
27887
|
+
const children = orderedChildren.map(
|
|
27888
|
+
(subagent) => buildNode({
|
|
27889
|
+
key: subagent.meta.agentId,
|
|
27890
|
+
agentType: subagent.meta.agentType,
|
|
27891
|
+
description: subagent.meta.description,
|
|
27892
|
+
depth: subagent.meta.spawnDepth,
|
|
27893
|
+
models: subagent.transcript.models,
|
|
27894
|
+
transcriptsByKey,
|
|
27895
|
+
matchedChildrenByParentKey,
|
|
27896
|
+
orphans
|
|
27897
|
+
})
|
|
27898
|
+
);
|
|
27899
|
+
return {
|
|
27900
|
+
agentType,
|
|
27901
|
+
description,
|
|
27902
|
+
depth,
|
|
27903
|
+
models: [...models].sort(),
|
|
27904
|
+
children
|
|
27905
|
+
};
|
|
27906
|
+
}
|
|
27907
|
+
|
|
27908
|
+
// ../../extensions/drm-copilot/src/lib/subagent-tree/transcript-parser.ts
|
|
27909
|
+
function parseTranscriptLines(lines) {
|
|
27910
|
+
const models = [];
|
|
27911
|
+
const seenModels = /* @__PURE__ */ new Set();
|
|
27912
|
+
const agentToolUseIds = [];
|
|
27913
|
+
for (const line of lines) {
|
|
27914
|
+
const trimmed = line.trim();
|
|
27915
|
+
if (trimmed.length === 0) {
|
|
27916
|
+
continue;
|
|
27917
|
+
}
|
|
27918
|
+
const parsed = tryParseJson(trimmed);
|
|
27919
|
+
if (!isRecord2(parsed)) {
|
|
27920
|
+
continue;
|
|
27921
|
+
}
|
|
27922
|
+
const message = parsed["message"];
|
|
27923
|
+
if (!isRecord2(message)) {
|
|
27924
|
+
continue;
|
|
27925
|
+
}
|
|
27926
|
+
recordModel(message["model"], models, seenModels);
|
|
27927
|
+
collectAgentToolUseIds(message["content"], agentToolUseIds);
|
|
27928
|
+
}
|
|
27929
|
+
return { models, agentToolUseIds };
|
|
27930
|
+
}
|
|
27931
|
+
function tryParseJson(text) {
|
|
27932
|
+
try {
|
|
27933
|
+
return JSON.parse(text);
|
|
27934
|
+
} catch {
|
|
27935
|
+
return void 0;
|
|
27936
|
+
}
|
|
27937
|
+
}
|
|
27938
|
+
function isRecord2(value) {
|
|
27939
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27940
|
+
}
|
|
27941
|
+
function recordModel(model, models, seenModels) {
|
|
27942
|
+
if (typeof model === "string" && model.length > 0 && !seenModels.has(model)) {
|
|
27943
|
+
seenModels.add(model);
|
|
27944
|
+
models.push(model);
|
|
27945
|
+
}
|
|
27946
|
+
}
|
|
27947
|
+
function collectAgentToolUseIds(content, agentToolUseIds) {
|
|
27948
|
+
if (!Array.isArray(content)) {
|
|
27949
|
+
return;
|
|
27950
|
+
}
|
|
27951
|
+
for (const block of content) {
|
|
27952
|
+
if (!isRecord2(block)) {
|
|
27953
|
+
continue;
|
|
27954
|
+
}
|
|
27955
|
+
if (block["type"] === "tool_use" && block["name"] === "Agent" && typeof block["id"] === "string") {
|
|
27956
|
+
agentToolUseIds.push(block["id"]);
|
|
27957
|
+
}
|
|
27958
|
+
}
|
|
27959
|
+
}
|
|
27960
|
+
|
|
27961
|
+
// ../../extensions/drm-copilot/src/lib/subagent-tree/transcript-scanner.ts
|
|
27962
|
+
var META_SUFFIX = ".meta.json";
|
|
27963
|
+
var TRANSCRIPT_SUFFIX = ".jsonl";
|
|
27964
|
+
var META_FILENAME_PATTERN = /agent-([^/\\]+)\.meta\.json$/;
|
|
27965
|
+
function scanTranscripts(rootSessionPath, fileSystem) {
|
|
27966
|
+
if (!rootSessionPath.endsWith(TRANSCRIPT_SUFFIX)) {
|
|
27967
|
+
throw new Error(
|
|
27968
|
+
`scanTranscripts: rootSessionPath must end in "${TRANSCRIPT_SUFFIX}", got: ${rootSessionPath}`
|
|
27969
|
+
);
|
|
27970
|
+
}
|
|
27971
|
+
const root = readTranscript(rootSessionPath, fileSystem);
|
|
27972
|
+
const subagentsDir = `${rootSessionPath.slice(0, -TRANSCRIPT_SUFFIX.length)}/subagents`;
|
|
27973
|
+
const metaPaths = fileSystem.glob(subagentsDir, "agent-*.meta.json");
|
|
27974
|
+
const subagents = metaPaths.map((metaPath) => readSubagent(metaPath, fileSystem)).filter((subagent) => subagent !== void 0);
|
|
27975
|
+
return { root, subagents };
|
|
27976
|
+
}
|
|
27977
|
+
function readTranscript(path11, fileSystem) {
|
|
27978
|
+
const content = fileSystem.readTextFile(path11);
|
|
27979
|
+
return parseTranscriptLines(content.split(/\r?\n/));
|
|
27980
|
+
}
|
|
27981
|
+
function readSubagent(metaPath, fileSystem) {
|
|
27982
|
+
const filenameMatch = META_FILENAME_PATTERN.exec(metaPath);
|
|
27983
|
+
const agentId = filenameMatch?.[1];
|
|
27984
|
+
if (agentId === void 0) {
|
|
27985
|
+
return void 0;
|
|
27986
|
+
}
|
|
27987
|
+
const metaContent = fileSystem.readTextFile(metaPath);
|
|
27988
|
+
const meta2 = parseSubagentMeta(agentId, metaContent);
|
|
27989
|
+
if (!meta2) {
|
|
27990
|
+
return void 0;
|
|
27991
|
+
}
|
|
27992
|
+
const transcriptPath = metaPath.slice(0, -META_SUFFIX.length) + TRANSCRIPT_SUFFIX;
|
|
27993
|
+
const transcript = readTranscript(transcriptPath, fileSystem);
|
|
27994
|
+
return { meta: meta2, transcript };
|
|
27995
|
+
}
|
|
27996
|
+
function parseSubagentMeta(agentId, content) {
|
|
27997
|
+
let parsed;
|
|
27998
|
+
try {
|
|
27999
|
+
parsed = JSON.parse(content);
|
|
28000
|
+
} catch {
|
|
28001
|
+
return void 0;
|
|
28002
|
+
}
|
|
28003
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
28004
|
+
return void 0;
|
|
28005
|
+
}
|
|
28006
|
+
const record2 = parsed;
|
|
28007
|
+
const agentType = record2["agentType"];
|
|
28008
|
+
const description = record2["description"];
|
|
28009
|
+
const toolUseId = record2["toolUseId"];
|
|
28010
|
+
const spawnDepth = record2["spawnDepth"];
|
|
28011
|
+
if (typeof agentType !== "string" || typeof description !== "string" || typeof toolUseId !== "string" || typeof spawnDepth !== "number") {
|
|
28012
|
+
return void 0;
|
|
28013
|
+
}
|
|
28014
|
+
const worktreePath = record2["worktreePath"];
|
|
28015
|
+
const worktreeBranch = record2["worktreeBranch"];
|
|
28016
|
+
return {
|
|
28017
|
+
agentId,
|
|
28018
|
+
agentType,
|
|
28019
|
+
description,
|
|
28020
|
+
toolUseId,
|
|
28021
|
+
spawnDepth,
|
|
28022
|
+
...typeof worktreePath === "string" ? { worktreePath } : {},
|
|
28023
|
+
...typeof worktreeBranch === "string" ? { worktreeBranch } : {}
|
|
28024
|
+
};
|
|
28025
|
+
}
|
|
28026
|
+
|
|
28027
|
+
// ../../extensions/drm-copilot/src/lib/subagent-tree/tree-formatter.ts
|
|
28028
|
+
function formatTree(node) {
|
|
28029
|
+
return renderLines(node).join("\n");
|
|
28030
|
+
}
|
|
28031
|
+
function renderLines(node) {
|
|
28032
|
+
const indent = " ".repeat(node.depth);
|
|
28033
|
+
const sortedModels = [...node.models].sort();
|
|
28034
|
+
const line = `${indent}${node.agentType} \xB7 [${sortedModels.join(",")}] \xB7 ${node.depth} \xB7 ${node.description}`;
|
|
28035
|
+
const childLines = node.children.flatMap((child) => renderLines(child));
|
|
28036
|
+
return [line, ...childLines];
|
|
28037
|
+
}
|
|
28038
|
+
|
|
28039
|
+
// ../../extensions/drm-copilot/src/lib/subagent-tree/index.ts
|
|
28040
|
+
function buildSubagentTree(rootSessionPath, deps) {
|
|
28041
|
+
const scanned = scanTranscripts(rootSessionPath, deps.fileSystem);
|
|
28042
|
+
return assembleTree(scanned);
|
|
28043
|
+
}
|
|
28044
|
+
|
|
28045
|
+
// ../../extensions/drm-copilot/src/lib/subagent-tree/workspace-encoding.ts
|
|
28046
|
+
var WORKTREE_INFIX = "-wt-";
|
|
28047
|
+
function encodeWorkspacePath(workspacePath) {
|
|
28048
|
+
return workspacePath.replace(/[\\/:]/g, "-");
|
|
28049
|
+
}
|
|
28050
|
+
function matchEncodedDirectories(directoryNames, encodedWorkspaceName) {
|
|
28051
|
+
const target = encodedWorkspaceName.toLowerCase();
|
|
28052
|
+
const worktreePrefix = `${target}${WORKTREE_INFIX}`;
|
|
28053
|
+
return directoryNames.filter((directoryName) => {
|
|
28054
|
+
const lowerDirectoryName = directoryName.toLowerCase();
|
|
28055
|
+
return lowerDirectoryName === target || lowerDirectoryName.startsWith(worktreePrefix);
|
|
28056
|
+
});
|
|
28057
|
+
}
|
|
28058
|
+
|
|
28059
|
+
// ../../extensions/drm-copilot/src/lib/subagent-tree/session-transcript-resolver.ts
|
|
28060
|
+
var SESSION_ID_PATTERN = /^[0-9A-Za-z-]{8,64}$/;
|
|
28061
|
+
var SESSION_ID_RULE = "^[0-9A-Za-z-]{8,64}$ (8-64 characters of digits, ASCII letters, or hyphen)";
|
|
28062
|
+
function resolveSessionTranscriptPath(sessionId, workspaceRoot, claudeProjectsRoot, fileSystem) {
|
|
28063
|
+
if (!SESSION_ID_PATTERN.test(sessionId)) {
|
|
28064
|
+
throw new Error(
|
|
28065
|
+
`Invalid session id '${sessionId}': must match ${SESSION_ID_RULE}.`
|
|
28066
|
+
);
|
|
28067
|
+
}
|
|
28068
|
+
const encodedWorkspaceName = encodeWorkspacePath(workspaceRoot);
|
|
28069
|
+
const matchingDirectories = matchEncodedDirectories(
|
|
28070
|
+
fileSystem.listDirectory(claudeProjectsRoot),
|
|
28071
|
+
encodedWorkspaceName
|
|
28072
|
+
);
|
|
28073
|
+
for (const directoryName of matchingDirectories) {
|
|
28074
|
+
const transcriptPath = `${claudeProjectsRoot}/${directoryName}/${sessionId}.jsonl`;
|
|
28075
|
+
if (fileSystem.isFile(transcriptPath)) {
|
|
28076
|
+
return transcriptPath;
|
|
28077
|
+
}
|
|
28078
|
+
}
|
|
28079
|
+
const searched = matchingDirectories.length === 0 ? "(no directories matched the encoded workspace path)" : matchingDirectories.map((directoryName) => `${claudeProjectsRoot}/${directoryName}`).join(", ");
|
|
28080
|
+
throw new Error(
|
|
28081
|
+
`No transcript found for session id '${sessionId}' under ${claudeProjectsRoot}. Searched: ${searched}.`
|
|
28082
|
+
);
|
|
28083
|
+
}
|
|
28084
|
+
|
|
28085
|
+
// ../../extensions/drm-copilot/src/repo-automation-service-subagent-tree.ts
|
|
28086
|
+
function renderSubagentTreeServiceCall(input, env = process.env) {
|
|
28087
|
+
const claudeProjectsRoot = getClaudeProjectsRoot(env);
|
|
28088
|
+
const transcriptPath = resolveSessionTranscriptPath(
|
|
28089
|
+
input.sessionId,
|
|
28090
|
+
input.workspaceRoot,
|
|
28091
|
+
claudeProjectsRoot,
|
|
28092
|
+
input.fileSystem
|
|
28093
|
+
);
|
|
28094
|
+
const renderedTree = formatTree(
|
|
28095
|
+
buildSubagentTree(transcriptPath, { fileSystem: input.fileSystem })
|
|
28096
|
+
);
|
|
28097
|
+
return {
|
|
28098
|
+
tool: "render_subagent_tree",
|
|
28099
|
+
workspaceRoot: input.workspaceRoot,
|
|
28100
|
+
summary: `Rendered subagent tree for session ${input.sessionId} (${transcriptPath}).`,
|
|
28101
|
+
renderedTree
|
|
28102
|
+
};
|
|
28103
|
+
}
|
|
28104
|
+
|
|
27634
28105
|
// ../../extensions/drm-copilot/src/repo-automation-service.ts
|
|
27635
28106
|
var DefaultRepoAutomationService = class {
|
|
27636
28107
|
extensionRoot;
|
|
@@ -27800,23 +28271,14 @@ var DefaultRepoAutomationService = class {
|
|
|
27800
28271
|
buildValidateOrchestrationServiceCallInput(this.fileSystem, input)
|
|
27801
28272
|
);
|
|
27802
28273
|
}
|
|
27803
|
-
async
|
|
27804
|
-
|
|
27805
|
-
|
|
27806
|
-
|
|
27807
|
-
commandId: options.invocationId,
|
|
27808
|
-
args: options.args,
|
|
27809
|
-
extensionRoot: this.extensionRoot,
|
|
27810
|
-
workspaceRoot: options.workspaceRoot
|
|
28274
|
+
async renderSubagentTree(input) {
|
|
28275
|
+
return renderSubagentTreeServiceCall({
|
|
28276
|
+
...input,
|
|
28277
|
+
fileSystem: this.fileSystem
|
|
27811
28278
|
});
|
|
27812
|
-
|
|
27813
|
-
|
|
27814
|
-
return
|
|
27815
|
-
tool: options.tool,
|
|
27816
|
-
workspaceRoot: options.workspaceRoot,
|
|
27817
|
-
summary: options.summary,
|
|
27818
|
-
...artifacts === void 0 ? {} : { artifacts }
|
|
27819
|
-
};
|
|
28279
|
+
}
|
|
28280
|
+
async executeScript(options) {
|
|
28281
|
+
return executeScriptServiceCall(this.output, this.extensionRoot, options);
|
|
27820
28282
|
}
|
|
27821
28283
|
};
|
|
27822
28284
|
function createRepoAutomationService(options) {
|