@harness-engineering/cli 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +9 -8
- package/dist/agents/skills/claude-code/pre-merge-brief/SKILL.md +86 -0
- package/dist/agents/skills/claude-code/pre-merge-brief/skill.yaml +67 -0
- package/dist/agents/skills/claude-code/product-advisor/SKILL.md +202 -0
- package/dist/agents/skills/claude-code/product-advisor/skill.yaml +74 -0
- package/dist/agents/skills/codex/harness-autopilot/SKILL.md +9 -8
- package/dist/agents/skills/codex/pre-merge-brief/SKILL.md +86 -0
- package/dist/agents/skills/codex/pre-merge-brief/skill.yaml +67 -0
- package/dist/agents/skills/codex/product-advisor/SKILL.md +202 -0
- package/dist/agents/skills/codex/product-advisor/skill.yaml +74 -0
- package/dist/agents/skills/cursor/harness-autopilot/SKILL.md +9 -8
- package/dist/agents/skills/cursor/pre-merge-brief/SKILL.md +86 -0
- package/dist/agents/skills/cursor/pre-merge-brief/skill.yaml +67 -0
- package/dist/agents/skills/cursor/product-advisor/SKILL.md +202 -0
- package/dist/agents/skills/cursor/product-advisor/skill.yaml +74 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +9 -8
- package/dist/agents/skills/gemini-cli/pre-merge-brief/SKILL.md +86 -0
- package/dist/agents/skills/gemini-cli/pre-merge-brief/skill.yaml +67 -0
- package/dist/agents/skills/gemini-cli/product-advisor/SKILL.md +202 -0
- package/dist/agents/skills/gemini-cli/product-advisor/skill.yaml +74 -0
- package/dist/{agents-md-7OSNWU52.js → agents-md-7L4PKKOM.js} +4 -4
- package/dist/analyzer-XRCV63KC-HLTEIKAJ.js +26 -0
- package/dist/{architecture-2XYGJGT3.js → architecture-RCHFDI7E.js} +5 -5
- package/dist/{assess-project-3KPP2D6M.js → assess-project-YUDPNRS6.js} +5 -3
- package/dist/bin/harness-mcp.js +16 -16
- package/dist/bin/harness.js +27 -27
- package/dist/{check-phase-gate-46U5AAXE.js → check-phase-gate-56GS3A72.js} +5 -5
- package/dist/{chunk-MSBJ445U.js → chunk-4SKWGVYD.js} +5 -5
- package/dist/{chunk-CLI4K2CH.js → chunk-4U5LDFCY.js} +1 -1
- package/dist/{chunk-6YXCZV33.js → chunk-ABRYIEWJ.js} +1090 -714
- package/dist/{chunk-AK67S3O4.js → chunk-AU4YPEIE.js} +3 -3
- package/dist/{chunk-BV45354Q.js → chunk-DGVT4DBI.js} +9 -9
- package/dist/{chunk-363V6GPR.js → chunk-GLHLXTKC.js} +9 -9
- package/dist/{chunk-VTUINXWR.js → chunk-GSYBGOY3.js} +1 -1
- package/dist/{chunk-FZ4Q73HA.js → chunk-IGWJRAJT.js} +1 -1
- package/dist/{chunk-S2RQPPL6.js → chunk-N4AI2WFH.js} +1 -1
- package/dist/{chunk-HXMAIVV2.js → chunk-NCMJXBEO.js} +1 -1
- package/dist/{chunk-ZEYAOYJL.js → chunk-OZSKLJQW.js} +1 -1
- package/dist/{chunk-VTU3QOJT.js → chunk-P4NA5OQX.js} +1 -1
- package/dist/{chunk-WL3O2PKJ.js → chunk-RY2U77OY.js} +8 -8
- package/dist/{chunk-TTWNGOBT.js → chunk-RZQZXWEL.js} +32 -7
- package/dist/{chunk-KLPX55TI.js → chunk-UACYZCW4.js} +239 -146
- package/dist/{chunk-IYWT3JJW.js → chunk-VG4G3R2V.js} +1 -1
- package/dist/{chunk-PP6ZRL5T.js → chunk-WZJR6SOI.js} +536 -422
- package/dist/{chunk-PHX45JYN.js → chunk-XW5XVVMI.js} +2 -2
- package/dist/{chunk-MYVTYFQD.js → chunk-XZNCONFG.js} +1 -1
- package/dist/{chunk-GXCPDAS5.js → chunk-Y33P35U3.js} +26 -8
- package/dist/{chunk-XFHZ7GCI.js → chunk-Y5HPJMTM.js} +19 -3
- package/dist/{chunk-N55WOGN3.js → chunk-YJYUJSWK.js} +59 -21
- package/dist/{chunk-SPE7P4GL.js → chunk-YWRPQZL7.js} +1 -1
- package/dist/{chunk-6NCREWWM.js → chunk-YXOPQEFZ.js} +3 -3
- package/dist/{chunk-2N4OENGE.js → chunk-YYFSFSB3.js} +1 -1
- package/dist/{chunk-ERILXQBP.js → chunk-Z4XWWNYX.js} +615 -433
- package/dist/{chunk-HMW3C5DP.js → chunk-ZU6T7W3U.js} +2 -2
- package/dist/{ci-workflow-XJN4UO3Q.js → ci-workflow-TFAA5BK7.js} +4 -4
- package/dist/{dist-OWHMNL4W.js → dist-DWBTZXR5.js} +1 -1
- package/dist/{dist-IPVFYGY2.js → dist-MCTEX5QH.js} +5 -3
- package/dist/{docs-RSFZTNPG.js → docs-BBMAN3CY.js} +5 -5
- package/dist/{engine-DJIHY4JT.js → engine-R2YH74AL.js} +4 -4
- package/dist/{entropy-EAEKJKRM.js → entropy-5UP5N6AF.js} +7 -4
- package/dist/{feedback-JT5X3DBC.js → feedback-6MDCCFZL.js} +1 -1
- package/dist/{generate-agent-definitions-CC6KED3E.js → generate-agent-definitions-KKAN5DB5.js} +5 -5
- package/dist/{glob-helper-GLZAURJC.js → glob-helper-VR6UCZZB.js} +1 -1
- package/dist/{graph-loader-HHXN5FLP.js → graph-loader-STFGYKZH.js} +1 -1
- package/dist/hooks/sentinel-pre.js +15 -138
- package/dist/index.d.ts +61 -0
- package/dist/index.js +27 -27
- package/dist/{loader-UWNVTYBY.js → loader-2WT2ZE2T.js} +4 -4
- package/dist/{mcp-TCLNK7HG.js → mcp-5V4LPMB3.js} +16 -16
- package/dist/{performance-R6O3N3UB.js → performance-2N3CFXLR.js} +5 -5
- package/dist/{review-pipeline-MOOWXWSQ.js → review-pipeline-XZIGBU3Q.js} +4 -4
- package/dist/{runtime-RIWQUKBQ.js → runtime-POME3GTR.js} +4 -4
- package/dist/{scan-P7YFKB77.js → scan-IYSVRPD2.js} +1 -1
- package/dist/{security-U76C54W6.js → security-QLJLMSIW.js} +1 -1
- package/dist/{state-events-F44CUUZG.js → state-events-YY5KBZTC.js} +4 -4
- package/dist/{validate-IUAV7MOU.js → validate-VZORVK43.js} +5 -5
- package/dist/{validate-cross-check-M2ZM6RFY.js → validate-cross-check-OYKEDCST.js} +4 -4
- package/package.json +5 -4
- package/dist/analyzer-V633GUHY-MBCQWKDU.js +0 -26
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generateRuntime
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-N4AI2WFH.js";
|
|
4
4
|
import {
|
|
5
5
|
generateAgentsMd
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-VG4G3R2V.js";
|
|
7
7
|
import {
|
|
8
8
|
generateCIWorkflow
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-P4NA5OQX.js";
|
|
10
10
|
import {
|
|
11
11
|
readHarnessState
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YWRPQZL7.js";
|
|
13
13
|
import {
|
|
14
14
|
runCrossCheck
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-GSYBGOY3.js";
|
|
16
16
|
import {
|
|
17
17
|
createGenerateAgentDefinitionsCommand,
|
|
18
18
|
generateAgentDefinitions
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-XZNCONFG.js";
|
|
20
20
|
import {
|
|
21
21
|
toKebabCase
|
|
22
22
|
} from "./chunk-KET4QQZB.js";
|
|
23
23
|
import {
|
|
24
24
|
createScanCommand,
|
|
25
25
|
loadIngestOptions
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-YYFSFSB3.js";
|
|
27
27
|
import {
|
|
28
28
|
TemplateEngine
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-IGWJRAJT.js";
|
|
30
30
|
import {
|
|
31
31
|
generate,
|
|
32
32
|
validate
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
import {
|
|
38
38
|
listPersonas,
|
|
39
39
|
loadPersona
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-NCMJXBEO.js";
|
|
41
41
|
import {
|
|
42
42
|
runPersona
|
|
43
43
|
} from "./chunk-GISMXMVL.js";
|
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
OutputFormatter,
|
|
52
52
|
OutputMode,
|
|
53
53
|
createCheckPhaseGateCommand
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-XW5XVVMI.js";
|
|
55
55
|
import {
|
|
56
56
|
appendFrameworkAgents,
|
|
57
57
|
captureHealthSnapshot,
|
|
@@ -79,13 +79,13 @@ import {
|
|
|
79
79
|
runSecurityCraft,
|
|
80
80
|
runSpecCraft,
|
|
81
81
|
runTestCraft
|
|
82
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-Z4XWWNYX.js";
|
|
83
83
|
import {
|
|
84
84
|
VALID_PLATFORMS
|
|
85
85
|
} from "./chunk-3ISINLYT.js";
|
|
86
86
|
import {
|
|
87
87
|
loadGraphStore
|
|
88
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-4U5LDFCY.js";
|
|
89
89
|
import {
|
|
90
90
|
loadOrRebuildIndex
|
|
91
91
|
} from "./chunk-WBVCN35T.js";
|
|
@@ -108,7 +108,7 @@ import {
|
|
|
108
108
|
BranchingConfigSchema,
|
|
109
109
|
findConfigFile,
|
|
110
110
|
resolveConfig
|
|
111
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-Y5HPJMTM.js";
|
|
112
112
|
import {
|
|
113
113
|
logger
|
|
114
114
|
} from "./chunk-EBJQ6N4M.js";
|
|
@@ -188,6 +188,7 @@ import {
|
|
|
188
188
|
parseDiff,
|
|
189
189
|
parseFileRegions,
|
|
190
190
|
parseManifest,
|
|
191
|
+
parseReferencedIssues,
|
|
191
192
|
parseRoadmap,
|
|
192
193
|
parseSecurityConfig,
|
|
193
194
|
pruneLearnings,
|
|
@@ -224,7 +225,7 @@ import {
|
|
|
224
225
|
writeConfig,
|
|
225
226
|
writeLockfile,
|
|
226
227
|
writeRegeneratedRoadmap
|
|
227
|
-
} from "./chunk-
|
|
228
|
+
} from "./chunk-UACYZCW4.js";
|
|
228
229
|
import {
|
|
229
230
|
CLI_VERSION
|
|
230
231
|
} from "./chunk-BM3PWGXQ.js";
|
|
@@ -237,7 +238,7 @@ import {
|
|
|
237
238
|
detectDocDrift,
|
|
238
239
|
generateSuggestions,
|
|
239
240
|
validateDependencies
|
|
240
|
-
} from "./chunk-
|
|
241
|
+
} from "./chunk-YJYUJSWK.js";
|
|
241
242
|
import {
|
|
242
243
|
Err,
|
|
243
244
|
INDEXED_FILE_KINDS,
|
|
@@ -250,7 +251,7 @@ import {
|
|
|
250
251
|
DesignConstraintAdapter,
|
|
251
252
|
GraphStore,
|
|
252
253
|
init_dist as init_dist2
|
|
253
|
-
} from "./chunk-
|
|
254
|
+
} from "./chunk-WZJR6SOI.js";
|
|
254
255
|
import {
|
|
255
256
|
ArchConfigSchema,
|
|
256
257
|
TimelineManager
|
|
@@ -261,7 +262,7 @@ import {
|
|
|
261
262
|
} from "./chunk-KFQGP6VL.js";
|
|
262
263
|
|
|
263
264
|
// src/index.ts
|
|
264
|
-
import { Command as
|
|
265
|
+
import { Command as Command130 } from "commander";
|
|
265
266
|
|
|
266
267
|
// src/commands/add.ts
|
|
267
268
|
init_dist3();
|
|
@@ -450,7 +451,7 @@ function registerSkillsCommand(adoption) {
|
|
|
450
451
|
const globalOpts = cmd.optsWithGlobals();
|
|
451
452
|
const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
|
|
452
453
|
const cwd = process.cwd();
|
|
453
|
-
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-
|
|
454
|
+
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-MCTEX5QH.js");
|
|
454
455
|
const records = readAdoptionRecords(cwd);
|
|
455
456
|
if (records.length === 0) {
|
|
456
457
|
if (globalOpts.json) {
|
|
@@ -486,7 +487,7 @@ function registerRecentCommand(adoption) {
|
|
|
486
487
|
const globalOpts = cmd.optsWithGlobals();
|
|
487
488
|
const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
|
|
488
489
|
const cwd = process.cwd();
|
|
489
|
-
const { readAdoptionRecords } = await import("./dist-
|
|
490
|
+
const { readAdoptionRecords } = await import("./dist-MCTEX5QH.js");
|
|
490
491
|
const records = readAdoptionRecords(cwd);
|
|
491
492
|
if (records.length === 0) {
|
|
492
493
|
if (globalOpts.json) {
|
|
@@ -564,7 +565,7 @@ function registerSkillCommand(adoption) {
|
|
|
564
565
|
adoption.command("skill <name>").description("Show detail for a specific skill").action(async (name, _opts, cmd) => {
|
|
565
566
|
const globalOpts = cmd.optsWithGlobals();
|
|
566
567
|
const cwd = process.cwd();
|
|
567
|
-
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-
|
|
568
|
+
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-MCTEX5QH.js");
|
|
568
569
|
const records = readAdoptionRecords(cwd);
|
|
569
570
|
const skillRecords = records.filter((r) => r.skill === name);
|
|
570
571
|
if (skillRecords.length === 0) {
|
|
@@ -1995,10 +1996,24 @@ function createCheckHarnessStrengthCommand() {
|
|
|
1995
1996
|
init_dist3();
|
|
1996
1997
|
import { Command as Command15 } from "commander";
|
|
1997
1998
|
import * as path9 from "path";
|
|
1999
|
+
function resolveConfiguredEntryPoints(configPath) {
|
|
2000
|
+
const configResult = resolveConfig(configPath);
|
|
2001
|
+
if (!configResult.ok) return void 0;
|
|
2002
|
+
const config = configResult.value;
|
|
2003
|
+
const fromPerformance = config.performance?.entryPoints;
|
|
2004
|
+
if (Array.isArray(fromPerformance) && fromPerformance.length > 0) {
|
|
2005
|
+
return fromPerformance.filter((e) => typeof e === "string");
|
|
2006
|
+
}
|
|
2007
|
+
const fromEntropy = config.entropy?.entryPoints;
|
|
2008
|
+
if (Array.isArray(fromEntropy) && fromEntropy.length > 0) return fromEntropy;
|
|
2009
|
+
return void 0;
|
|
2010
|
+
}
|
|
1998
2011
|
async function runCheckPerf(cwd, options) {
|
|
1999
2012
|
const runAll2 = !options.structural && !options.size && !options.coupling;
|
|
2013
|
+
const entryPoints = resolveConfiguredEntryPoints(options.configPath);
|
|
2000
2014
|
const analyzer = new EntropyAnalyzer({
|
|
2001
2015
|
rootDir: path9.resolve(cwd),
|
|
2016
|
+
...entryPoints && { entryPoints },
|
|
2002
2017
|
analyze: {
|
|
2003
2018
|
complexity: runAll2 || !!options.structural,
|
|
2004
2019
|
coupling: runAll2 || !!options.coupling,
|
|
@@ -2682,12 +2697,14 @@ async function runCleanup(options) {
|
|
|
2682
2697
|
};
|
|
2683
2698
|
const rootDir = path12.resolve(cwd, config.rootDir);
|
|
2684
2699
|
const docsDir = path12.resolve(cwd, config.docsDir);
|
|
2700
|
+
const driftEnabled = type === "all" || type === "drift";
|
|
2701
|
+
const driftConfig = config.entropy?.drift;
|
|
2685
2702
|
const entropyConfig = {
|
|
2686
2703
|
rootDir,
|
|
2687
2704
|
...config.entropy?.entryPoints && { entryPoints: config.entropy.entryPoints },
|
|
2688
2705
|
docPaths: [path12.join(docsDir, "**/*.md")],
|
|
2689
2706
|
analyze: {
|
|
2690
|
-
drift:
|
|
2707
|
+
drift: driftEnabled ? driftConfig ?? true : false,
|
|
2691
2708
|
deadCode: type === "all" || type === "dead-code",
|
|
2692
2709
|
patterns: type === "all" || type === "patterns" ? { patterns: [] } : false
|
|
2693
2710
|
},
|
|
@@ -4331,8 +4348,7 @@ function promptYesNo(message) {
|
|
|
4331
4348
|
});
|
|
4332
4349
|
});
|
|
4333
4350
|
}
|
|
4334
|
-
function
|
|
4335
|
-
const cmd = new Command32("deliveries").description("Inspect and manage webhook delivery queue");
|
|
4351
|
+
function registerListCommand(cmd) {
|
|
4336
4352
|
cmd.command("list").description("List delivery queue entries (newest first; capped at 200 rows)").option("--status <status>", "Filter by status: pending|failed|delivered|dead").option("--subscription <id>", "Filter by subscription ID").action((opts) => {
|
|
4337
4353
|
const queue = getQueue();
|
|
4338
4354
|
try {
|
|
@@ -4345,6 +4361,8 @@ function createDeliveriesCommand() {
|
|
|
4345
4361
|
queue.close();
|
|
4346
4362
|
}
|
|
4347
4363
|
});
|
|
4364
|
+
}
|
|
4365
|
+
function registerRetryCommand(cmd) {
|
|
4348
4366
|
cmd.command("retry <id>").description("Re-enqueue a dead-lettered delivery by ID").action((id) => {
|
|
4349
4367
|
const queue = getQueue();
|
|
4350
4368
|
try {
|
|
@@ -4359,23 +4377,30 @@ function createDeliveriesCommand() {
|
|
|
4359
4377
|
queue.close();
|
|
4360
4378
|
}
|
|
4361
4379
|
});
|
|
4380
|
+
}
|
|
4381
|
+
function buildPurgeOptions(opts) {
|
|
4382
|
+
const purgeOpts = {};
|
|
4383
|
+
if (opts.deadOnly) purgeOpts.deadOnly = true;
|
|
4384
|
+
if (opts.olderThan !== void 0) purgeOpts.olderThanMs = Number(opts.olderThan);
|
|
4385
|
+
if (opts.all) purgeOpts.all = true;
|
|
4386
|
+
return purgeOpts;
|
|
4387
|
+
}
|
|
4388
|
+
function ttyPurgeConfirm(count) {
|
|
4389
|
+
if (count === 0) {
|
|
4390
|
+
console.log("No matching rows to delete.");
|
|
4391
|
+
return false;
|
|
4392
|
+
}
|
|
4393
|
+
return promptYesNo(`Delete ${count} row(s)? [y/N] `);
|
|
4394
|
+
}
|
|
4395
|
+
function registerPurgeCommand(cmd) {
|
|
4362
4396
|
cmd.command("purge").description("Delete delivery rows from the queue (requires at least one filter)").option("--dead-only", "Delete only dead-lettered rows").option("--older-than <ms>", "Delete delivered rows older than N milliseconds").option("--all", "Delete every row in the queue (use with caution)").action(async (opts) => {
|
|
4363
4397
|
const queue = getQueue();
|
|
4364
4398
|
try {
|
|
4365
|
-
const purgeOpts =
|
|
4366
|
-
if (opts.deadOnly) purgeOpts.deadOnly = true;
|
|
4367
|
-
if (opts.olderThan !== void 0) purgeOpts.olderThanMs = Number(opts.olderThan);
|
|
4368
|
-
if (opts.all) purgeOpts.all = true;
|
|
4399
|
+
const purgeOpts = buildPurgeOptions(opts);
|
|
4369
4400
|
const isTty = Boolean(process.stdout.isTTY);
|
|
4370
4401
|
const runOpts = {};
|
|
4371
4402
|
if (isTty) {
|
|
4372
|
-
runOpts.confirm =
|
|
4373
|
-
if (count === 0) {
|
|
4374
|
-
console.log("No matching rows to delete.");
|
|
4375
|
-
return false;
|
|
4376
|
-
}
|
|
4377
|
-
return promptYesNo(`Delete ${count} row(s)? [y/N] `);
|
|
4378
|
-
};
|
|
4403
|
+
runOpts.confirm = ttyPurgeConfirm;
|
|
4379
4404
|
}
|
|
4380
4405
|
const result = await runDeliveriesPurge(queue, purgeOpts, runOpts);
|
|
4381
4406
|
if (result === -1) {
|
|
@@ -4387,6 +4412,12 @@ function createDeliveriesCommand() {
|
|
|
4387
4412
|
queue.close();
|
|
4388
4413
|
}
|
|
4389
4414
|
});
|
|
4415
|
+
}
|
|
4416
|
+
function createDeliveriesCommand() {
|
|
4417
|
+
const cmd = new Command32("deliveries").description("Inspect and manage webhook delivery queue");
|
|
4418
|
+
registerListCommand(cmd);
|
|
4419
|
+
registerRetryCommand(cmd);
|
|
4420
|
+
registerPurgeCommand(cmd);
|
|
4390
4421
|
return cmd;
|
|
4391
4422
|
}
|
|
4392
4423
|
|
|
@@ -4483,16 +4514,16 @@ async function readConnectorSyncStatus(graphDir) {
|
|
|
4483
4514
|
return result;
|
|
4484
4515
|
}
|
|
4485
4516
|
async function runGraphStatus(projectPath) {
|
|
4486
|
-
const { GraphStore: GraphStore2, loadGraphMetadata } = await import("./dist-
|
|
4517
|
+
const { GraphStore: GraphStore2, loadGraphMetadata } = await import("./dist-DWBTZXR5.js");
|
|
4487
4518
|
const graphDir = path18.join(projectPath, ".harness", "graph");
|
|
4488
4519
|
const metaResult = await loadGraphMetadata(graphDir);
|
|
4489
4520
|
if (metaResult.status === "not_found") {
|
|
4490
|
-
return { status: "no_graph", message: "No graph found. Run `harness scan` first." };
|
|
4521
|
+
return { status: "no_graph", message: "No graph found. Run `harness graph scan` first." };
|
|
4491
4522
|
}
|
|
4492
4523
|
if (metaResult.status === "schema_mismatch") {
|
|
4493
4524
|
return {
|
|
4494
4525
|
status: "schema_mismatch",
|
|
4495
|
-
message: `Graph schema version mismatch: file is v${metaResult.found}, CLI expects v${metaResult.expected}. Run \`harness scan\` to rebuild.`
|
|
4526
|
+
message: `Graph schema version mismatch: file is v${metaResult.found}, CLI expects v${metaResult.expected}. Run \`harness graph scan\` to rebuild.`
|
|
4496
4527
|
};
|
|
4497
4528
|
}
|
|
4498
4529
|
const meta = metaResult.metadata;
|
|
@@ -4535,11 +4566,11 @@ async function runGraphStatus(projectPath) {
|
|
|
4535
4566
|
// src/commands/graph/export.ts
|
|
4536
4567
|
import * as path19 from "path";
|
|
4537
4568
|
async function runGraphExport(projectPath, format) {
|
|
4538
|
-
const { GraphStore: GraphStore2 } = await import("./dist-
|
|
4569
|
+
const { GraphStore: GraphStore2 } = await import("./dist-DWBTZXR5.js");
|
|
4539
4570
|
const graphDir = path19.join(projectPath, ".harness", "graph");
|
|
4540
4571
|
const store = new GraphStore2();
|
|
4541
4572
|
const loaded = await store.load(graphDir);
|
|
4542
|
-
if (!loaded) throw new Error("No graph found. Run `harness scan` first.");
|
|
4573
|
+
if (!loaded) throw new Error("No graph found. Run `harness graph scan` first.");
|
|
4543
4574
|
if (format === "json") {
|
|
4544
4575
|
const nodes = store.findNodes({});
|
|
4545
4576
|
const edges = store.getEdges({});
|
|
@@ -4568,11 +4599,11 @@ async function runGraphExport(projectPath, format) {
|
|
|
4568
4599
|
import { Command as Command35 } from "commander";
|
|
4569
4600
|
import * as path20 from "path";
|
|
4570
4601
|
async function runQuery(projectPath, rootNodeId, opts) {
|
|
4571
|
-
const { GraphStore: GraphStore2, ContextQL } = await import("./dist-
|
|
4602
|
+
const { GraphStore: GraphStore2, ContextQL } = await import("./dist-DWBTZXR5.js");
|
|
4572
4603
|
const store = new GraphStore2();
|
|
4573
4604
|
const graphDir = path20.join(projectPath, ".harness", "graph");
|
|
4574
4605
|
const loaded = await store.load(graphDir);
|
|
4575
|
-
if (!loaded) throw new Error("No graph found. Run `harness scan` first.");
|
|
4606
|
+
if (!loaded) throw new Error("No graph found. Run `harness graph scan` first.");
|
|
4576
4607
|
const params = {
|
|
4577
4608
|
rootNodeIds: [rootNodeId],
|
|
4578
4609
|
maxDepth: opts.depth ?? 3,
|
|
@@ -4673,7 +4704,7 @@ async function runIngest(projectPath, source, opts) {
|
|
|
4673
4704
|
ConfluenceConnector,
|
|
4674
4705
|
FigmaConnector,
|
|
4675
4706
|
MiroConnector
|
|
4676
|
-
} = await import("./dist-
|
|
4707
|
+
} = await import("./dist-DWBTZXR5.js");
|
|
4677
4708
|
const graphDir = path21.join(projectPath, ".harness", "graph");
|
|
4678
4709
|
const store = new GraphStore2();
|
|
4679
4710
|
await store.load(graphDir);
|
|
@@ -4689,7 +4720,7 @@ async function runIngest(projectPath, source, opts) {
|
|
|
4689
4720
|
path21.join(projectPath, "docs", "changes")
|
|
4690
4721
|
);
|
|
4691
4722
|
const gitResult = await new GitIngestor(store).ingest(projectPath);
|
|
4692
|
-
const { createExtractionRunner } = await import("./dist-
|
|
4723
|
+
const { createExtractionRunner } = await import("./dist-DWBTZXR5.js");
|
|
4693
4724
|
const extractedDir = path21.join(projectPath, ".harness", "knowledge", "extracted");
|
|
4694
4725
|
const signalsResult = await createExtractionRunner().run(projectPath, store, extractedDir);
|
|
4695
4726
|
const syncManager = new SyncManager(store, graphDir);
|
|
@@ -4739,7 +4770,7 @@ async function runIngest(projectPath, source, opts) {
|
|
|
4739
4770
|
);
|
|
4740
4771
|
break;
|
|
4741
4772
|
case "business-signals": {
|
|
4742
|
-
const { createExtractionRunner } = await import("./dist-
|
|
4773
|
+
const { createExtractionRunner } = await import("./dist-DWBTZXR5.js");
|
|
4743
4774
|
const extractedDir = path21.join(projectPath, ".harness", "knowledge", "extracted");
|
|
4744
4775
|
result = await createExtractionRunner().run(projectPath, store, extractedDir);
|
|
4745
4776
|
break;
|
|
@@ -5451,7 +5482,7 @@ async function runImpactPreview(options) {
|
|
|
5451
5482
|
const stagedFiles = getStagedFiles(projectPath);
|
|
5452
5483
|
if (stagedFiles.length === 0) return "Impact Preview: no staged changes";
|
|
5453
5484
|
if (!graphExists(projectPath)) {
|
|
5454
|
-
return "Impact Preview: skipped (no graph \u2014 run `harness scan` to enable)";
|
|
5485
|
+
return "Impact Preview: skipped (no graph \u2014 run `harness graph scan` to enable)";
|
|
5455
5486
|
}
|
|
5456
5487
|
const mode = options.detailed ? "detailed" : "summary";
|
|
5457
5488
|
const acc = {
|
|
@@ -6131,7 +6162,7 @@ function createInsightsCommand() {
|
|
|
6131
6162
|
return new Command46("insights").description("Composite project report \u2014 health, entropy, decay, attention, impact.").option("--json", "Emit JSON to stdout instead of pretty text").option("--skip <list>", `Comma-separated keys to skip (${INSIGHTS_KEYS.join(",")})`).action(async (opts) => {
|
|
6132
6163
|
const cwd = process.cwd();
|
|
6133
6164
|
const skip = parseSkip2(opts.skip);
|
|
6134
|
-
const { composeInsights } = await import("./dist-
|
|
6165
|
+
const { composeInsights } = await import("./dist-MCTEX5QH.js");
|
|
6135
6166
|
const report = await composeInsights(cwd, { skip });
|
|
6136
6167
|
if (opts.json) {
|
|
6137
6168
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -7323,6 +7354,166 @@ ${file}`);
|
|
|
7323
7354
|
import { Command as Command55 } from "commander";
|
|
7324
7355
|
import * as path41 from "path";
|
|
7325
7356
|
import chalk7 from "chalk";
|
|
7357
|
+
function resolveInferenceOptions(cfgKnowledge) {
|
|
7358
|
+
const patterns = cfgKnowledge?.domainPatterns;
|
|
7359
|
+
const blocklist = cfgKnowledge?.domainBlocklist;
|
|
7360
|
+
const hasPatterns = (patterns?.length ?? 0) > 0;
|
|
7361
|
+
const hasBlocklist = (blocklist?.length ?? 0) > 0;
|
|
7362
|
+
if (!hasPatterns && !hasBlocklist) {
|
|
7363
|
+
return void 0;
|
|
7364
|
+
}
|
|
7365
|
+
return {
|
|
7366
|
+
...hasPatterns ? { extraPatterns: patterns } : {},
|
|
7367
|
+
...hasBlocklist ? { extraBlocklist: blocklist } : {}
|
|
7368
|
+
};
|
|
7369
|
+
}
|
|
7370
|
+
function buildPipelineOptions(opts, projectDir, graphDir, inferenceOptions) {
|
|
7371
|
+
const pipelineOpts = {
|
|
7372
|
+
projectDir,
|
|
7373
|
+
fix: Boolean(opts.fix),
|
|
7374
|
+
ci: Boolean(opts.ci),
|
|
7375
|
+
...opts.domain ? { domain: opts.domain } : {},
|
|
7376
|
+
graphDir,
|
|
7377
|
+
analyzeImages: Boolean(opts.analyzeImages),
|
|
7378
|
+
...inferenceOptions ? { inferenceOptions } : {}
|
|
7379
|
+
};
|
|
7380
|
+
if (opts.imagePaths) {
|
|
7381
|
+
pipelineOpts.imagePaths = opts.imagePaths.split(",").map((p) => p.trim());
|
|
7382
|
+
}
|
|
7383
|
+
return pipelineOpts;
|
|
7384
|
+
}
|
|
7385
|
+
async function createAnalysisProvider() {
|
|
7386
|
+
try {
|
|
7387
|
+
const intelligence = await import("@harness-engineering/intelligence");
|
|
7388
|
+
const Provider = intelligence.AnthropicAnalysisProvider;
|
|
7389
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
7390
|
+
if (!apiKey) {
|
|
7391
|
+
logger.error("ANTHROPIC_API_KEY environment variable is required for --analyze-images");
|
|
7392
|
+
process.exit(1);
|
|
7393
|
+
}
|
|
7394
|
+
return new Provider({ apiKey });
|
|
7395
|
+
} catch {
|
|
7396
|
+
logger.error(
|
|
7397
|
+
"Image analysis requires @harness-engineering/intelligence with ANTHROPIC_API_KEY set."
|
|
7398
|
+
);
|
|
7399
|
+
process.exit(1);
|
|
7400
|
+
}
|
|
7401
|
+
}
|
|
7402
|
+
function printJsonResult(result) {
|
|
7403
|
+
console.log(
|
|
7404
|
+
JSON.stringify(
|
|
7405
|
+
{
|
|
7406
|
+
verdict: result.verdict,
|
|
7407
|
+
driftScore: result.driftScore,
|
|
7408
|
+
iterations: result.iterations,
|
|
7409
|
+
findings: result.findings,
|
|
7410
|
+
extraction: result.extraction,
|
|
7411
|
+
errors: result.errors,
|
|
7412
|
+
gaps: {
|
|
7413
|
+
domains: result.gaps.domains.length,
|
|
7414
|
+
totalEntries: result.gaps.totalEntries,
|
|
7415
|
+
totalExtracted: result.gaps.totalExtracted,
|
|
7416
|
+
totalGaps: result.gaps.totalGaps
|
|
7417
|
+
},
|
|
7418
|
+
remediations: result.remediations,
|
|
7419
|
+
contradictions: {
|
|
7420
|
+
count: result.contradictions.contradictions.length,
|
|
7421
|
+
sourcePairCounts: result.contradictions.sourcePairCounts
|
|
7422
|
+
},
|
|
7423
|
+
coverage: {
|
|
7424
|
+
overallScore: result.coverage.overallScore,
|
|
7425
|
+
overallGrade: result.coverage.overallGrade,
|
|
7426
|
+
domains: result.coverage.domains.length
|
|
7427
|
+
},
|
|
7428
|
+
...result.materialization ? {
|
|
7429
|
+
materialization: {
|
|
7430
|
+
created: result.materialization.created.length,
|
|
7431
|
+
skipped: result.materialization.skipped.length,
|
|
7432
|
+
files: result.materialization.created.map((d) => d.filePath)
|
|
7433
|
+
}
|
|
7434
|
+
} : {}
|
|
7435
|
+
},
|
|
7436
|
+
null,
|
|
7437
|
+
2
|
|
7438
|
+
)
|
|
7439
|
+
);
|
|
7440
|
+
}
|
|
7441
|
+
function printSummary(result) {
|
|
7442
|
+
const verdictColor = result.verdict === "pass" ? chalk7.green("PASS") : result.verdict === "warn" ? chalk7.yellow("WARN") : chalk7.red("FAIL");
|
|
7443
|
+
console.log("");
|
|
7444
|
+
console.log(`KNOWLEDGE PIPELINE -- Verdict: ${verdictColor}`);
|
|
7445
|
+
console.log("");
|
|
7446
|
+
console.log(` Drift Score: ${result.driftScore.toFixed(2)}`);
|
|
7447
|
+
console.log(
|
|
7448
|
+
` Findings: ${result.findings.new} new, ${result.findings.stale} stale, ${result.findings.drifted} drifted, ${result.findings.contradicting} contradicting`
|
|
7449
|
+
);
|
|
7450
|
+
console.log(
|
|
7451
|
+
` Extraction: ${result.extraction.codeSignals} code signals, ${result.extraction.diagrams} diagrams, ${result.extraction.linkerFacts} linker facts, ${result.extraction.businessKnowledge} business knowledge, ${result.extraction.decisions} decisions, ${result.extraction.images} images`
|
|
7452
|
+
);
|
|
7453
|
+
console.log(
|
|
7454
|
+
` Gaps: ${result.gaps.domains.length} domains \u2014 ${result.gaps.totalEntries} documented / ${result.gaps.totalExtracted} extracted / ${result.gaps.totalGaps} undocumented`
|
|
7455
|
+
);
|
|
7456
|
+
if (result.iterations > 1) {
|
|
7457
|
+
console.log(` Convergence: ${result.iterations} iterations`);
|
|
7458
|
+
}
|
|
7459
|
+
if (result.remediations.length > 0) {
|
|
7460
|
+
console.log(` Remediations: ${result.remediations.length} applied`);
|
|
7461
|
+
}
|
|
7462
|
+
}
|
|
7463
|
+
function printIngestionErrors(result) {
|
|
7464
|
+
if (result.errors.length === 0) {
|
|
7465
|
+
return;
|
|
7466
|
+
}
|
|
7467
|
+
console.warn("");
|
|
7468
|
+
console.warn(` ${result.errors.length} ingestion warning(s):`);
|
|
7469
|
+
for (const err of result.errors) {
|
|
7470
|
+
console.warn(` - ${err}`);
|
|
7471
|
+
}
|
|
7472
|
+
}
|
|
7473
|
+
function printMaterialization(result) {
|
|
7474
|
+
if (!result.materialization) {
|
|
7475
|
+
return;
|
|
7476
|
+
}
|
|
7477
|
+
const mat = result.materialization;
|
|
7478
|
+
console.log(
|
|
7479
|
+
` Materialization: ${mat.created.length} docs created, ${mat.skipped.length} skipped`
|
|
7480
|
+
);
|
|
7481
|
+
for (const doc of mat.created) {
|
|
7482
|
+
console.log(` ${chalk7.green("+")} ${doc.filePath}`);
|
|
7483
|
+
}
|
|
7484
|
+
}
|
|
7485
|
+
function printContradictions(result, opts) {
|
|
7486
|
+
if (!opts.checkContradictions && result.contradictions.contradictions.length === 0) {
|
|
7487
|
+
return;
|
|
7488
|
+
}
|
|
7489
|
+
console.log("");
|
|
7490
|
+
console.log(
|
|
7491
|
+
` Contradictions: ${result.contradictions.contradictions.length} detected across ${result.contradictions.totalChecked} knowledge nodes`
|
|
7492
|
+
);
|
|
7493
|
+
for (const c of result.contradictions.contradictions) {
|
|
7494
|
+
console.log(` ${chalk7.red("!")} ${c.description} [${c.conflictType}] (${c.severity})`);
|
|
7495
|
+
}
|
|
7496
|
+
}
|
|
7497
|
+
function printCoverage(result, opts) {
|
|
7498
|
+
if (!opts.coverage && result.coverage.domains.length === 0) {
|
|
7499
|
+
return;
|
|
7500
|
+
}
|
|
7501
|
+
console.log("");
|
|
7502
|
+
console.log(` Coverage: ${result.coverage.overallGrade} (${result.coverage.overallScore}/100)`);
|
|
7503
|
+
for (const d of result.coverage.domains) {
|
|
7504
|
+
console.log(
|
|
7505
|
+
` ${d.domain}: ${d.grade} (${d.score}/100) \u2014 ${d.knowledgeEntries} knowledge, ${d.linkedEntities}/${d.codeEntities} code linked`
|
|
7506
|
+
);
|
|
7507
|
+
}
|
|
7508
|
+
}
|
|
7509
|
+
function printHumanResult(result, opts) {
|
|
7510
|
+
printSummary(result);
|
|
7511
|
+
printIngestionErrors(result);
|
|
7512
|
+
printMaterialization(result);
|
|
7513
|
+
printContradictions(result, opts);
|
|
7514
|
+
printCoverage(result, opts);
|
|
7515
|
+
console.log("");
|
|
7516
|
+
}
|
|
7326
7517
|
function createKnowledgePipelineCommand() {
|
|
7327
7518
|
return new Command55("knowledge-pipeline").description("Run knowledge extraction, drift detection, and gap analysis").option("--fix", "Enable convergence-based auto-remediation (default: detect-only)").option("--ci", "Non-interactive mode \u2014 apply safe fixes only, report everything else").option("--domain <name>", "Limit pipeline to a specific knowledge domain").option("--drift-check", "Exit 1 if unresolved drift exists (CI gate mode)").option("--analyze-images", "Enable vision model analysis of image files").option("--image-paths <paths>", "Comma-separated image file paths for analysis").option("--coverage", "Display per-domain coverage report").option("--check-contradictions", "Display cross-source contradiction report").action(async (opts, cmd) => {
|
|
7328
7519
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -7331,7 +7522,7 @@ function createKnowledgePipelineCommand() {
|
|
|
7331
7522
|
const graphDir = path41.join(projectDir, ".harness", "graph");
|
|
7332
7523
|
const fs50 = await import("fs/promises");
|
|
7333
7524
|
await fs50.mkdir(graphDir, { recursive: true });
|
|
7334
|
-
const { GraphStore: GraphStore2, KnowledgePipelineRunner } = await import("./dist-
|
|
7525
|
+
const { GraphStore: GraphStore2, KnowledgePipelineRunner } = await import("./dist-DWBTZXR5.js");
|
|
7335
7526
|
const store = new GraphStore2();
|
|
7336
7527
|
try {
|
|
7337
7528
|
await store.load(graphDir);
|
|
@@ -7339,145 +7530,19 @@ function createKnowledgePipelineCommand() {
|
|
|
7339
7530
|
}
|
|
7340
7531
|
const cfgResult = resolveConfig();
|
|
7341
7532
|
const cfgKnowledge = cfgResult.ok ? cfgResult.value.knowledge : void 0;
|
|
7342
|
-
const inferenceOptions =
|
|
7343
|
-
|
|
7344
|
-
...(cfgKnowledge.domainBlocklist?.length ?? 0) > 0 ? { extraBlocklist: cfgKnowledge.domainBlocklist } : {}
|
|
7345
|
-
} : void 0;
|
|
7346
|
-
const pipelineOpts = {
|
|
7347
|
-
projectDir,
|
|
7348
|
-
fix: Boolean(opts.fix),
|
|
7349
|
-
ci: Boolean(opts.ci),
|
|
7350
|
-
...opts.domain ? { domain: opts.domain } : {},
|
|
7351
|
-
graphDir,
|
|
7352
|
-
analyzeImages: Boolean(opts.analyzeImages),
|
|
7353
|
-
...inferenceOptions ? { inferenceOptions } : {}
|
|
7354
|
-
};
|
|
7355
|
-
if (opts.imagePaths) {
|
|
7356
|
-
pipelineOpts.imagePaths = opts.imagePaths.split(",").map((p) => p.trim());
|
|
7357
|
-
}
|
|
7533
|
+
const inferenceOptions = resolveInferenceOptions(cfgKnowledge);
|
|
7534
|
+
const pipelineOpts = buildPipelineOptions(opts, projectDir, graphDir, inferenceOptions);
|
|
7358
7535
|
if (opts.analyzeImages) {
|
|
7359
|
-
|
|
7360
|
-
const intelligence = await import("@harness-engineering/intelligence");
|
|
7361
|
-
const Provider = intelligence.AnthropicAnalysisProvider;
|
|
7362
|
-
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
7363
|
-
if (!apiKey) {
|
|
7364
|
-
logger.error(
|
|
7365
|
-
"ANTHROPIC_API_KEY environment variable is required for --analyze-images"
|
|
7366
|
-
);
|
|
7367
|
-
process.exit(1);
|
|
7368
|
-
}
|
|
7369
|
-
pipelineOpts.analysisProvider = new Provider({ apiKey });
|
|
7370
|
-
} catch {
|
|
7371
|
-
logger.error(
|
|
7372
|
-
"Image analysis requires @harness-engineering/intelligence with ANTHROPIC_API_KEY set."
|
|
7373
|
-
);
|
|
7374
|
-
process.exit(1);
|
|
7375
|
-
}
|
|
7536
|
+
pipelineOpts.analysisProvider = await createAnalysisProvider();
|
|
7376
7537
|
}
|
|
7377
7538
|
const runner = new KnowledgePipelineRunner(store);
|
|
7378
7539
|
const result = await runner.run(
|
|
7379
7540
|
pipelineOpts
|
|
7380
7541
|
);
|
|
7381
7542
|
if (globalOpts.json) {
|
|
7382
|
-
|
|
7383
|
-
JSON.stringify(
|
|
7384
|
-
{
|
|
7385
|
-
verdict: result.verdict,
|
|
7386
|
-
driftScore: result.driftScore,
|
|
7387
|
-
iterations: result.iterations,
|
|
7388
|
-
findings: result.findings,
|
|
7389
|
-
extraction: result.extraction,
|
|
7390
|
-
errors: result.errors,
|
|
7391
|
-
gaps: {
|
|
7392
|
-
domains: result.gaps.domains.length,
|
|
7393
|
-
totalEntries: result.gaps.totalEntries,
|
|
7394
|
-
totalExtracted: result.gaps.totalExtracted,
|
|
7395
|
-
totalGaps: result.gaps.totalGaps
|
|
7396
|
-
},
|
|
7397
|
-
remediations: result.remediations,
|
|
7398
|
-
contradictions: {
|
|
7399
|
-
count: result.contradictions.contradictions.length,
|
|
7400
|
-
sourcePairCounts: result.contradictions.sourcePairCounts
|
|
7401
|
-
},
|
|
7402
|
-
coverage: {
|
|
7403
|
-
overallScore: result.coverage.overallScore,
|
|
7404
|
-
overallGrade: result.coverage.overallGrade,
|
|
7405
|
-
domains: result.coverage.domains.length
|
|
7406
|
-
},
|
|
7407
|
-
...result.materialization ? {
|
|
7408
|
-
materialization: {
|
|
7409
|
-
created: result.materialization.created.length,
|
|
7410
|
-
skipped: result.materialization.skipped.length,
|
|
7411
|
-
files: result.materialization.created.map(
|
|
7412
|
-
(d) => d.filePath
|
|
7413
|
-
)
|
|
7414
|
-
}
|
|
7415
|
-
} : {}
|
|
7416
|
-
},
|
|
7417
|
-
null,
|
|
7418
|
-
2
|
|
7419
|
-
)
|
|
7420
|
-
);
|
|
7543
|
+
printJsonResult(result);
|
|
7421
7544
|
} else {
|
|
7422
|
-
|
|
7423
|
-
console.log("");
|
|
7424
|
-
console.log(`KNOWLEDGE PIPELINE -- Verdict: ${verdictColor}`);
|
|
7425
|
-
console.log("");
|
|
7426
|
-
console.log(` Drift Score: ${result.driftScore.toFixed(2)}`);
|
|
7427
|
-
console.log(
|
|
7428
|
-
` Findings: ${result.findings.new} new, ${result.findings.stale} stale, ${result.findings.drifted} drifted, ${result.findings.contradicting} contradicting`
|
|
7429
|
-
);
|
|
7430
|
-
console.log(
|
|
7431
|
-
` Extraction: ${result.extraction.codeSignals} code signals, ${result.extraction.diagrams} diagrams, ${result.extraction.linkerFacts} linker facts, ${result.extraction.businessKnowledge} business knowledge, ${result.extraction.decisions} decisions, ${result.extraction.images} images`
|
|
7432
|
-
);
|
|
7433
|
-
console.log(
|
|
7434
|
-
` Gaps: ${result.gaps.domains.length} domains \u2014 ${result.gaps.totalEntries} documented / ${result.gaps.totalExtracted} extracted / ${result.gaps.totalGaps} undocumented`
|
|
7435
|
-
);
|
|
7436
|
-
if (result.iterations > 1) {
|
|
7437
|
-
console.log(` Convergence: ${result.iterations} iterations`);
|
|
7438
|
-
}
|
|
7439
|
-
if (result.remediations.length > 0) {
|
|
7440
|
-
console.log(` Remediations: ${result.remediations.length} applied`);
|
|
7441
|
-
}
|
|
7442
|
-
if (result.errors.length > 0) {
|
|
7443
|
-
console.warn("");
|
|
7444
|
-
console.warn(` ${result.errors.length} ingestion warning(s):`);
|
|
7445
|
-
for (const err of result.errors) {
|
|
7446
|
-
console.warn(` - ${err}`);
|
|
7447
|
-
}
|
|
7448
|
-
}
|
|
7449
|
-
if (result.materialization) {
|
|
7450
|
-
const mat = result.materialization;
|
|
7451
|
-
console.log(
|
|
7452
|
-
` Materialization: ${mat.created.length} docs created, ${mat.skipped.length} skipped`
|
|
7453
|
-
);
|
|
7454
|
-
for (const doc of mat.created) {
|
|
7455
|
-
console.log(` ${chalk7.green("+")} ${doc.filePath}`);
|
|
7456
|
-
}
|
|
7457
|
-
}
|
|
7458
|
-
if (opts.checkContradictions || result.contradictions.contradictions.length > 0) {
|
|
7459
|
-
console.log("");
|
|
7460
|
-
console.log(
|
|
7461
|
-
` Contradictions: ${result.contradictions.contradictions.length} detected across ${result.contradictions.totalChecked} knowledge nodes`
|
|
7462
|
-
);
|
|
7463
|
-
for (const c of result.contradictions.contradictions) {
|
|
7464
|
-
console.log(
|
|
7465
|
-
` ${chalk7.red("!")} ${c.description} [${c.conflictType}] (${c.severity})`
|
|
7466
|
-
);
|
|
7467
|
-
}
|
|
7468
|
-
}
|
|
7469
|
-
if (opts.coverage || result.coverage.domains.length > 0) {
|
|
7470
|
-
console.log("");
|
|
7471
|
-
console.log(
|
|
7472
|
-
` Coverage: ${result.coverage.overallGrade} (${result.coverage.overallScore}/100)`
|
|
7473
|
-
);
|
|
7474
|
-
for (const d of result.coverage.domains) {
|
|
7475
|
-
console.log(
|
|
7476
|
-
` ${d.domain}: ${d.grade} (${d.score}/100) \u2014 ${d.knowledgeEntries} knowledge, ${d.linkedEntities}/${d.codeEntities} code linked`
|
|
7477
|
-
);
|
|
7478
|
-
}
|
|
7479
|
-
}
|
|
7480
|
-
console.log("");
|
|
7545
|
+
printHumanResult(result, opts);
|
|
7481
7546
|
}
|
|
7482
7547
|
const unresolvedDrift = result.findings.drifted + result.findings.stale + result.findings.contradicting;
|
|
7483
7548
|
if (opts.driftCheck && unresolvedDrift > 0) {
|
|
@@ -8208,7 +8273,7 @@ function createMcpCommand() {
|
|
|
8208
8273
|
parseBudget
|
|
8209
8274
|
).action(async (opts) => {
|
|
8210
8275
|
const [{ startServer: startServer2, getToolDefinitions: getToolDefinitions2 }, { selectTier }] = await Promise.all([
|
|
8211
|
-
import("./mcp-
|
|
8276
|
+
import("./mcp-5V4LPMB3.js"),
|
|
8212
8277
|
import("./tool-tiers-OKK5FE57.js")
|
|
8213
8278
|
]);
|
|
8214
8279
|
if (opts.tools && opts.tools.length > 0) {
|
|
@@ -9283,7 +9348,7 @@ function registerBenchCommand(perf) {
|
|
|
9283
9348
|
perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob2, _opts, cmd) => {
|
|
9284
9349
|
const globalOpts = cmd.optsWithGlobals();
|
|
9285
9350
|
const cwd = process.cwd();
|
|
9286
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
9351
|
+
const { BenchmarkRunner } = await import("./dist-MCTEX5QH.js");
|
|
9287
9352
|
const runner = new BenchmarkRunner();
|
|
9288
9353
|
const benchFiles = runner.discover(cwd, glob2);
|
|
9289
9354
|
if (benchFiles.length === 0) {
|
|
@@ -9347,7 +9412,7 @@ async function runBaselinesShow(globalOpts) {
|
|
|
9347
9412
|
}
|
|
9348
9413
|
async function runBaselinesUpdate(globalOpts) {
|
|
9349
9414
|
const cwd = process.cwd();
|
|
9350
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
9415
|
+
const { BenchmarkRunner } = await import("./dist-MCTEX5QH.js");
|
|
9351
9416
|
const runner = new BenchmarkRunner();
|
|
9352
9417
|
const manager = new BaselineManager(cwd);
|
|
9353
9418
|
logger.info("Running benchmarks to update baselines...");
|
|
@@ -9388,7 +9453,7 @@ function registerReportCommand(perf) {
|
|
|
9388
9453
|
perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
|
|
9389
9454
|
const globalOpts = cmd.optsWithGlobals();
|
|
9390
9455
|
const cwd = process.cwd();
|
|
9391
|
-
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-
|
|
9456
|
+
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-MCTEX5QH.js");
|
|
9392
9457
|
const analyzer = new EntropyAnalyzer2({
|
|
9393
9458
|
rootDir: path50.resolve(cwd),
|
|
9394
9459
|
analyze: { complexity: true, coupling: true }
|
|
@@ -9691,79 +9756,560 @@ function createPredictCommand() {
|
|
|
9691
9756
|
return command;
|
|
9692
9757
|
}
|
|
9693
9758
|
|
|
9694
|
-
// src/commands/
|
|
9759
|
+
// src/commands/pre-merge-brief.ts
|
|
9760
|
+
init_dist2();
|
|
9761
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
9762
|
+
import { readFileSync as readFileSync18 } from "fs";
|
|
9763
|
+
import { join as join40 } from "path";
|
|
9764
|
+
import { Command as Command77 } from "commander";
|
|
9765
|
+
import { gatherSignals } from "@harness-engineering/signals";
|
|
9766
|
+
|
|
9767
|
+
// src/commands/review-ci.ts
|
|
9695
9768
|
init_dist3();
|
|
9696
|
-
import {
|
|
9697
|
-
import {
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
|
|
9704
|
-
|
|
9705
|
-
|
|
9706
|
-
|
|
9707
|
-
|
|
9708
|
-
|
|
9709
|
-
|
|
9710
|
-
|
|
9711
|
-
|
|
9712
|
-
|
|
9713
|
-
}
|
|
9714
|
-
|
|
9715
|
-
|
|
9716
|
-
|
|
9717
|
-
|
|
9718
|
-
|
|
9719
|
-
|
|
9720
|
-
|
|
9721
|
-
|
|
9769
|
+
import { execFileSync as execFileSync6 } from "child_process";
|
|
9770
|
+
import { writeFileSync as writeFileSync18 } from "fs";
|
|
9771
|
+
import { Command as Command76, Option as Option2 } from "commander";
|
|
9772
|
+
|
|
9773
|
+
// src/commands/review-ci-local-adapter.ts
|
|
9774
|
+
import { z } from "zod";
|
|
9775
|
+
import { OpenAICompatibleAnalysisProvider } from "@harness-engineering/intelligence";
|
|
9776
|
+
var FindingSchema = z.object({
|
|
9777
|
+
id: z.string(),
|
|
9778
|
+
file: z.string(),
|
|
9779
|
+
lineRange: z.tuple([z.number(), z.number()]),
|
|
9780
|
+
domain: z.enum(["compliance", "bug", "security", "architecture", "learnings"]),
|
|
9781
|
+
severity: z.enum(["critical", "important", "suggestion"]),
|
|
9782
|
+
title: z.string(),
|
|
9783
|
+
rationale: z.string(),
|
|
9784
|
+
suggestion: z.string().optional(),
|
|
9785
|
+
evidence: z.array(z.string())
|
|
9786
|
+
});
|
|
9787
|
+
var LocalVerdictSchema = z.object({
|
|
9788
|
+
assessment: z.enum(["approve", "comment", "request-changes"]),
|
|
9789
|
+
findings: z.array(FindingSchema)
|
|
9790
|
+
});
|
|
9791
|
+
var MAX_SURFACED_ERROR_LEN = 200;
|
|
9792
|
+
function sanitizeProviderError(err) {
|
|
9793
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
9794
|
+
const redacted = raw.replace(/https?:\/\/\S+/gi, "[endpoint]").replace(/\b(bearer|authorization|api[-_]?key|token)\b\s*[:=]?\s*\S+/gi, "[redacted]").replace(/\s+/g, " ").trim();
|
|
9795
|
+
const capped = redacted.length > MAX_SURFACED_ERROR_LEN ? redacted.slice(0, MAX_SURFACED_ERROR_LEN - 1) + "\u2026" : redacted;
|
|
9796
|
+
return `local runner provider error: ${capped}`;
|
|
9722
9797
|
}
|
|
9723
|
-
|
|
9724
|
-
|
|
9725
|
-
|
|
9726
|
-
|
|
9727
|
-
|
|
9728
|
-
|
|
9798
|
+
function createLocalInvoke() {
|
|
9799
|
+
return async ({ endpoint, model, instruction, diff: diff2 }) => {
|
|
9800
|
+
if (!/^https?:\/\//i.test(endpoint)) {
|
|
9801
|
+
throw new Error(
|
|
9802
|
+
`HARNESS_LOCAL_ENDPOINT must be an http(s) URL (got '${endpoint}'); e.g. http://localhost:1234/v1`
|
|
9803
|
+
);
|
|
9804
|
+
}
|
|
9805
|
+
const provider = new OpenAICompatibleAnalysisProvider({
|
|
9806
|
+
apiKey: process.env.HARNESS_LOCAL_API_KEY ?? "local",
|
|
9807
|
+
baseUrl: endpoint,
|
|
9808
|
+
defaultModel: model
|
|
9809
|
+
});
|
|
9810
|
+
try {
|
|
9811
|
+
const { result } = await provider.analyze({
|
|
9812
|
+
prompt: `${instruction}
|
|
9813
|
+
|
|
9814
|
+
---
|
|
9815
|
+
DIFF UNDER REVIEW:
|
|
9816
|
+
${diff2}`,
|
|
9817
|
+
responseSchema: LocalVerdictSchema,
|
|
9818
|
+
model
|
|
9819
|
+
});
|
|
9820
|
+
return JSON.stringify(result);
|
|
9821
|
+
} catch (err) {
|
|
9822
|
+
throw new Error(sanitizeProviderError(err), { cause: err });
|
|
9823
|
+
}
|
|
9729
9824
|
};
|
|
9730
|
-
return updateProposal(projectRoot(), id, { status: "rejected", decision });
|
|
9731
|
-
}
|
|
9732
|
-
var ALLOWED_STATUSES = [
|
|
9733
|
-
"open",
|
|
9734
|
-
"gate-running",
|
|
9735
|
-
"gate-failed",
|
|
9736
|
-
"approved",
|
|
9737
|
-
"rejected",
|
|
9738
|
-
"all"
|
|
9739
|
-
];
|
|
9740
|
-
function fail(message) {
|
|
9741
|
-
console.error(message);
|
|
9742
|
-
process.exitCode = 1;
|
|
9743
|
-
}
|
|
9744
|
-
async function actListCommand(opts) {
|
|
9745
|
-
const raw = opts.status ?? "open";
|
|
9746
|
-
if (!ALLOWED_STATUSES.includes(raw)) {
|
|
9747
|
-
fail(`Error: unknown status "${raw}"`);
|
|
9748
|
-
return;
|
|
9749
|
-
}
|
|
9750
|
-
const proposals = await runProposalsList(raw);
|
|
9751
|
-
console.log(JSON.stringify(proposals, null, 2));
|
|
9752
9825
|
}
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9826
|
+
|
|
9827
|
+
// src/commands/review-ci.ts
|
|
9828
|
+
var KNOWN_RUNNERS = Object.keys(RUNNER_PRESETS);
|
|
9829
|
+
var BLOCK_ON_LEVELS = [...CI_ASSESSMENTS, "none"];
|
|
9830
|
+
function assertKnownRunner(runner) {
|
|
9831
|
+
if (runner === void 0) return;
|
|
9832
|
+
if (!KNOWN_RUNNERS.includes(runner)) {
|
|
9833
|
+
throw new Error(`unknown runner '${runner}' (expected: ${KNOWN_RUNNERS.join("|")})`);
|
|
9758
9834
|
}
|
|
9759
|
-
console.log(JSON.stringify(proposal, null, 2));
|
|
9760
9835
|
}
|
|
9761
|
-
|
|
9836
|
+
var defaultRunGit = (args) => execFileSync6("git", args, { encoding: "utf-8" }).toString().trim();
|
|
9837
|
+
function resolveDiffRange(opts) {
|
|
9838
|
+
if (opts.range) return opts.range;
|
|
9839
|
+
const runGit = opts.runGit ?? defaultRunGit;
|
|
9840
|
+
let base = "main";
|
|
9762
9841
|
try {
|
|
9763
|
-
const
|
|
9764
|
-
|
|
9765
|
-
|
|
9766
|
-
|
|
9842
|
+
const ref = runGit(["symbolic-ref", "refs/remotes/origin/HEAD"]);
|
|
9843
|
+
const m = ref.match(/origin\/(.+)$/);
|
|
9844
|
+
if (m?.[1]) base = m[1];
|
|
9845
|
+
} catch {
|
|
9846
|
+
}
|
|
9847
|
+
return `origin/${base}...HEAD`;
|
|
9848
|
+
}
|
|
9849
|
+
function splitDiffByFile(rawDiff) {
|
|
9850
|
+
const sections = /* @__PURE__ */ new Map();
|
|
9851
|
+
const headerRe = /^diff --git a\/(.+?) b\/(.+?)$/;
|
|
9852
|
+
let currentPath = null;
|
|
9853
|
+
let buffer = [];
|
|
9854
|
+
const flush = () => {
|
|
9855
|
+
if (currentPath !== null) sections.set(currentPath, buffer.join("\n"));
|
|
9856
|
+
};
|
|
9857
|
+
for (const line of rawDiff.split("\n")) {
|
|
9858
|
+
const m = line.match(headerRe);
|
|
9859
|
+
if (m?.[2]) {
|
|
9860
|
+
flush();
|
|
9861
|
+
currentPath = m[2];
|
|
9862
|
+
buffer = [line];
|
|
9863
|
+
} else if (currentPath !== null) {
|
|
9864
|
+
buffer.push(line);
|
|
9865
|
+
}
|
|
9866
|
+
}
|
|
9867
|
+
flush();
|
|
9868
|
+
return sections;
|
|
9869
|
+
}
|
|
9870
|
+
function buildDiffInfo(rawDiff) {
|
|
9871
|
+
const parsed = parseDiff(rawDiff);
|
|
9872
|
+
if (!parsed.ok) throw new Error(`Failed to parse diff: ${parsed.error.message}`);
|
|
9873
|
+
const files = parsed.value.files;
|
|
9874
|
+
const perFile = splitDiffByFile(rawDiff);
|
|
9875
|
+
return {
|
|
9876
|
+
changedFiles: files.map((f) => f.path),
|
|
9877
|
+
newFiles: files.filter((f) => f.status === "added").map((f) => f.path),
|
|
9878
|
+
deletedFiles: files.filter((f) => f.status === "deleted").map((f) => f.path),
|
|
9879
|
+
totalDiffLines: rawDiff ? rawDiff.split("\n").length : 0,
|
|
9880
|
+
// On a path-key miss, fall back to '' (the file contributes no per-file diff)
|
|
9881
|
+
// rather than the ENTIRE raw diff — substituting the whole diff would duplicate
|
|
9882
|
+
// every file's content into one section, inflating the STDIN payload to the LLM
|
|
9883
|
+
// (and risking core's execMaxStdoutBytes). With splitDiffByFile aligned to core's
|
|
9884
|
+
// path extraction, ordinary paths never miss; this is the safe degenerate case.
|
|
9885
|
+
fileDiffs: new Map(files.map((f) => [f.path, perFile.get(f.path) ?? ""]))
|
|
9886
|
+
};
|
|
9887
|
+
}
|
|
9888
|
+
function defaultResolveRaw(range, _cwd, runGit) {
|
|
9889
|
+
return runGit(["diff", range]);
|
|
9890
|
+
}
|
|
9891
|
+
function buildCallOpts(opts, cwd, diff2) {
|
|
9892
|
+
const runner = opts.runner;
|
|
9893
|
+
return {
|
|
9894
|
+
projectRoot: cwd,
|
|
9895
|
+
diff: diff2,
|
|
9896
|
+
...runner ? { runner } : {},
|
|
9897
|
+
...opts.blockOn ? { blockOn: opts.blockOn } : {},
|
|
9898
|
+
...runner === "local" ? { localInvoke: opts.localInvoke ?? createLocalInvoke() } : {}
|
|
9899
|
+
};
|
|
9900
|
+
}
|
|
9901
|
+
async function runReviewCi(opts) {
|
|
9902
|
+
assertKnownRunner(opts.runner);
|
|
9903
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
9904
|
+
const runGit = opts.runGit ?? defaultRunGit;
|
|
9905
|
+
const range = resolveDiffRange({
|
|
9906
|
+
...opts.diffRange ? { range: opts.diffRange } : {},
|
|
9907
|
+
cwd,
|
|
9908
|
+
runGit
|
|
9909
|
+
});
|
|
9910
|
+
const rawDiff = (opts.resolveRaw ?? defaultResolveRaw)(range, cwd, runGit);
|
|
9911
|
+
const diff2 = buildDiffInfo(rawDiff);
|
|
9912
|
+
const callOpts = buildCallOpts(opts, cwd, diff2);
|
|
9913
|
+
return (opts.runCiReviewImpl ?? runCiReview)(callOpts);
|
|
9914
|
+
}
|
|
9915
|
+
function findingLine(f) {
|
|
9916
|
+
const loc = f.lineRange ? `${f.file}:${f.lineRange[0]}` : f.file;
|
|
9917
|
+
return `- \`${f.severity}\` **${loc}** \u2014 ${f.title}`;
|
|
9918
|
+
}
|
|
9919
|
+
function buildReviewBody(verdict) {
|
|
9920
|
+
const findings = verdict.findings ?? [];
|
|
9921
|
+
const blocking = verdict.blockingFindings ?? [];
|
|
9922
|
+
const icon = verdict.assessment === "approve" ? "\u2705" : verdict.assessment === "request-changes" ? "\u{1F6D1}" : "\u{1F4AC}";
|
|
9923
|
+
const out = [
|
|
9924
|
+
`## ${icon} harness review-ci \u2014 ${verdict.assessment}`,
|
|
9925
|
+
"",
|
|
9926
|
+
`**Runner:** \`${verdict.runner}\` \u2022 **Findings:** ${findings.length} (blocking: ${blocking.length})`
|
|
9927
|
+
];
|
|
9928
|
+
if (verdict.skipped) out.push("", `> \u26A0\uFE0F ${verdict.skipReason ?? "A review tier was skipped."}`);
|
|
9929
|
+
if (blocking.length) out.push("", "### Blocking", ...blocking.map(findingLine));
|
|
9930
|
+
const nonBlocking = findings.filter((f) => !blocking.some((b) => b.id === f.id));
|
|
9931
|
+
if (nonBlocking.length) out.push("", "### Other findings", ...nonBlocking.map(findingLine));
|
|
9932
|
+
if (!findings.length) out.push("", "No findings. \u{1F389}");
|
|
9933
|
+
out.push("", "<sub>Posted by `harness review-ci`. The CI exit code is authoritative.</sub>");
|
|
9934
|
+
return out.join("\n");
|
|
9935
|
+
}
|
|
9936
|
+
var defaultPostReview = (verdict) => {
|
|
9937
|
+
execFileSync6("gh", ["pr", "comment", "--body-file", "-"], {
|
|
9938
|
+
input: buildReviewBody(verdict),
|
|
9939
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
9940
|
+
encoding: "utf-8"
|
|
9941
|
+
});
|
|
9942
|
+
};
|
|
9943
|
+
function emitReviewCi(result, opts, writeFile2 = (p, d) => writeFileSync18(p, d), log = (m) => process.stdout.write(m + "\n"), postReview = defaultPostReview) {
|
|
9944
|
+
const serialized = JSON.stringify(result.verdict, null, 2);
|
|
9945
|
+
const jsonToStdout = opts.jsonPath === true;
|
|
9946
|
+
if (!jsonToStdout) log(result.terminalOutput);
|
|
9947
|
+
if (typeof opts.jsonPath === "string") writeFile2(opts.jsonPath, serialized);
|
|
9948
|
+
else if (jsonToStdout) log(serialized);
|
|
9949
|
+
if (opts.comment) {
|
|
9950
|
+
try {
|
|
9951
|
+
postReview(result.verdict);
|
|
9952
|
+
} catch (err) {
|
|
9953
|
+
logger.warn(
|
|
9954
|
+
`review-ci: failed to post PR comment (${err instanceof Error ? err.message : String(err)}). The verdict above is authoritative; the exit code still reflects the gate.`
|
|
9955
|
+
);
|
|
9956
|
+
}
|
|
9957
|
+
}
|
|
9958
|
+
}
|
|
9959
|
+
function createReviewCiCommand() {
|
|
9960
|
+
return new Command76("review-ci").description("Run the tiered code-review gate (floor + optional LLM runner) for CI").addOption(
|
|
9961
|
+
new Option2("--runner <runner>", `${KNOWN_RUNNERS.join(" | ")} (omit = floor-only)`).choices(
|
|
9962
|
+
KNOWN_RUNNERS
|
|
9963
|
+
)
|
|
9964
|
+
).addOption(
|
|
9965
|
+
new Option2("--block-on <level>", BLOCK_ON_LEVELS.join(" | ")).choices(BLOCK_ON_LEVELS).default("request-changes")
|
|
9966
|
+
).option("--diff <range>", "git range (default: origin/<base>...HEAD)").option("--comment", "post the verdict as a comment on the current branch's PR via gh").option(
|
|
9967
|
+
"--out <path>",
|
|
9968
|
+
"write the verdict JSON artifact to a file (use the global --json to stream it to stdout instead)"
|
|
9969
|
+
).action(async (opts, cmd) => {
|
|
9970
|
+
const result = await runReviewCi({
|
|
9971
|
+
runner: opts.runner,
|
|
9972
|
+
blockOn: opts.blockOn,
|
|
9973
|
+
diffRange: opts.diff
|
|
9974
|
+
});
|
|
9975
|
+
const streamJson = cmd.optsWithGlobals().json === true;
|
|
9976
|
+
emitReviewCi(result, {
|
|
9977
|
+
jsonPath: typeof opts.out === "string" ? opts.out : streamJson ? true : void 0,
|
|
9978
|
+
comment: opts.comment
|
|
9979
|
+
});
|
|
9980
|
+
process.exit(result.exitCode);
|
|
9981
|
+
});
|
|
9982
|
+
}
|
|
9983
|
+
|
|
9984
|
+
// src/commands/pre-merge-brief.ts
|
|
9985
|
+
var BRIEF_MARKER = "<!-- harness:pre-merge-brief -->";
|
|
9986
|
+
var UNAVAILABLE = "> _unavailable / not configured._";
|
|
9987
|
+
function renderDiffSummary(diff2) {
|
|
9988
|
+
const out = ["## Diff summary", ""];
|
|
9989
|
+
if (!diff2) {
|
|
9990
|
+
out.push(UNAVAILABLE);
|
|
9991
|
+
return out;
|
|
9992
|
+
}
|
|
9993
|
+
out.push(
|
|
9994
|
+
`**Files changed:** ${diff2.changedFiles.length} (new: ${diff2.newFiles.length}, deleted: ${diff2.deletedFiles.length}) \u2022 **Diff lines:** ${diff2.totalDiffLines}`
|
|
9995
|
+
);
|
|
9996
|
+
return out;
|
|
9997
|
+
}
|
|
9998
|
+
function findingLine2(f) {
|
|
9999
|
+
const loc = f.lineRange ? `${f.file}:${f.lineRange[0]}` : f.file;
|
|
10000
|
+
return `- \`${f.severity}\` **${loc}** \u2014 ${f.title}`;
|
|
10001
|
+
}
|
|
10002
|
+
function renderPopulatedVerdict(verdict) {
|
|
10003
|
+
const findings = verdict.findings ?? [];
|
|
10004
|
+
const blocking = verdict.blockingFindings ?? [];
|
|
10005
|
+
const out = [
|
|
10006
|
+
`**Assessment:** \`${verdict.assessment}\` \u2022 **Runner:** \`${verdict.runner}\` \u2022 **Findings:** ${findings.length} (blocking: ${blocking.length})`
|
|
10007
|
+
];
|
|
10008
|
+
if (verdict.skipped) {
|
|
10009
|
+
out.push("", `> \u26A0\uFE0F ${verdict.skipReason ?? "A review tier was skipped."}`);
|
|
10010
|
+
}
|
|
10011
|
+
if (blocking.length) out.push("", "### Blocking", ...blocking.map(findingLine2));
|
|
10012
|
+
const nonBlocking = findings.filter((f) => !blocking.some((b) => b.id === f.id));
|
|
10013
|
+
if (nonBlocking.length) out.push("", "### Other findings", ...nonBlocking.map(findingLine2));
|
|
10014
|
+
return out;
|
|
10015
|
+
}
|
|
10016
|
+
function renderReviewVerdict(verdict) {
|
|
10017
|
+
if (!verdict) return ["## Review verdict", "", UNAVAILABLE];
|
|
10018
|
+
return ["## Review verdict", "", ...renderPopulatedVerdict(verdict)];
|
|
10019
|
+
}
|
|
10020
|
+
function signalLine(s) {
|
|
10021
|
+
const value = s.value === null ? "\u2014" : `${s.value}${s.unit ?? ""}`;
|
|
10022
|
+
return `- \`${s.status}\` **${s.label}** \u2014 ${value}`;
|
|
10023
|
+
}
|
|
10024
|
+
function renderSignalStatus(signals) {
|
|
10025
|
+
const out = ["## Signal status", ""];
|
|
10026
|
+
if (!signals || signals.length === 0) {
|
|
10027
|
+
out.push(UNAVAILABLE);
|
|
10028
|
+
return out;
|
|
10029
|
+
}
|
|
10030
|
+
out.push(...signals.map(signalLine));
|
|
10031
|
+
return out;
|
|
10032
|
+
}
|
|
10033
|
+
function renderOutcomeEval(outcome) {
|
|
10034
|
+
const out = ["## Outcome evaluation", ""];
|
|
10035
|
+
if (!outcome) {
|
|
10036
|
+
out.push("> _not yet evaluated._");
|
|
10037
|
+
return out;
|
|
10038
|
+
}
|
|
10039
|
+
out.push(
|
|
10040
|
+
`**Verdict:** \`${outcome.verdict}\` \u2022 **Confidence:** \`${outcome.confidence}\` \u2022 **Authority:** \`${outcome.authority}\``,
|
|
10041
|
+
"",
|
|
10042
|
+
outcome.rationale
|
|
10043
|
+
);
|
|
10044
|
+
return out;
|
|
10045
|
+
}
|
|
10046
|
+
function blockingBullets(inputs) {
|
|
10047
|
+
return (inputs.review?.blockingFindings ?? []).map(
|
|
10048
|
+
(f) => `- \u{1F6D1} ${findingLine2(f).replace(/^- /, "")}`
|
|
10049
|
+
);
|
|
10050
|
+
}
|
|
10051
|
+
function signalBullets(inputs) {
|
|
10052
|
+
return (inputs.signals ?? []).filter((s) => s.status === "warn" || s.status === "alert").map((s) => `- \u{1F4CA} ${signalLine(s).replace(/^- /, "")}`);
|
|
10053
|
+
}
|
|
10054
|
+
function unmetBullets(inputs) {
|
|
10055
|
+
const unmet = inputs.outcome?.verdict === "NOT_SATISFIED" ? inputs.outcome.unmetCriteria ?? [] : [];
|
|
10056
|
+
return unmet.map((c) => `- \u{1F3AF} ${c}`);
|
|
10057
|
+
}
|
|
10058
|
+
function collectWorthYourEyesBullets(inputs) {
|
|
10059
|
+
return [...blockingBullets(inputs), ...signalBullets(inputs), ...unmetBullets(inputs)];
|
|
10060
|
+
}
|
|
10061
|
+
function deriveWorthYourEyes(inputs) {
|
|
10062
|
+
const bullets = collectWorthYourEyesBullets(inputs);
|
|
10063
|
+
if (bullets.length === 0) {
|
|
10064
|
+
return [
|
|
10065
|
+
"## \u{1F440} Worth your eyes",
|
|
10066
|
+
"",
|
|
10067
|
+
"_Nothing flagged \u2014 no blocking findings, no warn/alert signals, no unmet criteria._"
|
|
10068
|
+
];
|
|
10069
|
+
}
|
|
10070
|
+
return ["## \u{1F440} Worth your eyes", "", ...bullets];
|
|
10071
|
+
}
|
|
10072
|
+
function buildBriefBody(inputs) {
|
|
10073
|
+
const lines = [
|
|
10074
|
+
BRIEF_MARKER,
|
|
10075
|
+
"# \u{1F9ED} Pre-merge brief",
|
|
10076
|
+
"",
|
|
10077
|
+
...renderDiffSummary(inputs.diff),
|
|
10078
|
+
"",
|
|
10079
|
+
...renderReviewVerdict(inputs.review),
|
|
10080
|
+
"",
|
|
10081
|
+
...renderSignalStatus(inputs.signals),
|
|
10082
|
+
"",
|
|
10083
|
+
...renderOutcomeEval(inputs.outcome),
|
|
10084
|
+
"",
|
|
10085
|
+
...deriveWorthYourEyes(inputs)
|
|
10086
|
+
];
|
|
10087
|
+
return lines.join("\n");
|
|
10088
|
+
}
|
|
10089
|
+
function upsertComment(comments, body, patch, post) {
|
|
10090
|
+
const marked = comments.find((c) => c.body.trimStart().startsWith(BRIEF_MARKER));
|
|
10091
|
+
if (marked) {
|
|
10092
|
+
patch(marked.id, body);
|
|
10093
|
+
} else {
|
|
10094
|
+
post(body);
|
|
10095
|
+
}
|
|
10096
|
+
}
|
|
10097
|
+
var defaultPostBrief = (body) => {
|
|
10098
|
+
const raw = execFileSync7("gh", ["pr", "view", "--json", "comments"], {
|
|
10099
|
+
encoding: "utf-8"
|
|
10100
|
+
}).toString();
|
|
10101
|
+
const parsed = JSON.parse(raw);
|
|
10102
|
+
const comments = (parsed.comments ?? []).filter(
|
|
10103
|
+
(c) => typeof c.id === "number" && typeof c.body === "string"
|
|
10104
|
+
).map((c) => ({ id: c.id, body: c.body }));
|
|
10105
|
+
upsertComment(
|
|
10106
|
+
comments,
|
|
10107
|
+
body,
|
|
10108
|
+
(id, patchBody) => {
|
|
10109
|
+
execFileSync7(
|
|
10110
|
+
"gh",
|
|
10111
|
+
["api", "-X", "PATCH", `/repos/{owner}/{repo}/issues/comments/${id}`, "-F", "body=@-"],
|
|
10112
|
+
{ input: patchBody, stdio: ["pipe", "pipe", "pipe"], encoding: "utf-8" }
|
|
10113
|
+
);
|
|
10114
|
+
},
|
|
10115
|
+
(postBody) => {
|
|
10116
|
+
execFileSync7("gh", ["pr", "comment", "--body-file", "-"], {
|
|
10117
|
+
input: postBody,
|
|
10118
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
10119
|
+
encoding: "utf-8"
|
|
10120
|
+
});
|
|
10121
|
+
}
|
|
10122
|
+
);
|
|
10123
|
+
};
|
|
10124
|
+
var defaultReadFile = (path80) => readFileSync18(path80, "utf-8");
|
|
10125
|
+
function readReview(path80, readFile4 = defaultReadFile) {
|
|
10126
|
+
if (!path80) return void 0;
|
|
10127
|
+
try {
|
|
10128
|
+
const parsed = JSON.parse(readFile4(path80));
|
|
10129
|
+
return parsed?.verdict && typeof parsed.verdict === "object" ? parsed.verdict : void 0;
|
|
10130
|
+
} catch {
|
|
10131
|
+
return void 0;
|
|
10132
|
+
}
|
|
10133
|
+
}
|
|
10134
|
+
async function gatherSignalsSafe(projectPath, gather = gatherSignals) {
|
|
10135
|
+
try {
|
|
10136
|
+
const result = await gather(projectPath);
|
|
10137
|
+
return result.signals;
|
|
10138
|
+
} catch {
|
|
10139
|
+
return [];
|
|
10140
|
+
}
|
|
10141
|
+
}
|
|
10142
|
+
var GRAPH_DIR = ".harness/graph";
|
|
10143
|
+
async function loadOutcomeStore(projectPath) {
|
|
10144
|
+
try {
|
|
10145
|
+
const store = new GraphStore();
|
|
10146
|
+
const loaded = await store.load(join40(projectPath, GRAPH_DIR));
|
|
10147
|
+
return loaded ? store : void 0;
|
|
10148
|
+
} catch {
|
|
10149
|
+
return void 0;
|
|
10150
|
+
}
|
|
10151
|
+
}
|
|
10152
|
+
function findOutcomeVerdict(store, headSha) {
|
|
10153
|
+
if (!store || !headSha) return void 0;
|
|
10154
|
+
try {
|
|
10155
|
+
const nodes = store.findNodes({ type: "execution_outcome" });
|
|
10156
|
+
const match = nodes.find((n) => {
|
|
10157
|
+
const m2 = n.metadata ?? {};
|
|
10158
|
+
return m2.commit === headSha || m2.headSha === headSha;
|
|
10159
|
+
});
|
|
10160
|
+
if (!match) return void 0;
|
|
10161
|
+
const m = match.metadata;
|
|
10162
|
+
return {
|
|
10163
|
+
verdict: m.verdict,
|
|
10164
|
+
confidence: m.confidence ?? "low",
|
|
10165
|
+
rationale: m.rationale ?? "",
|
|
10166
|
+
judgedAgainst: m.judgedAgainst ?? "success-criteria",
|
|
10167
|
+
unmetCriteria: Array.isArray(m.unmetCriteria) ? m.unmetCriteria : [],
|
|
10168
|
+
authority: m.authority ?? "advisory"
|
|
10169
|
+
};
|
|
10170
|
+
} catch {
|
|
10171
|
+
return void 0;
|
|
10172
|
+
}
|
|
10173
|
+
}
|
|
10174
|
+
function defaultResolveRaw2(range, _cwd, runGit) {
|
|
10175
|
+
return runGit(["diff", range]);
|
|
10176
|
+
}
|
|
10177
|
+
async function runPreMergeBrief(opts) {
|
|
10178
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
10179
|
+
const runGit = opts.runGit ?? ((args) => execFileSync7("git", args, { encoding: "utf-8" }).toString().trim());
|
|
10180
|
+
const range = resolveDiffRange({
|
|
10181
|
+
...opts.diffRange ? { range: opts.diffRange } : {},
|
|
10182
|
+
cwd,
|
|
10183
|
+
runGit
|
|
10184
|
+
});
|
|
10185
|
+
let diff2;
|
|
10186
|
+
try {
|
|
10187
|
+
const rawDiff = (opts.resolveRaw ?? defaultResolveRaw2)(range, cwd, runGit);
|
|
10188
|
+
diff2 = rawDiff.trim() ? buildDiffInfo(rawDiff) : void 0;
|
|
10189
|
+
} catch {
|
|
10190
|
+
diff2 = void 0;
|
|
10191
|
+
}
|
|
10192
|
+
const review = readReview(opts.from, opts.readFile);
|
|
10193
|
+
const signals = await gatherSignalsSafe(cwd, opts.gather);
|
|
10194
|
+
const outcome = findOutcomeVerdict(opts.store, opts.headSha);
|
|
10195
|
+
const body = buildBriefBody({ diff: diff2, review, signals, outcome });
|
|
10196
|
+
const log = opts.log ?? ((m) => process.stdout.write(m + "\n"));
|
|
10197
|
+
if (opts.comment) {
|
|
10198
|
+
try {
|
|
10199
|
+
(opts.postBrief ?? defaultPostBrief)(body);
|
|
10200
|
+
} catch (err) {
|
|
10201
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
10202
|
+
(opts.warn ?? ((m) => process.stderr.write(m + "\n")))(
|
|
10203
|
+
`\u26A0\uFE0F pre-merge-brief: could not post sticky comment (${reason}); printing brief instead.`
|
|
10204
|
+
);
|
|
10205
|
+
log(body);
|
|
10206
|
+
}
|
|
10207
|
+
} else {
|
|
10208
|
+
log(body);
|
|
10209
|
+
}
|
|
10210
|
+
return { body };
|
|
10211
|
+
}
|
|
10212
|
+
function createPreMergeBriefCommand() {
|
|
10213
|
+
return new Command77("pre-merge-brief").description(
|
|
10214
|
+
'Compose a senior-facing pre-merge PR brief (diff, review, signals, outcome, "worth your eyes")'
|
|
10215
|
+
).option("--from <path>", "review-ci --json verdict artifact").option("--comment", "upsert the brief as a sticky comment on the current branch's PR").option("--diff <range>", "git range (default: origin/<base>...HEAD)").option("--head <sha>", "head commit sha for the outcome lookup (default: git rev-parse HEAD)").action(async (opts) => {
|
|
10216
|
+
const cwd = process.cwd();
|
|
10217
|
+
const runGit = (args) => execFileSync7("git", args, { encoding: "utf-8" }).toString().trim();
|
|
10218
|
+
let headSha = opts.head;
|
|
10219
|
+
if (!headSha) {
|
|
10220
|
+
try {
|
|
10221
|
+
headSha = runGit(["rev-parse", "HEAD"]) || void 0;
|
|
10222
|
+
} catch {
|
|
10223
|
+
headSha = void 0;
|
|
10224
|
+
}
|
|
10225
|
+
}
|
|
10226
|
+
const store = await loadOutcomeStore(cwd);
|
|
10227
|
+
await runPreMergeBrief({
|
|
10228
|
+
cwd,
|
|
10229
|
+
from: opts.from,
|
|
10230
|
+
comment: opts.comment,
|
|
10231
|
+
diffRange: opts.diff,
|
|
10232
|
+
headSha,
|
|
10233
|
+
store,
|
|
10234
|
+
runGit
|
|
10235
|
+
});
|
|
10236
|
+
process.exit(0);
|
|
10237
|
+
});
|
|
10238
|
+
}
|
|
10239
|
+
|
|
10240
|
+
// src/commands/proposals.ts
|
|
10241
|
+
init_dist3();
|
|
10242
|
+
import { Command as Command78 } from "commander";
|
|
10243
|
+
import { resolve as resolve34 } from "path";
|
|
10244
|
+
function projectRoot() {
|
|
10245
|
+
return resolve34(process.env["HARNESS_PROJECT_ROOT"] ?? process.cwd());
|
|
10246
|
+
}
|
|
10247
|
+
function summarizeProposal(p) {
|
|
10248
|
+
return {
|
|
10249
|
+
id: p.id,
|
|
10250
|
+
kind: p.kind,
|
|
10251
|
+
targetSkill: p.targetSkill,
|
|
10252
|
+
name: p.content.name,
|
|
10253
|
+
status: p.status,
|
|
10254
|
+
proposedBy: p.proposedBy,
|
|
10255
|
+
createdAt: p.createdAt,
|
|
10256
|
+
gateLastRunAt: p.gate?.lastRunAt,
|
|
10257
|
+
findings: p.gate?.findings?.length ?? 0
|
|
10258
|
+
};
|
|
10259
|
+
}
|
|
10260
|
+
async function runProposalsList(status) {
|
|
10261
|
+
const opts = {};
|
|
10262
|
+
if (status) opts.status = status;
|
|
10263
|
+
const proposals = await listProposals(projectRoot(), opts);
|
|
10264
|
+
return proposals.map(summarizeProposal);
|
|
10265
|
+
}
|
|
10266
|
+
async function runProposalsShow(id) {
|
|
10267
|
+
return getProposal(projectRoot(), id);
|
|
10268
|
+
}
|
|
10269
|
+
async function runProposalsReject(id, reason) {
|
|
10270
|
+
const decision = {
|
|
10271
|
+
decidedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10272
|
+
decidedBy: process.env["USER"] ?? "cli",
|
|
10273
|
+
action: "rejected",
|
|
10274
|
+
reason
|
|
10275
|
+
};
|
|
10276
|
+
return updateProposal(projectRoot(), id, { status: "rejected", decision });
|
|
10277
|
+
}
|
|
10278
|
+
var ALLOWED_STATUSES = [
|
|
10279
|
+
"open",
|
|
10280
|
+
"gate-running",
|
|
10281
|
+
"gate-failed",
|
|
10282
|
+
"approved",
|
|
10283
|
+
"rejected",
|
|
10284
|
+
"all"
|
|
10285
|
+
];
|
|
10286
|
+
function fail(message) {
|
|
10287
|
+
console.error(message);
|
|
10288
|
+
process.exitCode = 1;
|
|
10289
|
+
}
|
|
10290
|
+
async function actListCommand(opts) {
|
|
10291
|
+
const raw = opts.status ?? "open";
|
|
10292
|
+
if (!ALLOWED_STATUSES.includes(raw)) {
|
|
10293
|
+
fail(`Error: unknown status "${raw}"`);
|
|
10294
|
+
return;
|
|
10295
|
+
}
|
|
10296
|
+
const proposals = await runProposalsList(raw);
|
|
10297
|
+
console.log(JSON.stringify(proposals, null, 2));
|
|
10298
|
+
}
|
|
10299
|
+
async function actShowCommand(id) {
|
|
10300
|
+
const proposal = await runProposalsShow(id);
|
|
10301
|
+
if (!proposal) {
|
|
10302
|
+
fail(`No such proposal: ${id}`);
|
|
10303
|
+
return;
|
|
10304
|
+
}
|
|
10305
|
+
console.log(JSON.stringify(proposal, null, 2));
|
|
10306
|
+
}
|
|
10307
|
+
async function actRejectCommand(id, opts) {
|
|
10308
|
+
try {
|
|
10309
|
+
const updated = await runProposalsReject(id, opts.reason);
|
|
10310
|
+
console.log(JSON.stringify(summarizeProposal(updated), null, 2));
|
|
10311
|
+
} catch (err) {
|
|
10312
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
9767
10313
|
}
|
|
9768
10314
|
}
|
|
9769
10315
|
async function actApproveCommand(id) {
|
|
@@ -9788,7 +10334,7 @@ async function actApproveCommand(id) {
|
|
|
9788
10334
|
}
|
|
9789
10335
|
}
|
|
9790
10336
|
function createProposalsCommand() {
|
|
9791
|
-
const cmd = new
|
|
10337
|
+
const cmd = new Command78("proposals").description("Skill-proposal review queue");
|
|
9792
10338
|
cmd.command("list").description("List skill proposals in the local queue").option(
|
|
9793
10339
|
"--status <status>",
|
|
9794
10340
|
`Filter by status \u2014 one of ${ALLOWED_STATUSES.join(" | ")}`,
|
|
@@ -9805,7 +10351,7 @@ function createProposalsCommand() {
|
|
|
9805
10351
|
// src/commands/publish-analyses.ts
|
|
9806
10352
|
import * as fs31 from "fs";
|
|
9807
10353
|
import * as path52 from "path";
|
|
9808
|
-
import { Command as
|
|
10354
|
+
import { Command as Command79 } from "commander";
|
|
9809
10355
|
init_dist3();
|
|
9810
10356
|
import {
|
|
9811
10357
|
renderAnalysisComment,
|
|
@@ -9917,7 +10463,7 @@ async function runPublishAnalyses(opts) {
|
|
|
9917
10463
|
const nameToExternalId = await buildNameToExternalIdMap(projectPath);
|
|
9918
10464
|
if (!nameToExternalId) return process.exit(1);
|
|
9919
10465
|
const { AnalysisArchive } = await import("@harness-engineering/orchestrator");
|
|
9920
|
-
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-
|
|
10466
|
+
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-MCTEX5QH.js");
|
|
9921
10467
|
const archive = new AnalysisArchive(path52.join(projectPath, ".harness", "analyses"));
|
|
9922
10468
|
const analyses = await archive.list();
|
|
9923
10469
|
if (analyses.length === 0) {
|
|
@@ -9940,7 +10486,7 @@ async function runPublishAnalyses(opts) {
|
|
|
9940
10486
|
}
|
|
9941
10487
|
}
|
|
9942
10488
|
function createPublishAnalysesCommand() {
|
|
9943
|
-
const command = new
|
|
10489
|
+
const command = new Command79("publish-analyses").description(
|
|
9944
10490
|
"Publishes locally generated intelligence analyses to the external issue tracker (e.g., GitHub)"
|
|
9945
10491
|
).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
9946
10492
|
try {
|
|
@@ -9956,18 +10502,18 @@ function createPublishAnalysesCommand() {
|
|
|
9956
10502
|
}
|
|
9957
10503
|
|
|
9958
10504
|
// src/commands/pulse/index.ts
|
|
9959
|
-
import { Command as
|
|
10505
|
+
import { Command as Command81 } from "commander";
|
|
9960
10506
|
|
|
9961
10507
|
// src/commands/pulse/run.ts
|
|
9962
10508
|
init_dist3();
|
|
9963
|
-
import { readFileSync as
|
|
9964
|
-
import { dirname as dirname18, join as
|
|
9965
|
-
import { Command as
|
|
10509
|
+
import { readFileSync as readFileSync19, mkdirSync as mkdirSync15, writeFileSync as writeFileSync19 } from "fs";
|
|
10510
|
+
import { dirname as dirname18, join as join42, resolve as resolve36 } from "path";
|
|
10511
|
+
import { Command as Command80 } from "commander";
|
|
9966
10512
|
async function runPulseRunCommand(opts) {
|
|
9967
10513
|
const startedAt = Date.now();
|
|
9968
10514
|
let raw;
|
|
9969
10515
|
try {
|
|
9970
|
-
raw = JSON.parse(
|
|
10516
|
+
raw = JSON.parse(readFileSync19(opts.configPath, "utf-8"));
|
|
9971
10517
|
} catch (err) {
|
|
9972
10518
|
return emit2(
|
|
9973
10519
|
{
|
|
@@ -9993,9 +10539,9 @@ async function runPulseRunCommand(opts) {
|
|
|
9993
10539
|
const report = assembleReport(result, productName, lookback);
|
|
9994
10540
|
const now = /* @__PURE__ */ new Date();
|
|
9995
10541
|
const ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}_${String(now.getHours()).padStart(2, "0")}-${String(now.getMinutes()).padStart(2, "0")}`;
|
|
9996
|
-
const filePath =
|
|
10542
|
+
const filePath = join42(opts.outputDir, `${ts}.md`);
|
|
9997
10543
|
mkdirSync15(dirname18(filePath), { recursive: true });
|
|
9998
|
-
|
|
10544
|
+
writeFileSync19(filePath, report);
|
|
9999
10545
|
const headlines = extractHeadlines(report);
|
|
10000
10546
|
return emit2(
|
|
10001
10547
|
{
|
|
@@ -10027,7 +10573,7 @@ function emit2(status, nonInteractive) {
|
|
|
10027
10573
|
return status;
|
|
10028
10574
|
}
|
|
10029
10575
|
function createRunCommand2() {
|
|
10030
|
-
return new
|
|
10576
|
+
return new Command80("run").description("Run a pulse: query configured adapters, sanitize, assemble single-page report").option(
|
|
10031
10577
|
"--lookback <window>",
|
|
10032
10578
|
"Lookback window (e.g. 24h, 7d). Defaults to pulse.lookbackDefault."
|
|
10033
10579
|
).option(
|
|
@@ -10051,13 +10597,13 @@ function createRunCommand2() {
|
|
|
10051
10597
|
|
|
10052
10598
|
// src/commands/pulse/index.ts
|
|
10053
10599
|
function createPulseCommand() {
|
|
10054
|
-
const command = new
|
|
10600
|
+
const command = new Command81("pulse").description("Pulse (read-side observability) commands");
|
|
10055
10601
|
command.addCommand(createRunCommand2());
|
|
10056
10602
|
return command;
|
|
10057
10603
|
}
|
|
10058
10604
|
|
|
10059
10605
|
// src/commands/recommend.ts
|
|
10060
|
-
import { Command as
|
|
10606
|
+
import { Command as Command82 } from "commander";
|
|
10061
10607
|
import chalk13 from "chalk";
|
|
10062
10608
|
async function resolveSnapshot(cwd, noCache) {
|
|
10063
10609
|
if (!noCache) {
|
|
@@ -10084,301 +10630,84 @@ async function runRecommend(options) {
|
|
|
10084
10630
|
const { snapshot, usedCache } = await resolveSnapshot(cwd, options.noCache);
|
|
10085
10631
|
const skills = buildSkillsRecord(cwd);
|
|
10086
10632
|
const result = recommend(snapshot, skills, { top });
|
|
10087
|
-
return {
|
|
10088
|
-
...result,
|
|
10089
|
-
snapshotAge: usedCache ? "cached" : "fresh"
|
|
10090
|
-
};
|
|
10091
|
-
}
|
|
10092
|
-
function formatRecommendation(rec) {
|
|
10093
|
-
const lines = [];
|
|
10094
|
-
if (rec.urgency === "critical") {
|
|
10095
|
-
lines.push(` ${chalk13.red("[CRITICAL]")} ${rec.sequence}. ${rec.skillName}`);
|
|
10096
|
-
} else {
|
|
10097
|
-
lines.push(` ${rec.sequence}. ${rec.skillName} (${rec.score.toFixed(2)})`);
|
|
10098
|
-
}
|
|
10099
|
-
for (const reason of rec.reasons) {
|
|
10100
|
-
lines.push(` ${chalk13.dim("\u2192")} ${reason}`);
|
|
10101
|
-
}
|
|
10102
|
-
return lines.join("\n");
|
|
10103
|
-
}
|
|
10104
|
-
function printRecommendations(result) {
|
|
10105
|
-
if (result.recommendations.length === 0) {
|
|
10106
|
-
console.log("");
|
|
10107
|
-
console.log("No recommendations. Codebase health looks good!");
|
|
10108
|
-
console.log("");
|
|
10109
|
-
return;
|
|
10110
|
-
}
|
|
10111
|
-
console.log("");
|
|
10112
|
-
console.log(
|
|
10113
|
-
`Recommended workflow (${result.recommendations.length} skill${result.recommendations.length === 1 ? "" : "s"}):`
|
|
10114
|
-
);
|
|
10115
|
-
console.log("");
|
|
10116
|
-
for (const rec of result.recommendations) {
|
|
10117
|
-
console.log(formatRecommendation(rec));
|
|
10118
|
-
console.log("");
|
|
10119
|
-
}
|
|
10120
|
-
console.log(`Sequence reasoning: ${result.sequenceReasoning}`);
|
|
10121
|
-
console.log("");
|
|
10122
|
-
}
|
|
10123
|
-
function createRecommendCommand() {
|
|
10124
|
-
const command = new Command80("recommend").description("Recommend skills based on codebase health analysis").option("--no-cache", "Force fresh health snapshot").option("--top <n>", "Max recommendations (default 5)", "5").action(async (opts, cmd) => {
|
|
10125
|
-
const globalOpts = cmd.optsWithGlobals();
|
|
10126
|
-
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
10127
|
-
try {
|
|
10128
|
-
const top = parseInt(opts.top, 10);
|
|
10129
|
-
if (isNaN(top) || top < 1) {
|
|
10130
|
-
logger.error("--top must be a positive integer");
|
|
10131
|
-
process.exit(1);
|
|
10132
|
-
}
|
|
10133
|
-
if (mode === OutputMode.TEXT) {
|
|
10134
|
-
console.log("");
|
|
10135
|
-
console.log("Analyzing codebase health...");
|
|
10136
|
-
}
|
|
10137
|
-
const result = await runRecommend({
|
|
10138
|
-
noCache: opts.cache === false,
|
|
10139
|
-
top
|
|
10140
|
-
});
|
|
10141
|
-
if (mode === OutputMode.JSON) {
|
|
10142
|
-
console.log(JSON.stringify(result, null, 2));
|
|
10143
|
-
} else {
|
|
10144
|
-
printRecommendations(result);
|
|
10145
|
-
}
|
|
10146
|
-
} catch (err) {
|
|
10147
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
10148
|
-
if (mode === OutputMode.JSON) {
|
|
10149
|
-
console.log(JSON.stringify({ error: message }));
|
|
10150
|
-
} else {
|
|
10151
|
-
logger.error(message);
|
|
10152
|
-
}
|
|
10153
|
-
process.exit(1);
|
|
10154
|
-
}
|
|
10155
|
-
});
|
|
10156
|
-
return command;
|
|
10157
|
-
}
|
|
10158
|
-
|
|
10159
|
-
// src/commands/review-ci.ts
|
|
10160
|
-
init_dist3();
|
|
10161
|
-
import { execFileSync as execFileSync6 } from "child_process";
|
|
10162
|
-
import { writeFileSync as writeFileSync19 } from "fs";
|
|
10163
|
-
import { Command as Command81, Option as Option2 } from "commander";
|
|
10164
|
-
|
|
10165
|
-
// src/commands/review-ci-local-adapter.ts
|
|
10166
|
-
import { z } from "zod";
|
|
10167
|
-
import { OpenAICompatibleAnalysisProvider } from "@harness-engineering/intelligence";
|
|
10168
|
-
var FindingSchema = z.object({
|
|
10169
|
-
id: z.string(),
|
|
10170
|
-
file: z.string(),
|
|
10171
|
-
lineRange: z.tuple([z.number(), z.number()]),
|
|
10172
|
-
domain: z.enum(["compliance", "bug", "security", "architecture", "learnings"]),
|
|
10173
|
-
severity: z.enum(["critical", "important", "suggestion"]),
|
|
10174
|
-
title: z.string(),
|
|
10175
|
-
rationale: z.string(),
|
|
10176
|
-
suggestion: z.string().optional(),
|
|
10177
|
-
evidence: z.array(z.string())
|
|
10178
|
-
});
|
|
10179
|
-
var LocalVerdictSchema = z.object({
|
|
10180
|
-
assessment: z.enum(["approve", "comment", "request-changes"]),
|
|
10181
|
-
findings: z.array(FindingSchema)
|
|
10182
|
-
});
|
|
10183
|
-
var MAX_SURFACED_ERROR_LEN = 200;
|
|
10184
|
-
function sanitizeProviderError(err) {
|
|
10185
|
-
const raw = err instanceof Error ? err.message : String(err);
|
|
10186
|
-
const redacted = raw.replace(/https?:\/\/\S+/gi, "[endpoint]").replace(/\b(bearer|authorization|api[-_]?key|token)\b\s*[:=]?\s*\S+/gi, "[redacted]").replace(/\s+/g, " ").trim();
|
|
10187
|
-
const capped = redacted.length > MAX_SURFACED_ERROR_LEN ? redacted.slice(0, MAX_SURFACED_ERROR_LEN - 1) + "\u2026" : redacted;
|
|
10188
|
-
return `local runner provider error: ${capped}`;
|
|
10189
|
-
}
|
|
10190
|
-
function createLocalInvoke() {
|
|
10191
|
-
return async ({ endpoint, model, instruction, diff: diff2 }) => {
|
|
10192
|
-
if (!/^https?:\/\//i.test(endpoint)) {
|
|
10193
|
-
throw new Error(
|
|
10194
|
-
`HARNESS_LOCAL_ENDPOINT must be an http(s) URL (got '${endpoint}'); e.g. http://localhost:1234/v1`
|
|
10195
|
-
);
|
|
10196
|
-
}
|
|
10197
|
-
const provider = new OpenAICompatibleAnalysisProvider({
|
|
10198
|
-
apiKey: process.env.HARNESS_LOCAL_API_KEY ?? "local",
|
|
10199
|
-
baseUrl: endpoint,
|
|
10200
|
-
defaultModel: model
|
|
10201
|
-
});
|
|
10202
|
-
try {
|
|
10203
|
-
const { result } = await provider.analyze({
|
|
10204
|
-
prompt: `${instruction}
|
|
10205
|
-
|
|
10206
|
-
---
|
|
10207
|
-
DIFF UNDER REVIEW:
|
|
10208
|
-
${diff2}`,
|
|
10209
|
-
responseSchema: LocalVerdictSchema,
|
|
10210
|
-
model
|
|
10211
|
-
});
|
|
10212
|
-
return JSON.stringify(result);
|
|
10213
|
-
} catch (err) {
|
|
10214
|
-
throw new Error(sanitizeProviderError(err), { cause: err });
|
|
10215
|
-
}
|
|
10216
|
-
};
|
|
10217
|
-
}
|
|
10218
|
-
|
|
10219
|
-
// src/commands/review-ci.ts
|
|
10220
|
-
var KNOWN_RUNNERS = Object.keys(RUNNER_PRESETS);
|
|
10221
|
-
var BLOCK_ON_LEVELS = [...CI_ASSESSMENTS, "none"];
|
|
10222
|
-
function assertKnownRunner(runner) {
|
|
10223
|
-
if (runner === void 0) return;
|
|
10224
|
-
if (!KNOWN_RUNNERS.includes(runner)) {
|
|
10225
|
-
throw new Error(`unknown runner '${runner}' (expected: ${KNOWN_RUNNERS.join("|")})`);
|
|
10226
|
-
}
|
|
10227
|
-
}
|
|
10228
|
-
var defaultRunGit = (args) => execFileSync6("git", args, { encoding: "utf-8" }).toString().trim();
|
|
10229
|
-
function resolveDiffRange(opts) {
|
|
10230
|
-
if (opts.range) return opts.range;
|
|
10231
|
-
const runGit = opts.runGit ?? defaultRunGit;
|
|
10232
|
-
let base = "main";
|
|
10233
|
-
try {
|
|
10234
|
-
const ref = runGit(["symbolic-ref", "refs/remotes/origin/HEAD"]);
|
|
10235
|
-
const m = ref.match(/origin\/(.+)$/);
|
|
10236
|
-
if (m?.[1]) base = m[1];
|
|
10237
|
-
} catch {
|
|
10238
|
-
}
|
|
10239
|
-
return `origin/${base}...HEAD`;
|
|
10240
|
-
}
|
|
10241
|
-
function splitDiffByFile(rawDiff) {
|
|
10242
|
-
const sections = /* @__PURE__ */ new Map();
|
|
10243
|
-
const headerRe = /^diff --git a\/(.+?) b\/(.+?)$/;
|
|
10244
|
-
let currentPath = null;
|
|
10245
|
-
let buffer = [];
|
|
10246
|
-
const flush = () => {
|
|
10247
|
-
if (currentPath !== null) sections.set(currentPath, buffer.join("\n"));
|
|
10248
|
-
};
|
|
10249
|
-
for (const line of rawDiff.split("\n")) {
|
|
10250
|
-
const m = line.match(headerRe);
|
|
10251
|
-
if (m?.[2]) {
|
|
10252
|
-
flush();
|
|
10253
|
-
currentPath = m[2];
|
|
10254
|
-
buffer = [line];
|
|
10255
|
-
} else if (currentPath !== null) {
|
|
10256
|
-
buffer.push(line);
|
|
10257
|
-
}
|
|
10258
|
-
}
|
|
10259
|
-
flush();
|
|
10260
|
-
return sections;
|
|
10261
|
-
}
|
|
10262
|
-
function buildDiffInfo(rawDiff) {
|
|
10263
|
-
const parsed = parseDiff(rawDiff);
|
|
10264
|
-
if (!parsed.ok) throw new Error(`Failed to parse diff: ${parsed.error.message}`);
|
|
10265
|
-
const files = parsed.value.files;
|
|
10266
|
-
const perFile = splitDiffByFile(rawDiff);
|
|
10267
|
-
return {
|
|
10268
|
-
changedFiles: files.map((f) => f.path),
|
|
10269
|
-
newFiles: files.filter((f) => f.status === "added").map((f) => f.path),
|
|
10270
|
-
deletedFiles: files.filter((f) => f.status === "deleted").map((f) => f.path),
|
|
10271
|
-
totalDiffLines: rawDiff ? rawDiff.split("\n").length : 0,
|
|
10272
|
-
// On a path-key miss, fall back to '' (the file contributes no per-file diff)
|
|
10273
|
-
// rather than the ENTIRE raw diff — substituting the whole diff would duplicate
|
|
10274
|
-
// every file's content into one section, inflating the STDIN payload to the LLM
|
|
10275
|
-
// (and risking core's execMaxStdoutBytes). With splitDiffByFile aligned to core's
|
|
10276
|
-
// path extraction, ordinary paths never miss; this is the safe degenerate case.
|
|
10277
|
-
fileDiffs: new Map(files.map((f) => [f.path, perFile.get(f.path) ?? ""]))
|
|
10278
|
-
};
|
|
10279
|
-
}
|
|
10280
|
-
function defaultResolveRaw(range, _cwd, runGit) {
|
|
10281
|
-
return runGit(["diff", range]);
|
|
10282
|
-
}
|
|
10283
|
-
function buildCallOpts(opts, cwd, diff2) {
|
|
10284
|
-
const runner = opts.runner;
|
|
10285
|
-
return {
|
|
10286
|
-
projectRoot: cwd,
|
|
10287
|
-
diff: diff2,
|
|
10288
|
-
...runner ? { runner } : {},
|
|
10289
|
-
...opts.blockOn ? { blockOn: opts.blockOn } : {},
|
|
10290
|
-
...runner === "local" ? { localInvoke: opts.localInvoke ?? createLocalInvoke() } : {}
|
|
10291
|
-
};
|
|
10292
|
-
}
|
|
10293
|
-
async function runReviewCi(opts) {
|
|
10294
|
-
assertKnownRunner(opts.runner);
|
|
10295
|
-
const cwd = opts.cwd ?? process.cwd();
|
|
10296
|
-
const runGit = opts.runGit ?? defaultRunGit;
|
|
10297
|
-
const range = resolveDiffRange({
|
|
10298
|
-
...opts.diffRange ? { range: opts.diffRange } : {},
|
|
10299
|
-
cwd,
|
|
10300
|
-
runGit
|
|
10301
|
-
});
|
|
10302
|
-
const rawDiff = (opts.resolveRaw ?? defaultResolveRaw)(range, cwd, runGit);
|
|
10303
|
-
const diff2 = buildDiffInfo(rawDiff);
|
|
10304
|
-
const callOpts = buildCallOpts(opts, cwd, diff2);
|
|
10305
|
-
return (opts.runCiReviewImpl ?? runCiReview)(callOpts);
|
|
10633
|
+
return {
|
|
10634
|
+
...result,
|
|
10635
|
+
snapshotAge: usedCache ? "cached" : "fresh"
|
|
10636
|
+
};
|
|
10306
10637
|
}
|
|
10307
|
-
function
|
|
10308
|
-
const
|
|
10309
|
-
|
|
10638
|
+
function formatRecommendation(rec) {
|
|
10639
|
+
const lines = [];
|
|
10640
|
+
if (rec.urgency === "critical") {
|
|
10641
|
+
lines.push(` ${chalk13.red("[CRITICAL]")} ${rec.sequence}. ${rec.skillName}`);
|
|
10642
|
+
} else {
|
|
10643
|
+
lines.push(` ${rec.sequence}. ${rec.skillName} (${rec.score.toFixed(2)})`);
|
|
10644
|
+
}
|
|
10645
|
+
for (const reason of rec.reasons) {
|
|
10646
|
+
lines.push(` ${chalk13.dim("\u2192")} ${reason}`);
|
|
10647
|
+
}
|
|
10648
|
+
return lines.join("\n");
|
|
10310
10649
|
}
|
|
10311
|
-
function
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10650
|
+
function printRecommendations(result) {
|
|
10651
|
+
if (result.recommendations.length === 0) {
|
|
10652
|
+
console.log("");
|
|
10653
|
+
console.log("No recommendations. Codebase health looks good!");
|
|
10654
|
+
console.log("");
|
|
10655
|
+
return;
|
|
10656
|
+
}
|
|
10657
|
+
console.log("");
|
|
10658
|
+
console.log(
|
|
10659
|
+
`Recommended workflow (${result.recommendations.length} skill${result.recommendations.length === 1 ? "" : "s"}):`
|
|
10660
|
+
);
|
|
10661
|
+
console.log("");
|
|
10662
|
+
for (const rec of result.recommendations) {
|
|
10663
|
+
console.log(formatRecommendation(rec));
|
|
10664
|
+
console.log("");
|
|
10665
|
+
}
|
|
10666
|
+
console.log(`Sequence reasoning: ${result.sequenceReasoning}`);
|
|
10667
|
+
console.log("");
|
|
10327
10668
|
}
|
|
10328
|
-
|
|
10329
|
-
|
|
10330
|
-
|
|
10331
|
-
|
|
10332
|
-
encoding: "utf-8"
|
|
10333
|
-
});
|
|
10334
|
-
};
|
|
10335
|
-
function emitReviewCi(result, opts, writeFile2 = (p, d) => writeFileSync19(p, d), log = (m) => process.stdout.write(m + "\n"), postReview = defaultPostReview) {
|
|
10336
|
-
const serialized = JSON.stringify(result.verdict, null, 2);
|
|
10337
|
-
const jsonToStdout = opts.jsonPath === true;
|
|
10338
|
-
if (!jsonToStdout) log(result.terminalOutput);
|
|
10339
|
-
if (typeof opts.jsonPath === "string") writeFile2(opts.jsonPath, serialized);
|
|
10340
|
-
else if (jsonToStdout) log(serialized);
|
|
10341
|
-
if (opts.comment) {
|
|
10669
|
+
function createRecommendCommand() {
|
|
10670
|
+
const command = new Command82("recommend").description("Recommend skills based on codebase health analysis").option("--no-cache", "Force fresh health snapshot").option("--top <n>", "Max recommendations (default 5)", "5").action(async (opts, cmd) => {
|
|
10671
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
10672
|
+
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
10342
10673
|
try {
|
|
10343
|
-
|
|
10674
|
+
const top = parseInt(opts.top, 10);
|
|
10675
|
+
if (isNaN(top) || top < 1) {
|
|
10676
|
+
logger.error("--top must be a positive integer");
|
|
10677
|
+
process.exit(1);
|
|
10678
|
+
}
|
|
10679
|
+
if (mode === OutputMode.TEXT) {
|
|
10680
|
+
console.log("");
|
|
10681
|
+
console.log("Analyzing codebase health...");
|
|
10682
|
+
}
|
|
10683
|
+
const result = await runRecommend({
|
|
10684
|
+
noCache: opts.cache === false,
|
|
10685
|
+
top
|
|
10686
|
+
});
|
|
10687
|
+
if (mode === OutputMode.JSON) {
|
|
10688
|
+
console.log(JSON.stringify(result, null, 2));
|
|
10689
|
+
} else {
|
|
10690
|
+
printRecommendations(result);
|
|
10691
|
+
}
|
|
10344
10692
|
} catch (err) {
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
10693
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
10694
|
+
if (mode === OutputMode.JSON) {
|
|
10695
|
+
console.log(JSON.stringify({ error: message }));
|
|
10696
|
+
} else {
|
|
10697
|
+
logger.error(message);
|
|
10698
|
+
}
|
|
10699
|
+
process.exit(1);
|
|
10348
10700
|
}
|
|
10349
|
-
}
|
|
10350
|
-
}
|
|
10351
|
-
function createReviewCiCommand() {
|
|
10352
|
-
return new Command81("review-ci").description("Run the tiered code-review gate (floor + optional LLM runner) for CI").addOption(
|
|
10353
|
-
new Option2("--runner <runner>", `${KNOWN_RUNNERS.join(" | ")} (omit = floor-only)`).choices(
|
|
10354
|
-
KNOWN_RUNNERS
|
|
10355
|
-
)
|
|
10356
|
-
).addOption(
|
|
10357
|
-
new Option2("--block-on <level>", BLOCK_ON_LEVELS.join(" | ")).choices(BLOCK_ON_LEVELS).default("request-changes")
|
|
10358
|
-
).option("--diff <range>", "git range (default: origin/<base>...HEAD)").option("--comment", "post the verdict as a comment on the current branch's PR via gh").option(
|
|
10359
|
-
"--out <path>",
|
|
10360
|
-
"write the verdict JSON artifact to a file (use the global --json to stream it to stdout instead)"
|
|
10361
|
-
).action(async (opts, cmd) => {
|
|
10362
|
-
const result = await runReviewCi({
|
|
10363
|
-
runner: opts.runner,
|
|
10364
|
-
blockOn: opts.blockOn,
|
|
10365
|
-
diffRange: opts.diff
|
|
10366
|
-
});
|
|
10367
|
-
const streamJson = cmd.optsWithGlobals().json === true;
|
|
10368
|
-
emitReviewCi(result, {
|
|
10369
|
-
jsonPath: typeof opts.out === "string" ? opts.out : streamJson ? true : void 0,
|
|
10370
|
-
comment: opts.comment
|
|
10371
|
-
});
|
|
10372
|
-
process.exit(result.exitCode);
|
|
10373
10701
|
});
|
|
10702
|
+
return command;
|
|
10374
10703
|
}
|
|
10375
10704
|
|
|
10376
10705
|
// src/commands/roadmap/index.ts
|
|
10377
|
-
import { Command as
|
|
10706
|
+
import { Command as Command89 } from "commander";
|
|
10378
10707
|
|
|
10379
10708
|
// src/commands/roadmap/migrate.ts
|
|
10380
10709
|
init_dist3();
|
|
10381
|
-
import { Command as
|
|
10710
|
+
import { Command as Command83 } from "commander";
|
|
10382
10711
|
import * as fs33 from "fs";
|
|
10383
10712
|
import * as path54 from "path";
|
|
10384
10713
|
import chalk14 from "chalk";
|
|
@@ -10788,7 +11117,7 @@ async function runReverseMigrate(opts) {
|
|
|
10788
11117
|
}
|
|
10789
11118
|
}
|
|
10790
11119
|
function createRoadmapMigrateCommand() {
|
|
10791
|
-
return new
|
|
11120
|
+
return new Command83("migrate").description("Migrate the project roadmap to a different storage mode").requiredOption("--to <target>", 'Migration target: "file-less" or "file-backed"').option("--dry-run", "Print the migration plan without making any changes", false).option(
|
|
10792
11121
|
"--format <fmt>",
|
|
10793
11122
|
'Output format: "human" (default) or "json" (single JSON object for CI consumers)',
|
|
10794
11123
|
"human"
|
|
@@ -10823,7 +11152,7 @@ function createRoadmapMigrateCommand() {
|
|
|
10823
11152
|
|
|
10824
11153
|
// src/commands/roadmap/shard.ts
|
|
10825
11154
|
init_dist3();
|
|
10826
|
-
import { Command as
|
|
11155
|
+
import { Command as Command84 } from "commander";
|
|
10827
11156
|
import * as path55 from "path";
|
|
10828
11157
|
|
|
10829
11158
|
// src/commands/roadmap/shard-io.ts
|
|
@@ -10922,7 +11251,7 @@ async function runRoadmapShard(opts = {}) {
|
|
|
10922
11251
|
return Ok(report);
|
|
10923
11252
|
}
|
|
10924
11253
|
function createRoadmapShardCommand() {
|
|
10925
|
-
return new
|
|
11254
|
+
return new Command84("shard").description("Migrate docs/roadmap.md to per-row shards under docs/roadmap.d").option("--cwd <dir>", "Project root (defaults to the current working directory)").option("--dry-run", "Report the migration plan without writing anything", false).option("--force", "Proceed even if docs/roadmap.d already exists", false).option(
|
|
10926
11255
|
"--format <fmt>",
|
|
10927
11256
|
'Output format: "human" (default) or "json" (single JSON object for CI consumers)',
|
|
10928
11257
|
"human"
|
|
@@ -10949,7 +11278,7 @@ function createRoadmapShardCommand() {
|
|
|
10949
11278
|
|
|
10950
11279
|
// src/commands/roadmap/unshard.ts
|
|
10951
11280
|
init_dist3();
|
|
10952
|
-
import { Command as
|
|
11281
|
+
import { Command as Command85 } from "commander";
|
|
10953
11282
|
import * as path56 from "path";
|
|
10954
11283
|
async function runRoadmapUnshard(opts = {}) {
|
|
10955
11284
|
const cwd = opts.cwd ?? process.cwd();
|
|
@@ -10981,7 +11310,7 @@ async function runRoadmapUnshard(opts = {}) {
|
|
|
10981
11310
|
return Ok(report);
|
|
10982
11311
|
}
|
|
10983
11312
|
function createRoadmapUnshardCommand() {
|
|
10984
|
-
return new
|
|
11313
|
+
return new Command85("unshard").description("Reassemble the aggregate from shards and remove docs/roadmap.d").option("--cwd <dir>", "Project root (defaults to the current working directory)").option("--dry-run", "Preview the reassembly without writing or deleting the shard dir", false).option(
|
|
10985
11314
|
"--format <fmt>",
|
|
10986
11315
|
'Output format: "human" (default) or "json" (single JSON object for CI consumers)',
|
|
10987
11316
|
"human"
|
|
@@ -11005,7 +11334,7 @@ function createRoadmapUnshardCommand() {
|
|
|
11005
11334
|
|
|
11006
11335
|
// src/commands/roadmap/regen.ts
|
|
11007
11336
|
init_dist3();
|
|
11008
|
-
import { Command as
|
|
11337
|
+
import { Command as Command86 } from "commander";
|
|
11009
11338
|
import * as path57 from "path";
|
|
11010
11339
|
async function runRoadmapRegen(opts = {}) {
|
|
11011
11340
|
const cwd = opts.cwd ?? process.cwd();
|
|
@@ -11034,7 +11363,7 @@ async function runRoadmapRegen(opts = {}) {
|
|
|
11034
11363
|
return Ok(report);
|
|
11035
11364
|
}
|
|
11036
11365
|
function createRoadmapRegenCommand() {
|
|
11037
|
-
return new
|
|
11366
|
+
return new Command86("regen").description("Regenerate the aggregate from the shard directory (docs/roadmap.d)").option("--cwd <dir>", "Project root (defaults to the current working directory)").option("--dry-run", "Report what would be regenerated without writing anything", false).option(
|
|
11038
11367
|
"--format <fmt>",
|
|
11039
11368
|
'Output format: "human" (default) or "json" (single JSON object for CI consumers)',
|
|
11040
11369
|
"human"
|
|
@@ -11058,7 +11387,7 @@ function createRoadmapRegenCommand() {
|
|
|
11058
11387
|
|
|
11059
11388
|
// src/commands/roadmap/reconcile.ts
|
|
11060
11389
|
init_dist3();
|
|
11061
|
-
import { Command as
|
|
11390
|
+
import { Command as Command87 } from "commander";
|
|
11062
11391
|
import * as fs34 from "fs";
|
|
11063
11392
|
import * as path58 from "path";
|
|
11064
11393
|
async function runRoadmapReconcile(opts = {}) {
|
|
@@ -11163,8 +11492,35 @@ function logSummary(result) {
|
|
|
11163
11492
|
`Reconciled ${markedDone.length} row(s) to done: ${markedDone.join(", ")} (already-done: ${alreadyDone.length}, unmatched: ${unmatched.length}).`
|
|
11164
11493
|
);
|
|
11165
11494
|
}
|
|
11495
|
+
function parseFromRefsFlag(raw) {
|
|
11496
|
+
const refs = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
11497
|
+
if (refs.length === 0) {
|
|
11498
|
+
logger.error(
|
|
11499
|
+
`--from-refs was provided ("${raw}") but contained no valid references; expected a comma-separated list of owner/repo#number`
|
|
11500
|
+
);
|
|
11501
|
+
process.exit(ExitCode.ERROR);
|
|
11502
|
+
}
|
|
11503
|
+
return refs;
|
|
11504
|
+
}
|
|
11505
|
+
function parseFromIssuesFlag(raw) {
|
|
11506
|
+
const parsed = raw.split(",").map((s) => Number.parseInt(s.trim(), 10)).filter((n) => Number.isInteger(n));
|
|
11507
|
+
if (parsed.length === 0) {
|
|
11508
|
+
logger.error(
|
|
11509
|
+
`--from-issues was provided ("${raw}") but contained no valid issue numbers; expected a comma-separated list of integers`
|
|
11510
|
+
);
|
|
11511
|
+
process.exit(ExitCode.ERROR);
|
|
11512
|
+
}
|
|
11513
|
+
return parsed;
|
|
11514
|
+
}
|
|
11515
|
+
function buildReconcileOptions(options) {
|
|
11516
|
+
const opts = {};
|
|
11517
|
+
if (options.cwd) opts.cwd = options.cwd;
|
|
11518
|
+
if (options.fromRefs !== void 0) opts.fromRefs = parseFromRefsFlag(options.fromRefs);
|
|
11519
|
+
if (options.fromIssues !== void 0) opts.fromIssues = parseFromIssuesFlag(options.fromIssues);
|
|
11520
|
+
return opts;
|
|
11521
|
+
}
|
|
11166
11522
|
function createRoadmapReconcileCommand() {
|
|
11167
|
-
return new
|
|
11523
|
+
return new Command87("reconcile").description(
|
|
11168
11524
|
"Flip roadmap rows whose linked GitHub issue is closed to done. Offline mode flips only issues closed as 'completed' (a 'not planned'/'wontfix' close is left untouched); the PR-merge auto-done workflow remains authoritative for cross-repo correctness."
|
|
11169
11525
|
).option("--cwd <dir>", "Project root (defaults to the current working directory)").option(
|
|
11170
11526
|
"--from-issues <numbers>",
|
|
@@ -11173,29 +11529,7 @@ function createRoadmapReconcileCommand() {
|
|
|
11173
11529
|
"--from-refs <refs>",
|
|
11174
11530
|
"comma-separated owner/repo#number closing-issue references (preferred; cross-repo safe; skips the network fetch)"
|
|
11175
11531
|
).action(async (options) => {
|
|
11176
|
-
const
|
|
11177
|
-
if (options.cwd) opts.cwd = options.cwd;
|
|
11178
|
-
if (options.fromRefs !== void 0) {
|
|
11179
|
-
const refs = options.fromRefs.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
11180
|
-
if (refs.length === 0) {
|
|
11181
|
-
logger.error(
|
|
11182
|
-
`--from-refs was provided ("${options.fromRefs}") but contained no valid references; expected a comma-separated list of owner/repo#number`
|
|
11183
|
-
);
|
|
11184
|
-
process.exit(ExitCode.ERROR);
|
|
11185
|
-
}
|
|
11186
|
-
opts.fromRefs = refs;
|
|
11187
|
-
}
|
|
11188
|
-
if (options.fromIssues !== void 0) {
|
|
11189
|
-
const parsed = options.fromIssues.split(",").map((s) => Number.parseInt(s.trim(), 10)).filter((n) => Number.isInteger(n));
|
|
11190
|
-
if (parsed.length === 0) {
|
|
11191
|
-
logger.error(
|
|
11192
|
-
`--from-issues was provided ("${options.fromIssues}") but contained no valid issue numbers; expected a comma-separated list of integers`
|
|
11193
|
-
);
|
|
11194
|
-
process.exit(ExitCode.ERROR);
|
|
11195
|
-
}
|
|
11196
|
-
opts.fromIssues = parsed;
|
|
11197
|
-
}
|
|
11198
|
-
const result = await runRoadmapReconcile(opts);
|
|
11532
|
+
const result = await runRoadmapReconcile(buildReconcileOptions(options));
|
|
11199
11533
|
if (!result.ok) {
|
|
11200
11534
|
logger.error(result.error.message);
|
|
11201
11535
|
process.exit(result.error.exitCode);
|
|
@@ -11203,22 +11537,40 @@ function createRoadmapReconcileCommand() {
|
|
|
11203
11537
|
});
|
|
11204
11538
|
}
|
|
11205
11539
|
|
|
11540
|
+
// src/commands/roadmap/referenced-issues.ts
|
|
11541
|
+
init_dist3();
|
|
11542
|
+
import { Command as Command88 } from "commander";
|
|
11543
|
+
function runReferencedIssues(text, print) {
|
|
11544
|
+
for (const n of parseReferencedIssues(text)) print(String(n));
|
|
11545
|
+
}
|
|
11546
|
+
function createRoadmapReferencedIssuesCommand() {
|
|
11547
|
+
return new Command88("referenced-issues").description(
|
|
11548
|
+
"Parse issue references (#N, Closes/Fixes/Resolves #N, owner/repo#N) from stdin text (PR body + title) and print each issue number on its own line. Backstop for auto-done when a PR's closing keyword is malformed."
|
|
11549
|
+
).action(async () => {
|
|
11550
|
+
const chunks = [];
|
|
11551
|
+
for await (const c of process.stdin) chunks.push(c);
|
|
11552
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
11553
|
+
runReferencedIssues(text, (line) => process.stdout.write(line + "\n"));
|
|
11554
|
+
});
|
|
11555
|
+
}
|
|
11556
|
+
|
|
11206
11557
|
// src/commands/roadmap/index.ts
|
|
11207
11558
|
function createRoadmapCommand() {
|
|
11208
|
-
const roadmap = new
|
|
11559
|
+
const roadmap = new Command89("roadmap").description("Roadmap management");
|
|
11209
11560
|
roadmap.addCommand(createRoadmapMigrateCommand());
|
|
11210
11561
|
roadmap.addCommand(createRoadmapShardCommand());
|
|
11211
11562
|
roadmap.addCommand(createRoadmapUnshardCommand());
|
|
11212
11563
|
roadmap.addCommand(createRoadmapRegenCommand());
|
|
11213
11564
|
roadmap.addCommand(createRoadmapReconcileCommand());
|
|
11565
|
+
roadmap.addCommand(createRoadmapReferencedIssuesCommand());
|
|
11214
11566
|
return roadmap;
|
|
11215
11567
|
}
|
|
11216
11568
|
|
|
11217
11569
|
// src/commands/routing/index.ts
|
|
11218
|
-
import { Command as
|
|
11570
|
+
import { Command as Command93 } from "commander";
|
|
11219
11571
|
|
|
11220
11572
|
// src/commands/routing/config.ts
|
|
11221
|
-
import { Command as
|
|
11573
|
+
import { Command as Command90 } from "commander";
|
|
11222
11574
|
|
|
11223
11575
|
// src/commands/routing/http-client.ts
|
|
11224
11576
|
function orchestratorBase() {
|
|
@@ -11283,7 +11635,7 @@ function renderHuman(data) {
|
|
|
11283
11635
|
}
|
|
11284
11636
|
}
|
|
11285
11637
|
function createConfigCommand() {
|
|
11286
|
-
return new
|
|
11638
|
+
return new Command90("config").description("Print active routing config and resolved fallback chains").option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
|
|
11287
11639
|
const r = await getJson("/api/v1/routing/config");
|
|
11288
11640
|
if (!r.ok) {
|
|
11289
11641
|
if (r.status === 0) {
|
|
@@ -11309,7 +11661,7 @@ function createConfigCommand() {
|
|
|
11309
11661
|
}
|
|
11310
11662
|
|
|
11311
11663
|
// src/commands/routing/trace.ts
|
|
11312
|
-
import { Command as
|
|
11664
|
+
import { Command as Command91 } from "commander";
|
|
11313
11665
|
function buildUseCase(opts) {
|
|
11314
11666
|
if (opts.skill) {
|
|
11315
11667
|
return opts.mode ? { kind: "skill", skillName: opts.skill, cognitiveMode: opts.mode } : { kind: "skill", skillName: opts.skill };
|
|
@@ -11330,7 +11682,7 @@ function renderHuman2(r) {
|
|
|
11330
11682
|
}
|
|
11331
11683
|
}
|
|
11332
11684
|
function createTraceCommand() {
|
|
11333
|
-
return new
|
|
11685
|
+
return new Command91("trace").description("Dry-run a routing decision without dispatching (Spec B F7)").option("--skill <name>", "Skill name to trace").option("--mode <m>", "Cognitive mode to trace (or attach to --skill per spec D12)").option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
|
|
11334
11686
|
const useCase = buildUseCase(opts);
|
|
11335
11687
|
if (!useCase) {
|
|
11336
11688
|
logger.error("Either --skill <name> or --mode <m> is required");
|
|
@@ -11362,7 +11714,7 @@ function createTraceCommand() {
|
|
|
11362
11714
|
}
|
|
11363
11715
|
|
|
11364
11716
|
// src/commands/routing/decisions.ts
|
|
11365
|
-
import { Command as
|
|
11717
|
+
import { Command as Command92 } from "commander";
|
|
11366
11718
|
function summarizeUseCase(uc) {
|
|
11367
11719
|
switch (uc.kind) {
|
|
11368
11720
|
case "skill":
|
|
@@ -11410,7 +11762,7 @@ function buildQuery(opts) {
|
|
|
11410
11762
|
return q ? `?${q}` : "";
|
|
11411
11763
|
}
|
|
11412
11764
|
function createDecisionsCommand() {
|
|
11413
|
-
return new
|
|
11765
|
+
return new Command92("decisions").description("List recent routing decisions from the orchestrator ring buffer (Spec B F8)").option("--skill <name>", "Filter by useCase.skillName").option("--mode <m>", "Filter by useCase.cognitiveMode").option("--backend <name>", "Filter by chosen backendName").option("--last <N>", "Limit to the N most recent decisions").option("--json", "Emit JSON to stdout instead of human-readable text").action(
|
|
11414
11766
|
async (opts) => {
|
|
11415
11767
|
const query = buildQuery(opts);
|
|
11416
11768
|
const r = await getJson(`/api/v1/routing/decisions${query}`);
|
|
@@ -11440,7 +11792,7 @@ function createDecisionsCommand() {
|
|
|
11440
11792
|
|
|
11441
11793
|
// src/commands/routing/index.ts
|
|
11442
11794
|
function createRoutingCommand() {
|
|
11443
|
-
const cmd = new
|
|
11795
|
+
const cmd = new Command93("routing").description(
|
|
11444
11796
|
"Inspect routing config, trace decisions, and read recent dispatches"
|
|
11445
11797
|
);
|
|
11446
11798
|
cmd.addCommand(createConfigCommand());
|
|
@@ -11451,9 +11803,9 @@ function createRoutingCommand() {
|
|
|
11451
11803
|
|
|
11452
11804
|
// src/commands/scan-config.ts
|
|
11453
11805
|
init_dist3();
|
|
11454
|
-
import { Command as
|
|
11455
|
-
import { existsSync as existsSync30, readFileSync as
|
|
11456
|
-
import { join as
|
|
11806
|
+
import { Command as Command94 } from "commander";
|
|
11807
|
+
import { existsSync as existsSync30, readFileSync as readFileSync22, writeFileSync as writeFileSync22 } from "fs";
|
|
11808
|
+
import { join as join49, relative as relative3 } from "path";
|
|
11457
11809
|
var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
|
|
11458
11810
|
function stripHighSeverityPatterns(content, injectionFindings) {
|
|
11459
11811
|
const highLines = /* @__PURE__ */ new Set();
|
|
@@ -11489,7 +11841,7 @@ function scanSingleFile(filePath, targetDir, scanner, options) {
|
|
|
11489
11841
|
if (!existsSync30(filePath)) return null;
|
|
11490
11842
|
let content;
|
|
11491
11843
|
try {
|
|
11492
|
-
content =
|
|
11844
|
+
content = readFileSync22(filePath, "utf8");
|
|
11493
11845
|
} catch {
|
|
11494
11846
|
return null;
|
|
11495
11847
|
}
|
|
@@ -11510,7 +11862,7 @@ async function runScanConfig(targetDir, options) {
|
|
|
11510
11862
|
const scanner = new SecurityScanner(parseSecurityConfig({}));
|
|
11511
11863
|
const results = [];
|
|
11512
11864
|
for (const configFile of CONFIG_FILES) {
|
|
11513
|
-
const result = scanSingleFile(
|
|
11865
|
+
const result = scanSingleFile(join49(targetDir, configFile), targetDir, scanner, options);
|
|
11514
11866
|
if (result) results.push(result);
|
|
11515
11867
|
}
|
|
11516
11868
|
return { exitCode: computeScanExitCode(results), results };
|
|
@@ -11540,7 +11892,7 @@ function formatTextOutput(result) {
|
|
|
11540
11892
|
}
|
|
11541
11893
|
}
|
|
11542
11894
|
function createScanConfigCommand() {
|
|
11543
|
-
const command = new
|
|
11895
|
+
const command = new Command94("scan-config").description(
|
|
11544
11896
|
"Scan CLAUDE.md, AGENTS.md, .gemini/settings.json, and skill.yaml for prompt injection patterns"
|
|
11545
11897
|
).option("--path <dir>", "Target directory to scan (default: cwd)").option("--fix", "Strip high-severity patterns from files in-place").action(async (opts, cmd) => {
|
|
11546
11898
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -11558,7 +11910,7 @@ function createScanConfigCommand() {
|
|
|
11558
11910
|
|
|
11559
11911
|
// src/commands/search.ts
|
|
11560
11912
|
init_dist();
|
|
11561
|
-
import { Command as
|
|
11913
|
+
import { Command as Command95 } from "commander";
|
|
11562
11914
|
function parseFileKinds(raw) {
|
|
11563
11915
|
if (!raw) return void 0;
|
|
11564
11916
|
const set = /* @__PURE__ */ new Set();
|
|
@@ -11579,7 +11931,7 @@ function fmtBytes(n) {
|
|
|
11579
11931
|
return n.toFixed(0);
|
|
11580
11932
|
}
|
|
11581
11933
|
function createSearchCommand() {
|
|
11582
|
-
return new
|
|
11934
|
+
return new Command95("search").description("Full-text search over archived + live session content.").argument(
|
|
11583
11935
|
"<query>",
|
|
11584
11936
|
"FTS5 query (bare words AND-joined; quotes/AND/OR/NOT/column: for advanced syntax)"
|
|
11585
11937
|
).option("-n, --limit <n>", "Max results", "20").option("--archived-only", "Skip live sessions, only search archived ones").option("--json", "Emit JSON to stdout instead of pretty text").option(
|
|
@@ -11639,9 +11991,9 @@ function createSearchCommand() {
|
|
|
11639
11991
|
}
|
|
11640
11992
|
|
|
11641
11993
|
// src/commands/security-craft.ts
|
|
11642
|
-
import { Command as
|
|
11994
|
+
import { Command as Command96 } from "commander";
|
|
11643
11995
|
function createSecurityCraftCommand() {
|
|
11644
|
-
return new
|
|
11996
|
+
return new Command96("security-craft").description(
|
|
11645
11997
|
"LLM-judgment critique of security posture (TS/JS source). Sixth non-design craft-pipeline ceiling skill (the final sub-project). AST-driven signal detection fires only on files with security-relevant constructs; conservative confidence defaults manage the FP risk inherent in judgment-based security."
|
|
11646
11998
|
).option("-f, --files <files...>", "Optional file scope (overrides discovery)").option("-p, --packages <names...>", "Restrict to specific packages under packages/").option("--max-files <n>", "Cap source-file count (default: 100)").option("--max-signals-per-file <n>", "Cap per-file signal critique (default: 10)").action(async (opts, cmd) => {
|
|
11647
11999
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -11707,7 +12059,7 @@ ${file}`);
|
|
|
11707
12059
|
}
|
|
11708
12060
|
|
|
11709
12061
|
// src/commands/setup.ts
|
|
11710
|
-
import { Command as
|
|
12062
|
+
import { Command as Command97 } from "commander";
|
|
11711
12063
|
import * as fs37 from "fs";
|
|
11712
12064
|
import * as os9 from "os";
|
|
11713
12065
|
import * as path61 from "path";
|
|
@@ -12013,7 +12365,7 @@ async function detectLegacyLayout(cwd) {
|
|
|
12013
12365
|
}
|
|
12014
12366
|
async function runInitialGraphScan(cwd) {
|
|
12015
12367
|
try {
|
|
12016
|
-
const { runScan: runScan2 } = await import("./scan-
|
|
12368
|
+
const { runScan: runScan2 } = await import("./scan-IYSVRPD2.js");
|
|
12017
12369
|
const result = await runScan2(cwd);
|
|
12018
12370
|
return {
|
|
12019
12371
|
status: "pass",
|
|
@@ -12052,7 +12404,7 @@ async function runSetup(cwd) {
|
|
|
12052
12404
|
return { steps, success };
|
|
12053
12405
|
}
|
|
12054
12406
|
function createSetupCommand() {
|
|
12055
|
-
return new
|
|
12407
|
+
return new Command97("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
|
|
12056
12408
|
const cwd = process.cwd();
|
|
12057
12409
|
console.log("");
|
|
12058
12410
|
console.log(` ${chalk16.bold("harness setup")}`);
|
|
@@ -12075,7 +12427,7 @@ function createSetupCommand() {
|
|
|
12075
12427
|
|
|
12076
12428
|
// src/commands/share.ts
|
|
12077
12429
|
init_dist3();
|
|
12078
|
-
import { Command as
|
|
12430
|
+
import { Command as Command98 } from "commander";
|
|
12079
12431
|
import * as fs38 from "fs";
|
|
12080
12432
|
import * as path62 from "path";
|
|
12081
12433
|
import { parse as parseYaml3 } from "yaml";
|
|
@@ -12134,16 +12486,16 @@ Create a constraints.yaml in your project root to define what to share.`
|
|
|
12134
12486
|
logger.success(`Bundle written to ${outputPath}`);
|
|
12135
12487
|
}
|
|
12136
12488
|
function createShareCommand() {
|
|
12137
|
-
return new
|
|
12489
|
+
return new Command98("share").description("Extract and publish a constraints bundle from constraints.yaml").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory for the bundle", ".").action(async (projectPath, options) => {
|
|
12138
12490
|
await runShareAction(projectPath, options);
|
|
12139
12491
|
});
|
|
12140
12492
|
}
|
|
12141
12493
|
|
|
12142
12494
|
// src/commands/skill/index.ts
|
|
12143
|
-
import { Command as
|
|
12495
|
+
import { Command as Command106 } from "commander";
|
|
12144
12496
|
|
|
12145
12497
|
// src/commands/skill/list.ts
|
|
12146
|
-
import { Command as
|
|
12498
|
+
import { Command as Command99 } from "commander";
|
|
12147
12499
|
import * as fs39 from "fs";
|
|
12148
12500
|
import * as path63 from "path";
|
|
12149
12501
|
import { parse } from "yaml";
|
|
@@ -12246,7 +12598,7 @@ function printSkillsVerbose(skills) {
|
|
|
12246
12598
|
for (const s of skills) printSkillEntry(s);
|
|
12247
12599
|
}
|
|
12248
12600
|
function createListCommand3() {
|
|
12249
|
-
return new
|
|
12601
|
+
return new Command99("list").description("List available skills").option("--installed", "Show only community-installed skills").option("--local", "Show only project-local skills").option("--all", "Show all skills (default)").action(async (opts, cmd) => {
|
|
12250
12602
|
const globalOpts = cmd.optsWithGlobals();
|
|
12251
12603
|
const skills = collectSkills({ filter: resolveFilter(opts) });
|
|
12252
12604
|
if (globalOpts.json) {
|
|
@@ -12261,13 +12613,13 @@ function createListCommand3() {
|
|
|
12261
12613
|
}
|
|
12262
12614
|
|
|
12263
12615
|
// src/commands/skill/run.ts
|
|
12264
|
-
import { Command as
|
|
12616
|
+
import { Command as Command100 } from "commander";
|
|
12265
12617
|
import * as fs40 from "fs";
|
|
12266
12618
|
import * as path64 from "path";
|
|
12267
12619
|
import { parse as parse2 } from "yaml";
|
|
12268
12620
|
|
|
12269
12621
|
// src/skill/complexity.ts
|
|
12270
|
-
import { execFileSync as
|
|
12622
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
12271
12623
|
function evaluateSignals(signals) {
|
|
12272
12624
|
if (signals.fileCount >= 3) return "thorough";
|
|
12273
12625
|
if (signals.newDir) return "thorough";
|
|
@@ -12279,17 +12631,17 @@ function evaluateSignals(signals) {
|
|
|
12279
12631
|
}
|
|
12280
12632
|
function detectComplexity(projectPath) {
|
|
12281
12633
|
try {
|
|
12282
|
-
const base =
|
|
12634
|
+
const base = execFileSync8("git", ["merge-base", "HEAD", "main"], {
|
|
12283
12635
|
cwd: projectPath,
|
|
12284
12636
|
encoding: "utf-8",
|
|
12285
12637
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12286
12638
|
}).trim();
|
|
12287
|
-
const diffFiles =
|
|
12639
|
+
const diffFiles = execFileSync8("git", ["diff", "--name-only", base], {
|
|
12288
12640
|
cwd: projectPath,
|
|
12289
12641
|
encoding: "utf-8",
|
|
12290
12642
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12291
12643
|
}).trim().split("\n").filter(Boolean);
|
|
12292
|
-
const diffStat =
|
|
12644
|
+
const diffStat = execFileSync8("git", ["diff", "--stat", base], {
|
|
12293
12645
|
cwd: projectPath,
|
|
12294
12646
|
encoding: "utf-8",
|
|
12295
12647
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -12409,7 +12761,7 @@ function resolvePhaseState(metadata, projectPath, phase) {
|
|
|
12409
12761
|
}
|
|
12410
12762
|
async function appendProjectState(content, metadata, projectPath, hasPathOpt) {
|
|
12411
12763
|
if (!metadata?.state.persistent || !hasPathOpt) return content;
|
|
12412
|
-
const { readHarnessState: readHarnessState2, isEmptyHarnessState } = await import("./state-events-
|
|
12764
|
+
const { readHarnessState: readHarnessState2, isEmptyHarnessState } = await import("./state-events-YY5KBZTC.js");
|
|
12413
12765
|
const stateResult = await readHarnessState2(projectPath);
|
|
12414
12766
|
if (!stateResult.ok || isEmptyHarnessState(stateResult.value)) return content;
|
|
12415
12767
|
const stateContent = JSON.stringify(stateResult.value, null, 2);
|
|
@@ -12475,14 +12827,14 @@ async function runSkill(name, opts) {
|
|
|
12475
12827
|
process.exit(ExitCode.SUCCESS);
|
|
12476
12828
|
}
|
|
12477
12829
|
function createRunCommand3() {
|
|
12478
|
-
return new
|
|
12830
|
+
return new Command100("run").description("Run a skill (outputs SKILL.md content with context preamble)").argument("<name>", "Skill name (e.g., harness-tdd)").option("--path <path>", "Project root path for context injection").option("--complexity <level>", "Rigor level: fast, standard, thorough", "standard").option("--phase <name>", "Start at a specific phase (for re-entry)").option("--party", "Enable multi-perspective evaluation").option(
|
|
12479
12831
|
"--backend <name>",
|
|
12480
12832
|
"Spec B: one-shot routing override forwarded to the orchestrator as HARNESS_BACKEND_OVERRIDE"
|
|
12481
12833
|
).action(async (name, opts) => runSkill(name, opts));
|
|
12482
12834
|
}
|
|
12483
12835
|
|
|
12484
12836
|
// src/commands/skill/validate.ts
|
|
12485
|
-
import { Command as
|
|
12837
|
+
import { Command as Command101 } from "commander";
|
|
12486
12838
|
import * as fs41 from "fs";
|
|
12487
12839
|
import * as path65 from "path";
|
|
12488
12840
|
import { parse as parse3 } from "yaml";
|
|
@@ -12546,7 +12898,7 @@ function validateSkillEntry(name, skillsDir, errors) {
|
|
|
12546
12898
|
}
|
|
12547
12899
|
}
|
|
12548
12900
|
function createValidateCommand2() {
|
|
12549
|
-
return new
|
|
12901
|
+
return new Command101("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
|
|
12550
12902
|
const globalOpts = cmd.optsWithGlobals();
|
|
12551
12903
|
const skillsDir = resolveSkillsDir();
|
|
12552
12904
|
if (!fs41.existsSync(skillsDir)) {
|
|
@@ -12576,7 +12928,7 @@ function createValidateCommand2() {
|
|
|
12576
12928
|
}
|
|
12577
12929
|
|
|
12578
12930
|
// src/commands/skill/info.ts
|
|
12579
|
-
import { Command as
|
|
12931
|
+
import { Command as Command102 } from "commander";
|
|
12580
12932
|
import * as fs42 from "fs";
|
|
12581
12933
|
import * as path66 from "path";
|
|
12582
12934
|
import { parse as parse4 } from "yaml";
|
|
@@ -12621,7 +12973,7 @@ function printSkillInfo(skill) {
|
|
|
12621
12973
|
console.log(`Persistent: ${skill.state.persistent}`);
|
|
12622
12974
|
}
|
|
12623
12975
|
function createInfoCommand() {
|
|
12624
|
-
return new
|
|
12976
|
+
return new Command102("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
|
|
12625
12977
|
const globalOpts = cmd.optsWithGlobals();
|
|
12626
12978
|
const loaded = loadSkillMetadata2(name);
|
|
12627
12979
|
if (!loaded.ok) {
|
|
@@ -12638,7 +12990,7 @@ function createInfoCommand() {
|
|
|
12638
12990
|
}
|
|
12639
12991
|
|
|
12640
12992
|
// src/commands/skill/search.ts
|
|
12641
|
-
import { Command as
|
|
12993
|
+
import { Command as Command103 } from "commander";
|
|
12642
12994
|
async function runSearch(query, opts) {
|
|
12643
12995
|
const results = await searchNpmRegistry(query, opts.registry);
|
|
12644
12996
|
return results.filter((r) => {
|
|
@@ -12683,13 +13035,13 @@ async function runSearchAction(query, opts, globalOpts) {
|
|
|
12683
13035
|
}
|
|
12684
13036
|
}
|
|
12685
13037
|
function createSearchCommand2() {
|
|
12686
|
-
return new
|
|
13038
|
+
return new Command103("search").description("Search for community skills on the @harness-skills registry").argument("<query>", "Search query").option("--platform <platform>", "Filter by platform (e.g., claude-code)").option("--trigger <trigger>", "Filter by trigger type (e.g., manual, automatic)").option("--registry <url>", "Use a custom npm registry URL").action(async (query, opts, cmd) => {
|
|
12687
13039
|
await runSearchAction(query, opts, cmd.optsWithGlobals());
|
|
12688
13040
|
});
|
|
12689
13041
|
}
|
|
12690
13042
|
|
|
12691
13043
|
// src/commands/skill/create.ts
|
|
12692
|
-
import { Command as
|
|
13044
|
+
import { Command as Command104 } from "commander";
|
|
12693
13045
|
import * as path67 from "path";
|
|
12694
13046
|
import * as fs43 from "fs";
|
|
12695
13047
|
import YAML from "yaml";
|
|
@@ -12809,7 +13161,7 @@ Next steps:`);
|
|
|
12809
13161
|
logger.info(` 3. Run: harness skills publish`);
|
|
12810
13162
|
}
|
|
12811
13163
|
function createCreateCommand() {
|
|
12812
|
-
return new
|
|
13164
|
+
return new Command104("create").description("Scaffold a new community skill").argument("<name>", "Skill name (kebab-case)").option("--description <desc>", "Skill description").option("--type <type>", "Skill type: rigid or flexible", "flexible").option("--platforms <platforms>", "Comma-separated platforms (default: claude-code)").option("--triggers <triggers>", "Comma-separated triggers (default: manual)").option("--output-dir <dir>", "Output directory (default: agents/skills/claude-code/)").action(async (name, opts, cmd) => {
|
|
12813
13165
|
const globalOpts = cmd.optsWithGlobals();
|
|
12814
13166
|
try {
|
|
12815
13167
|
const result = runCreate(name, {
|
|
@@ -12832,10 +13184,10 @@ function createCreateCommand() {
|
|
|
12832
13184
|
}
|
|
12833
13185
|
|
|
12834
13186
|
// src/commands/skill/publish.ts
|
|
12835
|
-
import { Command as
|
|
13187
|
+
import { Command as Command105 } from "commander";
|
|
12836
13188
|
import * as fs45 from "fs";
|
|
12837
13189
|
import * as path69 from "path";
|
|
12838
|
-
import { execFileSync as
|
|
13190
|
+
import { execFileSync as execFileSync9 } from "child_process";
|
|
12839
13191
|
|
|
12840
13192
|
// src/registry/validator.ts
|
|
12841
13193
|
import * as fs44 from "fs";
|
|
@@ -12989,7 +13341,7 @@ ${skillMdContent}`;
|
|
|
12989
13341
|
if (opts.registry) {
|
|
12990
13342
|
publishArgs.push("--registry", opts.registry);
|
|
12991
13343
|
}
|
|
12992
|
-
|
|
13344
|
+
execFileSync9("npm", publishArgs, {
|
|
12993
13345
|
cwd: skillDir,
|
|
12994
13346
|
stdio: "pipe",
|
|
12995
13347
|
timeout: 6e4
|
|
@@ -13001,7 +13353,7 @@ ${skillMdContent}`;
|
|
|
13001
13353
|
};
|
|
13002
13354
|
}
|
|
13003
13355
|
function createPublishCommand() {
|
|
13004
|
-
return new
|
|
13356
|
+
return new Command105("publish").description("Validate and publish a skill to @harness-skills on npm").option("--dry-run", "Run validation and generate package.json without publishing").option("--dir <dir>", "Skill directory (default: current directory)").option("--registry <url>", "Use a custom npm registry URL").action(async (opts, cmd) => {
|
|
13005
13357
|
const globalOpts = cmd.optsWithGlobals();
|
|
13006
13358
|
const skillDir = opts.dir || process.cwd();
|
|
13007
13359
|
try {
|
|
@@ -13026,7 +13378,7 @@ function createPublishCommand() {
|
|
|
13026
13378
|
|
|
13027
13379
|
// src/commands/skill/index.ts
|
|
13028
13380
|
function createSkillCommand() {
|
|
13029
|
-
const command = new
|
|
13381
|
+
const command = new Command106("skill").description("Skill management commands");
|
|
13030
13382
|
command.addCommand(createListCommand3());
|
|
13031
13383
|
command.addCommand(createRunCommand3());
|
|
13032
13384
|
command.addCommand(createValidateCommand2());
|
|
@@ -13039,7 +13391,7 @@ function createSkillCommand() {
|
|
|
13039
13391
|
|
|
13040
13392
|
// src/commands/snapshot.ts
|
|
13041
13393
|
init_dist3();
|
|
13042
|
-
import { Command as
|
|
13394
|
+
import { Command as Command107 } from "commander";
|
|
13043
13395
|
import { execSync as execSync5 } from "child_process";
|
|
13044
13396
|
import chalk17 from "chalk";
|
|
13045
13397
|
function getCommitHash3(cwd) {
|
|
@@ -13208,7 +13560,7 @@ function registerTrendsCommand(parent) {
|
|
|
13208
13560
|
}
|
|
13209
13561
|
});
|
|
13210
13562
|
}
|
|
13211
|
-
function
|
|
13563
|
+
function registerListCommand2(parent) {
|
|
13212
13564
|
parent.command("list").description("List all captured architecture snapshots").action(async (_opts, cmd) => {
|
|
13213
13565
|
const globalOpts = cmd.optsWithGlobals();
|
|
13214
13566
|
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
@@ -13221,17 +13573,17 @@ function registerListCommand(parent) {
|
|
|
13221
13573
|
});
|
|
13222
13574
|
}
|
|
13223
13575
|
function createSnapshotCommand() {
|
|
13224
|
-
const command = new
|
|
13576
|
+
const command = new Command107("snapshot").description("Architecture timeline snapshot commands");
|
|
13225
13577
|
registerCaptureCommand(command);
|
|
13226
13578
|
registerTrendsCommand(command);
|
|
13227
|
-
|
|
13579
|
+
registerListCommand2(command);
|
|
13228
13580
|
return command;
|
|
13229
13581
|
}
|
|
13230
13582
|
|
|
13231
13583
|
// src/commands/spec-craft.ts
|
|
13232
|
-
import { Command as
|
|
13584
|
+
import { Command as Command108 } from "commander";
|
|
13233
13585
|
function createSpecCraftCommand() {
|
|
13234
|
-
return new
|
|
13586
|
+
return new Command108("spec-craft").description(
|
|
13235
13587
|
"LLM-judgment critique of spec quality (proposals + ADRs). Second craft-pipeline ceiling skill; 7 seed rubrics from the spec-quality canon. Per-section critique."
|
|
13236
13588
|
).option("-f, --files <files...>", "Optional spec file/glob scope").option("-k, --kinds <kinds...>", "Restrict to proposal / adr (default: both)").option("-s, --sections <names...>", "Restrict to specific canonical section names").option("--max-files <n>", "Cap doc count (default: 50)").option("--max-sections-per-file <n>", "Cap per-doc section critique (default: 10)").action(async (opts, cmd) => {
|
|
13237
13589
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -13299,7 +13651,7 @@ ${file}`);
|
|
|
13299
13651
|
|
|
13300
13652
|
// src/commands/stale-constraints.ts
|
|
13301
13653
|
init_dist3();
|
|
13302
|
-
import { Command as
|
|
13654
|
+
import { Command as Command109 } from "commander";
|
|
13303
13655
|
import chalk18 from "chalk";
|
|
13304
13656
|
var CATEGORIES = [
|
|
13305
13657
|
"circular-deps",
|
|
@@ -13386,7 +13738,7 @@ async function runStaleConstraintsCommand(options) {
|
|
|
13386
13738
|
);
|
|
13387
13739
|
}
|
|
13388
13740
|
function createStaleConstraintsCommand() {
|
|
13389
|
-
return new
|
|
13741
|
+
return new Command109("stale-constraints").description(
|
|
13390
13742
|
"Detect architectural constraints not violated within a window (candidates for removal)"
|
|
13391
13743
|
).option(
|
|
13392
13744
|
"--window <days>",
|
|
@@ -13404,10 +13756,10 @@ function createStaleConstraintsCommand() {
|
|
|
13404
13756
|
}
|
|
13405
13757
|
|
|
13406
13758
|
// src/commands/state/index.ts
|
|
13407
|
-
import { Command as
|
|
13759
|
+
import { Command as Command114 } from "commander";
|
|
13408
13760
|
|
|
13409
13761
|
// src/commands/state/show.ts
|
|
13410
|
-
import { Command as
|
|
13762
|
+
import { Command as Command110 } from "commander";
|
|
13411
13763
|
import * as path70 from "path";
|
|
13412
13764
|
function printStateText(state, stream) {
|
|
13413
13765
|
if (stream) console.log(`Stream: ${stream}`);
|
|
@@ -13432,7 +13784,7 @@ function printStateProgress(progress) {
|
|
|
13432
13784
|
}
|
|
13433
13785
|
}
|
|
13434
13786
|
function createShowCommand() {
|
|
13435
|
-
return new
|
|
13787
|
+
return new Command110("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
|
|
13436
13788
|
const globalOpts = cmd.optsWithGlobals();
|
|
13437
13789
|
const result = await readHarnessState(path70.resolve(opts.path), { stream: opts.stream });
|
|
13438
13790
|
if (!result.ok) {
|
|
@@ -13450,7 +13802,7 @@ function createShowCommand() {
|
|
|
13450
13802
|
|
|
13451
13803
|
// src/commands/state/reset.ts
|
|
13452
13804
|
init_dist3();
|
|
13453
|
-
import { Command as
|
|
13805
|
+
import { Command as Command111 } from "commander";
|
|
13454
13806
|
import * as path71 from "path";
|
|
13455
13807
|
import * as readline3 from "readline";
|
|
13456
13808
|
async function confirmReset() {
|
|
@@ -13476,15 +13828,15 @@ async function runReset(opts) {
|
|
|
13476
13828
|
process.exit(ExitCode.SUCCESS);
|
|
13477
13829
|
}
|
|
13478
13830
|
function createResetCommand() {
|
|
13479
|
-
return new
|
|
13831
|
+
return new Command111("reset").description("Reset project state (truncates the event log to a fresh default)").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").option("--yes", "Skip confirmation prompt").action(async (opts) => runReset(opts));
|
|
13480
13832
|
}
|
|
13481
13833
|
|
|
13482
13834
|
// src/commands/state/learn.ts
|
|
13483
13835
|
init_dist3();
|
|
13484
|
-
import { Command as
|
|
13836
|
+
import { Command as Command112 } from "commander";
|
|
13485
13837
|
import * as path72 from "path";
|
|
13486
13838
|
function createLearnCommand() {
|
|
13487
|
-
return new
|
|
13839
|
+
return new Command112("learn").description("Append a learning to .harness/learnings.md").argument("<message>", "The learning to record").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (message, opts, _cmd) => {
|
|
13488
13840
|
const projectPath = path72.resolve(opts.path);
|
|
13489
13841
|
const result = await appendLearning(projectPath, message, void 0, void 0, opts.stream);
|
|
13490
13842
|
if (!result.ok) {
|
|
@@ -13499,7 +13851,7 @@ function createLearnCommand() {
|
|
|
13499
13851
|
|
|
13500
13852
|
// src/commands/state/streams.ts
|
|
13501
13853
|
init_dist3();
|
|
13502
|
-
import { Command as
|
|
13854
|
+
import { Command as Command113 } from "commander";
|
|
13503
13855
|
import * as path73 from "path";
|
|
13504
13856
|
async function runListStreams(opts, globalOpts) {
|
|
13505
13857
|
const projectPath = path73.resolve(opts.path);
|
|
@@ -13550,7 +13902,7 @@ async function runActivateStream(name, opts) {
|
|
|
13550
13902
|
process.exit(ExitCode.SUCCESS);
|
|
13551
13903
|
}
|
|
13552
13904
|
function createStreamsCommand() {
|
|
13553
|
-
const command = new
|
|
13905
|
+
const command = new Command113("streams").description("Manage state streams");
|
|
13554
13906
|
command.command("list").description("List all known streams").option("--path <path>", "Project root path", ".").action(async (opts, cmd) => runListStreams(opts, cmd.optsWithGlobals()));
|
|
13555
13907
|
command.command("create <name>").description("Create a new stream").option("--path <path>", "Project root path", ".").option("--branch <branch>", "Associate with a git branch").action(async (name, opts) => runCreateStream(name, opts));
|
|
13556
13908
|
command.command("archive <name>").description("Archive a stream").option("--path <path>", "Project root path", ".").action(async (name, opts) => runArchiveStream(name, opts));
|
|
@@ -13560,7 +13912,7 @@ function createStreamsCommand() {
|
|
|
13560
13912
|
|
|
13561
13913
|
// src/commands/state/index.ts
|
|
13562
13914
|
function createStateCommand() {
|
|
13563
|
-
const command = new
|
|
13915
|
+
const command = new Command114("state").description("Project state management commands");
|
|
13564
13916
|
command.addCommand(createShowCommand());
|
|
13565
13917
|
command.addCommand(createResetCommand());
|
|
13566
13918
|
command.addCommand(createLearnCommand());
|
|
@@ -13571,7 +13923,7 @@ function createStateCommand() {
|
|
|
13571
13923
|
// src/commands/sync-analyses.ts
|
|
13572
13924
|
import * as fs46 from "fs";
|
|
13573
13925
|
import * as path74 from "path";
|
|
13574
|
-
import { Command as
|
|
13926
|
+
import { Command as Command115 } from "commander";
|
|
13575
13927
|
init_dist3();
|
|
13576
13928
|
function isValidRecord(record) {
|
|
13577
13929
|
return typeof record.issueId === "string" && !!record.issueId && typeof record.identifier === "string" && !!record.identifier && typeof record.analyzedAt === "string" && !/[/\\]/.test(record.issueId);
|
|
@@ -13696,7 +14048,7 @@ async function runSyncAnalyses(opts) {
|
|
|
13696
14048
|
return;
|
|
13697
14049
|
}
|
|
13698
14050
|
const { AnalysisArchive, loadPublishedIndex: loadPublishedIndex2, savePublishedIndex: savePublishedIndex2 } = await import("@harness-engineering/orchestrator");
|
|
13699
|
-
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-
|
|
14051
|
+
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-MCTEX5QH.js");
|
|
13700
14052
|
const adapter = new GitHubIssuesSyncAdapter2({ token, config: trackerConfig });
|
|
13701
14053
|
const archive = new AnalysisArchive(path74.join(projectPath, ".harness", "analyses"));
|
|
13702
14054
|
const publishedIndex = loadPublishedIndex2(projectPath);
|
|
@@ -13718,7 +14070,7 @@ async function runSyncAnalyses(opts) {
|
|
|
13718
14070
|
}
|
|
13719
14071
|
}
|
|
13720
14072
|
function createSyncAnalysesCommand() {
|
|
13721
|
-
const command = new
|
|
14073
|
+
const command = new Command115("sync-analyses").description(
|
|
13722
14074
|
"Pull published intelligence analyses from the external issue tracker into the local .harness/analyses/ directory"
|
|
13723
14075
|
).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
13724
14076
|
try {
|
|
@@ -13732,7 +14084,7 @@ function createSyncAnalysesCommand() {
|
|
|
13732
14084
|
}
|
|
13733
14085
|
|
|
13734
14086
|
// src/commands/sync-main.ts
|
|
13735
|
-
import { Command as
|
|
14087
|
+
import { Command as Command116 } from "commander";
|
|
13736
14088
|
import * as path75 from "path";
|
|
13737
14089
|
import {
|
|
13738
14090
|
syncMain as defaultSyncMain
|
|
@@ -13763,7 +14115,7 @@ function formatHuman2(r) {
|
|
|
13763
14115
|
}
|
|
13764
14116
|
}
|
|
13765
14117
|
function createSyncMainCommand() {
|
|
13766
|
-
return new
|
|
14118
|
+
return new Command116("sync-main").description("Fast-forward the local default branch from origin (no-op on conflict)").option("--json", "Emit a SyncMainResult JSON object", false).option("--path <path>", "Project root path", ".").action(async (opts) => {
|
|
13767
14119
|
const cwd = path75.resolve(opts.path ?? ".");
|
|
13768
14120
|
const exitCode = await runSyncMain({ cwd, json: Boolean(opts.json) });
|
|
13769
14121
|
process.exit(exitCode);
|
|
@@ -13772,7 +14124,7 @@ function createSyncMainCommand() {
|
|
|
13772
14124
|
|
|
13773
14125
|
// src/commands/taint.ts
|
|
13774
14126
|
init_dist3();
|
|
13775
|
-
import { Command as
|
|
14127
|
+
import { Command as Command117 } from "commander";
|
|
13776
14128
|
function getProjectRoot() {
|
|
13777
14129
|
return process.cwd();
|
|
13778
14130
|
}
|
|
@@ -13844,18 +14196,18 @@ function registerStatusCommand(taint) {
|
|
|
13844
14196
|
});
|
|
13845
14197
|
}
|
|
13846
14198
|
function createTaintCommand() {
|
|
13847
|
-
const taint = new
|
|
14199
|
+
const taint = new Command117("taint").description("Manage sentinel session taint state");
|
|
13848
14200
|
registerClearCommand(taint);
|
|
13849
14201
|
registerStatusCommand(taint);
|
|
13850
14202
|
return taint;
|
|
13851
14203
|
}
|
|
13852
14204
|
|
|
13853
14205
|
// src/commands/telemetry/index.ts
|
|
13854
|
-
import { Command as
|
|
14206
|
+
import { Command as Command121 } from "commander";
|
|
13855
14207
|
|
|
13856
14208
|
// src/commands/telemetry/identify.ts
|
|
13857
14209
|
init_dist3();
|
|
13858
|
-
import { Command as
|
|
14210
|
+
import { Command as Command118 } from "commander";
|
|
13859
14211
|
import * as fs47 from "fs";
|
|
13860
14212
|
import * as path76 from "path";
|
|
13861
14213
|
function telemetryFilePath(cwd) {
|
|
@@ -13879,7 +14231,7 @@ function printIdentity(identity) {
|
|
|
13879
14231
|
}
|
|
13880
14232
|
}
|
|
13881
14233
|
function createIdentifyCommand() {
|
|
13882
|
-
const cmd = new
|
|
14234
|
+
const cmd = new Command118("identify").description("Set or clear telemetry identity fields in .harness/telemetry.json").option("--project <name>", "Project name").option("--team <name>", "Team name").option("--alias <name>", "User alias").option("--clear", "Remove all identity fields").action((opts) => {
|
|
13883
14235
|
const cwd = process.cwd();
|
|
13884
14236
|
if (opts.clear) {
|
|
13885
14237
|
writeTelemetryFile(cwd, { identity: {} });
|
|
@@ -13904,7 +14256,7 @@ function createIdentifyCommand() {
|
|
|
13904
14256
|
|
|
13905
14257
|
// src/commands/telemetry/status.ts
|
|
13906
14258
|
init_dist3();
|
|
13907
|
-
import { Command as
|
|
14259
|
+
import { Command as Command119 } from "commander";
|
|
13908
14260
|
function gatherEnvOverrides() {
|
|
13909
14261
|
const overrides = {};
|
|
13910
14262
|
if (process.env.DO_NOT_TRACK) overrides.DO_NOT_TRACK = process.env.DO_NOT_TRACK;
|
|
@@ -13946,7 +14298,7 @@ function printHumanStatus(result) {
|
|
|
13946
14298
|
printEnvOverrides(result.envOverrides);
|
|
13947
14299
|
}
|
|
13948
14300
|
function createStatusCommand() {
|
|
13949
|
-
const cmd = new
|
|
14301
|
+
const cmd = new Command119("status").description("Show current telemetry consent state, install ID, and identity").option("--json", "Output as JSON").action((opts) => {
|
|
13950
14302
|
const cwd = process.cwd();
|
|
13951
14303
|
const envOverrides = gatherEnvOverrides();
|
|
13952
14304
|
const consent = resolveConsent(cwd, void 0);
|
|
@@ -13979,11 +14331,11 @@ function createStatusCommand() {
|
|
|
13979
14331
|
|
|
13980
14332
|
// src/commands/telemetry/test.ts
|
|
13981
14333
|
init_dist3();
|
|
13982
|
-
import { Command as
|
|
14334
|
+
import { Command as Command120 } from "commander";
|
|
13983
14335
|
|
|
13984
14336
|
// src/bin/command-telemetry.ts
|
|
13985
|
-
import { existsSync as existsSync43, readFileSync as
|
|
13986
|
-
import { join as
|
|
14337
|
+
import { existsSync as existsSync43, readFileSync as readFileSync32, mkdirSync as mkdirSync22, appendFileSync, writeFileSync as writeFileSync28 } from "fs";
|
|
14338
|
+
import { join as join63, parse as parsePath, resolve as resolve45 } from "path";
|
|
13987
14339
|
import { spawn as spawn2 } from "child_process";
|
|
13988
14340
|
var POSTHOG_API_KEY = "phc_wNTdCMcfJXZPgdNeDociZW6vwoGGo4nb7vqEfWThFfsG";
|
|
13989
14341
|
var EXCLUDED_COMMANDS = /* @__PURE__ */ new Set(["help", "completion"]);
|
|
@@ -13991,7 +14343,7 @@ function findProjectRoot(cwd) {
|
|
|
13991
14343
|
let dir = resolve45(cwd);
|
|
13992
14344
|
const { root } = parsePath(dir);
|
|
13993
14345
|
while (dir !== root) {
|
|
13994
|
-
if (existsSync43(
|
|
14346
|
+
if (existsSync43(join63(dir, "harness.config.json"))) return dir;
|
|
13995
14347
|
dir = resolve45(dir, "..");
|
|
13996
14348
|
}
|
|
13997
14349
|
return cwd;
|
|
@@ -14029,7 +14381,7 @@ function resolveCommandName(cmd) {
|
|
|
14029
14381
|
}
|
|
14030
14382
|
function writeCommandRecordSync(cwd, command, duration, outcome) {
|
|
14031
14383
|
try {
|
|
14032
|
-
const metricsDir =
|
|
14384
|
+
const metricsDir = join63(cwd, ".harness", "metrics");
|
|
14033
14385
|
mkdirSync22(metricsDir, { recursive: true });
|
|
14034
14386
|
const record = {
|
|
14035
14387
|
skill: command,
|
|
@@ -14039,16 +14391,16 @@ function writeCommandRecordSync(cwd, command, duration, outcome) {
|
|
|
14039
14391
|
outcome,
|
|
14040
14392
|
phasesReached: []
|
|
14041
14393
|
};
|
|
14042
|
-
const adoptionFile =
|
|
14394
|
+
const adoptionFile = join63(metricsDir, "adoption.jsonl");
|
|
14043
14395
|
appendFileSync(adoptionFile, JSON.stringify(record) + "\n");
|
|
14044
14396
|
} catch {
|
|
14045
14397
|
}
|
|
14046
14398
|
}
|
|
14047
14399
|
function isTelemetryDisabledByConfig(cwd) {
|
|
14048
|
-
const configPath =
|
|
14400
|
+
const configPath = join63(cwd, "harness.config.json");
|
|
14049
14401
|
if (!existsSync43(configPath)) return false;
|
|
14050
14402
|
try {
|
|
14051
|
-
const config = JSON.parse(
|
|
14403
|
+
const config = JSON.parse(readFileSync32(configPath, "utf-8"));
|
|
14052
14404
|
return config?.telemetry?.enabled === false;
|
|
14053
14405
|
} catch {
|
|
14054
14406
|
return false;
|
|
@@ -14060,10 +14412,10 @@ function isTelemetryOptedOut(cwd) {
|
|
|
14060
14412
|
}
|
|
14061
14413
|
function flushTelemetryBackground(cwd) {
|
|
14062
14414
|
try {
|
|
14063
|
-
const adoptionFile =
|
|
14415
|
+
const adoptionFile = join63(cwd, ".harness", "metrics", "adoption.jsonl");
|
|
14064
14416
|
if (!existsSync43(adoptionFile)) return;
|
|
14065
14417
|
if (isTelemetryOptedOut(cwd)) return;
|
|
14066
|
-
const reporterPath =
|
|
14418
|
+
const reporterPath = join63(cwd, ".harness", "hooks", "telemetry-reporter.js");
|
|
14067
14419
|
if (!existsSync43(reporterPath)) return;
|
|
14068
14420
|
const child = spawn2(process.execPath, [reporterPath], {
|
|
14069
14421
|
cwd,
|
|
@@ -14101,7 +14453,7 @@ function reportTestSuccess(status, distinctId, identity) {
|
|
|
14101
14453
|
if (identity.team) logger.info(` team: ${identity.team}`);
|
|
14102
14454
|
}
|
|
14103
14455
|
function createTestCommand() {
|
|
14104
|
-
return new
|
|
14456
|
+
return new Command120("test").description("Send a test event to PostHog and verify connectivity").action(async () => {
|
|
14105
14457
|
const cwd = process.cwd();
|
|
14106
14458
|
const consent = resolveConsent(cwd, void 0);
|
|
14107
14459
|
if (!consent.allowed) {
|
|
@@ -14138,7 +14490,7 @@ function createTestCommand() {
|
|
|
14138
14490
|
|
|
14139
14491
|
// src/commands/telemetry/index.ts
|
|
14140
14492
|
function createTelemetryCommand() {
|
|
14141
|
-
const command = new
|
|
14493
|
+
const command = new Command121("telemetry").description("Telemetry identity and status management");
|
|
14142
14494
|
command.addCommand(createIdentifyCommand());
|
|
14143
14495
|
command.addCommand(createStatusCommand());
|
|
14144
14496
|
command.addCommand(createTestCommand());
|
|
@@ -14146,9 +14498,9 @@ function createTelemetryCommand() {
|
|
|
14146
14498
|
}
|
|
14147
14499
|
|
|
14148
14500
|
// src/commands/test-craft.ts
|
|
14149
|
-
import { Command as
|
|
14501
|
+
import { Command as Command122 } from "commander";
|
|
14150
14502
|
function createTestCraftCommand() {
|
|
14151
|
-
return new
|
|
14503
|
+
return new Command122("test-craft").description(
|
|
14152
14504
|
"LLM-judgment critique of test quality across vitest/jest/mocha/playwright. Fourth craft-pipeline ceiling skill. Per-test critique with best-effort source pairing."
|
|
14153
14505
|
).option("-f, --files <files...>", "Optional test file/glob scope").option("--frameworks <names...>", "Restrict to: vitest / jest / mocha / playwright").option("--max-files <n>", "Cap test file count (default: 100)").option("--max-tests-per-file <n>", "Cap per-file test critique (default: 20)").option("--no-source-pair", "Skip source-pairing resolution").action(async (opts, cmd) => {
|
|
14154
14506
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -14218,7 +14570,7 @@ ${file}`);
|
|
|
14218
14570
|
}
|
|
14219
14571
|
|
|
14220
14572
|
// src/commands/traceability.ts
|
|
14221
|
-
import { Command as
|
|
14573
|
+
import { Command as Command123 } from "commander";
|
|
14222
14574
|
import chalk19 from "chalk";
|
|
14223
14575
|
function confidenceLabel(maxConfidence) {
|
|
14224
14576
|
if (maxConfidence >= 0.8) return "explicit";
|
|
@@ -14260,9 +14612,11 @@ function buildFilterOptions(options) {
|
|
|
14260
14612
|
}
|
|
14261
14613
|
function handleNoStore2(mode) {
|
|
14262
14614
|
if (mode === OutputMode.JSON) {
|
|
14263
|
-
console.log(
|
|
14615
|
+
console.log(
|
|
14616
|
+
JSON.stringify({ error: "No knowledge graph found. Run `harness graph scan` first." })
|
|
14617
|
+
);
|
|
14264
14618
|
} else {
|
|
14265
|
-
logger.error("No knowledge graph found. Run `harness scan` first.");
|
|
14619
|
+
logger.error("No knowledge graph found. Run `harness graph scan` first.");
|
|
14266
14620
|
}
|
|
14267
14621
|
process.exit(ExitCode.ERROR);
|
|
14268
14622
|
}
|
|
@@ -14271,11 +14625,13 @@ function handleEmptyResults(mode) {
|
|
|
14271
14625
|
console.log(
|
|
14272
14626
|
JSON.stringify({
|
|
14273
14627
|
results: [],
|
|
14274
|
-
message: "No requirements found in graph. Run `harness scan` to ingest spec requirements."
|
|
14628
|
+
message: "No requirements found in graph. Run `harness graph scan` to ingest spec requirements."
|
|
14275
14629
|
})
|
|
14276
14630
|
);
|
|
14277
14631
|
} else if (mode !== OutputMode.QUIET) {
|
|
14278
|
-
logger.info(
|
|
14632
|
+
logger.info(
|
|
14633
|
+
"No requirements found in graph. Run `harness graph scan` to ingest spec requirements."
|
|
14634
|
+
);
|
|
14279
14635
|
}
|
|
14280
14636
|
process.exit(ExitCode.SUCCESS);
|
|
14281
14637
|
}
|
|
@@ -14339,7 +14695,7 @@ async function runTraceability(options) {
|
|
|
14339
14695
|
const projectPath = process.cwd();
|
|
14340
14696
|
const store = await loadGraphStore(projectPath);
|
|
14341
14697
|
if (!store) handleNoStore2(mode);
|
|
14342
|
-
const graphModule = await import("./dist-
|
|
14698
|
+
const graphModule = await import("./dist-DWBTZXR5.js");
|
|
14343
14699
|
const filterOptions = buildFilterOptions(options);
|
|
14344
14700
|
const results = graphModule.queryTraceability(store, filterOptions);
|
|
14345
14701
|
if (results.length === 0) handleEmptyResults(mode);
|
|
@@ -14354,7 +14710,7 @@ async function runTraceability(options) {
|
|
|
14354
14710
|
process.exit(ExitCode.SUCCESS);
|
|
14355
14711
|
}
|
|
14356
14712
|
function createTraceabilityCommand() {
|
|
14357
|
-
return new
|
|
14713
|
+
return new Command123("traceability").description("Show spec-to-implementation traceability from the knowledge graph").option("--spec <path>", "Filter by spec file path").option("--feature <name>", "Filter by feature name").action(async (opts, cmd) => {
|
|
14358
14714
|
const globalOpts = cmd.optsWithGlobals();
|
|
14359
14715
|
await runTraceability({
|
|
14360
14716
|
spec: opts.spec,
|
|
@@ -14368,7 +14724,7 @@ function createTraceabilityCommand() {
|
|
|
14368
14724
|
|
|
14369
14725
|
// src/commands/uninstall.ts
|
|
14370
14726
|
import * as path77 from "path";
|
|
14371
|
-
import { Command as
|
|
14727
|
+
import { Command as Command124 } from "commander";
|
|
14372
14728
|
async function runUninstall(skillName, options) {
|
|
14373
14729
|
const packageName = resolvePackageName(skillName);
|
|
14374
14730
|
const shortName = extractSkillName(packageName);
|
|
@@ -14405,7 +14761,7 @@ async function runUninstall(skillName, options) {
|
|
|
14405
14761
|
return result;
|
|
14406
14762
|
}
|
|
14407
14763
|
function createUninstallCommand() {
|
|
14408
|
-
const cmd = new
|
|
14764
|
+
const cmd = new Command124("uninstall");
|
|
14409
14765
|
cmd.description("Uninstall a community skill").argument("<skill>", "Skill name or @harness-skills/scoped package name").option("--force", "Remove even if other skills depend on this one").action(async (skill, opts) => {
|
|
14410
14766
|
try {
|
|
14411
14767
|
const result = await runUninstall(skill, opts);
|
|
@@ -14427,7 +14783,7 @@ function createUninstallCommand() {
|
|
|
14427
14783
|
init_dist3();
|
|
14428
14784
|
import * as fs48 from "fs/promises";
|
|
14429
14785
|
import * as path78 from "path";
|
|
14430
|
-
import { Command as
|
|
14786
|
+
import { Command as Command125 } from "commander";
|
|
14431
14787
|
async function runUninstallConstraints(options) {
|
|
14432
14788
|
const { packageName, configPath, lockfilePath } = options;
|
|
14433
14789
|
const lockfileResult = await readLockfile(lockfilePath);
|
|
@@ -14484,7 +14840,7 @@ async function runUninstallConstraints(options) {
|
|
|
14484
14840
|
};
|
|
14485
14841
|
}
|
|
14486
14842
|
function createUninstallConstraintsCommand() {
|
|
14487
|
-
const cmd = new
|
|
14843
|
+
const cmd = new Command125("uninstall-constraints");
|
|
14488
14844
|
cmd.description("Remove a previously installed constraints package").argument("<name>", "Name of the constraint package to uninstall").option("-c, --config <path>", "Path to harness.config.json").action(async (name, opts) => {
|
|
14489
14845
|
let configPath;
|
|
14490
14846
|
if (opts.config) {
|
|
@@ -14524,10 +14880,10 @@ function createUninstallConstraintsCommand() {
|
|
|
14524
14880
|
|
|
14525
14881
|
// src/commands/update.ts
|
|
14526
14882
|
init_dist3();
|
|
14527
|
-
import { Command as
|
|
14528
|
-
import { execFile as execFile2, execFileSync as
|
|
14529
|
-
import { realpathSync, existsSync as existsSync44, readFileSync as
|
|
14530
|
-
import { dirname as dirname24, join as
|
|
14883
|
+
import { Command as Command126 } from "commander";
|
|
14884
|
+
import { execFile as execFile2, execFileSync as execFileSync10 } from "child_process";
|
|
14885
|
+
import { realpathSync, existsSync as existsSync44, readFileSync as readFileSync33 } from "fs";
|
|
14886
|
+
import { dirname as dirname24, join as join66 } from "path";
|
|
14531
14887
|
import { promisify as promisify2 } from "util";
|
|
14532
14888
|
import readline4 from "readline";
|
|
14533
14889
|
import chalk20 from "chalk";
|
|
@@ -14567,7 +14923,7 @@ async function getLatestVersionAsync(pkg) {
|
|
|
14567
14923
|
function getInstalledVersions(pm, packages) {
|
|
14568
14924
|
const versions = {};
|
|
14569
14925
|
try {
|
|
14570
|
-
const output =
|
|
14926
|
+
const output = execFileSync10(pm, ["list", "-g", "--json"], {
|
|
14571
14927
|
encoding: "utf-8",
|
|
14572
14928
|
timeout: 15e3
|
|
14573
14929
|
});
|
|
@@ -14588,7 +14944,7 @@ function getInstalledVersions(pm, packages) {
|
|
|
14588
14944
|
}
|
|
14589
14945
|
function getInstalledPackages(pm) {
|
|
14590
14946
|
try {
|
|
14591
|
-
const output =
|
|
14947
|
+
const output = execFileSync10(pm, ["list", "-g", "--json"], {
|
|
14592
14948
|
encoding: "utf-8",
|
|
14593
14949
|
timeout: 15e3
|
|
14594
14950
|
});
|
|
@@ -14618,9 +14974,9 @@ function prompt3(question) {
|
|
|
14618
14974
|
function findPackageDir(resolvedBin) {
|
|
14619
14975
|
let dir = dirname24(resolvedBin);
|
|
14620
14976
|
for (let i = 0; i < 6; i++) {
|
|
14621
|
-
if (existsSync44(
|
|
14977
|
+
if (existsSync44(join66(dir, "package.json"))) {
|
|
14622
14978
|
try {
|
|
14623
|
-
const pkg = JSON.parse(
|
|
14979
|
+
const pkg = JSON.parse(readFileSync33(join66(dir, "package.json"), "utf-8"));
|
|
14624
14980
|
if (pkg?.name === CLI_PACKAGE) return dir;
|
|
14625
14981
|
} catch {
|
|
14626
14982
|
}
|
|
@@ -14643,7 +14999,7 @@ function findAllInstalls() {
|
|
|
14643
14999
|
const args = isWindows ? ["harness"] : ["-a", "harness"];
|
|
14644
15000
|
let output;
|
|
14645
15001
|
try {
|
|
14646
|
-
const raw =
|
|
15002
|
+
const raw = execFileSync10(cmd, args, { encoding: "utf-8", timeout: 5e3 });
|
|
14647
15003
|
if (typeof raw !== "string") return [];
|
|
14648
15004
|
output = raw;
|
|
14649
15005
|
} catch {
|
|
@@ -14665,7 +15021,7 @@ function findAllInstalls() {
|
|
|
14665
15021
|
if (!packageDir) continue;
|
|
14666
15022
|
let version = null;
|
|
14667
15023
|
try {
|
|
14668
|
-
const pkg = JSON.parse(
|
|
15024
|
+
const pkg = JSON.parse(readFileSync33(join66(packageDir, "package.json"), "utf-8"));
|
|
14669
15025
|
if (typeof pkg?.version === "string") version = pkg.version;
|
|
14670
15026
|
} catch {
|
|
14671
15027
|
}
|
|
@@ -14720,7 +15076,7 @@ async function offerCleanupOfOtherInstalls(activeDir) {
|
|
|
14720
15076
|
}
|
|
14721
15077
|
try {
|
|
14722
15078
|
logger.info(`Uninstalling: ${cmd.display}`);
|
|
14723
|
-
|
|
15079
|
+
execFileSync10(cmd.bin, cmd.args, { stdio: "inherit", timeout: 12e4 });
|
|
14724
15080
|
} catch {
|
|
14725
15081
|
logger.warn(`Uninstall failed for ${cmd.install.binPath}.`);
|
|
14726
15082
|
console.log(` Run manually: ${chalk20.cyan(cmd.display)}`);
|
|
@@ -14758,12 +15114,12 @@ async function ensureTelemetryIfNeeded() {
|
|
|
14758
15114
|
}
|
|
14759
15115
|
function refreshHooks() {
|
|
14760
15116
|
const cwd = process.cwd();
|
|
14761
|
-
const configPath =
|
|
15117
|
+
const configPath = join66(cwd, "harness.config.json");
|
|
14762
15118
|
if (!existsSync44(configPath)) return;
|
|
14763
15119
|
let profile = "standard";
|
|
14764
|
-
const profilePath =
|
|
15120
|
+
const profilePath = join66(cwd, ".harness", "hooks", "profile.json");
|
|
14765
15121
|
try {
|
|
14766
|
-
const data = JSON.parse(
|
|
15122
|
+
const data = JSON.parse(readFileSync33(profilePath, "utf-8"));
|
|
14767
15123
|
if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
|
|
14768
15124
|
profile = data.profile;
|
|
14769
15125
|
}
|
|
@@ -14780,7 +15136,7 @@ function refreshHooks() {
|
|
|
14780
15136
|
function runLocalGraphScan() {
|
|
14781
15137
|
try {
|
|
14782
15138
|
logger.info("Scanning codebase to rebuild knowledge graph...");
|
|
14783
|
-
|
|
15139
|
+
execFileSync10("harness", ["graph", "scan", "."], { stdio: "inherit" });
|
|
14784
15140
|
} catch {
|
|
14785
15141
|
logger.warn("Graph scan failed. Run manually:");
|
|
14786
15142
|
console.log(` ${chalk20.cyan("harness graph scan .")}`);
|
|
@@ -14795,7 +15151,7 @@ async function offerRegeneration() {
|
|
|
14795
15151
|
const scopeAnswer = await prompt3("Generate for (G)lobal or (l)ocal project? (G/l) ");
|
|
14796
15152
|
const isGlobal = scopeAnswer !== "l" && scopeAnswer !== "local";
|
|
14797
15153
|
try {
|
|
14798
|
-
|
|
15154
|
+
execFileSync10("harness", ["generate", ...isGlobal ? ["--global"] : []], {
|
|
14799
15155
|
stdio: "inherit"
|
|
14800
15156
|
});
|
|
14801
15157
|
} catch {
|
|
@@ -14875,7 +15231,7 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
14875
15231
|
}
|
|
14876
15232
|
try {
|
|
14877
15233
|
logger.info("Updating packages...");
|
|
14878
|
-
|
|
15234
|
+
execFileSync10(pm, ["install", "-g", ...installPkgs], { stdio: "inherit", timeout: 12e4 });
|
|
14879
15235
|
console.log("");
|
|
14880
15236
|
logger.success("Update complete");
|
|
14881
15237
|
invalidateCheckState();
|
|
@@ -14892,7 +15248,7 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
14892
15248
|
process.exit(ExitCode.SUCCESS);
|
|
14893
15249
|
}
|
|
14894
15250
|
function createUpdateCommand() {
|
|
14895
|
-
return new
|
|
15251
|
+
return new Command126("update").description("Update all @harness-engineering packages to the latest version").option("--version <semver>", "Pin @harness-engineering/cli to a specific version").option("--force", "Force update even if versions match").option(
|
|
14896
15252
|
"--regenerate",
|
|
14897
15253
|
"Only regenerate slash commands and agent definitions (skip package updates)"
|
|
14898
15254
|
).action(async (opts, cmd) => {
|
|
@@ -14902,9 +15258,9 @@ function createUpdateCommand() {
|
|
|
14902
15258
|
}
|
|
14903
15259
|
|
|
14904
15260
|
// src/commands/usage.ts
|
|
14905
|
-
import { Command as
|
|
15261
|
+
import { Command as Command127 } from "commander";
|
|
14906
15262
|
async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
|
|
14907
|
-
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-
|
|
15263
|
+
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-MCTEX5QH.js");
|
|
14908
15264
|
const records = readCostRecords(cwd);
|
|
14909
15265
|
if (includeClaudeSessions) {
|
|
14910
15266
|
const ccRecords = parseCCRecords();
|
|
@@ -14997,7 +15353,7 @@ function registerDailyCommand(usage) {
|
|
|
14997
15353
|
else logger.info("No usage data found. Run some harness sessions first.");
|
|
14998
15354
|
return;
|
|
14999
15355
|
}
|
|
15000
|
-
const { aggregateByDay } = await import("./dist-
|
|
15356
|
+
const { aggregateByDay } = await import("./dist-MCTEX5QH.js");
|
|
15001
15357
|
const limited = aggregateByDay(records).slice(0, days);
|
|
15002
15358
|
if (globalOpts.json) {
|
|
15003
15359
|
console.log(
|
|
@@ -15026,7 +15382,7 @@ function registerSessionsCommand(usage) {
|
|
|
15026
15382
|
}
|
|
15027
15383
|
return;
|
|
15028
15384
|
}
|
|
15029
|
-
const { aggregateBySession } = await import("./dist-
|
|
15385
|
+
const { aggregateBySession } = await import("./dist-MCTEX5QH.js");
|
|
15030
15386
|
const sessionData = aggregateBySession(records);
|
|
15031
15387
|
const limited = sessionData.slice(0, limit);
|
|
15032
15388
|
if (globalOpts.json) {
|
|
@@ -15106,7 +15462,7 @@ function registerSessionCommand(usage) {
|
|
|
15106
15462
|
cwd,
|
|
15107
15463
|
globalOpts.includeClaudeSessions
|
|
15108
15464
|
);
|
|
15109
|
-
const { aggregateBySession } = await import("./dist-
|
|
15465
|
+
const { aggregateBySession } = await import("./dist-MCTEX5QH.js");
|
|
15110
15466
|
const sessionData = aggregateBySession(records);
|
|
15111
15467
|
const match = sessionData.find((s) => s.sessionId === id);
|
|
15112
15468
|
if (!match) {
|
|
@@ -15141,7 +15497,7 @@ function registerLatestCommand(usage) {
|
|
|
15141
15497
|
}
|
|
15142
15498
|
return;
|
|
15143
15499
|
}
|
|
15144
|
-
const { aggregateBySession } = await import("./dist-
|
|
15500
|
+
const { aggregateBySession } = await import("./dist-MCTEX5QH.js");
|
|
15145
15501
|
const sessionData = aggregateBySession(records);
|
|
15146
15502
|
const latest = sessionData[0];
|
|
15147
15503
|
if (!latest) {
|
|
@@ -15167,7 +15523,7 @@ function registerLatestCommand(usage) {
|
|
|
15167
15523
|
});
|
|
15168
15524
|
}
|
|
15169
15525
|
function createUsageCommand() {
|
|
15170
|
-
const usage = new
|
|
15526
|
+
const usage = new Command127("usage").description("Token usage and cost tracking");
|
|
15171
15527
|
usage.option(
|
|
15172
15528
|
"--include-claude-sessions",
|
|
15173
15529
|
"Include Claude Code session data from ~/.claude/projects/"
|
|
@@ -15182,10 +15538,10 @@ function createUsageCommand() {
|
|
|
15182
15538
|
// src/commands/validate.ts
|
|
15183
15539
|
init_dist3();
|
|
15184
15540
|
init_dist3();
|
|
15185
|
-
import { Command as
|
|
15541
|
+
import { Command as Command128 } from "commander";
|
|
15186
15542
|
import * as fs49 from "fs";
|
|
15187
15543
|
import * as path79 from "path";
|
|
15188
|
-
import { execFileSync as
|
|
15544
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
15189
15545
|
async function runValidate(options) {
|
|
15190
15546
|
const configResult = resolveConfig(options.configPath);
|
|
15191
15547
|
if (!configResult.ok) {
|
|
@@ -15304,7 +15660,7 @@ async function runValidate(options) {
|
|
|
15304
15660
|
const gitattributesContent = fs49.readFileSync(gitattributesPath, "utf-8");
|
|
15305
15661
|
let driverConfigured = false;
|
|
15306
15662
|
try {
|
|
15307
|
-
const out =
|
|
15663
|
+
const out = execFileSync11("git", ["config", "--get", "merge.ours.driver"], {
|
|
15308
15664
|
cwd,
|
|
15309
15665
|
encoding: "utf-8",
|
|
15310
15666
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -15490,7 +15846,7 @@ function resolveValidateMode(globalOpts) {
|
|
|
15490
15846
|
return OutputMode.TEXT;
|
|
15491
15847
|
}
|
|
15492
15848
|
async function printCrossCheckWarnings(mode) {
|
|
15493
|
-
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-
|
|
15849
|
+
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-OYKEDCST.js");
|
|
15494
15850
|
const cwd = process.cwd();
|
|
15495
15851
|
const crossResult = await runCrossCheck2({
|
|
15496
15852
|
specsDir: path79.join(cwd, "docs", "specs"),
|
|
@@ -15506,7 +15862,7 @@ async function printCrossCheckWarnings(mode) {
|
|
|
15506
15862
|
${crossResult.value.warnings} warnings`);
|
|
15507
15863
|
}
|
|
15508
15864
|
function createValidateCommand3() {
|
|
15509
|
-
const command = new
|
|
15865
|
+
const command = new Command128("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").option(
|
|
15510
15866
|
"--agent-configs",
|
|
15511
15867
|
"Validate agent configs (CLAUDE.md, hooks, skills) via agnix or built-in fallback rules"
|
|
15512
15868
|
).option("--strict", "Treat warnings as errors (applies to --agent-configs)").option("--agnix-bin <path>", "Override the agnix binary path discovered on PATH").action(async (opts, cmd) => runValidateAction(opts, cmd.optsWithGlobals()));
|
|
@@ -15555,7 +15911,7 @@ Agent configs checked via ${engineLabel}${note}`);
|
|
|
15555
15911
|
|
|
15556
15912
|
// src/commands/verify.ts
|
|
15557
15913
|
init_dist3();
|
|
15558
|
-
import { Command as
|
|
15914
|
+
import { Command as Command129 } from "commander";
|
|
15559
15915
|
import { execSync as execSync6 } from "child_process";
|
|
15560
15916
|
function loadBranchingConfig(configPath) {
|
|
15561
15917
|
const shouldLoad = configPath !== void 0 || findConfigFile().ok;
|
|
@@ -15618,7 +15974,7 @@ async function runVerify(options) {
|
|
|
15618
15974
|
process.exit(ExitCode.VALIDATION_FAILED);
|
|
15619
15975
|
}
|
|
15620
15976
|
function createVerifyCommand() {
|
|
15621
|
-
return new
|
|
15977
|
+
return new Command129("verify").description(
|
|
15622
15978
|
"Verify project conventions (currently: branch naming). Works with or without a harness.config.json."
|
|
15623
15979
|
).option(
|
|
15624
15980
|
"--branch <name>",
|
|
@@ -15669,7 +16025,6 @@ var commandCreators = [
|
|
|
15669
16025
|
createGraphCommand,
|
|
15670
16026
|
createHooksCommand,
|
|
15671
16027
|
createImpactPreviewCommand,
|
|
15672
|
-
createIngestCommand,
|
|
15673
16028
|
createInitCommand3,
|
|
15674
16029
|
createInsightsCommand,
|
|
15675
16030
|
createInstallCommand,
|
|
@@ -15690,15 +16045,14 @@ var commandCreators = [
|
|
|
15690
16045
|
createPerfCommand,
|
|
15691
16046
|
createPersonaCommand,
|
|
15692
16047
|
createPredictCommand,
|
|
16048
|
+
createPreMergeBriefCommand,
|
|
15693
16049
|
createProposalsCommand,
|
|
15694
16050
|
createPublishAnalysesCommand,
|
|
15695
16051
|
createPulseCommand,
|
|
15696
|
-
createQueryCommand,
|
|
15697
16052
|
createRecommendCommand,
|
|
15698
16053
|
createReviewCiCommand,
|
|
15699
16054
|
createRoadmapCommand,
|
|
15700
16055
|
createRoutingCommand,
|
|
15701
|
-
createScanCommand,
|
|
15702
16056
|
createScanConfigCommand,
|
|
15703
16057
|
createSearchCommand,
|
|
15704
16058
|
createSecurityCraftCommand,
|
|
@@ -15724,13 +16078,35 @@ var commandCreators = [
|
|
|
15724
16078
|
createVerifyCommand
|
|
15725
16079
|
];
|
|
15726
16080
|
|
|
16081
|
+
// src/commands/graph/deprecated-aliases.ts
|
|
16082
|
+
var DEPRECATED_GRAPH_ALIASES = [
|
|
16083
|
+
{ factory: createScanCommand, canonical: "harness graph scan" },
|
|
16084
|
+
{ factory: createQueryCommand, canonical: "harness graph query" },
|
|
16085
|
+
{ factory: createIngestCommand, canonical: "harness graph ingest" }
|
|
16086
|
+
];
|
|
16087
|
+
function registerDeprecatedGraphAliases(program) {
|
|
16088
|
+
for (const { factory, canonical } of DEPRECATED_GRAPH_ALIASES) {
|
|
16089
|
+
const alias = factory();
|
|
16090
|
+
alias.hook("preAction", (thisCommand) => {
|
|
16091
|
+
const globalOpts = thisCommand.optsWithGlobals();
|
|
16092
|
+
if (globalOpts.quiet) return;
|
|
16093
|
+
process.stderr.write(
|
|
16094
|
+
`\u26A0 "harness ${alias.name()}" is deprecated and will be removed in the next major release. Use "${canonical}" instead.
|
|
16095
|
+
`
|
|
16096
|
+
);
|
|
16097
|
+
});
|
|
16098
|
+
program.addCommand(alias, { hidden: true });
|
|
16099
|
+
}
|
|
16100
|
+
}
|
|
16101
|
+
|
|
15727
16102
|
// src/index.ts
|
|
15728
16103
|
function createProgram() {
|
|
15729
|
-
const program = new
|
|
16104
|
+
const program = new Command130();
|
|
15730
16105
|
program.name("harness").description("CLI for Harness Engineering toolkit").version(CLI_VERSION).option("-c, --config <path>", "Path to config file").option("--json", "Output as JSON").option("--verbose", "Verbose output").option("--quiet", "Minimal output");
|
|
15731
16106
|
for (const creator of commandCreators) {
|
|
15732
16107
|
program.addCommand(creator());
|
|
15733
16108
|
}
|
|
16109
|
+
registerDeprecatedGraphAliases(program);
|
|
15734
16110
|
return program;
|
|
15735
16111
|
}
|
|
15736
16112
|
|