@harness-engineering/cli 1.21.0 → 1.22.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/cleanup-dead-code/skill.yaml +3 -0
- package/dist/agents/skills/claude-code/detect-doc-drift/skill.yaml +5 -0
- package/dist/agents/skills/claude-code/enforce-architecture/skill.yaml +13 -0
- package/dist/agents/skills/claude-code/harness-code-review/skill.yaml +5 -0
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/skill.yaml +5 -0
- package/dist/agents/skills/claude-code/harness-debugging/skill.yaml +5 -0
- package/dist/agents/skills/claude-code/harness-dependency-health/skill.yaml +9 -0
- package/dist/agents/skills/claude-code/harness-hotspot-detector/skill.yaml +9 -0
- package/dist/agents/skills/claude-code/harness-integrity/skill.yaml +5 -0
- package/dist/agents/skills/claude-code/harness-perf/skill.yaml +3 -0
- package/dist/agents/skills/claude-code/harness-refactoring/skill.yaml +9 -0
- package/dist/agents/skills/claude-code/harness-security-scan/skill.yaml +3 -0
- package/dist/agents/skills/claude-code/harness-soundness-review/skill.yaml +5 -0
- package/dist/agents/skills/claude-code/harness-supply-chain-audit/skill.yaml +3 -0
- package/dist/agents/skills/claude-code/harness-tdd/skill.yaml +3 -0
- package/dist/agents/skills/codex/cleanup-dead-code/skill.yaml +3 -0
- package/dist/agents/skills/codex/detect-doc-drift/skill.yaml +5 -0
- package/dist/agents/skills/codex/enforce-architecture/skill.yaml +13 -0
- package/dist/agents/skills/codex/harness-code-review/skill.yaml +5 -0
- package/dist/agents/skills/codex/harness-codebase-cleanup/skill.yaml +5 -0
- package/dist/agents/skills/codex/harness-debugging/skill.yaml +5 -0
- package/dist/agents/skills/codex/harness-dependency-health/skill.yaml +9 -0
- package/dist/agents/skills/codex/harness-hotspot-detector/skill.yaml +9 -0
- package/dist/agents/skills/codex/harness-integrity/skill.yaml +5 -0
- package/dist/agents/skills/codex/harness-perf/skill.yaml +3 -0
- package/dist/agents/skills/codex/harness-refactoring/skill.yaml +9 -0
- package/dist/agents/skills/codex/harness-security-scan/skill.yaml +3 -0
- package/dist/agents/skills/codex/harness-soundness-review/skill.yaml +5 -0
- package/dist/agents/skills/codex/harness-supply-chain-audit/skill.yaml +3 -0
- package/dist/agents/skills/codex/harness-tdd/skill.yaml +3 -0
- package/dist/agents/skills/cursor/cleanup-dead-code/skill.yaml +3 -0
- package/dist/agents/skills/cursor/detect-doc-drift/skill.yaml +5 -0
- package/dist/agents/skills/cursor/enforce-architecture/skill.yaml +13 -0
- package/dist/agents/skills/cursor/harness-code-review/skill.yaml +5 -0
- package/dist/agents/skills/cursor/harness-codebase-cleanup/skill.yaml +5 -0
- package/dist/agents/skills/cursor/harness-debugging/skill.yaml +5 -0
- package/dist/agents/skills/cursor/harness-dependency-health/skill.yaml +9 -0
- package/dist/agents/skills/cursor/harness-hotspot-detector/skill.yaml +9 -0
- package/dist/agents/skills/cursor/harness-integrity/skill.yaml +5 -0
- package/dist/agents/skills/cursor/harness-perf/skill.yaml +3 -0
- package/dist/agents/skills/cursor/harness-refactoring/skill.yaml +9 -0
- package/dist/agents/skills/cursor/harness-security-scan/skill.yaml +3 -0
- package/dist/agents/skills/cursor/harness-soundness-review/skill.yaml +5 -0
- package/dist/agents/skills/cursor/harness-supply-chain-audit/skill.yaml +3 -0
- package/dist/agents/skills/cursor/harness-tdd/skill.yaml +3 -0
- package/dist/agents/skills/gemini-cli/cleanup-dead-code/skill.yaml +3 -0
- package/dist/agents/skills/gemini-cli/detect-doc-drift/skill.yaml +5 -0
- package/dist/agents/skills/gemini-cli/enforce-architecture/skill.yaml +13 -0
- package/dist/agents/skills/gemini-cli/harness-code-review/skill.yaml +5 -0
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/skill.yaml +5 -0
- package/dist/agents/skills/gemini-cli/harness-debugging/skill.yaml +5 -0
- package/dist/agents/skills/gemini-cli/harness-dependency-health/skill.yaml +9 -0
- package/dist/agents/skills/gemini-cli/harness-hotspot-detector/skill.yaml +9 -0
- package/dist/agents/skills/gemini-cli/harness-integrity/skill.yaml +5 -0
- package/dist/agents/skills/gemini-cli/harness-perf/skill.yaml +3 -0
- package/dist/agents/skills/gemini-cli/harness-refactoring/skill.yaml +9 -0
- package/dist/agents/skills/gemini-cli/harness-security-scan/skill.yaml +3 -0
- package/dist/agents/skills/gemini-cli/harness-soundness-review/skill.yaml +5 -0
- package/dist/agents/skills/gemini-cli/harness-supply-chain-audit/skill.yaml +3 -0
- package/dist/agents/skills/gemini-cli/harness-tdd/skill.yaml +3 -0
- package/dist/{agents-md-TDTLYAQU.js → agents-md-PM7LO74M.js} +2 -1
- package/dist/{architecture-NANP4XPE.js → architecture-OVOCDTI6.js} +3 -2
- package/dist/assess-project-R2OZIDDS.js +9 -0
- package/dist/bin/harness-mcp.js +15 -13
- package/dist/bin/harness.js +21 -19
- package/dist/{check-phase-gate-I4NQOCSU.js → check-phase-gate-7JQ6EW5R.js} +4 -3
- package/dist/{chunk-M6TIO6NF.js → chunk-2PAPHA77.js} +1 -1
- package/dist/chunk-5FBWWMY2.js +293 -0
- package/dist/{chunk-YF5ROTWR.js → chunk-5QTWFO24.js} +8 -8
- package/dist/{chunk-CZZXE6BL.js → chunk-ASS5TD2Y.js} +1 -1
- package/dist/{chunk-L6LTNZQZ.js → chunk-B4WHXHF7.js} +1 -1
- package/dist/{chunk-TMSGI27F.js → chunk-DJEBBENF.js} +967 -385
- package/dist/{chunk-H6LXAH66.js → chunk-DXYOAQQC.js} +1 -1
- package/dist/{chunk-UVJFBKCX.js → chunk-FSLFBLYW.js} +7 -7
- package/dist/{chunk-SZ5TGZMI.js → chunk-GRJ7A4WT.js} +17 -2
- package/dist/{chunk-WXI5ONCU.js → chunk-IK5GSLW6.js} +4 -4
- package/dist/{chunk-SPUK5W4W.js → chunk-J7W4LTRK.js} +2 -2
- package/dist/{chunk-7G2ZUTZA.js → chunk-PUOMFNRO.js} +26 -3
- package/dist/{chunk-HKUX2X7O.js → chunk-SE4YPMLH.js} +9 -1
- package/dist/{chunk-UEKQ5G3V.js → chunk-SOTTK27D.js} +459 -37
- package/dist/{chunk-LRG3B43J.js → chunk-T5QWCVGK.js} +1 -1
- package/dist/{dist-U7EAO6T2.js → chunk-TEZI27SA.js} +401 -60
- package/dist/{chunk-YZYBQZVL.js → chunk-U44JNY3Y.js} +1539 -587
- package/dist/{chunk-HUDEBSR2.js → chunk-W6MPLFXU.js} +3 -3
- package/dist/{chunk-6GEYPBDU.js → chunk-ZEIEUCZL.js} +9 -9
- package/dist/{ci-workflow-Z4IUJBZL.js → ci-workflow-OTTEERPF.js} +2 -1
- package/dist/{create-skill-NDXQSTIK.js → create-skill-U3XCFRZN.js} +2 -2
- package/dist/dist-IA6XYKNO.js +92 -0
- package/dist/{dist-KV2ICL5X.js → dist-LCR2IO7U.js} +56 -3
- package/dist/{docs-2PCZVSGB.js → docs-CHAYSGOP.js} +4 -3
- package/dist/{engine-EOXMI5MD.js → engine-4MY2U5RZ.js} +2 -1
- package/dist/{entropy-VGXXBIGX.js → entropy-AKSZG7G5.js} +3 -2
- package/dist/{feedback-VTSPL3O7.js → feedback-QGCSW7SB.js} +1 -1
- package/dist/{generate-agent-definitions-QICSCGXB.js → generate-agent-definitions-KU6X2UQN.js} +2 -1
- package/dist/{graph-loader-KMHDQYDT.js → graph-loader-FJN4H7Y4.js} +1 -1
- package/dist/index.d.ts +58 -2
- package/dist/index.js +27 -23
- package/dist/{loader-7S4FYAPP.js → loader-AV5XEMER.js} +2 -1
- package/dist/{mcp-DF25USTE.js → mcp-LWHVQRG7.js} +15 -13
- package/dist/{performance-RV4DUMFI.js → performance-ETZVXXGQ.js} +4 -3
- package/dist/{review-pipeline-7KQJB4SI.js → review-pipeline-3ZS3GJSP.js} +1 -1
- package/dist/{runtime-XKOHGGRC.js → runtime-KQTJRK3H.js} +2 -1
- package/dist/{security-NLWTMK3G.js → security-LJCLZES6.js} +1 -1
- package/dist/{skill-executor-XEVDGXUM.js → skill-executor-2BZQLHYN.js} +2 -2
- package/dist/{validate-VHFE6J6O.js → validate-4IA5RPEX.js} +3 -2
- package/dist/{validate-cross-check-PFRKABCS.js → validate-cross-check-VX2BAHQI.js} +2 -1
- package/package.json +4 -4
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generateAgentsMd
|
|
3
|
+
} from "./chunk-OD3S2NHN.js";
|
|
1
4
|
import {
|
|
2
5
|
generateCIWorkflow
|
|
3
6
|
} from "./chunk-SD3SQOZ2.js";
|
|
@@ -6,11 +9,14 @@ import {
|
|
|
6
9
|
OutputMode,
|
|
7
10
|
createCheckPhaseGateCommand,
|
|
8
11
|
findFiles
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PUOMFNRO.js";
|
|
10
13
|
import {
|
|
11
14
|
createGenerateAgentDefinitionsCommand,
|
|
12
15
|
generateAgentDefinitions
|
|
13
16
|
} from "./chunk-6KWBH4EO.js";
|
|
17
|
+
import {
|
|
18
|
+
TemplateEngine
|
|
19
|
+
} from "./chunk-YLN34N65.js";
|
|
14
20
|
import {
|
|
15
21
|
listPersonas,
|
|
16
22
|
loadPersona
|
|
@@ -20,13 +26,13 @@ import {
|
|
|
20
26
|
} from "./chunk-TRAPF4IX.js";
|
|
21
27
|
import {
|
|
22
28
|
executeSkill
|
|
23
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-2PAPHA77.js";
|
|
24
30
|
import {
|
|
25
31
|
ALLOWED_PERSONA_COMMANDS
|
|
26
32
|
} from "./chunk-TEFCFC4H.js";
|
|
27
33
|
import {
|
|
28
34
|
createCreateSkillCommand
|
|
29
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-T5QWCVGK.js";
|
|
30
36
|
import {
|
|
31
37
|
logger
|
|
32
38
|
} from "./chunk-EBJQ6N4M.js";
|
|
@@ -40,24 +46,26 @@ import {
|
|
|
40
46
|
import {
|
|
41
47
|
toKebabCase
|
|
42
48
|
} from "./chunk-KET4QQZB.js";
|
|
43
|
-
import {
|
|
44
|
-
generateAgentsMd
|
|
45
|
-
} from "./chunk-OD3S2NHN.js";
|
|
46
49
|
import {
|
|
47
50
|
appendFrameworkAgents,
|
|
51
|
+
captureHealthSnapshot,
|
|
48
52
|
createGenerateSlashCommandsCommand,
|
|
49
53
|
generateSlashCommands,
|
|
50
54
|
handleGetImpact,
|
|
51
55
|
handleOrphanDeletion,
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
isSnapshotFresh,
|
|
57
|
+
loadCachedSnapshot,
|
|
58
|
+
loadOrRebuildIndex,
|
|
59
|
+
persistToolingConfig,
|
|
60
|
+
recommend
|
|
61
|
+
} from "./chunk-DJEBBENF.js";
|
|
54
62
|
import {
|
|
55
63
|
VALID_PLATFORMS
|
|
56
64
|
} from "./chunk-CJDVBBPB.js";
|
|
57
65
|
import {
|
|
58
66
|
findConfigFile,
|
|
59
67
|
resolveConfig
|
|
60
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-GRJ7A4WT.js";
|
|
61
69
|
import {
|
|
62
70
|
resolveGlobalSkillsDir,
|
|
63
71
|
resolvePersonasDir,
|
|
@@ -72,13 +80,10 @@ import {
|
|
|
72
80
|
} from "./chunk-3WGJMBKH.js";
|
|
73
81
|
import {
|
|
74
82
|
SkillMetadataSchema
|
|
75
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-SE4YPMLH.js";
|
|
76
84
|
import {
|
|
77
85
|
CLI_VERSION
|
|
78
86
|
} from "./chunk-BM3PWGXQ.js";
|
|
79
|
-
import {
|
|
80
|
-
TemplateEngine
|
|
81
|
-
} from "./chunk-YLN34N65.js";
|
|
82
87
|
import {
|
|
83
88
|
ArchBaselineManager,
|
|
84
89
|
ArchConfigSchema,
|
|
@@ -87,8 +92,11 @@ import {
|
|
|
87
92
|
BundleSchema,
|
|
88
93
|
CriticalPathResolver,
|
|
89
94
|
EntropyAnalyzer,
|
|
95
|
+
PredictionEngine,
|
|
90
96
|
ProjectScanner,
|
|
91
97
|
SecurityScanner,
|
|
98
|
+
SpecImpactEstimator,
|
|
99
|
+
TimelineManager,
|
|
92
100
|
TypeScriptParser,
|
|
93
101
|
addProvenance,
|
|
94
102
|
appendLearning,
|
|
@@ -135,14 +143,14 @@ import {
|
|
|
135
143
|
validateKnowledgeMap,
|
|
136
144
|
writeConfig,
|
|
137
145
|
writeLockfile
|
|
138
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-U44JNY3Y.js";
|
|
139
147
|
import {
|
|
140
148
|
Err,
|
|
141
149
|
Ok
|
|
142
150
|
} from "./chunk-ERS5EVUZ.js";
|
|
143
151
|
|
|
144
152
|
// src/index.ts
|
|
145
|
-
import { Command as
|
|
153
|
+
import { Command as Command73 } from "commander";
|
|
146
154
|
|
|
147
155
|
// src/commands/validate.ts
|
|
148
156
|
import { Command } from "commander";
|
|
@@ -221,7 +229,7 @@ function createValidateCommand() {
|
|
|
221
229
|
process.exit(result.error.exitCode);
|
|
222
230
|
}
|
|
223
231
|
if (opts.crossCheck) {
|
|
224
|
-
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-
|
|
232
|
+
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-VX2BAHQI.js");
|
|
225
233
|
const cwd = process.cwd();
|
|
226
234
|
const specsDir = path.join(cwd, "docs", "specs");
|
|
227
235
|
const plansDir = path.join(cwd, "docs", "plans");
|
|
@@ -578,7 +586,7 @@ function registerBenchCommand(perf) {
|
|
|
578
586
|
perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob, _opts, cmd) => {
|
|
579
587
|
const globalOpts = cmd.optsWithGlobals();
|
|
580
588
|
const cwd = process.cwd();
|
|
581
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
589
|
+
const { BenchmarkRunner } = await import("./dist-LCR2IO7U.js");
|
|
582
590
|
const runner = new BenchmarkRunner();
|
|
583
591
|
const benchFiles = runner.discover(cwd, glob);
|
|
584
592
|
if (benchFiles.length === 0) {
|
|
@@ -646,7 +654,7 @@ function registerBaselinesCommands(perf) {
|
|
|
646
654
|
baselines.command("update").description("Update baselines from latest benchmark run").action(async (_opts, cmd) => {
|
|
647
655
|
const globalOpts = cmd.optsWithGlobals();
|
|
648
656
|
const cwd = process.cwd();
|
|
649
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
657
|
+
const { BenchmarkRunner } = await import("./dist-LCR2IO7U.js");
|
|
650
658
|
const runner = new BenchmarkRunner();
|
|
651
659
|
const manager = new BaselineManager(cwd);
|
|
652
660
|
logger.info("Running benchmarks to update baselines...");
|
|
@@ -669,8 +677,8 @@ function registerBaselinesCommands(perf) {
|
|
|
669
677
|
}
|
|
670
678
|
async function getCommitHash(cwd) {
|
|
671
679
|
try {
|
|
672
|
-
const { execSync:
|
|
673
|
-
return
|
|
680
|
+
const { execSync: execSync6 } = await import("child_process");
|
|
681
|
+
return execSync6("git rev-parse --short HEAD", { cwd, encoding: "utf-8" }).trim();
|
|
674
682
|
} catch {
|
|
675
683
|
return "unknown";
|
|
676
684
|
}
|
|
@@ -679,7 +687,7 @@ function registerReportCommand(perf) {
|
|
|
679
687
|
perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
|
|
680
688
|
const globalOpts = cmd.optsWithGlobals();
|
|
681
689
|
const cwd = process.cwd();
|
|
682
|
-
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-
|
|
690
|
+
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-LCR2IO7U.js");
|
|
683
691
|
const analyzer = new EntropyAnalyzer2({
|
|
684
692
|
rootDir: path5.resolve(cwd),
|
|
685
693
|
analyze: { complexity: true, coupling: true }
|
|
@@ -1060,7 +1068,11 @@ var ALL_MCP_TOOLS = [
|
|
|
1060
1068
|
"search_skills",
|
|
1061
1069
|
"code_outline",
|
|
1062
1070
|
"code_search",
|
|
1063
|
-
"code_unfold"
|
|
1071
|
+
"code_unfold",
|
|
1072
|
+
"get_decay_trends",
|
|
1073
|
+
"check_traceability",
|
|
1074
|
+
"predict_failures",
|
|
1075
|
+
"recommend_skills"
|
|
1064
1076
|
];
|
|
1065
1077
|
async function runCursorToolPicker() {
|
|
1066
1078
|
try {
|
|
@@ -1975,7 +1987,7 @@ async function runAdd(componentType, name, options) {
|
|
|
1975
1987
|
break;
|
|
1976
1988
|
}
|
|
1977
1989
|
case "skill": {
|
|
1978
|
-
const { generateSkillFiles: generateSkillFiles2 } = await import("./create-skill-
|
|
1990
|
+
const { generateSkillFiles: generateSkillFiles2 } = await import("./create-skill-U3XCFRZN.js");
|
|
1979
1991
|
generateSkillFiles2({
|
|
1980
1992
|
name,
|
|
1981
1993
|
description: `${name} skill`,
|
|
@@ -3987,7 +3999,8 @@ var VALID_CHECKS = [
|
|
|
3987
3999
|
"security",
|
|
3988
4000
|
"perf",
|
|
3989
4001
|
"phase-gate",
|
|
3990
|
-
"arch"
|
|
4002
|
+
"arch",
|
|
4003
|
+
"traceability"
|
|
3991
4004
|
];
|
|
3992
4005
|
async function runCICheck(options) {
|
|
3993
4006
|
const configResult = resolveConfig(options.configPath);
|
|
@@ -4073,7 +4086,8 @@ var ALL_CHECKS = [
|
|
|
4073
4086
|
"security",
|
|
4074
4087
|
"perf",
|
|
4075
4088
|
"phase-gate",
|
|
4076
|
-
"arch"
|
|
4089
|
+
"arch",
|
|
4090
|
+
"traceability"
|
|
4077
4091
|
];
|
|
4078
4092
|
function buildSkipFlag(checks) {
|
|
4079
4093
|
if (!checks) return "";
|
|
@@ -4753,7 +4767,7 @@ function createGenerateCommand3() {
|
|
|
4753
4767
|
import { Command as Command46 } from "commander";
|
|
4754
4768
|
import * as path38 from "path";
|
|
4755
4769
|
async function runScan(projectPath) {
|
|
4756
|
-
const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-
|
|
4770
|
+
const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-IA6XYKNO.js");
|
|
4757
4771
|
const store = new GraphStore();
|
|
4758
4772
|
const start = Date.now();
|
|
4759
4773
|
await new CodeIngestor(store).ingest(projectPath);
|
|
@@ -4834,7 +4848,7 @@ async function runIngest(projectPath, source, opts) {
|
|
|
4834
4848
|
SyncManager,
|
|
4835
4849
|
JiraConnector,
|
|
4836
4850
|
SlackConnector
|
|
4837
|
-
} = await import("./dist-
|
|
4851
|
+
} = await import("./dist-IA6XYKNO.js");
|
|
4838
4852
|
const graphDir = path39.join(projectPath, ".harness", "graph");
|
|
4839
4853
|
const store = new GraphStore();
|
|
4840
4854
|
await store.load(graphDir);
|
|
@@ -4927,7 +4941,7 @@ function createIngestCommand() {
|
|
|
4927
4941
|
import { Command as Command48 } from "commander";
|
|
4928
4942
|
import * as path40 from "path";
|
|
4929
4943
|
async function runQuery(projectPath, rootNodeId, opts) {
|
|
4930
|
-
const { GraphStore, ContextQL } = await import("./dist-
|
|
4944
|
+
const { GraphStore, ContextQL } = await import("./dist-IA6XYKNO.js");
|
|
4931
4945
|
const store = new GraphStore();
|
|
4932
4946
|
const graphDir = path40.join(projectPath, ".harness", "graph");
|
|
4933
4947
|
const loaded = await store.load(graphDir);
|
|
@@ -4976,7 +4990,7 @@ import { Command as Command49 } from "commander";
|
|
|
4976
4990
|
// src/commands/graph/status.ts
|
|
4977
4991
|
import * as path41 from "path";
|
|
4978
4992
|
async function runGraphStatus(projectPath) {
|
|
4979
|
-
const { GraphStore } = await import("./dist-
|
|
4993
|
+
const { GraphStore } = await import("./dist-IA6XYKNO.js");
|
|
4980
4994
|
const graphDir = path41.join(projectPath, ".harness", "graph");
|
|
4981
4995
|
const store = new GraphStore();
|
|
4982
4996
|
const loaded = await store.load(graphDir);
|
|
@@ -5016,7 +5030,7 @@ async function runGraphStatus(projectPath) {
|
|
|
5016
5030
|
// src/commands/graph/export.ts
|
|
5017
5031
|
import * as path42 from "path";
|
|
5018
5032
|
async function runGraphExport(projectPath, format) {
|
|
5019
|
-
const { GraphStore } = await import("./dist-
|
|
5033
|
+
const { GraphStore } = await import("./dist-IA6XYKNO.js");
|
|
5020
5034
|
const graphDir = path42.join(projectPath, ".harness", "graph");
|
|
5021
5035
|
const store = new GraphStore();
|
|
5022
5036
|
const loaded = await store.load(graphDir);
|
|
@@ -5095,7 +5109,7 @@ function createGraphCommand() {
|
|
|
5095
5109
|
import { Command as Command50 } from "commander";
|
|
5096
5110
|
function createMcpCommand() {
|
|
5097
5111
|
return new Command50("mcp").description("Start the MCP (Model Context Protocol) server on stdio").option("--tools <tools...>", "Only register the specified tools (used by Cursor integration)").action(async (opts) => {
|
|
5098
|
-
const { startServer: startServer2 } = await import("./mcp-
|
|
5112
|
+
const { startServer: startServer2 } = await import("./mcp-LWHVQRG7.js");
|
|
5099
5113
|
await startServer2(opts.tools);
|
|
5100
5114
|
});
|
|
5101
5115
|
}
|
|
@@ -6594,7 +6608,7 @@ function createIntegrationsCommand() {
|
|
|
6594
6608
|
// src/commands/usage.ts
|
|
6595
6609
|
import { Command as Command67 } from "commander";
|
|
6596
6610
|
async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
|
|
6597
|
-
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-
|
|
6611
|
+
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-LCR2IO7U.js");
|
|
6598
6612
|
const records = readCostRecords(cwd);
|
|
6599
6613
|
if (includeClaudeSessions) {
|
|
6600
6614
|
const ccRecords = parseCCRecords();
|
|
@@ -6638,7 +6652,7 @@ function registerDailyCommand(usage) {
|
|
|
6638
6652
|
}
|
|
6639
6653
|
return;
|
|
6640
6654
|
}
|
|
6641
|
-
const { aggregateByDay } = await import("./dist-
|
|
6655
|
+
const { aggregateByDay } = await import("./dist-LCR2IO7U.js");
|
|
6642
6656
|
const dailyData = aggregateByDay(records);
|
|
6643
6657
|
const limited = dailyData.slice(0, days);
|
|
6644
6658
|
if (globalOpts.json) {
|
|
@@ -6674,7 +6688,7 @@ function registerSessionsCommand(usage) {
|
|
|
6674
6688
|
}
|
|
6675
6689
|
return;
|
|
6676
6690
|
}
|
|
6677
|
-
const { aggregateBySession } = await import("./dist-
|
|
6691
|
+
const { aggregateBySession } = await import("./dist-LCR2IO7U.js");
|
|
6678
6692
|
const sessionData = aggregateBySession(records);
|
|
6679
6693
|
const limited = sessionData.slice(0, limit);
|
|
6680
6694
|
if (globalOpts.json) {
|
|
@@ -6703,7 +6717,7 @@ function registerSessionCommand(usage) {
|
|
|
6703
6717
|
const globalOpts = cmd.optsWithGlobals();
|
|
6704
6718
|
const cwd = process.cwd();
|
|
6705
6719
|
const records = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
|
|
6706
|
-
const { aggregateBySession } = await import("./dist-
|
|
6720
|
+
const { aggregateBySession } = await import("./dist-LCR2IO7U.js");
|
|
6707
6721
|
const sessionData = aggregateBySession(records);
|
|
6708
6722
|
const match = sessionData.find((s) => s.sessionId === id);
|
|
6709
6723
|
if (!match) {
|
|
@@ -6769,7 +6783,7 @@ function registerLatestCommand(usage) {
|
|
|
6769
6783
|
}
|
|
6770
6784
|
return;
|
|
6771
6785
|
}
|
|
6772
|
-
const { aggregateBySession } = await import("./dist-
|
|
6786
|
+
const { aggregateBySession } = await import("./dist-LCR2IO7U.js");
|
|
6773
6787
|
const sessionData = aggregateBySession(records);
|
|
6774
6788
|
const latest = sessionData[0];
|
|
6775
6789
|
if (!latest) {
|
|
@@ -6986,9 +7000,413 @@ function createScanConfigCommand() {
|
|
|
6986
7000
|
return command;
|
|
6987
7001
|
}
|
|
6988
7002
|
|
|
7003
|
+
// src/commands/snapshot.ts
|
|
7004
|
+
import { Command as Command70 } from "commander";
|
|
7005
|
+
import { execSync as execSync5 } from "child_process";
|
|
7006
|
+
import chalk8 from "chalk";
|
|
7007
|
+
function getCommitHash3(cwd) {
|
|
7008
|
+
try {
|
|
7009
|
+
return execSync5("git rev-parse --short HEAD", { cwd, encoding: "utf-8" }).toString().trim();
|
|
7010
|
+
} catch {
|
|
7011
|
+
return "unknown";
|
|
7012
|
+
}
|
|
7013
|
+
}
|
|
7014
|
+
function resolveArchConfig(configPath) {
|
|
7015
|
+
const configResult = resolveConfig(configPath);
|
|
7016
|
+
if (!configResult.ok) {
|
|
7017
|
+
return { error: configResult.error };
|
|
7018
|
+
}
|
|
7019
|
+
const archConfig = configResult.value.architecture ?? ArchConfigSchema.parse({});
|
|
7020
|
+
return { archConfig };
|
|
7021
|
+
}
|
|
7022
|
+
function formatDelta(delta) {
|
|
7023
|
+
if (delta === 0) return "0";
|
|
7024
|
+
const sign = delta > 0 ? "+" : "";
|
|
7025
|
+
const formatted = Number.isInteger(delta) ? String(delta) : delta.toFixed(2).replace(/\.?0+$/, "");
|
|
7026
|
+
return `${sign}${formatted}`;
|
|
7027
|
+
}
|
|
7028
|
+
function directionSymbol(direction) {
|
|
7029
|
+
switch (direction) {
|
|
7030
|
+
case "improving":
|
|
7031
|
+
return chalk8.green("improving");
|
|
7032
|
+
case "declining":
|
|
7033
|
+
return chalk8.red("declining");
|
|
7034
|
+
case "stable":
|
|
7035
|
+
return "=";
|
|
7036
|
+
}
|
|
7037
|
+
}
|
|
7038
|
+
var CATEGORY_ORDER = [
|
|
7039
|
+
"circular-deps",
|
|
7040
|
+
"layer-violations",
|
|
7041
|
+
"complexity",
|
|
7042
|
+
"coupling",
|
|
7043
|
+
"forbidden-imports",
|
|
7044
|
+
"module-size",
|
|
7045
|
+
"dependency-depth"
|
|
7046
|
+
];
|
|
7047
|
+
async function runSnapshotCapture(options) {
|
|
7048
|
+
const cwd = options.cwd ?? process.cwd();
|
|
7049
|
+
const resolved = resolveArchConfig(options.configPath);
|
|
7050
|
+
if (resolved.error) {
|
|
7051
|
+
throw resolved.error;
|
|
7052
|
+
}
|
|
7053
|
+
const manager = new TimelineManager(cwd);
|
|
7054
|
+
const timelineBefore = manager.load();
|
|
7055
|
+
const previous = timelineBefore.snapshots.length > 0 ? timelineBefore.snapshots[timelineBefore.snapshots.length - 1] : void 0;
|
|
7056
|
+
const results = await runAll(resolved.archConfig, cwd);
|
|
7057
|
+
const commitHash = getCommitHash3(cwd);
|
|
7058
|
+
const snapshot = manager.capture(results, commitHash);
|
|
7059
|
+
return { snapshot, previous };
|
|
7060
|
+
}
|
|
7061
|
+
function printCaptureSummary(snapshot, previous) {
|
|
7062
|
+
const date = snapshot.capturedAt.slice(0, 10);
|
|
7063
|
+
const commit = snapshot.commitHash.slice(0, 7);
|
|
7064
|
+
console.log("");
|
|
7065
|
+
console.log(`Architecture Snapshot captured (${date}, ${commit})`);
|
|
7066
|
+
console.log("");
|
|
7067
|
+
const stabilityDelta = previous ? ` (${formatDelta(snapshot.stabilityScore - previous.stabilityScore)} from last)` : "";
|
|
7068
|
+
console.log(` Stability: ${snapshot.stabilityScore}/100${stabilityDelta}`);
|
|
7069
|
+
console.log("");
|
|
7070
|
+
const header = " Category".padEnd(22) + "Value".padStart(7) + "Delta".padStart(8) + " Trend";
|
|
7071
|
+
console.log(header);
|
|
7072
|
+
for (const category of CATEGORY_ORDER) {
|
|
7073
|
+
const current = snapshot.metrics[category];
|
|
7074
|
+
const prev = previous?.metrics[category];
|
|
7075
|
+
const value = current?.value ?? 0;
|
|
7076
|
+
const delta = prev ? value - prev.value : 0;
|
|
7077
|
+
const valueFmt = Number.isInteger(value) ? String(value) : value.toFixed(2);
|
|
7078
|
+
const deltaFmt = formatDelta(delta);
|
|
7079
|
+
const direction = Math.abs(delta) < 2 ? "stable" : delta < 0 ? "improving" : "declining";
|
|
7080
|
+
const line = ` ${category.padEnd(20)}${valueFmt.padStart(7)}${deltaFmt.padStart(8)} ${directionSymbol(direction)}`;
|
|
7081
|
+
console.log(line);
|
|
7082
|
+
}
|
|
7083
|
+
console.log("");
|
|
7084
|
+
}
|
|
7085
|
+
function printTrendsSummary(trends) {
|
|
7086
|
+
if (trends.snapshotCount === 0) {
|
|
7087
|
+
logger.warn("No snapshots found. Run `harness snapshot capture` first.");
|
|
7088
|
+
return;
|
|
7089
|
+
}
|
|
7090
|
+
const fromDate = trends.from.slice(0, 10);
|
|
7091
|
+
const toDate = trends.to.slice(0, 10);
|
|
7092
|
+
console.log("");
|
|
7093
|
+
console.log(`Architecture Trends (${trends.snapshotCount} snapshots, ${fromDate} to ${toDate})`);
|
|
7094
|
+
console.log("");
|
|
7095
|
+
const stabilityDelta = formatDelta(trends.stability.delta);
|
|
7096
|
+
console.log(
|
|
7097
|
+
` Stability: ${trends.stability.current}/100 (was ${trends.stability.previous} on ${fromDate}, ${stabilityDelta})`
|
|
7098
|
+
);
|
|
7099
|
+
console.log("");
|
|
7100
|
+
const header = " Category".padEnd(22) + "Current".padStart(9) + "Start".padStart(9) + "Delta".padStart(9) + " Trend";
|
|
7101
|
+
console.log(header);
|
|
7102
|
+
for (const category of CATEGORY_ORDER) {
|
|
7103
|
+
const trend = trends.categories[category];
|
|
7104
|
+
if (!trend) continue;
|
|
7105
|
+
const currentFmt = Number.isInteger(trend.current) ? String(trend.current) : trend.current.toFixed(2);
|
|
7106
|
+
const prevFmt = Number.isInteger(trend.previous) ? String(trend.previous) : trend.previous.toFixed(2);
|
|
7107
|
+
const deltaFmt = formatDelta(trend.delta);
|
|
7108
|
+
const line = ` ${category.padEnd(20)}${currentFmt.padStart(9)}${prevFmt.padStart(9)}${deltaFmt.padStart(9)} ${directionSymbol(trend.direction)}`;
|
|
7109
|
+
console.log(line);
|
|
7110
|
+
}
|
|
7111
|
+
console.log("");
|
|
7112
|
+
}
|
|
7113
|
+
function printSnapshotList(manager) {
|
|
7114
|
+
const timeline = manager.load();
|
|
7115
|
+
if (timeline.snapshots.length === 0) {
|
|
7116
|
+
logger.warn("No snapshots found. Run `harness snapshot capture` first.");
|
|
7117
|
+
return;
|
|
7118
|
+
}
|
|
7119
|
+
console.log("");
|
|
7120
|
+
console.log(`Architecture Snapshots (${timeline.snapshots.length} total)`);
|
|
7121
|
+
console.log("");
|
|
7122
|
+
const header = " #".padEnd(6) + "Date".padEnd(14) + "Commit".padEnd(12) + "Stability";
|
|
7123
|
+
console.log(header);
|
|
7124
|
+
timeline.snapshots.forEach((snap, idx) => {
|
|
7125
|
+
const date = snap.capturedAt.slice(0, 10);
|
|
7126
|
+
const commit = snap.commitHash.slice(0, 7);
|
|
7127
|
+
const num = String(idx + 1);
|
|
7128
|
+
const line = ` ${num.padEnd(4)}${date.padEnd(14)}${commit.padEnd(12)}${snap.stabilityScore}/100`;
|
|
7129
|
+
console.log(line);
|
|
7130
|
+
});
|
|
7131
|
+
console.log("");
|
|
7132
|
+
}
|
|
7133
|
+
function createSnapshotCommand() {
|
|
7134
|
+
const command = new Command70("snapshot").description("Architecture timeline snapshot commands");
|
|
7135
|
+
command.command("capture").description("Capture current architecture metrics as a timeline snapshot").action(async (_opts, cmd) => {
|
|
7136
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
7137
|
+
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
7138
|
+
try {
|
|
7139
|
+
const { snapshot, previous } = await runSnapshotCapture({
|
|
7140
|
+
configPath: globalOpts.config
|
|
7141
|
+
});
|
|
7142
|
+
if (mode === OutputMode.JSON) {
|
|
7143
|
+
console.log(JSON.stringify({ snapshot, previous: previous ?? null }, null, 2));
|
|
7144
|
+
} else {
|
|
7145
|
+
printCaptureSummary(snapshot, previous);
|
|
7146
|
+
}
|
|
7147
|
+
} catch (err) {
|
|
7148
|
+
if (err instanceof CLIError) {
|
|
7149
|
+
if (mode === OutputMode.JSON) {
|
|
7150
|
+
console.log(JSON.stringify({ error: err.message }));
|
|
7151
|
+
} else {
|
|
7152
|
+
logger.error(err.message);
|
|
7153
|
+
}
|
|
7154
|
+
process.exit(err.exitCode);
|
|
7155
|
+
}
|
|
7156
|
+
throw err;
|
|
7157
|
+
}
|
|
7158
|
+
});
|
|
7159
|
+
command.command("trends").description("Show architecture metric trends over time").option("--last <n>", "Number of recent snapshots to analyze", "10").option("--since <date>", "Show trends since ISO date").action(async (opts, cmd) => {
|
|
7160
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
7161
|
+
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
7162
|
+
const cwd = process.cwd();
|
|
7163
|
+
const manager = new TimelineManager(cwd);
|
|
7164
|
+
const trends = manager.trends({
|
|
7165
|
+
last: parseInt(opts.last, 10),
|
|
7166
|
+
since: opts.since
|
|
7167
|
+
});
|
|
7168
|
+
if (mode === OutputMode.JSON) {
|
|
7169
|
+
console.log(JSON.stringify(trends, null, 2));
|
|
7170
|
+
} else {
|
|
7171
|
+
printTrendsSummary(trends);
|
|
7172
|
+
}
|
|
7173
|
+
});
|
|
7174
|
+
command.command("list").description("List all captured architecture snapshots").action(async (_opts, cmd) => {
|
|
7175
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
7176
|
+
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
7177
|
+
const cwd = process.cwd();
|
|
7178
|
+
const manager = new TimelineManager(cwd);
|
|
7179
|
+
if (mode === OutputMode.JSON) {
|
|
7180
|
+
const timeline = manager.load();
|
|
7181
|
+
console.log(JSON.stringify(timeline, null, 2));
|
|
7182
|
+
} else {
|
|
7183
|
+
printSnapshotList(manager);
|
|
7184
|
+
}
|
|
7185
|
+
});
|
|
7186
|
+
return command;
|
|
7187
|
+
}
|
|
7188
|
+
|
|
7189
|
+
// src/commands/predict.ts
|
|
7190
|
+
import { Command as Command71 } from "commander";
|
|
7191
|
+
import chalk9 from "chalk";
|
|
7192
|
+
var CATEGORY_ORDER2 = [
|
|
7193
|
+
"circular-deps",
|
|
7194
|
+
"layer-violations",
|
|
7195
|
+
"complexity",
|
|
7196
|
+
"coupling",
|
|
7197
|
+
"forbidden-imports",
|
|
7198
|
+
"module-size",
|
|
7199
|
+
"dependency-depth"
|
|
7200
|
+
];
|
|
7201
|
+
function formatValue(value) {
|
|
7202
|
+
if (Number.isInteger(value)) return String(value);
|
|
7203
|
+
return value.toFixed(2);
|
|
7204
|
+
}
|
|
7205
|
+
function crossingLabel(weeks) {
|
|
7206
|
+
if (weeks === null || weeks <= 0) return "--";
|
|
7207
|
+
return `~${Math.round(weeks)} weeks`;
|
|
7208
|
+
}
|
|
7209
|
+
function severityPrefix(severity) {
|
|
7210
|
+
switch (severity) {
|
|
7211
|
+
case "critical":
|
|
7212
|
+
return chalk9.red("[critical]");
|
|
7213
|
+
case "warning":
|
|
7214
|
+
return chalk9.yellow("[warning]");
|
|
7215
|
+
case "info":
|
|
7216
|
+
return chalk9.blue("[info]");
|
|
7217
|
+
}
|
|
7218
|
+
}
|
|
7219
|
+
function printPredictionReport(result) {
|
|
7220
|
+
const sf = result.stabilityForecast;
|
|
7221
|
+
const horizonWeeks = 12;
|
|
7222
|
+
console.log("");
|
|
7223
|
+
console.log(
|
|
7224
|
+
`Architecture Prediction (${horizonWeeks}-week horizon, ${result.snapshotsUsed} snapshots)`
|
|
7225
|
+
);
|
|
7226
|
+
console.log("");
|
|
7227
|
+
console.log(
|
|
7228
|
+
` Stability: ${sf.current}/100 -> projected ${sf.projected12w}/100 in 12w (${sf.confidence} confidence)`
|
|
7229
|
+
);
|
|
7230
|
+
console.log("");
|
|
7231
|
+
const header = " " + "Category".padEnd(20) + "Current".padStart(9) + "Threshold".padStart(11) + "4w".padStart(7) + "8w".padStart(7) + "12w".padStart(7) + " Crossing".padEnd(16) + "Confidence";
|
|
7232
|
+
console.log(header);
|
|
7233
|
+
for (const category of CATEGORY_ORDER2) {
|
|
7234
|
+
const af = result.categories[category];
|
|
7235
|
+
if (!af) continue;
|
|
7236
|
+
const f = af.adjusted;
|
|
7237
|
+
const line = " " + category.padEnd(20) + formatValue(f.current).padStart(9) + formatValue(f.threshold).padStart(11) + formatValue(f.projectedValue4w).padStart(7) + formatValue(f.projectedValue8w).padStart(7) + formatValue(f.projectedValue12w).padStart(7) + (" " + crossingLabel(f.thresholdCrossingWeeks)).padEnd(16) + f.confidence;
|
|
7238
|
+
console.log(line);
|
|
7239
|
+
}
|
|
7240
|
+
if (result.warnings.length > 0) {
|
|
7241
|
+
console.log("");
|
|
7242
|
+
console.log(" Warnings:");
|
|
7243
|
+
for (const w of result.warnings) {
|
|
7244
|
+
console.log(` ${severityPrefix(w.severity)} ${w.message}`);
|
|
7245
|
+
if (w.contributingFeatures.length > 0) {
|
|
7246
|
+
console.log(` Accelerated by: ${w.contributingFeatures.join(", ")}`);
|
|
7247
|
+
}
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
7250
|
+
console.log("");
|
|
7251
|
+
}
|
|
7252
|
+
function runPredict(options) {
|
|
7253
|
+
const cwd = options.cwd ?? process.cwd();
|
|
7254
|
+
const configResult = resolveConfig(options.configPath);
|
|
7255
|
+
if (!configResult.ok) {
|
|
7256
|
+
throw configResult.error;
|
|
7257
|
+
}
|
|
7258
|
+
const manager = new TimelineManager(cwd);
|
|
7259
|
+
const estimator = options.noRoadmap === true ? null : new SpecImpactEstimator(cwd);
|
|
7260
|
+
const engine = new PredictionEngine(cwd, manager, estimator);
|
|
7261
|
+
const categories = options.category ? [options.category] : void 0;
|
|
7262
|
+
return engine.predict({
|
|
7263
|
+
...options.horizon !== void 0 ? { horizon: options.horizon } : {},
|
|
7264
|
+
includeRoadmap: options.noRoadmap !== true,
|
|
7265
|
+
categories
|
|
7266
|
+
});
|
|
7267
|
+
}
|
|
7268
|
+
function createPredictCommand() {
|
|
7269
|
+
const command = new Command71("predict").description("Predict which architectural constraints will break and when").option("--category <name>", "Filter to a single metric category").option("--no-roadmap", "Baseline only \u2014 skip roadmap spec impact").option("--horizon <weeks>", "Forecast horizon in weeks (default: 12)", "12").action(async (opts, cmd) => {
|
|
7270
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
7271
|
+
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
7272
|
+
try {
|
|
7273
|
+
const result = runPredict({
|
|
7274
|
+
configPath: globalOpts.config,
|
|
7275
|
+
category: opts.category,
|
|
7276
|
+
noRoadmap: opts.roadmap === false,
|
|
7277
|
+
horizon: (() => {
|
|
7278
|
+
const h = parseInt(opts.horizon, 10);
|
|
7279
|
+
if (isNaN(h) || h < 1) throw new Error("--horizon must be a positive integer");
|
|
7280
|
+
return h;
|
|
7281
|
+
})()
|
|
7282
|
+
});
|
|
7283
|
+
if (mode === OutputMode.JSON) {
|
|
7284
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7285
|
+
} else {
|
|
7286
|
+
printPredictionReport(result);
|
|
7287
|
+
}
|
|
7288
|
+
} catch (err) {
|
|
7289
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7290
|
+
if (err instanceof CLIError) {
|
|
7291
|
+
if (mode === OutputMode.JSON) {
|
|
7292
|
+
console.log(JSON.stringify({ error: message }));
|
|
7293
|
+
} else {
|
|
7294
|
+
logger.error(message);
|
|
7295
|
+
}
|
|
7296
|
+
process.exit(err.exitCode);
|
|
7297
|
+
}
|
|
7298
|
+
if (mode === OutputMode.JSON) {
|
|
7299
|
+
console.log(JSON.stringify({ error: message }));
|
|
7300
|
+
} else {
|
|
7301
|
+
logger.error(message);
|
|
7302
|
+
}
|
|
7303
|
+
process.exit(ExitCode.ERROR);
|
|
7304
|
+
}
|
|
7305
|
+
});
|
|
7306
|
+
return command;
|
|
7307
|
+
}
|
|
7308
|
+
|
|
7309
|
+
// src/commands/recommend.ts
|
|
7310
|
+
import { Command as Command72 } from "commander";
|
|
7311
|
+
import chalk10 from "chalk";
|
|
7312
|
+
async function runRecommend(options) {
|
|
7313
|
+
const cwd = options.cwd ?? process.cwd();
|
|
7314
|
+
const top = options.top ?? 5;
|
|
7315
|
+
let snapshot = null;
|
|
7316
|
+
let usedCache = false;
|
|
7317
|
+
if (!options.noCache) {
|
|
7318
|
+
const cached = loadCachedSnapshot(cwd);
|
|
7319
|
+
if (cached && isSnapshotFresh(cached, cwd)) {
|
|
7320
|
+
snapshot = cached;
|
|
7321
|
+
usedCache = true;
|
|
7322
|
+
}
|
|
7323
|
+
}
|
|
7324
|
+
if (!snapshot) {
|
|
7325
|
+
snapshot = await captureHealthSnapshot(cwd);
|
|
7326
|
+
}
|
|
7327
|
+
const configResult = resolveConfig();
|
|
7328
|
+
const tierOverrides = configResult.ok ? configResult.value.skills?.tierOverrides : void 0;
|
|
7329
|
+
const index = loadOrRebuildIndex("claude-code", cwd, tierOverrides);
|
|
7330
|
+
const skills = {};
|
|
7331
|
+
for (const [name, entry] of Object.entries(index.skills)) {
|
|
7332
|
+
skills[name] = { addresses: entry.addresses, dependsOn: entry.dependsOn };
|
|
7333
|
+
}
|
|
7334
|
+
const result = recommend(snapshot, skills, { top });
|
|
7335
|
+
return {
|
|
7336
|
+
...result,
|
|
7337
|
+
snapshotAge: usedCache ? "cached" : "fresh"
|
|
7338
|
+
};
|
|
7339
|
+
}
|
|
7340
|
+
function formatRecommendation(rec) {
|
|
7341
|
+
const lines = [];
|
|
7342
|
+
if (rec.urgency === "critical") {
|
|
7343
|
+
lines.push(` ${chalk10.red("[CRITICAL]")} ${rec.sequence}. ${rec.skillName}`);
|
|
7344
|
+
} else {
|
|
7345
|
+
lines.push(` ${rec.sequence}. ${rec.skillName} (${rec.score.toFixed(2)})`);
|
|
7346
|
+
}
|
|
7347
|
+
for (const reason of rec.reasons) {
|
|
7348
|
+
lines.push(` ${chalk10.dim("\u2192")} ${reason}`);
|
|
7349
|
+
}
|
|
7350
|
+
return lines.join("\n");
|
|
7351
|
+
}
|
|
7352
|
+
function printRecommendations(result) {
|
|
7353
|
+
if (result.recommendations.length === 0) {
|
|
7354
|
+
console.log("");
|
|
7355
|
+
console.log("No recommendations. Codebase health looks good!");
|
|
7356
|
+
console.log("");
|
|
7357
|
+
return;
|
|
7358
|
+
}
|
|
7359
|
+
console.log("");
|
|
7360
|
+
console.log(
|
|
7361
|
+
`Recommended workflow (${result.recommendations.length} skill${result.recommendations.length === 1 ? "" : "s"}):`
|
|
7362
|
+
);
|
|
7363
|
+
console.log("");
|
|
7364
|
+
for (const rec of result.recommendations) {
|
|
7365
|
+
console.log(formatRecommendation(rec));
|
|
7366
|
+
console.log("");
|
|
7367
|
+
}
|
|
7368
|
+
console.log(`Sequence reasoning: ${result.sequenceReasoning}`);
|
|
7369
|
+
console.log("");
|
|
7370
|
+
}
|
|
7371
|
+
function createRecommendCommand() {
|
|
7372
|
+
const command = new Command72("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) => {
|
|
7373
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
7374
|
+
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
7375
|
+
try {
|
|
7376
|
+
const top = parseInt(opts.top, 10);
|
|
7377
|
+
if (isNaN(top) || top < 1) {
|
|
7378
|
+
logger.error("--top must be a positive integer");
|
|
7379
|
+
process.exit(1);
|
|
7380
|
+
}
|
|
7381
|
+
if (mode === OutputMode.TEXT) {
|
|
7382
|
+
console.log("");
|
|
7383
|
+
console.log("Analyzing codebase health...");
|
|
7384
|
+
}
|
|
7385
|
+
const result = await runRecommend({
|
|
7386
|
+
noCache: opts.cache === false,
|
|
7387
|
+
top
|
|
7388
|
+
});
|
|
7389
|
+
if (mode === OutputMode.JSON) {
|
|
7390
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7391
|
+
} else {
|
|
7392
|
+
printRecommendations(result);
|
|
7393
|
+
}
|
|
7394
|
+
} catch (err) {
|
|
7395
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7396
|
+
if (mode === OutputMode.JSON) {
|
|
7397
|
+
console.log(JSON.stringify({ error: message }));
|
|
7398
|
+
} else {
|
|
7399
|
+
logger.error(message);
|
|
7400
|
+
}
|
|
7401
|
+
process.exit(1);
|
|
7402
|
+
}
|
|
7403
|
+
});
|
|
7404
|
+
return command;
|
|
7405
|
+
}
|
|
7406
|
+
|
|
6989
7407
|
// src/index.ts
|
|
6990
7408
|
function createProgram() {
|
|
6991
|
-
const program = new
|
|
7409
|
+
const program = new Command73();
|
|
6992
7410
|
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");
|
|
6993
7411
|
program.addCommand(createValidateCommand());
|
|
6994
7412
|
program.addCommand(createCheckDepsCommand());
|
|
@@ -7035,6 +7453,9 @@ function createProgram() {
|
|
|
7035
7453
|
program.addCommand(createUsageCommand());
|
|
7036
7454
|
program.addCommand(createTaintCommand());
|
|
7037
7455
|
program.addCommand(createScanConfigCommand());
|
|
7456
|
+
program.addCommand(createSnapshotCommand());
|
|
7457
|
+
program.addCommand(createPredictCommand());
|
|
7458
|
+
program.addCommand(createRecommendCommand());
|
|
7038
7459
|
return program;
|
|
7039
7460
|
}
|
|
7040
7461
|
|
|
@@ -7052,5 +7473,6 @@ export {
|
|
|
7052
7473
|
runInstallConstraints,
|
|
7053
7474
|
runUninstallConstraints,
|
|
7054
7475
|
runUninstall,
|
|
7476
|
+
runSnapshotCapture,
|
|
7055
7477
|
createProgram
|
|
7056
7478
|
};
|