@harness-engineering/cli 2.8.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/skills/claude-code/harness-audit-harness-strength/SKILL.md +188 -0
- package/dist/agents/skills/claude-code/harness-audit-harness-strength/skill.yaml +54 -0
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +28 -14
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +1 -1
- package/dist/agents/skills/claude-code/harness-git-workflow/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-ideate/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-knowledge-pipeline/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-roadmap/SKILL.md +62 -4
- package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-test-advisor/SKILL.md +80 -2
- package/dist/agents/skills/claude-code/harness-test-advisor/skill.yaml +4 -1
- package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +27 -25
- package/dist/agents/skills/claude-code/initialize-harness-project/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/outcome-eval/SKILL.md +97 -0
- package/dist/agents/skills/claude-code/outcome-eval/skill.yaml +51 -0
- package/dist/agents/skills/codex/harness-audit-harness-strength/SKILL.md +188 -0
- package/dist/agents/skills/codex/harness-audit-harness-strength/skill.yaml +54 -0
- package/dist/agents/skills/codex/harness-autopilot/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +28 -14
- package/dist/agents/skills/codex/harness-execution/SKILL.md +1 -1
- package/dist/agents/skills/codex/harness-git-workflow/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-ideate/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-knowledge-pipeline/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-roadmap/SKILL.md +62 -4
- package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-test-advisor/SKILL.md +80 -2
- package/dist/agents/skills/codex/harness-test-advisor/skill.yaml +4 -1
- package/dist/agents/skills/codex/initialize-harness-project/SKILL.md +27 -25
- package/dist/agents/skills/codex/initialize-harness-project/skill.yaml +1 -0
- package/dist/agents/skills/codex/outcome-eval/SKILL.md +97 -0
- package/dist/agents/skills/codex/outcome-eval/skill.yaml +51 -0
- package/dist/agents/skills/cursor/harness-audit-harness-strength/SKILL.md +188 -0
- package/dist/agents/skills/cursor/harness-audit-harness-strength/skill.yaml +54 -0
- package/dist/agents/skills/cursor/harness-autopilot/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +28 -14
- package/dist/agents/skills/cursor/harness-execution/SKILL.md +1 -1
- package/dist/agents/skills/cursor/harness-git-workflow/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-ideate/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-knowledge-pipeline/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-roadmap/SKILL.md +62 -4
- package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-test-advisor/SKILL.md +80 -2
- package/dist/agents/skills/cursor/harness-test-advisor/skill.yaml +4 -1
- package/dist/agents/skills/cursor/initialize-harness-project/SKILL.md +27 -25
- package/dist/agents/skills/cursor/initialize-harness-project/skill.yaml +1 -0
- package/dist/agents/skills/cursor/outcome-eval/SKILL.md +97 -0
- package/dist/agents/skills/cursor/outcome-eval/skill.yaml +51 -0
- package/dist/agents/skills/gemini-cli/harness-audit-harness-strength/SKILL.md +188 -0
- package/dist/agents/skills/gemini-cli/harness-audit-harness-strength/skill.yaml +54 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +28 -14
- package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +1 -1
- package/dist/agents/skills/gemini-cli/harness-git-workflow/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-ideate/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-knowledge-pipeline/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap/SKILL.md +62 -4
- package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-test-advisor/SKILL.md +80 -2
- package/dist/agents/skills/gemini-cli/harness-test-advisor/skill.yaml +4 -1
- package/dist/agents/skills/gemini-cli/initialize-harness-project/SKILL.md +27 -25
- package/dist/agents/skills/gemini-cli/initialize-harness-project/skill.yaml +1 -0
- package/dist/agents/skills/gemini-cli/outcome-eval/SKILL.md +97 -0
- package/dist/agents/skills/gemini-cli/outcome-eval/skill.yaml +51 -0
- package/dist/agents/skills/tests/harness-test-advisor.test.ts +94 -0
- package/dist/{agents-md-WMJO5HSM.js → agents-md-XOJE5ETA.js} +2 -2
- package/dist/{architecture-EVYVGPRZ.js → architecture-JEZPJ725.js} +3 -3
- package/dist/{assess-project-KZG563SO.js → assess-project-RHXOQNMM.js} +1 -1
- package/dist/bin/harness-mcp.js +13 -13
- package/dist/bin/harness.js +22 -22
- package/dist/{check-phase-gate-MK364VXS.js → check-phase-gate-GNDOMS35.js} +3 -3
- package/dist/{chunk-VBNJAKUH.js → chunk-3ISHDWO7.js} +1 -1
- package/dist/{chunk-UJFNIWC7.js → chunk-527G27VI.js} +2 -2
- package/dist/{chunk-5XL5QJ5B.js → chunk-6WQCLCBO.js} +1 -1
- package/dist/{chunk-UXPWSV3B.js → chunk-BYVT5LVO.js} +3 -3
- package/dist/{chunk-HRSE6IQD.js → chunk-DE5U6KOL.js} +1 -1
- package/dist/{chunk-B7KMTHN3.js → chunk-GGKRA7A7.js} +1 -1
- package/dist/{chunk-STESM73J.js → chunk-GSP2XIVS.js} +1 -1
- package/dist/{chunk-KBCPELBC.js → chunk-HEIMJJI4.js} +2 -2
- package/dist/{chunk-KI6PHH6Q.js → chunk-HWTUUQOW.js} +3 -3
- package/dist/{chunk-2SNRCAC3.js → chunk-KAJOS3BA.js} +2 -2
- package/dist/{chunk-C7J55C6E.js → chunk-MGUPSE6D.js} +5 -5
- package/dist/{chunk-GOHWCHCS.js → chunk-N24HCQA4.js} +2243 -776
- package/dist/{chunk-EEFRPEWT.js → chunk-NWLGL3IR.js} +1 -1
- package/dist/{chunk-UUO4K7NX.js → chunk-ONCPJGHY.js} +6 -6
- package/dist/{chunk-X4EFYVCZ.js → chunk-PC2R5RUJ.js} +1 -1
- package/dist/{chunk-7EQAZKJ5.js → chunk-QBC7DI4Q.js} +1 -1
- package/dist/{chunk-UBZQE3JN.js → chunk-UX3PQKVZ.js} +7 -2
- package/dist/{chunk-CAQPSFPT.js → chunk-WWEVS7RO.js} +453 -91
- package/dist/{chunk-4BDOSCNY.js → chunk-XFU6SB2Q.js} +1015 -648
- package/dist/{chunk-LADPYELQ.js → chunk-XX4OLNWQ.js} +2 -2
- package/dist/{chunk-FZ5MBXEG.js → chunk-YQSYCBAH.js} +6 -6
- package/dist/{chunk-ACOOG3UW.js → chunk-Z4AWEIBY.js} +3 -3
- package/dist/{ci-workflow-IW2H5DC4.js → ci-workflow-ORZ4F45F.js} +2 -2
- package/dist/{dist-JCFK263L.js → dist-LHINSVK4.js} +85 -1
- package/dist/{docs-7CP6VV42.js → docs-AU3DXFFO.js} +3 -3
- package/dist/{engine-MKJEBWU7.js → engine-6GPWOYQH.js} +2 -2
- package/dist/{entropy-6JOZJYG7.js → entropy-VLKDRMRT.js} +2 -2
- package/dist/{feedback-T65AEJEG.js → feedback-YXYY44ZC.js} +1 -1
- package/dist/{generate-agent-definitions-4VI4YTO2.js → generate-agent-definitions-XIHQPKG3.js} +3 -3
- package/dist/hooks/cost-tracker.js +29 -6
- package/dist/index.d.ts +8 -8
- package/dist/index.js +22 -22
- package/dist/{loader-AWTHHE3A.js → loader-YAN56MT3.js} +2 -2
- package/dist/{mcp-JBIBINO2.js → mcp-RK3SFVYB.js} +13 -13
- package/dist/{performance-NCOUDOMW.js → performance-64DPTLLQ.js} +3 -3
- package/dist/{review-pipeline-YIC6JPMY.js → review-pipeline-NENG6LW7.js} +2 -2
- package/dist/{runtime-5MHV4UEE.js → runtime-FFIIRT2T.js} +2 -2
- package/dist/{security-VZPJNIDP.js → security-3PIBN35B.js} +1 -1
- package/dist/templates/basic/harness.config.json.hbs +34 -0
- package/dist/templates/ci/README.md +86 -0
- package/dist/templates/ci/required-review.ruleset.json +20 -0
- package/dist/templates/ci/required-review.yml.hbs +57 -0
- package/dist/templates/ci/template.json +5 -0
- package/dist/templates/intermediate/harness.config.json.hbs +36 -0
- package/dist/templates/orchestrator/harness.orchestrator.md +9 -0
- package/dist/{tool-tiers-B7JC2XC3.js → tool-tiers-OKK5FE57.js} +2 -0
- package/dist/{validate-7BE4VTFI.js → validate-7IAF2ES3.js} +3 -3
- package/dist/{validate-cross-check-F7GEBRDH.js → validate-cross-check-QPSAOZKD.js} +2 -2
- package/package.json +7 -7
|
@@ -3,20 +3,20 @@ import {
|
|
|
3
3
|
handleGetSecurityTrends,
|
|
4
4
|
handleRunSecurityScan,
|
|
5
5
|
runSecurityScanDefinition
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-HEIMJJI4.js";
|
|
7
7
|
import {
|
|
8
8
|
handleRunCodeReview,
|
|
9
9
|
runCodeReviewDefinition,
|
|
10
10
|
sortFindingsBySeverity
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-XX4OLNWQ.js";
|
|
12
12
|
import {
|
|
13
13
|
assessProjectDefinition,
|
|
14
14
|
handleAssessProject
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-YQSYCBAH.js";
|
|
16
16
|
import {
|
|
17
17
|
detectEntropyDefinition,
|
|
18
18
|
handleDetectEntropy
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-Z4AWEIBY.js";
|
|
20
20
|
import {
|
|
21
21
|
checkPerformanceDefinition,
|
|
22
22
|
getCriticalPathsDefinition,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
handleGetPerfBaselines,
|
|
27
27
|
handleUpdatePerfBaselines,
|
|
28
28
|
updatePerfBaselinesDefinition
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-ONCPJGHY.js";
|
|
30
30
|
import {
|
|
31
31
|
getBusinessKnowledgeResource
|
|
32
32
|
} from "./chunk-IOW3MW2K.js";
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
handleCreateSelfReview,
|
|
38
38
|
handleRequestPeerReview,
|
|
39
39
|
requestPeerReviewDefinition
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-BYVT5LVO.js";
|
|
41
41
|
import {
|
|
42
42
|
GENERATED_HEADER_CLAUDE,
|
|
43
43
|
GENERATED_HEADER_CODEX,
|
|
@@ -53,18 +53,18 @@ import {
|
|
|
53
53
|
import {
|
|
54
54
|
handleValidateProject,
|
|
55
55
|
validateToolDefinition
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-HWTUUQOW.js";
|
|
57
57
|
import {
|
|
58
58
|
checkDependenciesDefinition,
|
|
59
59
|
handleCheckDependencies
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-527G27VI.js";
|
|
61
61
|
import {
|
|
62
62
|
resolveProjectConfig
|
|
63
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-DE5U6KOL.js";
|
|
64
64
|
import {
|
|
65
65
|
checkDocsDefinition,
|
|
66
66
|
handleCheckDocs
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-MGUPSE6D.js";
|
|
68
68
|
import {
|
|
69
69
|
resultToMcpResponse
|
|
70
70
|
} from "./chunk-RC3OI5NK.js";
|
|
@@ -90,7 +90,7 @@ import {
|
|
|
90
90
|
findConfigFile,
|
|
91
91
|
loadConfig,
|
|
92
92
|
resolveConfig
|
|
93
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-GGKRA7A7.js";
|
|
94
94
|
import {
|
|
95
95
|
logger
|
|
96
96
|
} from "./chunk-EBJQ6N4M.js";
|
|
@@ -109,6 +109,7 @@ import {
|
|
|
109
109
|
checkTaint,
|
|
110
110
|
computeLoadPlan,
|
|
111
111
|
createTrackerClient,
|
|
112
|
+
decidePromotionForRow,
|
|
112
113
|
detectChangeType,
|
|
113
114
|
estimateTokens,
|
|
114
115
|
extractLevel,
|
|
@@ -120,7 +121,7 @@ import {
|
|
|
120
121
|
scanForInjection,
|
|
121
122
|
serializeEnvelope,
|
|
122
123
|
writeTaint
|
|
123
|
-
} from "./chunk-
|
|
124
|
+
} from "./chunk-N24HCQA4.js";
|
|
124
125
|
import {
|
|
125
126
|
Err,
|
|
126
127
|
INDEXED_FILE_KINDS,
|
|
@@ -737,7 +738,7 @@ async function handleInsightsSummary(input) {
|
|
|
737
738
|
const skip = Array.isArray(input.skip) ? input.skip.filter(
|
|
738
739
|
(k) => typeof k === "string" && INSIGHTS_KEYS.includes(k)
|
|
739
740
|
) : void 0;
|
|
740
|
-
const { composeInsights } = await import("./dist-
|
|
741
|
+
const { composeInsights } = await import("./dist-LHINSVK4.js");
|
|
741
742
|
const report = await composeInsights(projectPath, {
|
|
742
743
|
...skip && skip.length > 0 && { skip }
|
|
743
744
|
});
|
|
@@ -913,7 +914,7 @@ ${skippedMsg}`
|
|
|
913
914
|
async function handleInitProject(input) {
|
|
914
915
|
const i = input;
|
|
915
916
|
try {
|
|
916
|
-
const { TemplateEngine } = await import("./engine-
|
|
917
|
+
const { TemplateEngine } = await import("./engine-6GPWOYQH.js");
|
|
917
918
|
const engine = new TemplateEngine(resolveTemplatesDir());
|
|
918
919
|
const safePath = sanitizePath(i.path);
|
|
919
920
|
const detected = tryDetectFramework(engine, safePath, i);
|
|
@@ -935,7 +936,7 @@ var listPersonasDefinition = {
|
|
|
935
936
|
inputSchema: { type: "object", properties: {} }
|
|
936
937
|
};
|
|
937
938
|
async function handleListPersonas() {
|
|
938
|
-
const { listPersonas } = await import("./loader-
|
|
939
|
+
const { listPersonas } = await import("./loader-YAN56MT3.js");
|
|
939
940
|
const result = listPersonas(resolvePersonasDir());
|
|
940
941
|
return resultToMcpResponse(result);
|
|
941
942
|
}
|
|
@@ -959,10 +960,10 @@ async function handleGeneratePersonaArtifacts(input) {
|
|
|
959
960
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.name)) {
|
|
960
961
|
return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.name}`)));
|
|
961
962
|
}
|
|
962
|
-
const { loadPersona } = await import("./loader-
|
|
963
|
-
const { generateRuntime } = await import("./runtime-
|
|
964
|
-
const { generateAgentsMd } = await import("./agents-md-
|
|
965
|
-
const { generateCIWorkflow } = await import("./ci-workflow-
|
|
963
|
+
const { loadPersona } = await import("./loader-YAN56MT3.js");
|
|
964
|
+
const { generateRuntime } = await import("./runtime-FFIIRT2T.js");
|
|
965
|
+
const { generateAgentsMd } = await import("./agents-md-XOJE5ETA.js");
|
|
966
|
+
const { generateCIWorkflow } = await import("./ci-workflow-ORZ4F45F.js");
|
|
966
967
|
const personasDir = resolvePersonasDir();
|
|
967
968
|
const filePath = path4.join(personasDir, `${input.name}.yaml`);
|
|
968
969
|
if (!filePath.startsWith(personasDir)) {
|
|
@@ -1017,7 +1018,7 @@ async function handleRunPersona(input) {
|
|
|
1017
1018
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.persona)) {
|
|
1018
1019
|
return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.persona}`)));
|
|
1019
1020
|
}
|
|
1020
|
-
const { loadPersona } = await import("./loader-
|
|
1021
|
+
const { loadPersona } = await import("./loader-YAN56MT3.js");
|
|
1021
1022
|
const { runPersona } = await import("./runner-AAEF2TXY.js");
|
|
1022
1023
|
const { executeSkill } = await import("./skill-executor-MOCUIAYS.js");
|
|
1023
1024
|
const personasDir = resolvePersonasDir();
|
|
@@ -1462,7 +1463,7 @@ function loadOrGenerateProfile(projectRoot) {
|
|
|
1462
1463
|
// src/mcp/tools/event-emitter.ts
|
|
1463
1464
|
async function emitSkillEvent(projectPath, event) {
|
|
1464
1465
|
try {
|
|
1465
|
-
const { emitEvent } = await import("./dist-
|
|
1466
|
+
const { emitEvent } = await import("./dist-LHINSVK4.js");
|
|
1466
1467
|
await emitEvent(projectPath, event);
|
|
1467
1468
|
} catch {
|
|
1468
1469
|
}
|
|
@@ -1734,7 +1735,7 @@ async function autoSyncRoadmap(projectPath) {
|
|
|
1734
1735
|
try {
|
|
1735
1736
|
const roadmapFile = path11.join(projectPath, "docs", "roadmap.md");
|
|
1736
1737
|
if (!fs10.existsSync(roadmapFile)) return;
|
|
1737
|
-
const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges } = await import("./dist-
|
|
1738
|
+
const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges } = await import("./dist-LHINSVK4.js");
|
|
1738
1739
|
const raw = fs10.readFileSync(roadmapFile, "utf-8");
|
|
1739
1740
|
const parseResult = parseRoadmap(raw);
|
|
1740
1741
|
if (!parseResult.ok) return;
|
|
@@ -1764,7 +1765,7 @@ async function triggerExternalSync(projectPath, roadmapFile) {
|
|
|
1764
1765
|
console.warn("[roadmap-sync] GITHUB_TOKEN not found \u2014 external sync skipped");
|
|
1765
1766
|
return;
|
|
1766
1767
|
}
|
|
1767
|
-
const { fullSync, GitHubIssuesSyncAdapter } = await import("./dist-
|
|
1768
|
+
const { fullSync, GitHubIssuesSyncAdapter } = await import("./dist-LHINSVK4.js");
|
|
1768
1769
|
const adapter = new GitHubIssuesSyncAdapter({
|
|
1769
1770
|
token,
|
|
1770
1771
|
config: trackerConfig
|
|
@@ -1861,12 +1862,12 @@ var manageStateDefinition = {
|
|
|
1861
1862
|
}
|
|
1862
1863
|
};
|
|
1863
1864
|
async function handleShow(projectPath, input) {
|
|
1864
|
-
const { loadState } = await import("./dist-
|
|
1865
|
+
const { loadState } = await import("./dist-LHINSVK4.js");
|
|
1865
1866
|
return resultToMcpResponse(await loadState(projectPath, input.stream, input.session));
|
|
1866
1867
|
}
|
|
1867
1868
|
async function handleLearn(projectPath, input) {
|
|
1868
1869
|
if (!input.learning) return mcpError("Error: learning is required for learn action");
|
|
1869
|
-
const { appendLearning } = await import("./dist-
|
|
1870
|
+
const { appendLearning } = await import("./dist-LHINSVK4.js");
|
|
1870
1871
|
const result = await appendLearning(
|
|
1871
1872
|
projectPath,
|
|
1872
1873
|
input.learning,
|
|
@@ -1881,7 +1882,7 @@ async function handleLearn(projectPath, input) {
|
|
|
1881
1882
|
async function handleFailure(projectPath, input) {
|
|
1882
1883
|
if (!input.description) return mcpError("Error: description is required for failure action");
|
|
1883
1884
|
if (!input.failureType) return mcpError("Error: failureType is required for failure action");
|
|
1884
|
-
const { appendFailure } = await import("./dist-
|
|
1885
|
+
const { appendFailure } = await import("./dist-LHINSVK4.js");
|
|
1885
1886
|
const result = await appendFailure(
|
|
1886
1887
|
projectPath,
|
|
1887
1888
|
input.description,
|
|
@@ -1900,19 +1901,19 @@ async function handleFailure(projectPath, input) {
|
|
|
1900
1901
|
return resultToMcpResponse(Ok({ recorded: true }));
|
|
1901
1902
|
}
|
|
1902
1903
|
async function handleArchive(projectPath, input) {
|
|
1903
|
-
const { archiveFailures } = await import("./dist-
|
|
1904
|
+
const { archiveFailures } = await import("./dist-LHINSVK4.js");
|
|
1904
1905
|
const result = await archiveFailures(projectPath, input.stream, input.session);
|
|
1905
1906
|
if (!result.ok) return resultToMcpResponse(result);
|
|
1906
1907
|
return resultToMcpResponse(Ok({ archived: true }));
|
|
1907
1908
|
}
|
|
1908
1909
|
async function handleReset(projectPath, input) {
|
|
1909
|
-
const { saveState, DEFAULT_STATE } = await import("./dist-
|
|
1910
|
+
const { saveState, DEFAULT_STATE } = await import("./dist-LHINSVK4.js");
|
|
1910
1911
|
const result = await saveState(projectPath, { ...DEFAULT_STATE }, input.stream, input.session);
|
|
1911
1912
|
if (!result.ok) return resultToMcpResponse(result);
|
|
1912
1913
|
return resultToMcpResponse(Ok({ reset: true }));
|
|
1913
1914
|
}
|
|
1914
1915
|
async function handleGate(projectPath, input) {
|
|
1915
|
-
const { runMechanicalGate } = await import("./dist-
|
|
1916
|
+
const { runMechanicalGate } = await import("./dist-LHINSVK4.js");
|
|
1916
1917
|
const result = await runMechanicalGate(projectPath);
|
|
1917
1918
|
if (result.ok) {
|
|
1918
1919
|
await emitSkillEvent(projectPath, {
|
|
@@ -1932,7 +1933,7 @@ async function handleGate(projectPath, input) {
|
|
|
1932
1933
|
}
|
|
1933
1934
|
async function handleSaveHandoff(projectPath, input) {
|
|
1934
1935
|
if (!input.handoff) return mcpError("Error: handoff is required for save-handoff action");
|
|
1935
|
-
const { saveHandoff } = await import("./dist-
|
|
1936
|
+
const { saveHandoff } = await import("./dist-LHINSVK4.js");
|
|
1936
1937
|
const result = await saveHandoff(
|
|
1937
1938
|
projectPath,
|
|
1938
1939
|
input.handoff,
|
|
@@ -1954,7 +1955,7 @@ async function handleSaveHandoff(projectPath, input) {
|
|
|
1954
1955
|
return resultToMcpResponse(Ok({ saved: true }));
|
|
1955
1956
|
}
|
|
1956
1957
|
async function handleLoadHandoff(projectPath, input) {
|
|
1957
|
-
const { loadHandoff } = await import("./dist-
|
|
1958
|
+
const { loadHandoff } = await import("./dist-LHINSVK4.js");
|
|
1958
1959
|
return resultToMcpResponse(await loadHandoff(projectPath, input.stream, input.session));
|
|
1959
1960
|
}
|
|
1960
1961
|
async function handleAppendEntry(projectPath, input) {
|
|
@@ -1962,7 +1963,7 @@ async function handleAppendEntry(projectPath, input) {
|
|
|
1962
1963
|
if (!input.authorSkill) return mcpError("Error: authorSkill is required for append_entry action");
|
|
1963
1964
|
if (!input.content) return mcpError("Error: content is required for append_entry action");
|
|
1964
1965
|
if (input.session) {
|
|
1965
|
-
const { appendSessionEntry } = await import("./dist-
|
|
1966
|
+
const { appendSessionEntry } = await import("./dist-LHINSVK4.js");
|
|
1966
1967
|
const result = await appendSessionEntry(
|
|
1967
1968
|
projectPath,
|
|
1968
1969
|
input.session,
|
|
@@ -1975,7 +1976,7 @@ async function handleAppendEntry(projectPath, input) {
|
|
|
1975
1976
|
if (input.section !== "decisions") {
|
|
1976
1977
|
return mcpError("Error: session is required for non-decisions sections");
|
|
1977
1978
|
}
|
|
1978
|
-
const { loadState, saveState } = await import("./dist-
|
|
1979
|
+
const { loadState, saveState } = await import("./dist-LHINSVK4.js");
|
|
1979
1980
|
const lr = await loadState(projectPath, input.stream);
|
|
1980
1981
|
if (!lr.ok) return resultToMcpResponse(lr);
|
|
1981
1982
|
lr.value.decisions.push({
|
|
@@ -1993,7 +1994,7 @@ async function handleUpdateEntryStatus(projectPath, input) {
|
|
|
1993
1994
|
if (!input.entryId) return mcpError("Error: entryId is required for update_entry_status action");
|
|
1994
1995
|
if (!input.newStatus)
|
|
1995
1996
|
return mcpError("Error: newStatus is required for update_entry_status action");
|
|
1996
|
-
const { updateSessionEntryStatus } = await import("./dist-
|
|
1997
|
+
const { updateSessionEntryStatus } = await import("./dist-LHINSVK4.js");
|
|
1997
1998
|
const result = await updateSessionEntryStatus(
|
|
1998
1999
|
projectPath,
|
|
1999
2000
|
input.session,
|
|
@@ -2006,7 +2007,7 @@ async function handleUpdateEntryStatus(projectPath, input) {
|
|
|
2006
2007
|
async function handleReadSection(projectPath, input) {
|
|
2007
2008
|
if (!input.session) return mcpError("Error: session is required for read_section action");
|
|
2008
2009
|
if (!input.section) return mcpError("Error: section is required for read_section action");
|
|
2009
|
-
const { readSessionSection } = await import("./dist-
|
|
2010
|
+
const { readSessionSection } = await import("./dist-LHINSVK4.js");
|
|
2010
2011
|
const result = await readSessionSection(
|
|
2011
2012
|
projectPath,
|
|
2012
2013
|
input.session,
|
|
@@ -2016,13 +2017,13 @@ async function handleReadSection(projectPath, input) {
|
|
|
2016
2017
|
}
|
|
2017
2018
|
async function handleReadSections(projectPath, input) {
|
|
2018
2019
|
if (!input.session) return mcpError("Error: session is required for read_sections action");
|
|
2019
|
-
const { readSessionSections } = await import("./dist-
|
|
2020
|
+
const { readSessionSections } = await import("./dist-LHINSVK4.js");
|
|
2020
2021
|
const result = await readSessionSections(projectPath, input.session);
|
|
2021
2022
|
return resultToMcpResponse(result);
|
|
2022
2023
|
}
|
|
2023
2024
|
async function handleArchiveSession(projectPath, input) {
|
|
2024
2025
|
if (!input.session) return mcpError("Error: session is required for archive_session action");
|
|
2025
|
-
const { archiveSession } = await import("./dist-
|
|
2026
|
+
const { archiveSession } = await import("./dist-LHINSVK4.js");
|
|
2026
2027
|
const { buildArchiveHooks } = await import("@harness-engineering/orchestrator");
|
|
2027
2028
|
const hooks = buildArchiveHooks({ projectPath });
|
|
2028
2029
|
const result = await archiveSession(projectPath, input.session, { hooks });
|
|
@@ -2104,7 +2105,7 @@ var listStreamsDefinition = {
|
|
|
2104
2105
|
};
|
|
2105
2106
|
async function handleListStreams(input) {
|
|
2106
2107
|
try {
|
|
2107
|
-
const { listStreams, loadStreamIndex } = await import("./dist-
|
|
2108
|
+
const { listStreams, loadStreamIndex } = await import("./dist-LHINSVK4.js");
|
|
2108
2109
|
const projectPath = sanitizePath(input.path);
|
|
2109
2110
|
const indexResult = await loadStreamIndex(projectPath);
|
|
2110
2111
|
const streamsResult = await listStreams(projectPath);
|
|
@@ -2142,7 +2143,7 @@ var checkPhaseGateDefinition = {
|
|
|
2142
2143
|
};
|
|
2143
2144
|
async function handleCheckPhaseGate(input) {
|
|
2144
2145
|
try {
|
|
2145
|
-
const { runCheckPhaseGate } = await import("./check-phase-gate-
|
|
2146
|
+
const { runCheckPhaseGate } = await import("./check-phase-gate-GNDOMS35.js");
|
|
2146
2147
|
const result = await runCheckPhaseGate({ cwd: sanitizePath(input.path) });
|
|
2147
2148
|
if (result.ok) {
|
|
2148
2149
|
return { content: [{ type: "text", text: JSON.stringify(result.value) }] };
|
|
@@ -2198,7 +2199,7 @@ async function handleValidateCrossCheck(input) {
|
|
|
2198
2199
|
};
|
|
2199
2200
|
}
|
|
2200
2201
|
try {
|
|
2201
|
-
const { runCrossCheck } = await import("./validate-cross-check-
|
|
2202
|
+
const { runCrossCheck } = await import("./validate-cross-check-QPSAOZKD.js");
|
|
2202
2203
|
const specsDir = path12.resolve(projectPath, input.specsDir ?? "docs/specs");
|
|
2203
2204
|
if (!specsDir.startsWith(projectPath)) {
|
|
2204
2205
|
return {
|
|
@@ -3021,7 +3022,7 @@ async function handleGenerateSlashCommands(input) {
|
|
|
3021
3022
|
// src/mcp/resources/state.ts
|
|
3022
3023
|
async function getStateResource(projectRoot) {
|
|
3023
3024
|
try {
|
|
3024
|
-
const { loadState, migrateToStreams } = await import("./dist-
|
|
3025
|
+
const { loadState, migrateToStreams } = await import("./dist-LHINSVK4.js");
|
|
3025
3026
|
await migrateToStreams(projectRoot);
|
|
3026
3027
|
const result = await loadState(projectRoot);
|
|
3027
3028
|
if (result.ok) {
|
|
@@ -4041,7 +4042,7 @@ var generateAgentDefinitionsDefinition = {
|
|
|
4041
4042
|
}
|
|
4042
4043
|
};
|
|
4043
4044
|
async function handleGenerateAgentDefinitions(input) {
|
|
4044
|
-
const { generateAgentDefinitions } = await import("./generate-agent-definitions-
|
|
4045
|
+
const { generateAgentDefinitions } = await import("./generate-agent-definitions-XIHQPKG3.js");
|
|
4045
4046
|
const platforms = input.platform === "all" || !input.platform ? ["claude-code", "gemini-cli"] : [input.platform];
|
|
4046
4047
|
const results = generateAgentDefinitions({
|
|
4047
4048
|
platforms: [...platforms],
|
|
@@ -4072,8 +4073,12 @@ async function handleManageRoadmapFileLess(input, client) {
|
|
|
4072
4073
|
return handleUpdate(input, client);
|
|
4073
4074
|
case "remove":
|
|
4074
4075
|
return handleRemove(input, client);
|
|
4076
|
+
case "promote":
|
|
4077
|
+
return handlePromote(input, client);
|
|
4075
4078
|
case "sync":
|
|
4076
4079
|
return handleSync();
|
|
4080
|
+
case "groom":
|
|
4081
|
+
return err("Error: groom is only supported in file-based roadmap mode (docs/roadmap.md).");
|
|
4077
4082
|
default:
|
|
4078
4083
|
return err(`Error: unknown action`);
|
|
4079
4084
|
}
|
|
@@ -4168,6 +4173,80 @@ async function handleRemove(input, client) {
|
|
|
4168
4173
|
});
|
|
4169
4174
|
return ok(`Removed feature: ${found.value.name} (translated to status:done in file-less mode)`);
|
|
4170
4175
|
}
|
|
4176
|
+
var EM_DASH = "\u2014";
|
|
4177
|
+
function isEmptySummaryFileLess(summary) {
|
|
4178
|
+
const trimmed = summary.trim();
|
|
4179
|
+
return trimmed === "" || trimmed === EM_DASH;
|
|
4180
|
+
}
|
|
4181
|
+
function envelope(result) {
|
|
4182
|
+
return {
|
|
4183
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
4184
|
+
isError: result.ok === false
|
|
4185
|
+
};
|
|
4186
|
+
}
|
|
4187
|
+
async function handlePromote(input, client) {
|
|
4188
|
+
if (!input.feature) return err("Error: promote requires feature name");
|
|
4189
|
+
if (!input.spec) return err("Error: promote requires spec path");
|
|
4190
|
+
const fetched = await client.fetchAll();
|
|
4191
|
+
if (!fetched.ok) return err(`Error: ${fetched.error.message}`);
|
|
4192
|
+
const query = input.feature.trim();
|
|
4193
|
+
const queryLower = query.toLowerCase();
|
|
4194
|
+
const matches = fetched.value.features.filter((f) => f.name.trim().toLowerCase() === queryLower);
|
|
4195
|
+
if (matches.length > 1) {
|
|
4196
|
+
const qualified = matches.map((f) => `${f.milestone ?? "(no milestone)"} > ${f.name}`);
|
|
4197
|
+
return envelope({
|
|
4198
|
+
ok: false,
|
|
4199
|
+
reason: "ambiguous",
|
|
4200
|
+
feature: query,
|
|
4201
|
+
detail: `"${query}" matches ${qualified.length} rows. Re-invoke milestone-qualified: ${qualified.join(", ")}.`,
|
|
4202
|
+
matches: qualified
|
|
4203
|
+
});
|
|
4204
|
+
}
|
|
4205
|
+
if (matches.length === 0) {
|
|
4206
|
+
const created = {
|
|
4207
|
+
name: query,
|
|
4208
|
+
summary: input.summary ?? query,
|
|
4209
|
+
status: "planned",
|
|
4210
|
+
spec: input.spec
|
|
4211
|
+
};
|
|
4212
|
+
if (input.milestone !== void 0) created.milestone = input.milestone;
|
|
4213
|
+
const c = await client.create(created);
|
|
4214
|
+
if (!c.ok) return err(`Error: ${c.error.message}`);
|
|
4215
|
+
return envelope({ ok: true, transitioned: "created", feature: query });
|
|
4216
|
+
}
|
|
4217
|
+
const target = matches[0];
|
|
4218
|
+
const decision = decidePromotionForRow(target.status, target.spec, target.summary, {
|
|
4219
|
+
feature: query,
|
|
4220
|
+
spec: input.spec,
|
|
4221
|
+
...input.summary !== void 0 ? { summary: input.summary } : {}
|
|
4222
|
+
});
|
|
4223
|
+
if (decision.action === "refuse") {
|
|
4224
|
+
const detail = decision.reason === "in-progress" ? `"${query}" is in-progress: an agent is dispatched against this row.` : `"${query}" is already 'done'. To revise a shipped feature, use a new name.`;
|
|
4225
|
+
return envelope({ ok: false, reason: decision.reason, feature: query, detail });
|
|
4226
|
+
}
|
|
4227
|
+
if (decision.action === "noop") {
|
|
4228
|
+
return envelope({ ok: true, transitioned: "noop", feature: query });
|
|
4229
|
+
}
|
|
4230
|
+
const patch = { spec: input.spec };
|
|
4231
|
+
if (decision.action === "set-planned") patch.status = "planned";
|
|
4232
|
+
if (input.summary !== void 0 && input.summary !== "" && isEmptySummaryFileLess(target.summary)) {
|
|
4233
|
+
patch.summary = input.summary;
|
|
4234
|
+
}
|
|
4235
|
+
const updated = await client.update(target.externalId, patch);
|
|
4236
|
+
if (!updated.ok) {
|
|
4237
|
+
if (updated.error instanceof ConflictError) {
|
|
4238
|
+
return err(
|
|
4239
|
+
`Error: conflict on ${updated.error.externalId}: ${JSON.stringify(updated.error.diff)}`
|
|
4240
|
+
);
|
|
4241
|
+
}
|
|
4242
|
+
return err(`Error: ${updated.error.message}`);
|
|
4243
|
+
}
|
|
4244
|
+
return envelope({
|
|
4245
|
+
ok: true,
|
|
4246
|
+
transitioned: decision.action === "set-planned" ? "backlog\u2192planned" : "spec-updated",
|
|
4247
|
+
feature: query
|
|
4248
|
+
});
|
|
4249
|
+
}
|
|
4171
4250
|
function handleSync() {
|
|
4172
4251
|
return ok("Roadmap is up to date (file-less mode; tracker is canonical).");
|
|
4173
4252
|
}
|
|
@@ -4199,17 +4278,20 @@ function renderRoadmap(features) {
|
|
|
4199
4278
|
// src/mcp/tools/roadmap.ts
|
|
4200
4279
|
var manageRoadmapDefinition = {
|
|
4201
4280
|
name: "manage_roadmap",
|
|
4202
|
-
description:
|
|
4281
|
+
description: 'Manage the project roadmap: show, add, update, remove, promote, sync, groom features, or query by filter. Reads and writes docs/roadmap.md. The "promote" action transitions an existing row toward planned (backlog\u2192planned) and links its spec atomically \u2014 creating a new planned row under the "Intake" lane if the feature does not exist \u2014 returning a structured RoadmapPromoteResult envelope. The "groom" action tidies the roadmap: it demotes unactionable planned rows (no spec & no plan) to backlog and moves completed features into docs/roadmap-archive.md, returning the list of changes.',
|
|
4203
4282
|
inputSchema: {
|
|
4204
4283
|
type: "object",
|
|
4205
4284
|
properties: {
|
|
4206
4285
|
path: { type: "string", description: "Path to project root" },
|
|
4207
4286
|
action: {
|
|
4208
4287
|
type: "string",
|
|
4209
|
-
enum: ["show", "add", "update", "remove", "query", "sync"],
|
|
4288
|
+
enum: ["show", "add", "update", "remove", "promote", "query", "sync", "groom"],
|
|
4210
4289
|
description: "Action to perform"
|
|
4211
4290
|
},
|
|
4212
|
-
feature: {
|
|
4291
|
+
feature: {
|
|
4292
|
+
type: "string",
|
|
4293
|
+
description: "Feature name (required for add, update, remove, promote)"
|
|
4294
|
+
},
|
|
4213
4295
|
milestone: {
|
|
4214
4296
|
type: "string",
|
|
4215
4297
|
description: "Milestone name (required for add; optional filter for show)"
|
|
@@ -4223,7 +4305,10 @@ var manageRoadmapDefinition = {
|
|
|
4223
4305
|
type: "string",
|
|
4224
4306
|
description: "Feature summary (required for add; optional for update)"
|
|
4225
4307
|
},
|
|
4226
|
-
spec: {
|
|
4308
|
+
spec: {
|
|
4309
|
+
type: "string",
|
|
4310
|
+
description: "Spec file path (optional for add/update; required for promote)"
|
|
4311
|
+
},
|
|
4227
4312
|
plans: {
|
|
4228
4313
|
type: "array",
|
|
4229
4314
|
items: { type: "string" },
|
|
@@ -4271,6 +4356,38 @@ function writeRoadmapFile(projectRoot, content) {
|
|
|
4271
4356
|
fs15.mkdirSync(dir, { recursive: true });
|
|
4272
4357
|
fs15.writeFileSync(filePath, content, "utf-8");
|
|
4273
4358
|
}
|
|
4359
|
+
function archiveFilePath(projectRoot) {
|
|
4360
|
+
return path18.join(projectRoot, "docs", "roadmap-archive.md");
|
|
4361
|
+
}
|
|
4362
|
+
function appendToArchive(projectRoot, archived, project, deps) {
|
|
4363
|
+
if (archived.length === 0) return;
|
|
4364
|
+
const { parseRoadmap, serializeRoadmap } = deps;
|
|
4365
|
+
const filePath = archiveFilePath(projectRoot);
|
|
4366
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
4367
|
+
let archive = null;
|
|
4368
|
+
try {
|
|
4369
|
+
const existing = parseRoadmap(fs15.readFileSync(filePath, "utf-8"));
|
|
4370
|
+
if (existing.ok) archive = existing.value;
|
|
4371
|
+
} catch {
|
|
4372
|
+
archive = null;
|
|
4373
|
+
}
|
|
4374
|
+
if (archive === null) {
|
|
4375
|
+
archive = {
|
|
4376
|
+
frontmatter: { project, version: 1, lastSynced: nowIso, lastManualEdit: nowIso },
|
|
4377
|
+
milestones: [],
|
|
4378
|
+
assignmentHistory: []
|
|
4379
|
+
};
|
|
4380
|
+
}
|
|
4381
|
+
let shipped = archive.milestones.find((m) => m.name === "Shipped");
|
|
4382
|
+
if (!shipped) {
|
|
4383
|
+
shipped = { name: "Shipped", isBacklog: false, features: [] };
|
|
4384
|
+
archive.milestones.push(shipped);
|
|
4385
|
+
}
|
|
4386
|
+
shipped.features.push(...archived);
|
|
4387
|
+
archive.frontmatter.lastManualEdit = nowIso;
|
|
4388
|
+
fs15.mkdirSync(path18.dirname(filePath), { recursive: true });
|
|
4389
|
+
fs15.writeFileSync(filePath, serializeRoadmap(archive), "utf-8");
|
|
4390
|
+
}
|
|
4274
4391
|
function roadmapNotFoundError() {
|
|
4275
4392
|
return {
|
|
4276
4393
|
content: [
|
|
@@ -4440,6 +4557,57 @@ function handleRemove2(projectPath, input, deps) {
|
|
|
4440
4557
|
writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
|
|
4441
4558
|
return resultToMcpResponse(Ok2(roadmap));
|
|
4442
4559
|
}
|
|
4560
|
+
function promoteEnvelopeResponse(envelope2) {
|
|
4561
|
+
return {
|
|
4562
|
+
content: [{ type: "text", text: JSON.stringify(envelope2) }],
|
|
4563
|
+
isError: envelope2.ok === false
|
|
4564
|
+
};
|
|
4565
|
+
}
|
|
4566
|
+
function handlePromote2(projectPath, input, deps) {
|
|
4567
|
+
const { parseRoadmap, serializeRoadmap, promoteFeature } = deps;
|
|
4568
|
+
if (!input.feature) {
|
|
4569
|
+
return {
|
|
4570
|
+
content: [{ type: "text", text: "Error: feature is required for promote action" }],
|
|
4571
|
+
isError: true
|
|
4572
|
+
};
|
|
4573
|
+
}
|
|
4574
|
+
if (!input.spec) {
|
|
4575
|
+
return {
|
|
4576
|
+
content: [{ type: "text", text: "Error: spec is required for promote action" }],
|
|
4577
|
+
isError: true
|
|
4578
|
+
};
|
|
4579
|
+
}
|
|
4580
|
+
const raw = readRoadmapFile(projectPath);
|
|
4581
|
+
if (raw === null) return roadmapNotFoundError();
|
|
4582
|
+
const result = parseRoadmap(raw);
|
|
4583
|
+
if (!result.ok) {
|
|
4584
|
+
return promoteEnvelopeResponse({
|
|
4585
|
+
ok: false,
|
|
4586
|
+
reason: "write-failed",
|
|
4587
|
+
feature: input.feature,
|
|
4588
|
+
detail: result.error.message
|
|
4589
|
+
});
|
|
4590
|
+
}
|
|
4591
|
+
const { result: envelope2, nextRoadmap } = promoteFeature(result.value, {
|
|
4592
|
+
feature: input.feature,
|
|
4593
|
+
spec: input.spec,
|
|
4594
|
+
...input.summary !== void 0 ? { summary: input.summary } : {}
|
|
4595
|
+
});
|
|
4596
|
+
if (envelope2.ok && envelope2.transitioned !== "noop") {
|
|
4597
|
+
nextRoadmap.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
|
|
4598
|
+
try {
|
|
4599
|
+
writeRoadmapFile(projectPath, serializeRoadmap(nextRoadmap));
|
|
4600
|
+
} catch (error) {
|
|
4601
|
+
return promoteEnvelopeResponse({
|
|
4602
|
+
ok: false,
|
|
4603
|
+
reason: "write-failed",
|
|
4604
|
+
feature: input.feature,
|
|
4605
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
4606
|
+
});
|
|
4607
|
+
}
|
|
4608
|
+
}
|
|
4609
|
+
return promoteEnvelopeResponse(envelope2);
|
|
4610
|
+
}
|
|
4443
4611
|
function handleQuery2(projectPath, input, deps) {
|
|
4444
4612
|
const { parseRoadmap, Ok: Ok2 } = deps;
|
|
4445
4613
|
if (!input.filter) {
|
|
@@ -4490,6 +4658,31 @@ function handleSync2(projectPath, input, deps) {
|
|
|
4490
4658
|
}
|
|
4491
4659
|
return resultToMcpResponse(Ok2({ changes, applied: false }));
|
|
4492
4660
|
}
|
|
4661
|
+
function handleGroom(projectPath, _input, deps) {
|
|
4662
|
+
const { parseRoadmap, serializeRoadmap, groomRoadmap, Ok: Ok2 } = deps;
|
|
4663
|
+
const raw = readRoadmapFile(projectPath);
|
|
4664
|
+
if (raw === null) return roadmapNotFoundError();
|
|
4665
|
+
const result = parseRoadmap(raw);
|
|
4666
|
+
if (!result.ok) return resultToMcpResponse(result);
|
|
4667
|
+
const { roadmap: groomed, archived, changes } = groomRoadmap(result.value);
|
|
4668
|
+
if (changes.length === 0) {
|
|
4669
|
+
return resultToMcpResponse(
|
|
4670
|
+
Ok2({ changes: [], archived: 0, demoted: 0, message: "Roadmap is already tidy." })
|
|
4671
|
+
);
|
|
4672
|
+
}
|
|
4673
|
+
appendToArchive(projectPath, archived, groomed.frontmatter.project, deps);
|
|
4674
|
+
groomed.frontmatter.lastManualEdit = (/* @__PURE__ */ new Date()).toISOString();
|
|
4675
|
+
writeRoadmapFile(projectPath, serializeRoadmap(groomed));
|
|
4676
|
+
const demoted = changes.filter((c) => c.kind === "demoted").length;
|
|
4677
|
+
return resultToMcpResponse(
|
|
4678
|
+
Ok2({
|
|
4679
|
+
changes,
|
|
4680
|
+
archived: archived.length,
|
|
4681
|
+
demoted,
|
|
4682
|
+
message: `Groomed: ${demoted} demoted to backlog, ${archived.length} archived to docs/roadmap-archive.md.`
|
|
4683
|
+
})
|
|
4684
|
+
);
|
|
4685
|
+
}
|
|
4493
4686
|
var readOnlyActions = /* @__PURE__ */ new Set(["show", "query"]);
|
|
4494
4687
|
function dispatchAction(action, projectPath, input, deps) {
|
|
4495
4688
|
switch (action) {
|
|
@@ -4501,10 +4694,14 @@ function dispatchAction(action, projectPath, input, deps) {
|
|
|
4501
4694
|
return handleUpdate2(projectPath, input, deps);
|
|
4502
4695
|
case "remove":
|
|
4503
4696
|
return handleRemove2(projectPath, input, deps);
|
|
4697
|
+
case "promote":
|
|
4698
|
+
return handlePromote2(projectPath, input, deps);
|
|
4504
4699
|
case "query":
|
|
4505
4700
|
return handleQuery2(projectPath, input, deps);
|
|
4506
4701
|
case "sync":
|
|
4507
4702
|
return handleSync2(projectPath, input, deps);
|
|
4703
|
+
case "groom":
|
|
4704
|
+
return handleGroom(projectPath, input, deps);
|
|
4508
4705
|
default:
|
|
4509
4706
|
return { content: [{ type: "text", text: `Error: unknown action` }], isError: true };
|
|
4510
4707
|
}
|
|
@@ -4512,6 +4709,7 @@ function dispatchAction(action, projectPath, input, deps) {
|
|
|
4512
4709
|
function shouldTriggerExternalSync(input, response) {
|
|
4513
4710
|
if (response.isError || readOnlyActions.has(input.action)) return false;
|
|
4514
4711
|
if (input.action === "sync") return input.apply === true;
|
|
4712
|
+
if (input.action === "groom") return false;
|
|
4515
4713
|
return true;
|
|
4516
4714
|
}
|
|
4517
4715
|
async function handleManageRoadmap(input) {
|
|
@@ -4535,7 +4733,15 @@ async function handleManageRoadmap(input) {
|
|
|
4535
4733
|
return handleManageRoadmapFileLess(input, clientResult.value);
|
|
4536
4734
|
}
|
|
4537
4735
|
try {
|
|
4538
|
-
const {
|
|
4736
|
+
const {
|
|
4737
|
+
parseRoadmap,
|
|
4738
|
+
serializeRoadmap,
|
|
4739
|
+
syncRoadmap,
|
|
4740
|
+
applySyncChanges,
|
|
4741
|
+
assignFeature,
|
|
4742
|
+
promoteFeature,
|
|
4743
|
+
groomRoadmap
|
|
4744
|
+
} = await import("./dist-LHINSVK4.js");
|
|
4539
4745
|
const { Ok: Ok2 } = await import("./dist-ICW4QUEW.js");
|
|
4540
4746
|
const projectPath = projectPathPre;
|
|
4541
4747
|
const deps = {
|
|
@@ -4544,6 +4750,8 @@ async function handleManageRoadmap(input) {
|
|
|
4544
4750
|
syncRoadmap,
|
|
4545
4751
|
applySyncChanges,
|
|
4546
4752
|
assignFeature,
|
|
4753
|
+
promoteFeature,
|
|
4754
|
+
groomRoadmap,
|
|
4547
4755
|
Ok: Ok2
|
|
4548
4756
|
};
|
|
4549
4757
|
const response = dispatchAction(input.action, projectPath, input, deps);
|
|
@@ -4974,7 +5182,7 @@ async function handleTransition(validInput, projectPath, id) {
|
|
|
4974
5182
|
const transition = transitionResult.data;
|
|
4975
5183
|
const prompt = renderTransition(transition);
|
|
4976
5184
|
try {
|
|
4977
|
-
const { saveHandoff } = await import("./dist-
|
|
5185
|
+
const { saveHandoff } = await import("./dist-LHINSVK4.js");
|
|
4978
5186
|
await saveHandoff(
|
|
4979
5187
|
projectPath,
|
|
4980
5188
|
{
|
|
@@ -5055,7 +5263,7 @@ async function handleEmitInteraction(input) {
|
|
|
5055
5263
|
}
|
|
5056
5264
|
async function recordInteraction(projectPath, id, type, decision, stream) {
|
|
5057
5265
|
try {
|
|
5058
|
-
const { loadState, saveState } = await import("./dist-
|
|
5266
|
+
const { loadState, saveState } = await import("./dist-LHINSVK4.js");
|
|
5059
5267
|
const stateResult = await loadState(projectPath, stream);
|
|
5060
5268
|
if (stateResult.ok) {
|
|
5061
5269
|
const state = stateResult.value;
|
|
@@ -5216,10 +5424,10 @@ async function handleGatherContext(input) {
|
|
|
5216
5424
|
input.include ?? ["state", "learnings", "handoff", "graph", "validation", "businessKnowledge"]
|
|
5217
5425
|
);
|
|
5218
5426
|
const errors = [];
|
|
5219
|
-
const statePromise = includeSet.has("state") ? import("./dist-
|
|
5427
|
+
const statePromise = includeSet.has("state") ? import("./dist-LHINSVK4.js").then(
|
|
5220
5428
|
(core) => core.loadState(projectPath, void 0, input.session)
|
|
5221
5429
|
) : Promise.resolve(null);
|
|
5222
|
-
const learningsPromise = includeSet.has("learnings") ? import("./dist-
|
|
5430
|
+
const learningsPromise = includeSet.has("learnings") ? import("./dist-LHINSVK4.js").then(
|
|
5223
5431
|
(core) => core.loadBudgetedLearnings(projectPath, {
|
|
5224
5432
|
intent: input.intent,
|
|
5225
5433
|
tokenBudget: input.learningsBudget ?? 1e3,
|
|
@@ -5228,7 +5436,7 @@ async function handleGatherContext(input) {
|
|
|
5228
5436
|
...input.depth !== void 0 && { depth: input.depth }
|
|
5229
5437
|
})
|
|
5230
5438
|
) : Promise.resolve(null);
|
|
5231
|
-
const handoffPromise = includeSet.has("handoff") ? import("./dist-
|
|
5439
|
+
const handoffPromise = includeSet.has("handoff") ? import("./dist-LHINSVK4.js").then(
|
|
5232
5440
|
(core) => core.loadHandoff(projectPath, void 0, input.session)
|
|
5233
5441
|
) : Promise.resolve(null);
|
|
5234
5442
|
const graphPromise = includeSet.has("graph") ? (async () => {
|
|
@@ -5272,11 +5480,11 @@ async function handleGatherContext(input) {
|
|
|
5272
5480
|
context: contextBlocks
|
|
5273
5481
|
};
|
|
5274
5482
|
})() : Promise.resolve(null);
|
|
5275
|
-
const sessionsPromise = includeSet.has("sessions") && input.session ? import("./dist-
|
|
5483
|
+
const sessionsPromise = includeSet.has("sessions") && input.session ? import("./dist-LHINSVK4.js").then(
|
|
5276
5484
|
(core) => core.readSessionSections(projectPath, input.session)
|
|
5277
5485
|
) : Promise.resolve(null);
|
|
5278
5486
|
const shouldIncludeEvents = input.includeEvents !== void 0 ? input.includeEvents : includeSet.has("events") || !!input.session && !input.include;
|
|
5279
|
-
const eventsPromise = shouldIncludeEvents ? import("./dist-
|
|
5487
|
+
const eventsPromise = shouldIncludeEvents ? import("./dist-LHINSVK4.js").then(async (core) => {
|
|
5280
5488
|
const result = await core.loadEvents(projectPath, {
|
|
5281
5489
|
session: input.session
|
|
5282
5490
|
});
|
|
@@ -5284,7 +5492,7 @@ async function handleGatherContext(input) {
|
|
|
5284
5492
|
return core.formatEventTimeline(result.value);
|
|
5285
5493
|
}) : Promise.resolve(null);
|
|
5286
5494
|
const validationPromise = includeSet.has("validation") ? (async () => {
|
|
5287
|
-
const { handleValidateProject: handleValidateProject2 } = await import("./validate-
|
|
5495
|
+
const { handleValidateProject: handleValidateProject2 } = await import("./validate-7IAF2ES3.js");
|
|
5288
5496
|
const result = await handleValidateProject2({ path: projectPath });
|
|
5289
5497
|
const first = result.content[0];
|
|
5290
5498
|
return first ? JSON.parse(first.text) : null;
|
|
@@ -5387,7 +5595,7 @@ async function handleGatherContext(input) {
|
|
|
5387
5595
|
};
|
|
5388
5596
|
if (input.session) {
|
|
5389
5597
|
try {
|
|
5390
|
-
const core = await import("./dist-
|
|
5598
|
+
const core = await import("./dist-LHINSVK4.js");
|
|
5391
5599
|
core.updateSessionIndex(
|
|
5392
5600
|
projectPath,
|
|
5393
5601
|
input.session,
|
|
@@ -5426,6 +5634,52 @@ async function handleGatherContext(input) {
|
|
|
5426
5634
|
};
|
|
5427
5635
|
}
|
|
5428
5636
|
|
|
5637
|
+
// src/mcp/tools/canary.ts
|
|
5638
|
+
import { createCanaryAdapter } from "@harness-engineering/intelligence";
|
|
5639
|
+
var canaryProbeDefinition = {
|
|
5640
|
+
name: "canary_probe",
|
|
5641
|
+
description: 'Probe availability of the optional canary test CLI (canary-test-cli). Returns { status: "available" | "degraded", version?, reason? } where reason is one of not-installed | binary-missing | exec-failed | bad-output. Never errors when canary is absent \u2014 call it before surfacing canary-backed steps so the audit can degrade gracefully.',
|
|
5642
|
+
inputSchema: {
|
|
5643
|
+
type: "object",
|
|
5644
|
+
properties: {}
|
|
5645
|
+
}
|
|
5646
|
+
};
|
|
5647
|
+
var canaryRecommendFrameworkDefinition = {
|
|
5648
|
+
name: "canary_recommend_framework",
|
|
5649
|
+
description: 'Classify a test prompt with canary and recommend a framework (deterministic, no API key). Returns { status, test_type, framework, file_extension, reasoning[], alternatives[] }. Degrades to a { status: "degraded" } sentinel when canary is unavailable.',
|
|
5650
|
+
inputSchema: {
|
|
5651
|
+
type: "object",
|
|
5652
|
+
properties: {
|
|
5653
|
+
prompt: {
|
|
5654
|
+
type: "string",
|
|
5655
|
+
description: 'Natural-language description of the test to scaffold, e.g. "end-to-end login flow in the browser".'
|
|
5656
|
+
}
|
|
5657
|
+
},
|
|
5658
|
+
required: ["prompt"]
|
|
5659
|
+
}
|
|
5660
|
+
};
|
|
5661
|
+
function jsonResponse(data) {
|
|
5662
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
5663
|
+
}
|
|
5664
|
+
async function handleCanaryProbe(_input, adapter = createCanaryAdapter()) {
|
|
5665
|
+
return jsonResponse(await adapter.probe());
|
|
5666
|
+
}
|
|
5667
|
+
async function handleCanaryRecommendFramework(input, adapter = createCanaryAdapter()) {
|
|
5668
|
+
const prompt = typeof input?.prompt === "string" ? input.prompt.trim() : "";
|
|
5669
|
+
if (!prompt) {
|
|
5670
|
+
return {
|
|
5671
|
+
content: [
|
|
5672
|
+
{
|
|
5673
|
+
type: "text",
|
|
5674
|
+
text: 'Error: "prompt" is required and must be a non-empty string.'
|
|
5675
|
+
}
|
|
5676
|
+
],
|
|
5677
|
+
isError: true
|
|
5678
|
+
};
|
|
5679
|
+
}
|
|
5680
|
+
return jsonResponse(await adapter.recommendFramework(prompt));
|
|
5681
|
+
}
|
|
5682
|
+
|
|
5429
5683
|
// src/mcp/tools/review-changes.ts
|
|
5430
5684
|
init_dist2();
|
|
5431
5685
|
var SIZE_GATE_LINES = 1e4;
|
|
@@ -5539,7 +5793,7 @@ async function handleReviewChanges(input) {
|
|
|
5539
5793
|
}
|
|
5540
5794
|
}
|
|
5541
5795
|
async function runQuickReview(projectPath, diff, diffLines, downgraded, offset, limit) {
|
|
5542
|
-
const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-
|
|
5796
|
+
const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-YXYY44ZC.js");
|
|
5543
5797
|
const result = await handleAnalyzeDiff2({ diff, path: projectPath });
|
|
5544
5798
|
const firstContent = result.content[0];
|
|
5545
5799
|
if (!firstContent) throw new Error("Empty analyze_diff response");
|
|
@@ -5574,7 +5828,7 @@ function extractFileCount(diffParsed) {
|
|
|
5574
5828
|
return files?.length ?? 0;
|
|
5575
5829
|
}
|
|
5576
5830
|
async function runStandardReview(projectPath, diff, diffLines, downgraded, offset, limit) {
|
|
5577
|
-
const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-
|
|
5831
|
+
const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-YXYY44ZC.js");
|
|
5578
5832
|
const [diffResult, reviewResult] = await Promise.all([
|
|
5579
5833
|
handleAnalyzeDiff2({ diff, path: projectPath }),
|
|
5580
5834
|
handleCreateSelfReview2({ path: projectPath, diff })
|
|
@@ -5609,7 +5863,7 @@ async function runStandardReview(projectPath, diff, diffLines, downgraded, offse
|
|
|
5609
5863
|
};
|
|
5610
5864
|
}
|
|
5611
5865
|
async function runDeepReview(projectPath, diff, diffLines, _downgraded, offset, limit) {
|
|
5612
|
-
const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-
|
|
5866
|
+
const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-NENG6LW7.js");
|
|
5613
5867
|
const result = await handleRunCodeReview2({
|
|
5614
5868
|
path: projectPath,
|
|
5615
5869
|
diff,
|
|
@@ -5621,6 +5875,7 @@ async function runDeepReview(projectPath, diff, diffLines, _downgraded, offset,
|
|
|
5621
5875
|
const rawFindings = parsed.findings ?? [];
|
|
5622
5876
|
const sorted = sortFindingsBySeverity(rawFindings);
|
|
5623
5877
|
const paged = paginate(sorted, offset ?? 0, limit ?? 20);
|
|
5878
|
+
const { findings: _full, findingCount: _fullCount, ...pipelineRest } = parsed;
|
|
5624
5879
|
return {
|
|
5625
5880
|
content: [
|
|
5626
5881
|
{
|
|
@@ -5633,7 +5888,7 @@ async function runDeepReview(projectPath, diff, diffLines, _downgraded, offset,
|
|
|
5633
5888
|
assessment: parsed.assessment,
|
|
5634
5889
|
findingCount: parsed.findingCount,
|
|
5635
5890
|
lineCount: diffLines,
|
|
5636
|
-
pipeline:
|
|
5891
|
+
pipeline: pipelineRest
|
|
5637
5892
|
})
|
|
5638
5893
|
}
|
|
5639
5894
|
]
|
|
@@ -5903,7 +6158,7 @@ async function handleDetectStaleConstraints(input) {
|
|
|
5903
6158
|
]
|
|
5904
6159
|
};
|
|
5905
6160
|
}
|
|
5906
|
-
const { detectStaleConstraints } = await import("./dist-
|
|
6161
|
+
const { detectStaleConstraints } = await import("./dist-LHINSVK4.js");
|
|
5907
6162
|
const result = detectStaleConstraints(
|
|
5908
6163
|
store,
|
|
5909
6164
|
windowDays,
|
|
@@ -6033,10 +6288,10 @@ function countCriticalFindings(securityData) {
|
|
|
6033
6288
|
return findings.filter((f) => f.severity === "error").length;
|
|
6034
6289
|
}
|
|
6035
6290
|
async function runHealthChecks(projectPath) {
|
|
6036
|
-
const { handleAssessProject: handleAssessProject2 } = await import("./assess-project-
|
|
6037
|
-
const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-
|
|
6038
|
-
const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-
|
|
6039
|
-
const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-
|
|
6291
|
+
const { handleAssessProject: handleAssessProject2 } = await import("./assess-project-RHXOQNMM.js");
|
|
6292
|
+
const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-JEZPJ725.js");
|
|
6293
|
+
const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-VLKDRMRT.js");
|
|
6294
|
+
const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-3PIBN35B.js");
|
|
6040
6295
|
const [assessResult, depsResult, entropyResult, securityResult] = await Promise.all([
|
|
6041
6296
|
handleAssessProject2({
|
|
6042
6297
|
path: projectPath,
|
|
@@ -6879,7 +7134,7 @@ async function handleGetDecayTrends(input) {
|
|
|
6879
7134
|
};
|
|
6880
7135
|
}
|
|
6881
7136
|
try {
|
|
6882
|
-
const core = await import("./dist-
|
|
7137
|
+
const core = await import("./dist-LHINSVK4.js");
|
|
6883
7138
|
const { TimelineManager } = core;
|
|
6884
7139
|
const manager = new TimelineManager(projectPath);
|
|
6885
7140
|
const timeline = manager.load();
|
|
@@ -7014,7 +7269,7 @@ async function handleCodeOutline(input) {
|
|
|
7014
7269
|
};
|
|
7015
7270
|
}
|
|
7016
7271
|
try {
|
|
7017
|
-
const { getOutline, formatOutline, EXTENSION_MAP } = await import("./dist-
|
|
7272
|
+
const { getOutline, formatOutline, EXTENSION_MAP } = await import("./dist-LHINSVK4.js");
|
|
7018
7273
|
const { stat } = await import("fs/promises");
|
|
7019
7274
|
const stats = await stat(targetPath).catch(() => null);
|
|
7020
7275
|
if (stats?.isFile()) {
|
|
@@ -7033,7 +7288,7 @@ async function handleCodeOutline(input) {
|
|
|
7033
7288
|
})
|
|
7034
7289
|
);
|
|
7035
7290
|
fileStats.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
7036
|
-
const { paginate: paginate2 } = await import("./dist-
|
|
7291
|
+
const { paginate: paginate2 } = await import("./dist-LHINSVK4.js");
|
|
7037
7292
|
const paged = paginate2(fileStats, input.offset ?? 0, input.limit ?? 30);
|
|
7038
7293
|
const results = [];
|
|
7039
7294
|
for (const entry of paged.items) {
|
|
@@ -7106,7 +7361,7 @@ async function handleCodeSearch(input) {
|
|
|
7106
7361
|
};
|
|
7107
7362
|
}
|
|
7108
7363
|
try {
|
|
7109
|
-
const { searchSymbols } = await import("./dist-
|
|
7364
|
+
const { searchSymbols } = await import("./dist-LHINSVK4.js");
|
|
7110
7365
|
const result = await searchSymbols(input.query, directory, input.glob);
|
|
7111
7366
|
const lines = [`Search: "${result.query}" \u2014 ${result.matches.length} matches`];
|
|
7112
7367
|
for (const match of result.matches) {
|
|
@@ -7175,7 +7430,7 @@ async function handleCodeUnfold(input) {
|
|
|
7175
7430
|
}
|
|
7176
7431
|
try {
|
|
7177
7432
|
if (input.symbol) {
|
|
7178
|
-
const { unfoldSymbol } = await import("./dist-
|
|
7433
|
+
const { unfoldSymbol } = await import("./dist-LHINSVK4.js");
|
|
7179
7434
|
const result = await unfoldSymbol(filePath, input.symbol);
|
|
7180
7435
|
const header = result.warning ? `${result.file}:${result.startLine}-${result.endLine} ${result.warning}
|
|
7181
7436
|
` : `${result.file}:${result.startLine}-${result.endLine}
|
|
@@ -7183,7 +7438,7 @@ async function handleCodeUnfold(input) {
|
|
|
7183
7438
|
return { content: [{ type: "text", text: header + result.content }] };
|
|
7184
7439
|
}
|
|
7185
7440
|
if (input.startLine != null && input.endLine != null) {
|
|
7186
|
-
const { unfoldRange } = await import("./dist-
|
|
7441
|
+
const { unfoldRange } = await import("./dist-LHINSVK4.js");
|
|
7187
7442
|
const result = await unfoldRange(filePath, input.startLine, input.endLine);
|
|
7188
7443
|
const header = `${result.file}:${result.startLine}-${result.endLine}
|
|
7189
7444
|
`;
|
|
@@ -7368,7 +7623,7 @@ async function handlePredictFailures(input) {
|
|
|
7368
7623
|
};
|
|
7369
7624
|
}
|
|
7370
7625
|
try {
|
|
7371
|
-
const core = await import("./dist-
|
|
7626
|
+
const core = await import("./dist-LHINSVK4.js");
|
|
7372
7627
|
const { TimelineManager, PredictionEngine, SpecImpactEstimator } = core;
|
|
7373
7628
|
const manager = new TimelineManager(projectPath);
|
|
7374
7629
|
const includeRoadmap = input.includeRoadmap !== false;
|
|
@@ -8240,14 +8495,14 @@ function buildEnvelope(originalContent, compactedSections, strategyNames, cached
|
|
|
8240
8495
|
}
|
|
8241
8496
|
function handleContentMode(content, pipeline, budget, source) {
|
|
8242
8497
|
const compacted = pipeline.apply(content, budget);
|
|
8243
|
-
const
|
|
8498
|
+
const envelope2 = buildEnvelope(
|
|
8244
8499
|
content,
|
|
8245
8500
|
[{ source, content: compacted }],
|
|
8246
8501
|
pipeline.strategyNames,
|
|
8247
8502
|
false
|
|
8248
8503
|
);
|
|
8249
8504
|
return {
|
|
8250
|
-
content: [{ type: "text", text: serializeEnvelope(
|
|
8505
|
+
content: [{ type: "text", text: serializeEnvelope(envelope2) }]
|
|
8251
8506
|
};
|
|
8252
8507
|
}
|
|
8253
8508
|
async function handleIntentMode(projectPath, intent, pipeline, budget, filterContent) {
|
|
@@ -8279,7 +8534,7 @@ async function handleIntentMode(projectPath, intent, pipeline, budget, filterCon
|
|
|
8279
8534
|
const searchQuery = filterContent ? `${intent} ${filterContent}` : intent;
|
|
8280
8535
|
const searchResults = fusion.search(searchQuery, 10);
|
|
8281
8536
|
if (searchResults.length === 0) {
|
|
8282
|
-
const
|
|
8537
|
+
const envelope3 = {
|
|
8283
8538
|
meta: {
|
|
8284
8539
|
strategy: pipeline.strategyNames,
|
|
8285
8540
|
originalTokenEstimate: 0,
|
|
@@ -8290,7 +8545,7 @@ async function handleIntentMode(projectPath, intent, pipeline, budget, filterCon
|
|
|
8290
8545
|
sections: [{ source: "compact", content: "No relevant context found for intent." }]
|
|
8291
8546
|
};
|
|
8292
8547
|
return {
|
|
8293
|
-
content: [{ type: "text", text: serializeEnvelope(
|
|
8548
|
+
content: [{ type: "text", text: serializeEnvelope(envelope3) }]
|
|
8294
8549
|
};
|
|
8295
8550
|
}
|
|
8296
8551
|
const totalScore = searchResults.reduce((sum, r) => sum + r.score, 0);
|
|
@@ -8317,7 +8572,7 @@ async function handleIntentMode(projectPath, intent, pipeline, budget, filterCon
|
|
|
8317
8572
|
const originalTokens = Math.ceil(totalOriginalChars / 4);
|
|
8318
8573
|
const compactedTokens = sections.reduce((sum, s) => sum + estimateTokens(s.content), 0);
|
|
8319
8574
|
const reductionPct = originalTokens > 0 ? Math.round((1 - compactedTokens / originalTokens) * 100) : 0;
|
|
8320
|
-
const
|
|
8575
|
+
const envelope2 = {
|
|
8321
8576
|
meta: {
|
|
8322
8577
|
strategy: pipeline.strategyNames,
|
|
8323
8578
|
originalTokenEstimate: originalTokens,
|
|
@@ -8327,9 +8582,9 @@ async function handleIntentMode(projectPath, intent, pipeline, budget, filterCon
|
|
|
8327
8582
|
},
|
|
8328
8583
|
sections
|
|
8329
8584
|
};
|
|
8330
|
-
cache.set(intent,
|
|
8585
|
+
cache.set(intent, envelope2, sourceNodeIds);
|
|
8331
8586
|
return {
|
|
8332
|
-
content: [{ type: "text", text: serializeEnvelope(
|
|
8587
|
+
content: [{ type: "text", text: serializeEnvelope(envelope2) }]
|
|
8333
8588
|
};
|
|
8334
8589
|
}
|
|
8335
8590
|
async function handleCompact(input) {
|
|
@@ -8477,7 +8732,7 @@ async function handleDetectConstraintEmergence(input) {
|
|
|
8477
8732
|
}
|
|
8478
8733
|
const nodePath = await import("path");
|
|
8479
8734
|
const historyPath = nodePath.resolve(projectPath, ".harness/arch/violation-history.json");
|
|
8480
|
-
const { ViolationHistoryManager, detectEmergentConstraints } = await import("./dist-
|
|
8735
|
+
const { ViolationHistoryManager, detectEmergentConstraints } = await import("./dist-LHINSVK4.js");
|
|
8481
8736
|
const manager = new ViolationHistoryManager(historyPath);
|
|
8482
8737
|
const history = manager.load();
|
|
8483
8738
|
const options = { windowWeeks, minOccurrences };
|
|
@@ -8565,7 +8820,7 @@ async function handleRunCIChecks(input) {
|
|
|
8565
8820
|
};
|
|
8566
8821
|
}
|
|
8567
8822
|
try {
|
|
8568
|
-
const { runCIChecks } = await import("./dist-
|
|
8823
|
+
const { runCIChecks } = await import("./dist-LHINSVK4.js");
|
|
8569
8824
|
const skip = input.checks ? VALID_CHECKS.filter((c) => !input.checks.includes(c)) : [];
|
|
8570
8825
|
const result = await runCIChecks({
|
|
8571
8826
|
projectRoot: projectPath,
|
|
@@ -8627,7 +8882,7 @@ async function handleGenerateBlueprint(input) {
|
|
|
8627
8882
|
};
|
|
8628
8883
|
}
|
|
8629
8884
|
try {
|
|
8630
|
-
const { ProjectScanner } = await import("./dist-
|
|
8885
|
+
const { ProjectScanner } = await import("./dist-LHINSVK4.js");
|
|
8631
8886
|
const scanner = new ProjectScanner(projectPath);
|
|
8632
8887
|
const data = await scanner.scan();
|
|
8633
8888
|
return {
|
|
@@ -8826,7 +9081,7 @@ async function handleEmitSkillProposal(input) {
|
|
|
8826
9081
|
let createProposal;
|
|
8827
9082
|
let ProposalConflictError;
|
|
8828
9083
|
try {
|
|
8829
|
-
const core = await import("./dist-
|
|
9084
|
+
const core = await import("./dist-LHINSVK4.js");
|
|
8830
9085
|
createProposal = core.createProposal;
|
|
8831
9086
|
ProposalConflictError = core.ProposalConflictError;
|
|
8832
9087
|
} catch (err2) {
|
|
@@ -12267,7 +12522,8 @@ var LazyLocalAdapter = class {
|
|
|
12267
12522
|
const inner = new OpenAICompatibleAnalysisProvider({
|
|
12268
12523
|
apiKey: this.opts.apiKey,
|
|
12269
12524
|
baseUrl: this.opts.endpoint,
|
|
12270
|
-
defaultModel: match
|
|
12525
|
+
defaultModel: match,
|
|
12526
|
+
...this.opts.llmTimeoutMs !== void 0 ? { timeoutMs: this.opts.llmTimeoutMs } : {}
|
|
12271
12527
|
});
|
|
12272
12528
|
const provider = new AnalysisProviderAdapter({
|
|
12273
12529
|
providerId: this.providerId,
|
|
@@ -18506,6 +18762,106 @@ async function handleSecurityCraft(input) {
|
|
|
18506
18762
|
}
|
|
18507
18763
|
}
|
|
18508
18764
|
|
|
18765
|
+
// src/mcp/tools/outcome-eval.ts
|
|
18766
|
+
var outcomeEvalDefinition = {
|
|
18767
|
+
name: "outcome_eval",
|
|
18768
|
+
description: "Post-execution LLM-judgment: did the implementation actually satisfy its spec? Reads the spec's acceptance section, the change diff, and test output, and emits a confidence-rated OutcomeVerdict (SATISFIED | NOT_SATISFIED | INCONCLUSIVE) with a rationale and unmetCriteria. Ship authority is DERIVED in TypeScript, never trusted from the LLM: a high-confidence NOT_SATISFIED is blocking; every other verdict is advisory. The harness's first blocking post-execution spec-satisfaction gate. IMPORTANT: diff and testOutput are required \u2014 omitting them degrades the verdict to INCONCLUSIVE/advisory (never blocking), so the calling agent MUST supply them from the session (git diff + test-runner output). Each verdict persists as an execution_outcome node.",
|
|
18769
|
+
inputSchema: {
|
|
18770
|
+
type: "object",
|
|
18771
|
+
properties: {
|
|
18772
|
+
specPath: {
|
|
18773
|
+
type: "string",
|
|
18774
|
+
description: "Absolute or repo-relative path to the spec markdown to judge against"
|
|
18775
|
+
},
|
|
18776
|
+
diff: {
|
|
18777
|
+
type: "string",
|
|
18778
|
+
description: "Unified diff of the change under judgment (e.g. `git diff` / `git diff <base>...HEAD`). Required: an empty diff degrades the verdict to INCONCLUSIVE/advisory."
|
|
18779
|
+
},
|
|
18780
|
+
testOutput: {
|
|
18781
|
+
type: "string",
|
|
18782
|
+
description: "Captured test-runner stdout+stderr. Required: empty/unparseable output is tolerated but degrades the verdict toward INCONCLUSIVE/advisory."
|
|
18783
|
+
},
|
|
18784
|
+
model: {
|
|
18785
|
+
type: "string",
|
|
18786
|
+
description: "Optional model override for the outcome-eval LLM call"
|
|
18787
|
+
},
|
|
18788
|
+
path: {
|
|
18789
|
+
type: "string",
|
|
18790
|
+
description: "Project root used to resolve the knowledge graph (default: cwd)"
|
|
18791
|
+
}
|
|
18792
|
+
},
|
|
18793
|
+
required: ["specPath", "diff", "testOutput"]
|
|
18794
|
+
}
|
|
18795
|
+
};
|
|
18796
|
+
async function resolveAnalysisProvider(model) {
|
|
18797
|
+
try {
|
|
18798
|
+
const intelligence = await import("@harness-engineering/intelligence");
|
|
18799
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
18800
|
+
if (!apiKey) return null;
|
|
18801
|
+
const Provider = intelligence.AnthropicAnalysisProvider;
|
|
18802
|
+
if (typeof Provider !== "function") return null;
|
|
18803
|
+
return new Provider(model !== void 0 ? { apiKey, defaultModel: model } : { apiKey });
|
|
18804
|
+
} catch {
|
|
18805
|
+
return null;
|
|
18806
|
+
}
|
|
18807
|
+
}
|
|
18808
|
+
async function emptyGraphStore() {
|
|
18809
|
+
const { GraphStore } = await import("./dist-OWHMNL4W.js");
|
|
18810
|
+
return new GraphStore();
|
|
18811
|
+
}
|
|
18812
|
+
function validateInput(input) {
|
|
18813
|
+
if (typeof input?.specPath !== "string" || input.specPath.length === 0) {
|
|
18814
|
+
return "outcome_eval: `specPath` is required";
|
|
18815
|
+
}
|
|
18816
|
+
if (typeof input?.diff !== "string") return "outcome_eval: `diff` is required";
|
|
18817
|
+
if (typeof input?.testOutput !== "string") return "outcome_eval: `testOutput` is required";
|
|
18818
|
+
return null;
|
|
18819
|
+
}
|
|
18820
|
+
async function buildEvaluator(input) {
|
|
18821
|
+
const projectRoot = sanitizePath(input.path ?? process.cwd());
|
|
18822
|
+
const { OutcomeEvaluator } = await import("@harness-engineering/intelligence");
|
|
18823
|
+
const provider = await resolveAnalysisProvider(input.model);
|
|
18824
|
+
const store = await loadGraphStore(projectRoot) ?? await emptyGraphStore();
|
|
18825
|
+
return new OutcomeEvaluator(
|
|
18826
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18827
|
+
provider ?? unconfiguredProvider(),
|
|
18828
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18829
|
+
store,
|
|
18830
|
+
input.model !== void 0 ? { model: input.model } : {}
|
|
18831
|
+
);
|
|
18832
|
+
}
|
|
18833
|
+
async function handleOutcomeEval(input) {
|
|
18834
|
+
const validationError = validateInput(input);
|
|
18835
|
+
if (validationError !== null) return errorResponse(validationError);
|
|
18836
|
+
try {
|
|
18837
|
+
const evaluator = await buildEvaluator(input);
|
|
18838
|
+
const verdict = await evaluator.evaluate({
|
|
18839
|
+
specPath: input.specPath,
|
|
18840
|
+
diff: input.diff,
|
|
18841
|
+
testOutput: input.testOutput
|
|
18842
|
+
});
|
|
18843
|
+
return { content: [{ type: "text", text: JSON.stringify(verdict, null, 2) }] };
|
|
18844
|
+
} catch (err2) {
|
|
18845
|
+
const message = err2 instanceof Error ? err2.message : String(err2);
|
|
18846
|
+
return errorResponse(`outcome_eval failed: ${message}`);
|
|
18847
|
+
}
|
|
18848
|
+
}
|
|
18849
|
+
function unconfiguredProvider() {
|
|
18850
|
+
return {
|
|
18851
|
+
analyze: () => Promise.reject(
|
|
18852
|
+
new Error(
|
|
18853
|
+
"No analysis provider configured (set ANTHROPIC_API_KEY). Degrading to an inconclusive, advisory verdict."
|
|
18854
|
+
)
|
|
18855
|
+
)
|
|
18856
|
+
};
|
|
18857
|
+
}
|
|
18858
|
+
function errorResponse(message) {
|
|
18859
|
+
return {
|
|
18860
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
18861
|
+
isError: true
|
|
18862
|
+
};
|
|
18863
|
+
}
|
|
18864
|
+
|
|
18509
18865
|
// src/mcp/tools/strategy.ts
|
|
18510
18866
|
import * as fs49 from "fs/promises";
|
|
18511
18867
|
import * as path52 from "path";
|
|
@@ -18534,7 +18890,7 @@ async function handleValidateStrategy(input) {
|
|
|
18534
18890
|
} catch (error) {
|
|
18535
18891
|
return mcpError2(error instanceof Error ? error.message : String(error));
|
|
18536
18892
|
}
|
|
18537
|
-
const { validateStrategy } = await import("./dist-
|
|
18893
|
+
const { validateStrategy } = await import("./dist-LHINSVK4.js");
|
|
18538
18894
|
const result = await validateStrategy(projectPath);
|
|
18539
18895
|
if (!result.ok) {
|
|
18540
18896
|
return mcpJson({ present: true, valid: false, error: result.error.message });
|
|
@@ -18559,7 +18915,7 @@ async function handleReadStrategy(input) {
|
|
|
18559
18915
|
} catch (error) {
|
|
18560
18916
|
return mcpError2(error instanceof Error ? error.message : String(error));
|
|
18561
18917
|
}
|
|
18562
|
-
const core = await import("./dist-
|
|
18918
|
+
const core = await import("./dist-LHINSVK4.js");
|
|
18563
18919
|
const validation = await core.validateStrategy(projectPath);
|
|
18564
18920
|
if (!validation.ok) {
|
|
18565
18921
|
return mcpJson({ present: true, valid: false, error: validation.error.message });
|
|
@@ -18611,7 +18967,7 @@ async function handleWriteStrategy(input) {
|
|
|
18611
18967
|
} catch (error) {
|
|
18612
18968
|
return mcpError2(error instanceof Error ? error.message : String(error));
|
|
18613
18969
|
}
|
|
18614
|
-
const core = await import("./dist-
|
|
18970
|
+
const core = await import("./dist-LHINSVK4.js");
|
|
18615
18971
|
try {
|
|
18616
18972
|
core.writeStrategyDoc(input.doc, {
|
|
18617
18973
|
cwd: projectPath,
|
|
@@ -18655,7 +19011,7 @@ async function handleSeedPulseFromStrategy(input) {
|
|
|
18655
19011
|
} catch (error) {
|
|
18656
19012
|
return mcpError3(error instanceof Error ? error.message : String(error));
|
|
18657
19013
|
}
|
|
18658
|
-
const core = await import("./dist-
|
|
19014
|
+
const core = await import("./dist-LHINSVK4.js");
|
|
18659
19015
|
const seed = core.seedFromStrategy({ cwd: projectPath });
|
|
18660
19016
|
return mcpJson2(seed);
|
|
18661
19017
|
}
|
|
@@ -18690,7 +19046,7 @@ async function handleWritePulseConfig(input) {
|
|
|
18690
19046
|
return mcpError3(error instanceof Error ? error.message : String(error));
|
|
18691
19047
|
}
|
|
18692
19048
|
const resolvedConfigPath = input.configPath !== void 0 ? path53.isAbsolute(input.configPath) ? input.configPath : path53.join(projectPath, input.configPath) : path53.join(projectPath, "harness.config.json");
|
|
18693
|
-
const core = await import("./dist-
|
|
19049
|
+
const core = await import("./dist-LHINSVK4.js");
|
|
18694
19050
|
try {
|
|
18695
19051
|
core.writePulseConfig(input.config, {
|
|
18696
19052
|
configPath: resolvedConfigPath,
|
|
@@ -18739,7 +19095,7 @@ async function handleAcquireCompoundLock(input) {
|
|
|
18739
19095
|
} catch (error) {
|
|
18740
19096
|
return mcpError4(error instanceof Error ? error.message : String(error));
|
|
18741
19097
|
}
|
|
18742
|
-
const core = await import("./dist-
|
|
19098
|
+
const core = await import("./dist-LHINSVK4.js");
|
|
18743
19099
|
try {
|
|
18744
19100
|
const handle = core.acquireCompoundLock(
|
|
18745
19101
|
input.category,
|
|
@@ -18856,6 +19212,8 @@ var TOOL_DEFINITIONS = [
|
|
|
18856
19212
|
runCodeReviewDefinition,
|
|
18857
19213
|
gatherContextDefinition,
|
|
18858
19214
|
assessProjectDefinition,
|
|
19215
|
+
canaryProbeDefinition,
|
|
19216
|
+
canaryRecommendFrameworkDefinition,
|
|
18859
19217
|
reviewChangesDefinition,
|
|
18860
19218
|
detectAnomaliesDefinition,
|
|
18861
19219
|
askGraphDefinition,
|
|
@@ -18897,6 +19255,7 @@ var TOOL_DEFINITIONS = [
|
|
|
18897
19255
|
testCraftDefinition,
|
|
18898
19256
|
knowledgeCraftDefinition,
|
|
18899
19257
|
securityCraftDefinition,
|
|
19258
|
+
outcomeEvalDefinition,
|
|
18900
19259
|
validateStrategyDefinition,
|
|
18901
19260
|
readStrategyDefinition,
|
|
18902
19261
|
writeStrategyDefinition,
|
|
@@ -18946,6 +19305,8 @@ var TOOL_HANDLERS = {
|
|
|
18946
19305
|
run_code_review: handleRunCodeReview,
|
|
18947
19306
|
gather_context: handleGatherContext,
|
|
18948
19307
|
assess_project: handleAssessProject,
|
|
19308
|
+
canary_probe: handleCanaryProbe,
|
|
19309
|
+
canary_recommend_framework: handleCanaryRecommendFramework,
|
|
18949
19310
|
review_changes: handleReviewChanges,
|
|
18950
19311
|
detect_anomalies: handleDetectAnomalies,
|
|
18951
19312
|
ask_graph: handleAskGraph,
|
|
@@ -18987,6 +19348,7 @@ var TOOL_HANDLERS = {
|
|
|
18987
19348
|
test_craft: handleTestCraft,
|
|
18988
19349
|
knowledge_craft: handleKnowledgeCraft,
|
|
18989
19350
|
security_craft: handleSecurityCraft,
|
|
19351
|
+
outcome_eval: handleOutcomeEval,
|
|
18990
19352
|
validate_strategy: handleValidateStrategy,
|
|
18991
19353
|
read_strategy: handleReadStrategy,
|
|
18992
19354
|
write_strategy: handleWriteStrategy,
|
|
@@ -19095,7 +19457,7 @@ async function appendUpdateNotification(result, resolvedRoot) {
|
|
|
19095
19457
|
shouldRunCheck,
|
|
19096
19458
|
readCheckState,
|
|
19097
19459
|
spawnBackgroundCheck
|
|
19098
|
-
} = await import("./dist-
|
|
19460
|
+
} = await import("./dist-LHINSVK4.js");
|
|
19099
19461
|
const { CLI_VERSION } = await import("./version-CUI434OP.js");
|
|
19100
19462
|
const configInterval = readConfigInterval(resolvedRoot);
|
|
19101
19463
|
const DEFAULT_INTERVAL = 864e5;
|