@harness-engineering/cli 1.14.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +240 -39
- package/dist/agents/skills/claude-code/harness-autopilot/skill.yaml +6 -0
- package/dist/agents/skills/claude-code/harness-product-spec/SKILL.md +5 -5
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +240 -39
- package/dist/agents/skills/gemini-cli/harness-autopilot/skill.yaml +6 -0
- package/dist/agents/skills/gemini-cli/harness-product-spec/SKILL.md +5 -5
- package/dist/agents/skills/package.json +1 -0
- package/dist/agents/skills/vitest.config.mts +5 -0
- package/dist/{agents-md-YTYQDA3P.js → agents-md-ZGNIDWAF.js} +1 -1
- package/dist/{architecture-JQZYM4US.js → architecture-ZLIH5533.js} +2 -2
- package/dist/bin/harness-mcp.js +11 -11
- package/dist/bin/harness.js +16 -14
- package/dist/{check-phase-gate-L3RADYWO.js → check-phase-gate-ZOXVBDCN.js} +3 -3
- package/dist/{chunk-7IP4JIFL.js → chunk-2BKLWLY6.js} +4 -4
- package/dist/{chunk-OSXBPAMK.js → chunk-3ZZKVN62.js} +1 -1
- package/dist/{chunk-O5OJVPL6.js → chunk-B2HKP423.js} +1 -1
- package/dist/{chunk-YPYGXRDR.js → chunk-EDXIVMAP.js} +4 -4
- package/dist/{chunk-XKECDXJS.js → chunk-J4RAX7YB.js} +738 -186
- package/dist/{chunk-6KTUUFRN.js → chunk-LGYBN7Y6.js} +1 -1
- package/dist/{chunk-3C2MLBPJ.js → chunk-N25INEIX.js} +1 -1
- package/dist/{chunk-NLVUVUGD.js → chunk-ND2ENWDM.js} +1 -1
- package/dist/{chunk-YZD2MRNQ.js → chunk-NNHDDXYT.js} +379 -119
- package/dist/{chunk-S2FXOWOR.js → chunk-OFXQSFOW.js} +2 -2
- package/dist/{chunk-OXLLOSSR.js → chunk-VEPAJXBW.js} +2 -2
- package/dist/{chunk-TPOTOBR7.js → chunk-YLXFKVJE.js} +3 -3
- package/dist/{chunk-ABQHQ6I5.js → chunk-Z2OOPXJO.js} +1238 -133
- package/dist/{ci-workflow-EQZFVX3P.js → ci-workflow-765LSHRD.js} +1 -1
- package/dist/{dist-HWXF2C3R.js → dist-ALQDD67R.js} +47 -1
- package/dist/{docs-7ECGYMAV.js → docs-NRMQCOJ6.js} +3 -3
- package/dist/{engine-EG4EH4IX.js → engine-3RB7MXPP.js} +1 -1
- package/dist/{entropy-5USWKLVS.js → entropy-6AGX2ZUN.js} +2 -2
- package/dist/{feedback-UTBXZZHF.js → feedback-MY4QZIFD.js} +1 -1
- package/dist/{generate-agent-definitions-3PM5EU7V.js → generate-agent-definitions-ZAE726AU.js} +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +13 -13
- package/dist/{loader-ZPALXIVR.js → loader-UUTVMQCC.js} +1 -1
- package/dist/{mcp-362EZHF4.js → mcp-VU5FMO52.js} +11 -11
- package/dist/{performance-OQAFMJUD.js → performance-2D7G6NMJ.js} +2 -2
- package/dist/{review-pipeline-C4GCFVGP.js → review-pipeline-RAQ55ISU.js} +1 -1
- package/dist/{runtime-7YLVK453.js → runtime-BCK5RRZQ.js} +1 -1
- package/dist/{security-PZOX7AQS.js → security-2RPQEN62.js} +1 -1
- package/dist/{validate-FD3Z6VJD.js → validate-KBYQAEWE.js} +2 -2
- package/dist/{validate-cross-check-WNJM6H2D.js → validate-cross-check-OABMREW4.js} +1 -1
- package/package.json +5 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
detectEntropyDefinition,
|
|
3
3
|
handleDetectEntropy
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VEPAJXBW.js";
|
|
5
5
|
import {
|
|
6
6
|
checkPerformanceDefinition,
|
|
7
7
|
getCriticalPathsDefinition,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
handleGetPerfBaselines,
|
|
12
12
|
handleUpdatePerfBaselines,
|
|
13
13
|
updatePerfBaselinesDefinition
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-EDXIVMAP.js";
|
|
15
15
|
import {
|
|
16
16
|
analyzeDiffDefinition,
|
|
17
17
|
createSelfReviewDefinition,
|
|
@@ -19,15 +19,15 @@ import {
|
|
|
19
19
|
handleCreateSelfReview,
|
|
20
20
|
handleRequestPeerReview,
|
|
21
21
|
requestPeerReviewDefinition
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-YLXFKVJE.js";
|
|
23
23
|
import {
|
|
24
24
|
handleRunSecurityScan,
|
|
25
25
|
runSecurityScanDefinition
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-3ZZKVN62.js";
|
|
27
27
|
import {
|
|
28
28
|
handleRunCodeReview,
|
|
29
29
|
runCodeReviewDefinition
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-ND2ENWDM.js";
|
|
31
31
|
import {
|
|
32
32
|
GENERATED_HEADER_CLAUDE,
|
|
33
33
|
GENERATED_HEADER_GEMINI,
|
|
@@ -38,24 +38,24 @@ import {
|
|
|
38
38
|
import {
|
|
39
39
|
handleValidateProject,
|
|
40
40
|
validateToolDefinition
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-OFXQSFOW.js";
|
|
42
42
|
import {
|
|
43
43
|
loadGraphStore
|
|
44
44
|
} from "./chunk-FTMXDOR6.js";
|
|
45
45
|
import {
|
|
46
46
|
checkDependenciesDefinition,
|
|
47
47
|
handleCheckDependencies
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-N25INEIX.js";
|
|
49
49
|
import {
|
|
50
50
|
resolveProjectConfig
|
|
51
51
|
} from "./chunk-H7Y5CKTM.js";
|
|
52
52
|
import {
|
|
53
53
|
checkDocsDefinition,
|
|
54
54
|
handleCheckDocs
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-2BKLWLY6.js";
|
|
56
56
|
import {
|
|
57
57
|
resolveConfig
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-B2HKP423.js";
|
|
59
59
|
import {
|
|
60
60
|
resultToMcpResponse
|
|
61
61
|
} from "./chunk-IDZNPTYD.js";
|
|
@@ -428,7 +428,7 @@ ${skippedMsg}`
|
|
|
428
428
|
async function handleInitProject(input) {
|
|
429
429
|
const i = input;
|
|
430
430
|
try {
|
|
431
|
-
const { TemplateEngine } = await import("./engine-
|
|
431
|
+
const { TemplateEngine } = await import("./engine-3RB7MXPP.js");
|
|
432
432
|
const engine = new TemplateEngine(resolveTemplatesDir());
|
|
433
433
|
const safePath = sanitizePath(i.path);
|
|
434
434
|
const detected = tryDetectFramework(engine, safePath, i);
|
|
@@ -449,7 +449,7 @@ var listPersonasDefinition = {
|
|
|
449
449
|
inputSchema: { type: "object", properties: {} }
|
|
450
450
|
};
|
|
451
451
|
async function handleListPersonas() {
|
|
452
|
-
const { listPersonas } = await import("./loader-
|
|
452
|
+
const { listPersonas } = await import("./loader-UUTVMQCC.js");
|
|
453
453
|
const result = listPersonas(resolvePersonasDir());
|
|
454
454
|
return resultToMcpResponse(result);
|
|
455
455
|
}
|
|
@@ -473,10 +473,10 @@ async function handleGeneratePersonaArtifacts(input) {
|
|
|
473
473
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.name)) {
|
|
474
474
|
return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.name}`)));
|
|
475
475
|
}
|
|
476
|
-
const { loadPersona } = await import("./loader-
|
|
477
|
-
const { generateRuntime } = await import("./runtime-
|
|
478
|
-
const { generateAgentsMd } = await import("./agents-md-
|
|
479
|
-
const { generateCIWorkflow } = await import("./ci-workflow-
|
|
476
|
+
const { loadPersona } = await import("./loader-UUTVMQCC.js");
|
|
477
|
+
const { generateRuntime } = await import("./runtime-BCK5RRZQ.js");
|
|
478
|
+
const { generateAgentsMd } = await import("./agents-md-ZGNIDWAF.js");
|
|
479
|
+
const { generateCIWorkflow } = await import("./ci-workflow-765LSHRD.js");
|
|
480
480
|
const personasDir = resolvePersonasDir();
|
|
481
481
|
const filePath = path3.join(personasDir, `${input.name}.yaml`);
|
|
482
482
|
if (!filePath.startsWith(personasDir)) {
|
|
@@ -531,7 +531,7 @@ async function handleRunPersona(input) {
|
|
|
531
531
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.persona)) {
|
|
532
532
|
return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.persona}`)));
|
|
533
533
|
}
|
|
534
|
-
const { loadPersona } = await import("./loader-
|
|
534
|
+
const { loadPersona } = await import("./loader-UUTVMQCC.js");
|
|
535
535
|
const { runPersona } = await import("./runner-VMYLHWOC.js");
|
|
536
536
|
const { executeSkill } = await import("./skill-executor-XZLYZYAK.js");
|
|
537
537
|
const personasDir = resolvePersonasDir();
|
|
@@ -1142,6 +1142,26 @@ async function getLearningsResource(projectRoot) {
|
|
|
1142
1142
|
return sections.length > 0 ? sections.join("\n\n---\n\n") : "No learnings files found.";
|
|
1143
1143
|
}
|
|
1144
1144
|
|
|
1145
|
+
// src/mcp/tools/roadmap-auto-sync.ts
|
|
1146
|
+
import * as fs10 from "fs";
|
|
1147
|
+
import * as path11 from "path";
|
|
1148
|
+
async function autoSyncRoadmap(projectPath) {
|
|
1149
|
+
try {
|
|
1150
|
+
const roadmapFile = path11.join(projectPath, "docs", "roadmap.md");
|
|
1151
|
+
if (!fs10.existsSync(roadmapFile)) return;
|
|
1152
|
+
const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges } = await import("./dist-ALQDD67R.js");
|
|
1153
|
+
const raw = fs10.readFileSync(roadmapFile, "utf-8");
|
|
1154
|
+
const parseResult = parseRoadmap(raw);
|
|
1155
|
+
if (!parseResult.ok) return;
|
|
1156
|
+
const roadmap = parseResult.value;
|
|
1157
|
+
const syncResult = syncRoadmap({ projectPath, roadmap });
|
|
1158
|
+
if (!syncResult.ok || syncResult.value.length === 0) return;
|
|
1159
|
+
applySyncChanges(roadmap, syncResult.value);
|
|
1160
|
+
fs10.writeFileSync(roadmapFile, serializeRoadmap(roadmap), "utf-8");
|
|
1161
|
+
} catch {
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1145
1165
|
// src/mcp/utils.ts
|
|
1146
1166
|
function mcpError(text) {
|
|
1147
1167
|
return { content: [{ type: "text", text }], isError: true };
|
|
@@ -1215,12 +1235,12 @@ var manageStateDefinition = {
|
|
|
1215
1235
|
}
|
|
1216
1236
|
};
|
|
1217
1237
|
async function handleShow(projectPath, input) {
|
|
1218
|
-
const { loadState } = await import("./dist-
|
|
1238
|
+
const { loadState } = await import("./dist-ALQDD67R.js");
|
|
1219
1239
|
return resultToMcpResponse(await loadState(projectPath, input.stream, input.session));
|
|
1220
1240
|
}
|
|
1221
1241
|
async function handleLearn(projectPath, input) {
|
|
1222
1242
|
if (!input.learning) return mcpError("Error: learning is required for learn action");
|
|
1223
|
-
const { appendLearning } = await import("./dist-
|
|
1243
|
+
const { appendLearning } = await import("./dist-ALQDD67R.js");
|
|
1224
1244
|
const result = await appendLearning(
|
|
1225
1245
|
projectPath,
|
|
1226
1246
|
input.learning,
|
|
@@ -1235,7 +1255,7 @@ async function handleLearn(projectPath, input) {
|
|
|
1235
1255
|
async function handleFailure(projectPath, input) {
|
|
1236
1256
|
if (!input.description) return mcpError("Error: description is required for failure action");
|
|
1237
1257
|
if (!input.failureType) return mcpError("Error: failureType is required for failure action");
|
|
1238
|
-
const { appendFailure } = await import("./dist-
|
|
1258
|
+
const { appendFailure } = await import("./dist-ALQDD67R.js");
|
|
1239
1259
|
const result = await appendFailure(
|
|
1240
1260
|
projectPath,
|
|
1241
1261
|
input.description,
|
|
@@ -1248,34 +1268,36 @@ async function handleFailure(projectPath, input) {
|
|
|
1248
1268
|
return resultToMcpResponse(Ok({ recorded: true }));
|
|
1249
1269
|
}
|
|
1250
1270
|
async function handleArchive(projectPath, input) {
|
|
1251
|
-
const { archiveFailures } = await import("./dist-
|
|
1271
|
+
const { archiveFailures } = await import("./dist-ALQDD67R.js");
|
|
1252
1272
|
const result = await archiveFailures(projectPath, input.stream, input.session);
|
|
1253
1273
|
if (!result.ok) return resultToMcpResponse(result);
|
|
1254
1274
|
return resultToMcpResponse(Ok({ archived: true }));
|
|
1255
1275
|
}
|
|
1256
1276
|
async function handleReset(projectPath, input) {
|
|
1257
|
-
const { saveState, DEFAULT_STATE } = await import("./dist-
|
|
1277
|
+
const { saveState, DEFAULT_STATE } = await import("./dist-ALQDD67R.js");
|
|
1258
1278
|
const result = await saveState(projectPath, { ...DEFAULT_STATE }, input.stream, input.session);
|
|
1259
1279
|
if (!result.ok) return resultToMcpResponse(result);
|
|
1260
1280
|
return resultToMcpResponse(Ok({ reset: true }));
|
|
1261
1281
|
}
|
|
1262
1282
|
async function handleGate(projectPath, _input) {
|
|
1263
|
-
const { runMechanicalGate } = await import("./dist-
|
|
1283
|
+
const { runMechanicalGate } = await import("./dist-ALQDD67R.js");
|
|
1264
1284
|
return resultToMcpResponse(await runMechanicalGate(projectPath));
|
|
1265
1285
|
}
|
|
1266
1286
|
async function handleSaveHandoff(projectPath, input) {
|
|
1267
1287
|
if (!input.handoff) return mcpError("Error: handoff is required for save-handoff action");
|
|
1268
|
-
const { saveHandoff } = await import("./dist-
|
|
1288
|
+
const { saveHandoff } = await import("./dist-ALQDD67R.js");
|
|
1269
1289
|
const result = await saveHandoff(
|
|
1270
1290
|
projectPath,
|
|
1271
1291
|
input.handoff,
|
|
1272
1292
|
input.stream,
|
|
1273
1293
|
input.session
|
|
1274
1294
|
);
|
|
1275
|
-
|
|
1295
|
+
if (!result.ok) return resultToMcpResponse(result);
|
|
1296
|
+
await autoSyncRoadmap(projectPath);
|
|
1297
|
+
return resultToMcpResponse(Ok({ saved: true }));
|
|
1276
1298
|
}
|
|
1277
1299
|
async function handleLoadHandoff(projectPath, input) {
|
|
1278
|
-
const { loadHandoff } = await import("./dist-
|
|
1300
|
+
const { loadHandoff } = await import("./dist-ALQDD67R.js");
|
|
1279
1301
|
return resultToMcpResponse(await loadHandoff(projectPath, input.stream, input.session));
|
|
1280
1302
|
}
|
|
1281
1303
|
async function handleAppendEntry(projectPath, input) {
|
|
@@ -1283,7 +1305,7 @@ async function handleAppendEntry(projectPath, input) {
|
|
|
1283
1305
|
if (!input.section) return mcpError("Error: section is required for append_entry action");
|
|
1284
1306
|
if (!input.authorSkill) return mcpError("Error: authorSkill is required for append_entry action");
|
|
1285
1307
|
if (!input.content) return mcpError("Error: content is required for append_entry action");
|
|
1286
|
-
const { appendSessionEntry } = await import("./dist-
|
|
1308
|
+
const { appendSessionEntry } = await import("./dist-ALQDD67R.js");
|
|
1287
1309
|
const result = await appendSessionEntry(
|
|
1288
1310
|
projectPath,
|
|
1289
1311
|
input.session,
|
|
@@ -1299,7 +1321,7 @@ async function handleUpdateEntryStatus(projectPath, input) {
|
|
|
1299
1321
|
if (!input.entryId) return mcpError("Error: entryId is required for update_entry_status action");
|
|
1300
1322
|
if (!input.newStatus)
|
|
1301
1323
|
return mcpError("Error: newStatus is required for update_entry_status action");
|
|
1302
|
-
const { updateSessionEntryStatus } = await import("./dist-
|
|
1324
|
+
const { updateSessionEntryStatus } = await import("./dist-ALQDD67R.js");
|
|
1303
1325
|
const result = await updateSessionEntryStatus(
|
|
1304
1326
|
projectPath,
|
|
1305
1327
|
input.session,
|
|
@@ -1312,7 +1334,7 @@ async function handleUpdateEntryStatus(projectPath, input) {
|
|
|
1312
1334
|
async function handleReadSection(projectPath, input) {
|
|
1313
1335
|
if (!input.session) return mcpError("Error: session is required for read_section action");
|
|
1314
1336
|
if (!input.section) return mcpError("Error: section is required for read_section action");
|
|
1315
|
-
const { readSessionSection } = await import("./dist-
|
|
1337
|
+
const { readSessionSection } = await import("./dist-ALQDD67R.js");
|
|
1316
1338
|
const result = await readSessionSection(
|
|
1317
1339
|
projectPath,
|
|
1318
1340
|
input.session,
|
|
@@ -1322,15 +1344,16 @@ async function handleReadSection(projectPath, input) {
|
|
|
1322
1344
|
}
|
|
1323
1345
|
async function handleReadSections(projectPath, input) {
|
|
1324
1346
|
if (!input.session) return mcpError("Error: session is required for read_sections action");
|
|
1325
|
-
const { readSessionSections } = await import("./dist-
|
|
1347
|
+
const { readSessionSections } = await import("./dist-ALQDD67R.js");
|
|
1326
1348
|
const result = await readSessionSections(projectPath, input.session);
|
|
1327
1349
|
return resultToMcpResponse(result);
|
|
1328
1350
|
}
|
|
1329
1351
|
async function handleArchiveSession(projectPath, input) {
|
|
1330
1352
|
if (!input.session) return mcpError("Error: session is required for archive_session action");
|
|
1331
|
-
const { archiveSession } = await import("./dist-
|
|
1353
|
+
const { archiveSession } = await import("./dist-ALQDD67R.js");
|
|
1332
1354
|
const result = await archiveSession(projectPath, input.session);
|
|
1333
1355
|
if (!result.ok) return resultToMcpResponse(result);
|
|
1356
|
+
await autoSyncRoadmap(projectPath);
|
|
1334
1357
|
return resultToMcpResponse(Ok({ archived: true }));
|
|
1335
1358
|
}
|
|
1336
1359
|
var ACTION_HANDLERS = {
|
|
@@ -1371,7 +1394,7 @@ var listStreamsDefinition = {
|
|
|
1371
1394
|
};
|
|
1372
1395
|
async function handleListStreams(input) {
|
|
1373
1396
|
try {
|
|
1374
|
-
const { listStreams, loadStreamIndex } = await import("./dist-
|
|
1397
|
+
const { listStreams, loadStreamIndex } = await import("./dist-ALQDD67R.js");
|
|
1375
1398
|
const projectPath = sanitizePath(input.path);
|
|
1376
1399
|
const indexResult = await loadStreamIndex(projectPath);
|
|
1377
1400
|
const streamsResult = await listStreams(projectPath);
|
|
@@ -1409,7 +1432,7 @@ var checkPhaseGateDefinition = {
|
|
|
1409
1432
|
};
|
|
1410
1433
|
async function handleCheckPhaseGate(input) {
|
|
1411
1434
|
try {
|
|
1412
|
-
const { runCheckPhaseGate } = await import("./check-phase-gate-
|
|
1435
|
+
const { runCheckPhaseGate } = await import("./check-phase-gate-ZOXVBDCN.js");
|
|
1413
1436
|
const result = await runCheckPhaseGate({ cwd: sanitizePath(input.path) });
|
|
1414
1437
|
if (result.ok) {
|
|
1415
1438
|
return { content: [{ type: "text", text: JSON.stringify(result.value) }] };
|
|
@@ -1429,7 +1452,7 @@ async function handleCheckPhaseGate(input) {
|
|
|
1429
1452
|
}
|
|
1430
1453
|
|
|
1431
1454
|
// src/mcp/tools/cross-check.ts
|
|
1432
|
-
import * as
|
|
1455
|
+
import * as path12 from "path";
|
|
1433
1456
|
var validateCrossCheckDefinition = {
|
|
1434
1457
|
name: "validate_cross_check",
|
|
1435
1458
|
description: "Validate plan-to-implementation coverage: checks that specs have plans and plans have implementations, detects staleness",
|
|
@@ -1465,15 +1488,15 @@ async function handleValidateCrossCheck(input) {
|
|
|
1465
1488
|
};
|
|
1466
1489
|
}
|
|
1467
1490
|
try {
|
|
1468
|
-
const { runCrossCheck } = await import("./validate-cross-check-
|
|
1469
|
-
const specsDir =
|
|
1491
|
+
const { runCrossCheck } = await import("./validate-cross-check-OABMREW4.js");
|
|
1492
|
+
const specsDir = path12.resolve(projectPath, input.specsDir ?? "docs/specs");
|
|
1470
1493
|
if (!specsDir.startsWith(projectPath)) {
|
|
1471
1494
|
return {
|
|
1472
1495
|
content: [{ type: "text", text: "Error: specsDir escapes project root" }],
|
|
1473
1496
|
isError: true
|
|
1474
1497
|
};
|
|
1475
1498
|
}
|
|
1476
|
-
const plansDir =
|
|
1499
|
+
const plansDir = path12.resolve(projectPath, input.plansDir ?? "docs/plans");
|
|
1477
1500
|
if (!plansDir.startsWith(projectPath)) {
|
|
1478
1501
|
return {
|
|
1479
1502
|
content: [{ type: "text", text: "Error: plansDir escapes project root" }],
|
|
@@ -1504,14 +1527,14 @@ async function handleValidateCrossCheck(input) {
|
|
|
1504
1527
|
|
|
1505
1528
|
// src/commands/generate-slash-commands.ts
|
|
1506
1529
|
import { Command } from "commander";
|
|
1507
|
-
import
|
|
1508
|
-
import
|
|
1530
|
+
import fs12 from "fs";
|
|
1531
|
+
import path14 from "path";
|
|
1509
1532
|
import os from "os";
|
|
1510
1533
|
import readline from "readline";
|
|
1511
1534
|
|
|
1512
1535
|
// src/slash-commands/normalize.ts
|
|
1513
|
-
import
|
|
1514
|
-
import
|
|
1536
|
+
import fs11 from "fs";
|
|
1537
|
+
import path13 from "path";
|
|
1515
1538
|
import { parse as parse3 } from "yaml";
|
|
1516
1539
|
|
|
1517
1540
|
// src/slash-commands/normalize-name.ts
|
|
@@ -1531,7 +1554,7 @@ function normalizeName(skillName) {
|
|
|
1531
1554
|
function readSkillYaml(yamlPath) {
|
|
1532
1555
|
let raw;
|
|
1533
1556
|
try {
|
|
1534
|
-
raw =
|
|
1557
|
+
raw = fs11.readFileSync(yamlPath, "utf-8");
|
|
1535
1558
|
} catch {
|
|
1536
1559
|
return null;
|
|
1537
1560
|
}
|
|
@@ -1591,10 +1614,10 @@ function buildProcessLines(meta) {
|
|
|
1591
1614
|
];
|
|
1592
1615
|
}
|
|
1593
1616
|
function buildSpec(meta, normalized, entry, skillsDir, source) {
|
|
1594
|
-
const skillMdPath =
|
|
1595
|
-
const skillMdContent =
|
|
1596
|
-
const skillMdRelative =
|
|
1597
|
-
const skillYamlRelative =
|
|
1617
|
+
const skillMdPath = path13.join(skillsDir, entry.name, "SKILL.md");
|
|
1618
|
+
const skillMdContent = fs11.existsSync(skillMdPath) ? fs11.readFileSync(skillMdPath, "utf-8") : "";
|
|
1619
|
+
const skillMdRelative = path13.relative(process.cwd(), skillMdPath).replaceAll("\\", "/");
|
|
1620
|
+
const skillYamlRelative = path13.relative(process.cwd(), path13.join(skillsDir, entry.name, "skill.yaml")).replaceAll("\\", "/");
|
|
1598
1621
|
const args = (meta.cli?.args ?? []).map((a) => ({
|
|
1599
1622
|
name: a.name,
|
|
1600
1623
|
description: a.description ?? "",
|
|
@@ -1631,11 +1654,11 @@ function normalizeSkills(skillSources, platforms) {
|
|
|
1631
1654
|
const specs = [];
|
|
1632
1655
|
const nameMap = /* @__PURE__ */ new Map();
|
|
1633
1656
|
for (const { dir: skillsDir, source } of skillSources) {
|
|
1634
|
-
if (!
|
|
1635
|
-
const entries =
|
|
1657
|
+
if (!fs11.existsSync(skillsDir)) continue;
|
|
1658
|
+
const entries = fs11.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
1636
1659
|
for (const entry of entries) {
|
|
1637
|
-
const yamlPath =
|
|
1638
|
-
if (!
|
|
1660
|
+
const yamlPath = path13.join(skillsDir, entry.name, "skill.yaml");
|
|
1661
|
+
if (!fs11.existsSync(yamlPath)) continue;
|
|
1639
1662
|
const result = readSkillYaml(yamlPath);
|
|
1640
1663
|
if (!result) continue;
|
|
1641
1664
|
if (!result.success) {
|
|
@@ -1746,13 +1769,13 @@ function renderGemini(spec, skillMdContent, skillYamlContent) {
|
|
|
1746
1769
|
// src/commands/generate-slash-commands.ts
|
|
1747
1770
|
function resolveOutputDir(platform, opts) {
|
|
1748
1771
|
if (opts.output) {
|
|
1749
|
-
return
|
|
1772
|
+
return path14.join(opts.output, "harness");
|
|
1750
1773
|
}
|
|
1751
1774
|
if (opts.global) {
|
|
1752
1775
|
const home = os.homedir();
|
|
1753
|
-
return platform === "claude-code" ?
|
|
1776
|
+
return platform === "claude-code" ? path14.join(home, ".claude", "commands", "harness") : path14.join(home, ".gemini", "commands", "harness");
|
|
1754
1777
|
}
|
|
1755
|
-
return platform === "claude-code" ?
|
|
1778
|
+
return platform === "claude-code" ? path14.join("agents", "commands", "claude-code", "harness") : path14.join("agents", "commands", "gemini-cli", "harness");
|
|
1756
1779
|
}
|
|
1757
1780
|
function fileExtension(platform) {
|
|
1758
1781
|
return platform === "claude-code" ? ".md" : ".toml";
|
|
@@ -1777,12 +1800,12 @@ function resolveSkillSources(opts) {
|
|
|
1777
1800
|
sources.push({ dir: projectDir, source: "project" });
|
|
1778
1801
|
}
|
|
1779
1802
|
const communityDir = resolveCommunitySkillsDir();
|
|
1780
|
-
if (
|
|
1803
|
+
if (fs12.existsSync(communityDir)) {
|
|
1781
1804
|
sources.push({ dir: communityDir, source: "community" });
|
|
1782
1805
|
}
|
|
1783
1806
|
if (opts.includeGlobal || sources.length === 0) {
|
|
1784
1807
|
const globalDir = resolveGlobalSkillsDir();
|
|
1785
|
-
if (!projectDir ||
|
|
1808
|
+
if (!projectDir || path14.resolve(globalDir) !== path14.resolve(projectDir)) {
|
|
1786
1809
|
sources.push({ dir: globalDir, source: "global" });
|
|
1787
1810
|
}
|
|
1788
1811
|
}
|
|
@@ -1807,7 +1830,7 @@ function generateSlashCommands(opts) {
|
|
|
1807
1830
|
executionContext: spec.prompt.executionContext.split("\n").map((line) => {
|
|
1808
1831
|
if (line.startsWith("@")) {
|
|
1809
1832
|
const relPath = line.slice(1);
|
|
1810
|
-
return `@${
|
|
1833
|
+
return `@${path14.resolve(relPath)}`;
|
|
1811
1834
|
}
|
|
1812
1835
|
return line;
|
|
1813
1836
|
}).join("\n")
|
|
@@ -1815,10 +1838,10 @@ function generateSlashCommands(opts) {
|
|
|
1815
1838
|
} : spec;
|
|
1816
1839
|
rendered.set(filename, renderClaudeCode(renderSpec));
|
|
1817
1840
|
} else {
|
|
1818
|
-
const mdPath =
|
|
1819
|
-
const yamlPath =
|
|
1820
|
-
const mdContent =
|
|
1821
|
-
const yamlContent =
|
|
1841
|
+
const mdPath = path14.join(spec.skillsBaseDir, spec.sourceDir, "SKILL.md");
|
|
1842
|
+
const yamlPath = path14.join(spec.skillsBaseDir, spec.sourceDir, "skill.yaml");
|
|
1843
|
+
const mdContent = fs12.existsSync(mdPath) ? fs12.readFileSync(mdPath, "utf-8") : "";
|
|
1844
|
+
const yamlContent = fs12.existsSync(yamlPath) ? fs12.readFileSync(yamlPath, "utf-8") : "";
|
|
1822
1845
|
rendered.set(filename, renderGemini(spec, mdContent, yamlContent));
|
|
1823
1846
|
}
|
|
1824
1847
|
}
|
|
@@ -1844,9 +1867,9 @@ async function handleOrphanDeletion(results, opts) {
|
|
|
1844
1867
|
const shouldDelete = opts.yes || await confirmDeletion(result.removed);
|
|
1845
1868
|
if (shouldDelete) {
|
|
1846
1869
|
for (const filename of result.removed) {
|
|
1847
|
-
const filePath =
|
|
1848
|
-
if (
|
|
1849
|
-
|
|
1870
|
+
const filePath = path14.join(result.outputDir, filename);
|
|
1871
|
+
if (fs12.existsSync(filePath)) {
|
|
1872
|
+
fs12.unlinkSync(filePath);
|
|
1850
1873
|
}
|
|
1851
1874
|
}
|
|
1852
1875
|
}
|
|
@@ -1972,7 +1995,7 @@ async function handleGenerateSlashCommands(input) {
|
|
|
1972
1995
|
// src/mcp/resources/state.ts
|
|
1973
1996
|
async function getStateResource(projectRoot) {
|
|
1974
1997
|
try {
|
|
1975
|
-
const { loadState, migrateToStreams } = await import("./dist-
|
|
1998
|
+
const { loadState, migrateToStreams } = await import("./dist-ALQDD67R.js");
|
|
1976
1999
|
await migrateToStreams(projectRoot);
|
|
1977
2000
|
const result = await loadState(projectRoot);
|
|
1978
2001
|
if (result.ok) {
|
|
@@ -2519,7 +2542,7 @@ async function handleGetImpact(input) {
|
|
|
2519
2542
|
}
|
|
2520
2543
|
|
|
2521
2544
|
// src/mcp/tools/graph/ingest-source.ts
|
|
2522
|
-
import * as
|
|
2545
|
+
import * as path15 from "path";
|
|
2523
2546
|
var ingestSourceDefinition = {
|
|
2524
2547
|
name: "ingest_source",
|
|
2525
2548
|
description: "Ingest sources into the project knowledge graph. Supports code analysis, knowledge documents, git history, or all at once.",
|
|
@@ -2539,10 +2562,10 @@ var ingestSourceDefinition = {
|
|
|
2539
2562
|
async function handleIngestSource(input) {
|
|
2540
2563
|
try {
|
|
2541
2564
|
const projectPath = sanitizePath(input.path);
|
|
2542
|
-
const graphDir =
|
|
2565
|
+
const graphDir = path15.join(projectPath, ".harness", "graph");
|
|
2543
2566
|
const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-B26DFXMP.js");
|
|
2544
|
-
const
|
|
2545
|
-
await
|
|
2567
|
+
const fs15 = await import("fs/promises");
|
|
2568
|
+
await fs15.mkdir(graphDir, { recursive: true });
|
|
2546
2569
|
const store = new GraphStore();
|
|
2547
2570
|
await store.load(graphDir);
|
|
2548
2571
|
const results = [];
|
|
@@ -2674,8 +2697,8 @@ async function handleAskGraph(input) {
|
|
|
2674
2697
|
}
|
|
2675
2698
|
|
|
2676
2699
|
// src/mcp/resources/graph.ts
|
|
2677
|
-
import * as
|
|
2678
|
-
import * as
|
|
2700
|
+
import * as fs13 from "fs/promises";
|
|
2701
|
+
import * as path16 from "path";
|
|
2679
2702
|
var MAX_ITEMS = 5e3;
|
|
2680
2703
|
function formatStaleness(isoTimestamp) {
|
|
2681
2704
|
const then = new Date(isoTimestamp).getTime();
|
|
@@ -2698,11 +2721,11 @@ async function getGraphResource(projectRoot) {
|
|
|
2698
2721
|
message: "No knowledge graph found. Run harness scan to build one."
|
|
2699
2722
|
});
|
|
2700
2723
|
}
|
|
2701
|
-
const graphDir =
|
|
2702
|
-
const metadataPath =
|
|
2724
|
+
const graphDir = path16.join(projectRoot, ".harness", "graph");
|
|
2725
|
+
const metadataPath = path16.join(graphDir, "metadata.json");
|
|
2703
2726
|
let lastScanTimestamp = null;
|
|
2704
2727
|
try {
|
|
2705
|
-
const raw = JSON.parse(await
|
|
2728
|
+
const raw = JSON.parse(await fs13.readFile(metadataPath, "utf-8"));
|
|
2706
2729
|
lastScanTimestamp = raw.lastScanTimestamp ?? null;
|
|
2707
2730
|
} catch {
|
|
2708
2731
|
}
|
|
@@ -2791,7 +2814,7 @@ var generateAgentDefinitionsDefinition = {
|
|
|
2791
2814
|
}
|
|
2792
2815
|
};
|
|
2793
2816
|
async function handleGenerateAgentDefinitions(input) {
|
|
2794
|
-
const { generateAgentDefinitions } = await import("./generate-agent-definitions-
|
|
2817
|
+
const { generateAgentDefinitions } = await import("./generate-agent-definitions-ZAE726AU.js");
|
|
2795
2818
|
const platforms = input.platform === "all" || !input.platform ? ["claude-code", "gemini-cli"] : [input.platform];
|
|
2796
2819
|
const results = generateAgentDefinitions({
|
|
2797
2820
|
platforms: [...platforms],
|
|
@@ -2802,8 +2825,8 @@ async function handleGenerateAgentDefinitions(input) {
|
|
|
2802
2825
|
}
|
|
2803
2826
|
|
|
2804
2827
|
// src/mcp/tools/roadmap.ts
|
|
2805
|
-
import * as
|
|
2806
|
-
import * as
|
|
2828
|
+
import * as fs14 from "fs";
|
|
2829
|
+
import * as path17 from "path";
|
|
2807
2830
|
var manageRoadmapDefinition = {
|
|
2808
2831
|
name: "manage_roadmap",
|
|
2809
2832
|
description: "Manage the project roadmap: show, add, update, remove, sync features, or query by filter. Reads and writes docs/roadmap.md.",
|
|
@@ -2858,21 +2881,21 @@ var manageRoadmapDefinition = {
|
|
|
2858
2881
|
}
|
|
2859
2882
|
};
|
|
2860
2883
|
function roadmapPath(projectRoot) {
|
|
2861
|
-
return
|
|
2884
|
+
return path17.join(projectRoot, "docs", "roadmap.md");
|
|
2862
2885
|
}
|
|
2863
2886
|
function readRoadmapFile(projectRoot) {
|
|
2864
2887
|
const filePath = roadmapPath(projectRoot);
|
|
2865
2888
|
try {
|
|
2866
|
-
return
|
|
2889
|
+
return fs14.readFileSync(filePath, "utf-8");
|
|
2867
2890
|
} catch {
|
|
2868
2891
|
return null;
|
|
2869
2892
|
}
|
|
2870
2893
|
}
|
|
2871
2894
|
function writeRoadmapFile(projectRoot, content) {
|
|
2872
2895
|
const filePath = roadmapPath(projectRoot);
|
|
2873
|
-
const dir =
|
|
2874
|
-
|
|
2875
|
-
|
|
2896
|
+
const dir = path17.dirname(filePath);
|
|
2897
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
2898
|
+
fs14.writeFileSync(filePath, content, "utf-8");
|
|
2876
2899
|
}
|
|
2877
2900
|
function roadmapNotFoundError() {
|
|
2878
2901
|
return {
|
|
@@ -3077,18 +3100,7 @@ function handleSync(projectPath, input, deps) {
|
|
|
3077
3100
|
return resultToMcpResponse(Ok2({ changes: [], message: "Roadmap is up to date." }));
|
|
3078
3101
|
}
|
|
3079
3102
|
if (input.apply) {
|
|
3080
|
-
|
|
3081
|
-
for (const m of roadmap.milestones) {
|
|
3082
|
-
const feature = m.features.find(
|
|
3083
|
-
(f) => f.name.toLowerCase() === change.feature.toLowerCase()
|
|
3084
|
-
);
|
|
3085
|
-
if (feature) {
|
|
3086
|
-
feature.status = change.to;
|
|
3087
|
-
break;
|
|
3088
|
-
}
|
|
3089
|
-
}
|
|
3090
|
-
}
|
|
3091
|
-
roadmap.frontmatter.lastSynced = (/* @__PURE__ */ new Date()).toISOString();
|
|
3103
|
+
deps.applySyncChanges(roadmap, changes);
|
|
3092
3104
|
writeRoadmapFile(projectPath, serializeRoadmap(roadmap));
|
|
3093
3105
|
return resultToMcpResponse(Ok2({ changes, applied: true, roadmap }));
|
|
3094
3106
|
}
|
|
@@ -3096,10 +3108,10 @@ function handleSync(projectPath, input, deps) {
|
|
|
3096
3108
|
}
|
|
3097
3109
|
async function handleManageRoadmap(input) {
|
|
3098
3110
|
try {
|
|
3099
|
-
const { parseRoadmap, serializeRoadmap, syncRoadmap } = await import("./dist-
|
|
3111
|
+
const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges } = await import("./dist-ALQDD67R.js");
|
|
3100
3112
|
const { Ok: Ok2 } = await import("./dist-USY2C5JL.js");
|
|
3101
3113
|
const projectPath = sanitizePath(input.path);
|
|
3102
|
-
const deps = { parseRoadmap, serializeRoadmap, syncRoadmap, Ok: Ok2 };
|
|
3114
|
+
const deps = { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges, Ok: Ok2 };
|
|
3103
3115
|
switch (input.action) {
|
|
3104
3116
|
case "show":
|
|
3105
3117
|
return handleShow2(projectPath, input, deps);
|
|
@@ -3524,7 +3536,7 @@ async function handleTransition(validInput, projectPath, id) {
|
|
|
3524
3536
|
const transition = transitionResult.data;
|
|
3525
3537
|
const prompt = renderTransition(transition);
|
|
3526
3538
|
try {
|
|
3527
|
-
const { saveHandoff } = await import("./dist-
|
|
3539
|
+
const { saveHandoff } = await import("./dist-ALQDD67R.js");
|
|
3528
3540
|
await saveHandoff(
|
|
3529
3541
|
projectPath,
|
|
3530
3542
|
{
|
|
@@ -3594,7 +3606,7 @@ async function handleEmitInteraction(input) {
|
|
|
3594
3606
|
}
|
|
3595
3607
|
async function recordInteraction(projectPath, id, type, decision, stream) {
|
|
3596
3608
|
try {
|
|
3597
|
-
const { loadState, saveState } = await import("./dist-
|
|
3609
|
+
const { loadState, saveState } = await import("./dist-ALQDD67R.js");
|
|
3598
3610
|
const stateResult = await loadState(projectPath, stream);
|
|
3599
3611
|
if (stateResult.ok) {
|
|
3600
3612
|
const state = stateResult.value;
|
|
@@ -3633,10 +3645,14 @@ var gatherContextDefinition = {
|
|
|
3633
3645
|
type: "array",
|
|
3634
3646
|
items: {
|
|
3635
3647
|
type: "string",
|
|
3636
|
-
enum: ["state", "learnings", "handoff", "graph", "validation", "sessions"]
|
|
3648
|
+
enum: ["state", "learnings", "handoff", "graph", "validation", "sessions", "events"]
|
|
3637
3649
|
},
|
|
3638
3650
|
description: "Which constituents to include (default: all)"
|
|
3639
3651
|
},
|
|
3652
|
+
includeEvents: {
|
|
3653
|
+
type: "boolean",
|
|
3654
|
+
description: "Include recent events timeline. Default: true when session is provided, false otherwise. Can also be controlled via include array."
|
|
3655
|
+
},
|
|
3640
3656
|
mode: {
|
|
3641
3657
|
type: "string",
|
|
3642
3658
|
enum: ["summary", "detailed"],
|
|
@@ -3649,6 +3665,11 @@ var gatherContextDefinition = {
|
|
|
3649
3665
|
session: {
|
|
3650
3666
|
type: "string",
|
|
3651
3667
|
description: "Session slug for session-scoped state. When provided, state/learnings/handoff/failures are read from .harness/sessions/<session>/ instead of .harness/. Omit for global fallback."
|
|
3668
|
+
},
|
|
3669
|
+
depth: {
|
|
3670
|
+
type: "string",
|
|
3671
|
+
enum: ["index", "summary", "full"],
|
|
3672
|
+
description: 'Retrieval depth for learnings. "index" returns one-line summaries, "summary" (default) returns full entries, "full" returns entries with linked context.'
|
|
3652
3673
|
}
|
|
3653
3674
|
},
|
|
3654
3675
|
required: ["path", "intent"]
|
|
@@ -3674,18 +3695,19 @@ async function handleGatherContext(input) {
|
|
|
3674
3695
|
input.include ?? ["state", "learnings", "handoff", "graph", "validation"]
|
|
3675
3696
|
);
|
|
3676
3697
|
const errors = [];
|
|
3677
|
-
const statePromise = includeSet.has("state") ? import("./dist-
|
|
3698
|
+
const statePromise = includeSet.has("state") ? import("./dist-ALQDD67R.js").then(
|
|
3678
3699
|
(core) => core.loadState(projectPath, void 0, input.session)
|
|
3679
3700
|
) : Promise.resolve(null);
|
|
3680
|
-
const learningsPromise = includeSet.has("learnings") ? import("./dist-
|
|
3701
|
+
const learningsPromise = includeSet.has("learnings") ? import("./dist-ALQDD67R.js").then(
|
|
3681
3702
|
(core) => core.loadBudgetedLearnings(projectPath, {
|
|
3682
3703
|
intent: input.intent,
|
|
3683
3704
|
tokenBudget: input.learningsBudget ?? 1e3,
|
|
3684
3705
|
...input.skill !== void 0 && { skill: input.skill },
|
|
3685
|
-
...input.session !== void 0 && { session: input.session }
|
|
3706
|
+
...input.session !== void 0 && { session: input.session },
|
|
3707
|
+
...input.depth !== void 0 && { depth: input.depth }
|
|
3686
3708
|
})
|
|
3687
3709
|
) : Promise.resolve(null);
|
|
3688
|
-
const handoffPromise = includeSet.has("handoff") ? import("./dist-
|
|
3710
|
+
const handoffPromise = includeSet.has("handoff") ? import("./dist-ALQDD67R.js").then(
|
|
3689
3711
|
(core) => core.loadHandoff(projectPath, void 0, input.session)
|
|
3690
3712
|
) : Promise.resolve(null);
|
|
3691
3713
|
const graphPromise = includeSet.has("graph") ? (async () => {
|
|
@@ -3729,11 +3751,19 @@ async function handleGatherContext(input) {
|
|
|
3729
3751
|
context: contextBlocks
|
|
3730
3752
|
};
|
|
3731
3753
|
})() : Promise.resolve(null);
|
|
3732
|
-
const sessionsPromise = includeSet.has("sessions") && input.session ? import("./dist-
|
|
3754
|
+
const sessionsPromise = includeSet.has("sessions") && input.session ? import("./dist-ALQDD67R.js").then(
|
|
3733
3755
|
(core) => core.readSessionSections(projectPath, input.session)
|
|
3734
3756
|
) : Promise.resolve(null);
|
|
3757
|
+
const shouldIncludeEvents = input.includeEvents !== void 0 ? input.includeEvents : includeSet.has("events") || !!input.session && !input.include;
|
|
3758
|
+
const eventsPromise = shouldIncludeEvents ? import("./dist-ALQDD67R.js").then(async (core) => {
|
|
3759
|
+
const result = await core.loadEvents(projectPath, {
|
|
3760
|
+
session: input.session
|
|
3761
|
+
});
|
|
3762
|
+
if (!result.ok) return null;
|
|
3763
|
+
return core.formatEventTimeline(result.value);
|
|
3764
|
+
}) : Promise.resolve(null);
|
|
3735
3765
|
const validationPromise = includeSet.has("validation") ? (async () => {
|
|
3736
|
-
const { handleValidateProject: handleValidateProject2 } = await import("./validate-
|
|
3766
|
+
const { handleValidateProject: handleValidateProject2 } = await import("./validate-KBYQAEWE.js");
|
|
3737
3767
|
const result = await handleValidateProject2({ path: projectPath });
|
|
3738
3768
|
const first = result.content[0];
|
|
3739
3769
|
return first ? JSON.parse(first.text) : null;
|
|
@@ -3744,14 +3774,16 @@ async function handleGatherContext(input) {
|
|
|
3744
3774
|
handoffResult,
|
|
3745
3775
|
graphResult,
|
|
3746
3776
|
validationResult,
|
|
3747
|
-
sessionsResult
|
|
3777
|
+
sessionsResult,
|
|
3778
|
+
eventsResult
|
|
3748
3779
|
] = await Promise.allSettled([
|
|
3749
3780
|
statePromise,
|
|
3750
3781
|
learningsPromise,
|
|
3751
3782
|
handoffPromise,
|
|
3752
3783
|
graphPromise,
|
|
3753
3784
|
validationPromise,
|
|
3754
|
-
sessionsPromise
|
|
3785
|
+
sessionsPromise,
|
|
3786
|
+
eventsPromise
|
|
3755
3787
|
]);
|
|
3756
3788
|
function extract(settled, name) {
|
|
3757
3789
|
if (settled.status === "rejected") {
|
|
@@ -3766,6 +3798,7 @@ async function handleGatherContext(input) {
|
|
|
3766
3798
|
const graphContextRaw = extract(graphResult, "graph");
|
|
3767
3799
|
const validationRaw = extract(validationResult, "validation");
|
|
3768
3800
|
const sessionsRaw = extract(sessionsResult, "sessions");
|
|
3801
|
+
const eventsTimeline = extract(eventsResult, "events");
|
|
3769
3802
|
const state = stateRaw && typeof stateRaw === "object" && "ok" in stateRaw ? stateRaw.ok ? stateRaw.value : (() => {
|
|
3770
3803
|
errors.push(`state: ${stateRaw.error.message}`);
|
|
3771
3804
|
return null;
|
|
@@ -3813,6 +3846,7 @@ async function handleGatherContext(input) {
|
|
|
3813
3846
|
graphContext: outputGraphContext,
|
|
3814
3847
|
validation: outputValidation,
|
|
3815
3848
|
sessionSections: sessionSections ?? null,
|
|
3849
|
+
events: eventsTimeline || null,
|
|
3816
3850
|
meta: {
|
|
3817
3851
|
assembledIn,
|
|
3818
3852
|
graphAvailable: graphContext !== null,
|
|
@@ -3823,7 +3857,7 @@ async function handleGatherContext(input) {
|
|
|
3823
3857
|
};
|
|
3824
3858
|
if (input.session) {
|
|
3825
3859
|
try {
|
|
3826
|
-
const core = await import("./dist-
|
|
3860
|
+
const core = await import("./dist-ALQDD67R.js");
|
|
3827
3861
|
core.updateSessionIndex(
|
|
3828
3862
|
projectPath,
|
|
3829
3863
|
input.session,
|
|
@@ -3893,7 +3927,7 @@ async function handleAssessProject(input) {
|
|
|
3893
3927
|
let validateResult = null;
|
|
3894
3928
|
if (checksToRun.has("validate")) {
|
|
3895
3929
|
try {
|
|
3896
|
-
const { handleValidateProject: handleValidateProject2 } = await import("./validate-
|
|
3930
|
+
const { handleValidateProject: handleValidateProject2 } = await import("./validate-KBYQAEWE.js");
|
|
3897
3931
|
const result = await handleValidateProject2({ path: projectPath });
|
|
3898
3932
|
const first = result.content[0];
|
|
3899
3933
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -3918,7 +3952,7 @@ async function handleAssessProject(input) {
|
|
|
3918
3952
|
parallelChecks.push(
|
|
3919
3953
|
(async () => {
|
|
3920
3954
|
try {
|
|
3921
|
-
const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-
|
|
3955
|
+
const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-ZLIH5533.js");
|
|
3922
3956
|
const result = await handleCheckDependencies2({ path: projectPath });
|
|
3923
3957
|
const first = result.content[0];
|
|
3924
3958
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -3945,7 +3979,7 @@ async function handleAssessProject(input) {
|
|
|
3945
3979
|
parallelChecks.push(
|
|
3946
3980
|
(async () => {
|
|
3947
3981
|
try {
|
|
3948
|
-
const { handleCheckDocs: handleCheckDocs2 } = await import("./docs-
|
|
3982
|
+
const { handleCheckDocs: handleCheckDocs2 } = await import("./docs-NRMQCOJ6.js");
|
|
3949
3983
|
const result = await handleCheckDocs2({ path: projectPath, scope: "coverage" });
|
|
3950
3984
|
const first = result.content[0];
|
|
3951
3985
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -3972,7 +4006,7 @@ async function handleAssessProject(input) {
|
|
|
3972
4006
|
parallelChecks.push(
|
|
3973
4007
|
(async () => {
|
|
3974
4008
|
try {
|
|
3975
|
-
const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-
|
|
4009
|
+
const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-6AGX2ZUN.js");
|
|
3976
4010
|
const result = await handleDetectEntropy2({ path: projectPath, type: "all" });
|
|
3977
4011
|
const first = result.content[0];
|
|
3978
4012
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -3999,7 +4033,7 @@ async function handleAssessProject(input) {
|
|
|
3999
4033
|
parallelChecks.push(
|
|
4000
4034
|
(async () => {
|
|
4001
4035
|
try {
|
|
4002
|
-
const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-
|
|
4036
|
+
const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-2RPQEN62.js");
|
|
4003
4037
|
const result = await handleRunSecurityScan2({ path: projectPath });
|
|
4004
4038
|
const first = result.content[0];
|
|
4005
4039
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -4031,7 +4065,7 @@ async function handleAssessProject(input) {
|
|
|
4031
4065
|
parallelChecks.push(
|
|
4032
4066
|
(async () => {
|
|
4033
4067
|
try {
|
|
4034
|
-
const { handleCheckPerformance: handleCheckPerformance2 } = await import("./performance-
|
|
4068
|
+
const { handleCheckPerformance: handleCheckPerformance2 } = await import("./performance-2D7G6NMJ.js");
|
|
4035
4069
|
const result = await handleCheckPerformance2({ path: projectPath });
|
|
4036
4070
|
const first = result.content[0];
|
|
4037
4071
|
const parsed = first ? JSON.parse(first.text) : {};
|
|
@@ -4220,7 +4254,7 @@ async function handleReviewChanges(input) {
|
|
|
4220
4254
|
}
|
|
4221
4255
|
}
|
|
4222
4256
|
async function runQuickReview(projectPath, diff, diffLines, downgraded) {
|
|
4223
|
-
const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-
|
|
4257
|
+
const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-MY4QZIFD.js");
|
|
4224
4258
|
const result = await handleAnalyzeDiff2({ diff, path: projectPath });
|
|
4225
4259
|
const firstContent = result.content[0];
|
|
4226
4260
|
if (!firstContent) throw new Error("Empty analyze_diff response");
|
|
@@ -4251,7 +4285,7 @@ function extractFileCount(diffParsed) {
|
|
|
4251
4285
|
return files?.length ?? 0;
|
|
4252
4286
|
}
|
|
4253
4287
|
async function runStandardReview(projectPath, diff, diffLines, downgraded) {
|
|
4254
|
-
const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-
|
|
4288
|
+
const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-MY4QZIFD.js");
|
|
4255
4289
|
const [diffResult, reviewResult] = await Promise.all([
|
|
4256
4290
|
handleAnalyzeDiff2({ diff, path: projectPath }),
|
|
4257
4291
|
handleCreateSelfReview2({ path: projectPath, diff })
|
|
@@ -4283,7 +4317,7 @@ async function runStandardReview(projectPath, diff, diffLines, downgraded) {
|
|
|
4283
4317
|
};
|
|
4284
4318
|
}
|
|
4285
4319
|
async function runDeepReview(projectPath, diff, diffLines, _downgraded) {
|
|
4286
|
-
const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-
|
|
4320
|
+
const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-RAQ55ISU.js");
|
|
4287
4321
|
const result = await handleRunCodeReview2({ path: projectPath, diff });
|
|
4288
4322
|
const deepContent = result.content[0];
|
|
4289
4323
|
if (!deepContent) throw new Error("Empty code review response");
|
|
@@ -4569,7 +4603,7 @@ async function handleDetectStaleConstraints(input) {
|
|
|
4569
4603
|
]
|
|
4570
4604
|
};
|
|
4571
4605
|
}
|
|
4572
|
-
const { detectStaleConstraints } = await import("./dist-
|
|
4606
|
+
const { detectStaleConstraints } = await import("./dist-ALQDD67R.js");
|
|
4573
4607
|
const result = detectStaleConstraints(
|
|
4574
4608
|
store,
|
|
4575
4609
|
windowDays,
|
|
@@ -4666,6 +4700,226 @@ async function handleSearchSkills(input) {
|
|
|
4666
4700
|
};
|
|
4667
4701
|
}
|
|
4668
4702
|
|
|
4703
|
+
// src/mcp/tools/code-nav.ts
|
|
4704
|
+
var codeOutlineDefinition = {
|
|
4705
|
+
name: "code_outline",
|
|
4706
|
+
description: "Get a structural skeleton of a file or files matching a glob: exports, classes, functions, types with signatures and line numbers. No implementation bodies. 4-8x token savings vs full file read.",
|
|
4707
|
+
inputSchema: {
|
|
4708
|
+
type: "object",
|
|
4709
|
+
properties: {
|
|
4710
|
+
path: {
|
|
4711
|
+
type: "string",
|
|
4712
|
+
description: "Absolute file path or directory path. When a directory, outlines all supported files within it."
|
|
4713
|
+
},
|
|
4714
|
+
glob: {
|
|
4715
|
+
type: "string",
|
|
4716
|
+
description: 'Optional glob pattern to filter files (e.g. "*.ts", "src/**/*.py"). Only used when path is a directory.'
|
|
4717
|
+
}
|
|
4718
|
+
},
|
|
4719
|
+
required: ["path"]
|
|
4720
|
+
}
|
|
4721
|
+
};
|
|
4722
|
+
async function handleCodeOutline(input) {
|
|
4723
|
+
let targetPath;
|
|
4724
|
+
try {
|
|
4725
|
+
targetPath = sanitizePath(input.path);
|
|
4726
|
+
} catch (error) {
|
|
4727
|
+
return {
|
|
4728
|
+
content: [
|
|
4729
|
+
{
|
|
4730
|
+
type: "text",
|
|
4731
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
4732
|
+
}
|
|
4733
|
+
],
|
|
4734
|
+
isError: true
|
|
4735
|
+
};
|
|
4736
|
+
}
|
|
4737
|
+
try {
|
|
4738
|
+
const { getOutline, formatOutline, EXTENSION_MAP } = await import("./dist-ALQDD67R.js");
|
|
4739
|
+
const { stat } = await import("fs/promises");
|
|
4740
|
+
const stats = await stat(targetPath).catch(() => null);
|
|
4741
|
+
if (stats?.isFile()) {
|
|
4742
|
+
const outline = await getOutline(targetPath);
|
|
4743
|
+
return { content: [{ type: "text", text: formatOutline(outline) }] };
|
|
4744
|
+
}
|
|
4745
|
+
if (stats?.isDirectory()) {
|
|
4746
|
+
const { glob } = await import("glob");
|
|
4747
|
+
const exts = Object.keys(EXTENSION_MAP).map((e) => e.slice(1));
|
|
4748
|
+
const pattern = input.glob ?? `**/*.{${exts.join(",")}}`;
|
|
4749
|
+
const files = await glob(pattern, { cwd: targetPath, absolute: true });
|
|
4750
|
+
const results = [];
|
|
4751
|
+
const MAX_FILES = 50;
|
|
4752
|
+
for (const file of files.slice(0, MAX_FILES)) {
|
|
4753
|
+
const outline = await getOutline(file);
|
|
4754
|
+
results.push(formatOutline(outline));
|
|
4755
|
+
}
|
|
4756
|
+
if (files.length > MAX_FILES) {
|
|
4757
|
+
results.push(
|
|
4758
|
+
`
|
|
4759
|
+
... and ${files.length - MAX_FILES} more files (use a narrower glob to see them)`
|
|
4760
|
+
);
|
|
4761
|
+
}
|
|
4762
|
+
return { content: [{ type: "text", text: results.join("\n\n") }] };
|
|
4763
|
+
}
|
|
4764
|
+
return {
|
|
4765
|
+
content: [{ type: "text", text: `Error: Path not found: ${targetPath}` }],
|
|
4766
|
+
isError: true
|
|
4767
|
+
};
|
|
4768
|
+
} catch (error) {
|
|
4769
|
+
return {
|
|
4770
|
+
content: [
|
|
4771
|
+
{
|
|
4772
|
+
type: "text",
|
|
4773
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
4774
|
+
}
|
|
4775
|
+
],
|
|
4776
|
+
isError: true
|
|
4777
|
+
};
|
|
4778
|
+
}
|
|
4779
|
+
}
|
|
4780
|
+
var codeSearchDefinition = {
|
|
4781
|
+
name: "code_search",
|
|
4782
|
+
description: "Search for symbols (functions, classes, types, variables) by name or pattern across a directory. Returns matching locations with file, line, kind, and one-line context. 6-12x token savings vs grep + read.",
|
|
4783
|
+
inputSchema: {
|
|
4784
|
+
type: "object",
|
|
4785
|
+
properties: {
|
|
4786
|
+
query: {
|
|
4787
|
+
type: "string",
|
|
4788
|
+
description: "Symbol name or substring to search for (case-insensitive)."
|
|
4789
|
+
},
|
|
4790
|
+
directory: {
|
|
4791
|
+
type: "string",
|
|
4792
|
+
description: "Absolute path to directory to search in."
|
|
4793
|
+
},
|
|
4794
|
+
glob: {
|
|
4795
|
+
type: "string",
|
|
4796
|
+
description: 'Optional glob pattern to filter files (e.g. "*.ts").'
|
|
4797
|
+
}
|
|
4798
|
+
},
|
|
4799
|
+
required: ["query", "directory"]
|
|
4800
|
+
}
|
|
4801
|
+
};
|
|
4802
|
+
async function handleCodeSearch(input) {
|
|
4803
|
+
let directory;
|
|
4804
|
+
try {
|
|
4805
|
+
directory = sanitizePath(input.directory);
|
|
4806
|
+
} catch (error) {
|
|
4807
|
+
return {
|
|
4808
|
+
content: [
|
|
4809
|
+
{
|
|
4810
|
+
type: "text",
|
|
4811
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
4812
|
+
}
|
|
4813
|
+
],
|
|
4814
|
+
isError: true
|
|
4815
|
+
};
|
|
4816
|
+
}
|
|
4817
|
+
try {
|
|
4818
|
+
const { searchSymbols } = await import("./dist-ALQDD67R.js");
|
|
4819
|
+
const result = await searchSymbols(input.query, directory, input.glob);
|
|
4820
|
+
const lines = [`Search: "${result.query}" \u2014 ${result.matches.length} matches`];
|
|
4821
|
+
for (const match of result.matches) {
|
|
4822
|
+
const { symbol } = match;
|
|
4823
|
+
lines.push(
|
|
4824
|
+
` ${symbol.file}:${symbol.line} [${symbol.kind}] ${symbol.name} \u2014 ${match.context}`
|
|
4825
|
+
);
|
|
4826
|
+
}
|
|
4827
|
+
if (result.skipped.length > 0) {
|
|
4828
|
+
lines.push(`
|
|
4829
|
+
Skipped ${result.skipped.length} files (unsupported or parse failed)`);
|
|
4830
|
+
}
|
|
4831
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4832
|
+
} catch (error) {
|
|
4833
|
+
return {
|
|
4834
|
+
content: [
|
|
4835
|
+
{
|
|
4836
|
+
type: "text",
|
|
4837
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
4838
|
+
}
|
|
4839
|
+
],
|
|
4840
|
+
isError: true
|
|
4841
|
+
};
|
|
4842
|
+
}
|
|
4843
|
+
}
|
|
4844
|
+
var codeUnfoldDefinition = {
|
|
4845
|
+
name: "code_unfold",
|
|
4846
|
+
description: "Extract the complete implementation of a specific symbol (function, class, type) or a line range from a file. Uses AST boundaries for precise extraction. 2-4x token savings vs full file read.",
|
|
4847
|
+
inputSchema: {
|
|
4848
|
+
type: "object",
|
|
4849
|
+
properties: {
|
|
4850
|
+
path: {
|
|
4851
|
+
type: "string",
|
|
4852
|
+
description: "Absolute path to the file."
|
|
4853
|
+
},
|
|
4854
|
+
symbol: {
|
|
4855
|
+
type: "string",
|
|
4856
|
+
description: "Name of the symbol to extract (function, class, type, etc.). Mutually exclusive with startLine/endLine."
|
|
4857
|
+
},
|
|
4858
|
+
startLine: {
|
|
4859
|
+
type: "number",
|
|
4860
|
+
description: "Start line number (1-indexed). Used with endLine for range extraction. Mutually exclusive with symbol."
|
|
4861
|
+
},
|
|
4862
|
+
endLine: {
|
|
4863
|
+
type: "number",
|
|
4864
|
+
description: "End line number (1-indexed, inclusive). Used with startLine for range extraction."
|
|
4865
|
+
}
|
|
4866
|
+
},
|
|
4867
|
+
required: ["path"]
|
|
4868
|
+
}
|
|
4869
|
+
};
|
|
4870
|
+
async function handleCodeUnfold(input) {
|
|
4871
|
+
let filePath;
|
|
4872
|
+
try {
|
|
4873
|
+
filePath = sanitizePath(input.path);
|
|
4874
|
+
} catch (error) {
|
|
4875
|
+
return {
|
|
4876
|
+
content: [
|
|
4877
|
+
{
|
|
4878
|
+
type: "text",
|
|
4879
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
4880
|
+
}
|
|
4881
|
+
],
|
|
4882
|
+
isError: true
|
|
4883
|
+
};
|
|
4884
|
+
}
|
|
4885
|
+
try {
|
|
4886
|
+
if (input.symbol) {
|
|
4887
|
+
const { unfoldSymbol } = await import("./dist-ALQDD67R.js");
|
|
4888
|
+
const result = await unfoldSymbol(filePath, input.symbol);
|
|
4889
|
+
const header = result.warning ? `${result.file}:${result.startLine}-${result.endLine} ${result.warning}
|
|
4890
|
+
` : `${result.file}:${result.startLine}-${result.endLine}
|
|
4891
|
+
`;
|
|
4892
|
+
return { content: [{ type: "text", text: header + result.content }] };
|
|
4893
|
+
}
|
|
4894
|
+
if (input.startLine != null && input.endLine != null) {
|
|
4895
|
+
const { unfoldRange } = await import("./dist-ALQDD67R.js");
|
|
4896
|
+
const result = await unfoldRange(filePath, input.startLine, input.endLine);
|
|
4897
|
+
const header = `${result.file}:${result.startLine}-${result.endLine}
|
|
4898
|
+
`;
|
|
4899
|
+
return { content: [{ type: "text", text: header + result.content }] };
|
|
4900
|
+
}
|
|
4901
|
+
return {
|
|
4902
|
+
content: [
|
|
4903
|
+
{
|
|
4904
|
+
type: "text",
|
|
4905
|
+
text: 'Error: Provide either "symbol" or "startLine" + "endLine".'
|
|
4906
|
+
}
|
|
4907
|
+
],
|
|
4908
|
+
isError: true
|
|
4909
|
+
};
|
|
4910
|
+
} catch (error) {
|
|
4911
|
+
return {
|
|
4912
|
+
content: [
|
|
4913
|
+
{
|
|
4914
|
+
type: "text",
|
|
4915
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
4916
|
+
}
|
|
4917
|
+
],
|
|
4918
|
+
isError: true
|
|
4919
|
+
};
|
|
4920
|
+
}
|
|
4921
|
+
}
|
|
4922
|
+
|
|
4669
4923
|
// src/mcp/server.ts
|
|
4670
4924
|
var TOOL_DEFINITIONS = [
|
|
4671
4925
|
validateToolDefinition,
|
|
@@ -4713,7 +4967,10 @@ var TOOL_DEFINITIONS = [
|
|
|
4713
4967
|
checkTaskIndependenceDefinition,
|
|
4714
4968
|
predictConflictsDefinition,
|
|
4715
4969
|
detectStaleConstraintsDefinition,
|
|
4716
|
-
searchSkillsDefinition
|
|
4970
|
+
searchSkillsDefinition,
|
|
4971
|
+
codeOutlineDefinition,
|
|
4972
|
+
codeSearchDefinition,
|
|
4973
|
+
codeUnfoldDefinition
|
|
4717
4974
|
];
|
|
4718
4975
|
var TOOL_HANDLERS = {
|
|
4719
4976
|
validate_project: handleValidateProject,
|
|
@@ -4761,7 +5018,10 @@ var TOOL_HANDLERS = {
|
|
|
4761
5018
|
check_task_independence: handleCheckTaskIndependence,
|
|
4762
5019
|
predict_conflicts: handlePredictConflicts,
|
|
4763
5020
|
detect_stale_constraints: handleDetectStaleConstraints,
|
|
4764
|
-
search_skills: handleSearchSkills
|
|
5021
|
+
search_skills: handleSearchSkills,
|
|
5022
|
+
code_outline: handleCodeOutline,
|
|
5023
|
+
code_search: handleCodeSearch,
|
|
5024
|
+
code_unfold: handleCodeUnfold
|
|
4765
5025
|
};
|
|
4766
5026
|
var RESOURCE_DEFINITIONS = [
|
|
4767
5027
|
{
|
|
@@ -4847,7 +5107,7 @@ async function appendUpdateNotification(result, resolvedRoot) {
|
|
|
4847
5107
|
shouldRunCheck,
|
|
4848
5108
|
readCheckState,
|
|
4849
5109
|
spawnBackgroundCheck
|
|
4850
|
-
} = await import("./dist-
|
|
5110
|
+
} = await import("./dist-ALQDD67R.js");
|
|
4851
5111
|
const { CLI_VERSION } = await import("./version-KFFPOQAX.js");
|
|
4852
5112
|
const configInterval = readConfigInterval(resolvedRoot);
|
|
4853
5113
|
const DEFAULT_INTERVAL = 864e5;
|