@harness-engineering/cli 1.25.7 → 1.26.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-knowledge-pipeline/SKILL.md +277 -0
- package/dist/agents/skills/claude-code/harness-knowledge-pipeline/skill.yaml +60 -0
- package/dist/agents/skills/codex/harness-knowledge-pipeline/SKILL.md +277 -0
- package/dist/agents/skills/codex/harness-knowledge-pipeline/skill.yaml +60 -0
- package/dist/agents/skills/cursor/harness-knowledge-pipeline/SKILL.md +277 -0
- package/dist/agents/skills/cursor/harness-knowledge-pipeline/skill.yaml +60 -0
- package/dist/agents/skills/gemini-cli/harness-knowledge-pipeline/SKILL.md +277 -0
- package/dist/agents/skills/gemini-cli/harness-knowledge-pipeline/skill.yaml +60 -0
- package/dist/agents/skills/package.json +2 -2
- package/dist/{agents-md-QPO3H5HX.js → agents-md-OPOZA5L7.js} +3 -3
- package/dist/{architecture-IJLXRHZA.js → architecture-PMVMO6SF.js} +4 -4
- package/dist/{assess-project-QU6XIVJK.js → assess-project-ZW7EKNIT.js} +1 -1
- package/dist/bin/harness-mcp.js +15 -15
- package/dist/bin/harness.js +25 -25
- package/dist/{check-phase-gate-TNY64AOS.js → check-phase-gate-NTLAU3LO.js} +4 -4
- package/dist/{chunk-TQRCODRJ.js → chunk-4KSKV5MK.js} +1 -1
- package/dist/{chunk-IT2KORSK.js → chunk-6SCA4NEZ.js} +1 -1
- package/dist/{chunk-ZIYLIYN4.js → chunk-77EZGPSR.js} +1 -1
- package/dist/{chunk-D3XL2FLX.js → chunk-7JNZXJKY.js} +5 -5
- package/dist/{chunk-JJQ3TW2E.js → chunk-CAS3TS4Y.js} +101 -89
- package/dist/{chunk-K35D7HF3.js → chunk-EXTWTJRF.js} +1 -1
- package/dist/{chunk-AS5DQT4S.js → chunk-FI3D6D7U.js} +9 -9
- package/dist/{chunk-2DF6OZLG.js → chunk-G6SYTGOH.js} +2 -2
- package/dist/{chunk-KVJZQ2MV.js → chunk-HAOBHL3W.js} +1 -1
- package/dist/{chunk-MLOGYWLY.js → chunk-IFHAUFJX.js} +2 -2
- package/dist/{chunk-IQO7IINR.js → chunk-J3O64D2A.js} +1 -1
- package/dist/{chunk-LTCEV7VF.js → chunk-JBJ4AVE4.js} +3 -3
- package/dist/{chunk-FRDS4XGD.js → chunk-JWSVLC4I.js} +1 -1
- package/dist/{chunk-K533WNZG.js → chunk-JZ6GORAK.js} +1 -1
- package/dist/{chunk-YRBNAHH4.js → chunk-KFE2X7LG.js} +4 -4
- package/dist/{chunk-MCDCZMKN.js → chunk-KSFUJT5B.js} +1 -1
- package/dist/{chunk-LXPRO2FH.js → chunk-KXIAHHHP.js} +2 -2
- package/dist/{chunk-E5Z6NTTQ.js → chunk-NIOB6FTG.js} +1 -1
- package/dist/{chunk-PCOU2UXU.js → chunk-NVGQO4VM.js} +8 -8
- package/dist/{chunk-G5SNXUIK.js → chunk-QYSWNPXZ.js} +1 -1
- package/dist/{chunk-XVJRFP7W.js → chunk-RNAGPTKF.js} +6 -6
- package/dist/{chunk-GVNT2YC7.js → chunk-UBRD5FH4.js} +9 -9
- package/dist/{chunk-NKQEMWGT.js → chunk-VV2PJT4K.js} +3321 -207
- package/dist/{chunk-JPZY7ZQX.js → chunk-Z2JORLRT.js} +1 -1
- package/dist/{chunk-SZ3Q4XEO.js → chunk-ZBQ3ZY75.js} +433 -283
- package/dist/{ci-workflow-FJYRFZYQ.js → ci-workflow-H52EMCL6.js} +3 -3
- package/dist/{dist-HPWNWCT6.js → dist-PGQ32ZI7.js} +41 -1
- package/dist/{dist-ZV6GO6FA.js → dist-TG63OKA5.js} +2 -2
- package/dist/{docs-7DW3DI4Z.js → docs-GP4VUSIB.js} +4 -4
- package/dist/{engine-P7EE2IWO.js → engine-KQG5RVXX.js} +3 -3
- package/dist/{entropy-HCXRTDFU.js → entropy-RXESIYKC.js} +3 -3
- package/dist/{feedback-Y4FYN3NR.js → feedback-HS7ZYXOU.js} +1 -1
- package/dist/{generate-agent-definitions-3EHPIWBO.js → generate-agent-definitions-I4B7CVOB.js} +4 -4
- package/dist/{graph-loader-KXVS3YK3.js → graph-loader-TIVI6NQ7.js} +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +25 -25
- package/dist/{loader-SKHF3JVV.js → loader-CWAH6B4H.js} +3 -3
- package/dist/{mcp-MWYIPDQU.js → mcp-KHK5KYER.js} +15 -15
- package/dist/{performance-ADWH5NJY.js → performance-WDW5WS3J.js} +4 -4
- package/dist/{review-pipeline-TLKE5OQD.js → review-pipeline-QOZGWCTY.js} +3 -3
- package/dist/{runtime-7LYAW7GU.js → runtime-SFEFRPLX.js} +3 -3
- package/dist/{scan-BGJ7TLLV.js → scan-IJ7EYTF7.js} +1 -1
- package/dist/{security-5XWINYVB.js → security-2K7UUK6T.js} +1 -1
- package/dist/{validate-BFFHYHY7.js → validate-HXM6DXRZ.js} +4 -4
- package/dist/{validate-cross-check-GQX7OVCR.js → validate-cross-check-ULQLEOME.js} +3 -3
- package/package.json +9 -9
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generateAgentsMd
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6SCA4NEZ.js";
|
|
4
4
|
import {
|
|
5
5
|
generateCIWorkflow
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-HAOBHL3W.js";
|
|
7
7
|
import {
|
|
8
8
|
TemplateEngine
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-JZ6GORAK.js";
|
|
10
10
|
import {
|
|
11
11
|
generate,
|
|
12
12
|
validate
|
|
13
13
|
} from "./chunk-CQ553GZO.js";
|
|
14
14
|
import {
|
|
15
15
|
generateRuntime
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-EXTWTJRF.js";
|
|
17
17
|
import {
|
|
18
18
|
runPersona
|
|
19
19
|
} from "./chunk-GISMXMVL.js";
|
|
@@ -28,21 +28,21 @@ import {
|
|
|
28
28
|
OutputMode,
|
|
29
29
|
createCheckPhaseGateCommand,
|
|
30
30
|
findFiles
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-KXIAHHHP.js";
|
|
32
32
|
import {
|
|
33
33
|
createGenerateAgentDefinitionsCommand,
|
|
34
34
|
generateAgentDefinitions
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-KSFUJT5B.js";
|
|
36
36
|
import {
|
|
37
37
|
toKebabCase
|
|
38
38
|
} from "./chunk-KET4QQZB.js";
|
|
39
39
|
import {
|
|
40
40
|
listPersonas,
|
|
41
41
|
loadPersona
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-JWSVLC4I.js";
|
|
43
43
|
import {
|
|
44
44
|
createScanCommand
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-NIOB6FTG.js";
|
|
46
46
|
import {
|
|
47
47
|
appendFrameworkAgents,
|
|
48
48
|
captureHealthSnapshot,
|
|
@@ -56,11 +56,11 @@ import {
|
|
|
56
56
|
loadOrRebuildIndex,
|
|
57
57
|
persistToolingConfig,
|
|
58
58
|
recommend
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-CAS3TS4Y.js";
|
|
60
60
|
import {
|
|
61
61
|
findConfigFile,
|
|
62
62
|
resolveConfig
|
|
63
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-4KSKV5MK.js";
|
|
64
64
|
import {
|
|
65
65
|
VALID_PLATFORMS
|
|
66
66
|
} from "./chunk-3ISINLYT.js";
|
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
} from "./chunk-6B6UN6SG.js";
|
|
75
75
|
import {
|
|
76
76
|
loadGraphStore
|
|
77
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-Z2JORLRT.js";
|
|
78
78
|
import {
|
|
79
79
|
CLI_VERSION
|
|
80
80
|
} from "./chunk-BM3PWGXQ.js";
|
|
@@ -148,7 +148,7 @@ import {
|
|
|
148
148
|
validateKnowledgeMap,
|
|
149
149
|
writeConfig,
|
|
150
150
|
writeLockfile
|
|
151
|
-
} from "./chunk-
|
|
151
|
+
} from "./chunk-77EZGPSR.js";
|
|
152
152
|
import {
|
|
153
153
|
Err,
|
|
154
154
|
Ok
|
|
@@ -173,7 +173,7 @@ import {
|
|
|
173
173
|
} from "./chunk-KFQGP6VL.js";
|
|
174
174
|
|
|
175
175
|
// src/index.ts
|
|
176
|
-
import { Command as
|
|
176
|
+
import { Command as Command85 } from "commander";
|
|
177
177
|
|
|
178
178
|
// src/commands/add.ts
|
|
179
179
|
init_dist();
|
|
@@ -362,7 +362,7 @@ function registerSkillsCommand(adoption) {
|
|
|
362
362
|
const globalOpts = cmd.optsWithGlobals();
|
|
363
363
|
const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
|
|
364
364
|
const cwd = process.cwd();
|
|
365
|
-
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-
|
|
365
|
+
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-TG63OKA5.js");
|
|
366
366
|
const records = readAdoptionRecords(cwd);
|
|
367
367
|
if (records.length === 0) {
|
|
368
368
|
if (globalOpts.json) {
|
|
@@ -398,7 +398,7 @@ function registerRecentCommand(adoption) {
|
|
|
398
398
|
const globalOpts = cmd.optsWithGlobals();
|
|
399
399
|
const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
|
|
400
400
|
const cwd = process.cwd();
|
|
401
|
-
const { readAdoptionRecords } = await import("./dist-
|
|
401
|
+
const { readAdoptionRecords } = await import("./dist-TG63OKA5.js");
|
|
402
402
|
const records = readAdoptionRecords(cwd);
|
|
403
403
|
if (records.length === 0) {
|
|
404
404
|
if (globalOpts.json) {
|
|
@@ -476,7 +476,7 @@ function registerSkillCommand(adoption) {
|
|
|
476
476
|
adoption.command("skill <name>").description("Show detail for a specific skill").action(async (name, _opts, cmd) => {
|
|
477
477
|
const globalOpts = cmd.optsWithGlobals();
|
|
478
478
|
const cwd = process.cwd();
|
|
479
|
-
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-
|
|
479
|
+
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-TG63OKA5.js");
|
|
480
480
|
const records = readAdoptionRecords(cwd);
|
|
481
481
|
const skillRecords = records.filter((r) => r.skill === name);
|
|
482
482
|
if (skillRecords.length === 0) {
|
|
@@ -2765,7 +2765,7 @@ import { Command as Command25 } from "commander";
|
|
|
2765
2765
|
// src/commands/graph/status.ts
|
|
2766
2766
|
import * as path15 from "path";
|
|
2767
2767
|
async function runGraphStatus(projectPath) {
|
|
2768
|
-
const { GraphStore } = await import("./dist-
|
|
2768
|
+
const { GraphStore } = await import("./dist-PGQ32ZI7.js");
|
|
2769
2769
|
const graphDir = path15.join(projectPath, ".harness", "graph");
|
|
2770
2770
|
const store = new GraphStore();
|
|
2771
2771
|
const loaded = await store.load(graphDir);
|
|
@@ -2805,7 +2805,7 @@ async function runGraphStatus(projectPath) {
|
|
|
2805
2805
|
// src/commands/graph/export.ts
|
|
2806
2806
|
import * as path16 from "path";
|
|
2807
2807
|
async function runGraphExport(projectPath, format) {
|
|
2808
|
-
const { GraphStore } = await import("./dist-
|
|
2808
|
+
const { GraphStore } = await import("./dist-PGQ32ZI7.js");
|
|
2809
2809
|
const graphDir = path16.join(projectPath, ".harness", "graph");
|
|
2810
2810
|
const store = new GraphStore();
|
|
2811
2811
|
const loaded = await store.load(graphDir);
|
|
@@ -2841,7 +2841,7 @@ import * as path19 from "path";
|
|
|
2841
2841
|
import { Command as Command23 } from "commander";
|
|
2842
2842
|
import * as path17 from "path";
|
|
2843
2843
|
async function runQuery(projectPath, rootNodeId, opts) {
|
|
2844
|
-
const { GraphStore, ContextQL } = await import("./dist-
|
|
2844
|
+
const { GraphStore, ContextQL } = await import("./dist-PGQ32ZI7.js");
|
|
2845
2845
|
const store = new GraphStore();
|
|
2846
2846
|
const graphDir = path17.join(projectPath, ".harness", "graph");
|
|
2847
2847
|
const loaded = await store.load(graphDir);
|
|
@@ -2935,7 +2935,7 @@ async function runIngest(projectPath, source, opts) {
|
|
|
2935
2935
|
SlackConnector,
|
|
2936
2936
|
CIConnector,
|
|
2937
2937
|
ConfluenceConnector
|
|
2938
|
-
} = await import("./dist-
|
|
2938
|
+
} = await import("./dist-PGQ32ZI7.js");
|
|
2939
2939
|
const graphDir = path18.join(projectPath, ".harness", "graph");
|
|
2940
2940
|
const store = new GraphStore();
|
|
2941
2941
|
await store.load(graphDir);
|
|
@@ -2945,6 +2945,9 @@ async function runIngest(projectPath, source, opts) {
|
|
|
2945
2945
|
new TopologicalLinker(store).link();
|
|
2946
2946
|
const knowledgeResult = await new KnowledgeIngestor(store).ingestAll(projectPath);
|
|
2947
2947
|
const gitResult = await new GitIngestor(store).ingest(projectPath);
|
|
2948
|
+
const { createExtractionRunner } = await import("./dist-PGQ32ZI7.js");
|
|
2949
|
+
const extractedDir = path18.join(projectPath, ".harness", "knowledge", "extracted");
|
|
2950
|
+
const signalsResult = await createExtractionRunner().run(projectPath, store, extractedDir);
|
|
2948
2951
|
const syncManager = new SyncManager(store, graphDir);
|
|
2949
2952
|
const connectorMap = {
|
|
2950
2953
|
jira: () => new JiraConnector(),
|
|
@@ -2958,7 +2961,13 @@ async function runIngest(projectPath, source, opts) {
|
|
|
2958
2961
|
}
|
|
2959
2962
|
const connectorResult = await syncManager.syncAll();
|
|
2960
2963
|
await store.save(graphDir);
|
|
2961
|
-
const merged = mergeResults(
|
|
2964
|
+
const merged = mergeResults(
|
|
2965
|
+
codeResult,
|
|
2966
|
+
knowledgeResult,
|
|
2967
|
+
gitResult,
|
|
2968
|
+
signalsResult,
|
|
2969
|
+
connectorResult
|
|
2970
|
+
);
|
|
2962
2971
|
return { ...merged, durationMs: Date.now() - startMs };
|
|
2963
2972
|
}
|
|
2964
2973
|
let result;
|
|
@@ -2973,11 +2982,17 @@ async function runIngest(projectPath, source, opts) {
|
|
|
2973
2982
|
case "git":
|
|
2974
2983
|
result = await new GitIngestor(store).ingest(projectPath);
|
|
2975
2984
|
break;
|
|
2985
|
+
case "business-signals": {
|
|
2986
|
+
const { createExtractionRunner } = await import("./dist-PGQ32ZI7.js");
|
|
2987
|
+
const extractedDir = path18.join(projectPath, ".harness", "knowledge", "extracted");
|
|
2988
|
+
result = await createExtractionRunner().run(projectPath, store, extractedDir);
|
|
2989
|
+
break;
|
|
2990
|
+
}
|
|
2976
2991
|
default: {
|
|
2977
2992
|
const knownConnectors = ["jira", "slack", "ci", "confluence"];
|
|
2978
2993
|
if (!knownConnectors.includes(source)) {
|
|
2979
2994
|
throw new Error(
|
|
2980
|
-
`Unknown source: ${source}. Available: code, knowledge, git, jira, slack, ci, confluence`
|
|
2995
|
+
`Unknown source: ${source}. Available: code, knowledge, git, business-signals, jira, slack, ci, confluence`
|
|
2981
2996
|
);
|
|
2982
2997
|
}
|
|
2983
2998
|
if (!SyncManager) {
|
|
@@ -3005,7 +3020,7 @@ async function runIngest(projectPath, source, opts) {
|
|
|
3005
3020
|
function createIngestCommand() {
|
|
3006
3021
|
return new Command24("ingest").description("Ingest data into the knowledge graph").option(
|
|
3007
3022
|
"--source <name>",
|
|
3008
|
-
"Source to ingest (code, knowledge, git, jira, slack, ci, confluence)"
|
|
3023
|
+
"Source to ingest (code, knowledge, git, business-signals, jira, slack, ci, confluence)"
|
|
3009
3024
|
).option("--all", "Run all sources (code, knowledge, git, and configured connectors)").option("--full", "Force full re-ingestion").action(async (opts, cmd) => {
|
|
3010
3025
|
if (!opts.source && !opts.all) {
|
|
3011
3026
|
console.error("Error: --source or --all is required");
|
|
@@ -5252,15 +5267,149 @@ function createIntegrationsCommand() {
|
|
|
5252
5267
|
return command;
|
|
5253
5268
|
}
|
|
5254
5269
|
|
|
5270
|
+
// src/commands/knowledge-pipeline.ts
|
|
5271
|
+
import { Command as Command41 } from "commander";
|
|
5272
|
+
import * as path38 from "path";
|
|
5273
|
+
import chalk6 from "chalk";
|
|
5274
|
+
function createKnowledgePipelineCommand() {
|
|
5275
|
+
return new Command41("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) => {
|
|
5276
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
5277
|
+
const projectDir = globalOpts.cwd ?? process.cwd();
|
|
5278
|
+
try {
|
|
5279
|
+
const graphDir = path38.join(projectDir, ".harness", "graph");
|
|
5280
|
+
const fs41 = await import("fs/promises");
|
|
5281
|
+
await fs41.mkdir(graphDir, { recursive: true });
|
|
5282
|
+
const { GraphStore, KnowledgePipelineRunner } = await import("./dist-PGQ32ZI7.js");
|
|
5283
|
+
const store = new GraphStore();
|
|
5284
|
+
try {
|
|
5285
|
+
await store.load(graphDir);
|
|
5286
|
+
} catch {
|
|
5287
|
+
}
|
|
5288
|
+
const pipelineOpts = {
|
|
5289
|
+
projectDir,
|
|
5290
|
+
fix: Boolean(opts.fix),
|
|
5291
|
+
ci: Boolean(opts.ci),
|
|
5292
|
+
...opts.domain ? { domain: opts.domain } : {},
|
|
5293
|
+
graphDir,
|
|
5294
|
+
analyzeImages: Boolean(opts.analyzeImages)
|
|
5295
|
+
};
|
|
5296
|
+
if (opts.imagePaths) {
|
|
5297
|
+
pipelineOpts.imagePaths = opts.imagePaths.split(",").map((p) => p.trim());
|
|
5298
|
+
}
|
|
5299
|
+
if (opts.analyzeImages) {
|
|
5300
|
+
try {
|
|
5301
|
+
const intelligence = await import("@harness-engineering/intelligence");
|
|
5302
|
+
const ProviderClass = intelligence.AnthropicAnalysisProvider;
|
|
5303
|
+
pipelineOpts.analysisProvider = new ProviderClass();
|
|
5304
|
+
} catch {
|
|
5305
|
+
logger.error(
|
|
5306
|
+
"Image analysis requires @harness-engineering/intelligence with ANTHROPIC_API_KEY set."
|
|
5307
|
+
);
|
|
5308
|
+
process.exit(1);
|
|
5309
|
+
}
|
|
5310
|
+
}
|
|
5311
|
+
const runner = new KnowledgePipelineRunner(store);
|
|
5312
|
+
const result = await runner.run(
|
|
5313
|
+
pipelineOpts
|
|
5314
|
+
);
|
|
5315
|
+
if (globalOpts.json) {
|
|
5316
|
+
console.log(
|
|
5317
|
+
JSON.stringify(
|
|
5318
|
+
{
|
|
5319
|
+
verdict: result.verdict,
|
|
5320
|
+
driftScore: result.driftScore,
|
|
5321
|
+
iterations: result.iterations,
|
|
5322
|
+
findings: result.findings,
|
|
5323
|
+
extraction: result.extraction,
|
|
5324
|
+
gaps: {
|
|
5325
|
+
domains: result.gaps.domains.length,
|
|
5326
|
+
totalEntries: result.gaps.totalEntries
|
|
5327
|
+
},
|
|
5328
|
+
remediations: result.remediations,
|
|
5329
|
+
contradictions: {
|
|
5330
|
+
count: result.contradictions.contradictions.length,
|
|
5331
|
+
sourcePairCounts: result.contradictions.sourcePairCounts
|
|
5332
|
+
},
|
|
5333
|
+
coverage: {
|
|
5334
|
+
overallScore: result.coverage.overallScore,
|
|
5335
|
+
overallGrade: result.coverage.overallGrade,
|
|
5336
|
+
domains: result.coverage.domains.length
|
|
5337
|
+
}
|
|
5338
|
+
},
|
|
5339
|
+
null,
|
|
5340
|
+
2
|
|
5341
|
+
)
|
|
5342
|
+
);
|
|
5343
|
+
} else {
|
|
5344
|
+
const verdictColor = result.verdict === "pass" ? chalk6.green("PASS") : result.verdict === "warn" ? chalk6.yellow("WARN") : chalk6.red("FAIL");
|
|
5345
|
+
console.log("");
|
|
5346
|
+
console.log(`KNOWLEDGE PIPELINE -- Verdict: ${verdictColor}`);
|
|
5347
|
+
console.log("");
|
|
5348
|
+
console.log(` Drift Score: ${result.driftScore.toFixed(2)}`);
|
|
5349
|
+
console.log(
|
|
5350
|
+
` Findings: ${result.findings.new} new, ${result.findings.stale} stale, ${result.findings.drifted} drifted, ${result.findings.contradicting} contradicting`
|
|
5351
|
+
);
|
|
5352
|
+
console.log(
|
|
5353
|
+
` Extraction: ${result.extraction.codeSignals} code signals, ${result.extraction.diagrams} diagrams, ${result.extraction.linkerFacts} linker facts, ${result.extraction.businessKnowledge} business knowledge, ${result.extraction.images} images`
|
|
5354
|
+
);
|
|
5355
|
+
console.log(
|
|
5356
|
+
` Gaps: ${result.gaps.domains.length} domains, ${result.gaps.totalEntries} total entries`
|
|
5357
|
+
);
|
|
5358
|
+
if (result.iterations > 1) {
|
|
5359
|
+
console.log(` Convergence: ${result.iterations} iterations`);
|
|
5360
|
+
}
|
|
5361
|
+
if (result.remediations.length > 0) {
|
|
5362
|
+
console.log(` Remediations: ${result.remediations.length} applied`);
|
|
5363
|
+
}
|
|
5364
|
+
if (opts.checkContradictions || result.contradictions.contradictions.length > 0) {
|
|
5365
|
+
console.log("");
|
|
5366
|
+
console.log(
|
|
5367
|
+
` Contradictions: ${result.contradictions.contradictions.length} detected across ${result.contradictions.totalChecked} knowledge nodes`
|
|
5368
|
+
);
|
|
5369
|
+
for (const c of result.contradictions.contradictions) {
|
|
5370
|
+
console.log(
|
|
5371
|
+
` ${chalk6.red("!")} ${c.description} [${c.conflictType}] (${c.severity})`
|
|
5372
|
+
);
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
if (opts.coverage || result.coverage.domains.length > 0) {
|
|
5376
|
+
console.log("");
|
|
5377
|
+
console.log(
|
|
5378
|
+
` Coverage: ${result.coverage.overallGrade} (${result.coverage.overallScore}/100)`
|
|
5379
|
+
);
|
|
5380
|
+
for (const d of result.coverage.domains) {
|
|
5381
|
+
console.log(
|
|
5382
|
+
` ${d.domain}: ${d.grade} (${d.score}/100) \u2014 ${d.knowledgeEntries} knowledge, ${d.linkedEntities}/${d.codeEntities} code linked`
|
|
5383
|
+
);
|
|
5384
|
+
}
|
|
5385
|
+
}
|
|
5386
|
+
console.log("");
|
|
5387
|
+
}
|
|
5388
|
+
const unresolvedDrift = result.findings.drifted + result.findings.stale + result.findings.contradicting;
|
|
5389
|
+
if (opts.driftCheck && unresolvedDrift > 0) {
|
|
5390
|
+
logger.error(
|
|
5391
|
+
`${unresolvedDrift} unresolved drift findings. Run /harness:knowledge-pipeline --fix to remediate.`
|
|
5392
|
+
);
|
|
5393
|
+
process.exit(1);
|
|
5394
|
+
}
|
|
5395
|
+
} catch (error) {
|
|
5396
|
+
logger.error(
|
|
5397
|
+
`Knowledge pipeline failed: ${error instanceof Error ? error.message : String(error)}`
|
|
5398
|
+
);
|
|
5399
|
+
process.exit(1);
|
|
5400
|
+
}
|
|
5401
|
+
});
|
|
5402
|
+
}
|
|
5403
|
+
|
|
5255
5404
|
// src/commands/learnings/index.ts
|
|
5256
|
-
import { Command as
|
|
5405
|
+
import { Command as Command43 } from "commander";
|
|
5257
5406
|
|
|
5258
5407
|
// src/commands/learnings/prune.ts
|
|
5259
5408
|
init_dist();
|
|
5260
|
-
import { Command as
|
|
5261
|
-
import * as
|
|
5409
|
+
import { Command as Command42 } from "commander";
|
|
5410
|
+
import * as path39 from "path";
|
|
5262
5411
|
async function handlePrune(opts) {
|
|
5263
|
-
const projectPath =
|
|
5412
|
+
const projectPath = path39.resolve(opts.path);
|
|
5264
5413
|
const result = await pruneLearnings(projectPath, opts.stream);
|
|
5265
5414
|
if (!result.ok) {
|
|
5266
5415
|
logger.error(result.error.message);
|
|
@@ -5299,23 +5448,23 @@ function printPatternProposals(patterns) {
|
|
|
5299
5448
|
);
|
|
5300
5449
|
}
|
|
5301
5450
|
function createPruneCommand() {
|
|
5302
|
-
return new
|
|
5451
|
+
return new Command42("prune").description(
|
|
5303
5452
|
"Analyze global learnings for patterns, present improvement proposals, and archive old entries"
|
|
5304
5453
|
).option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(handlePrune);
|
|
5305
5454
|
}
|
|
5306
5455
|
|
|
5307
5456
|
// src/commands/learnings/index.ts
|
|
5308
5457
|
function createLearningsCommand() {
|
|
5309
|
-
const command = new
|
|
5458
|
+
const command = new Command43("learnings").description("Learnings management commands");
|
|
5310
5459
|
command.addCommand(createPruneCommand());
|
|
5311
5460
|
return command;
|
|
5312
5461
|
}
|
|
5313
5462
|
|
|
5314
5463
|
// src/commands/linter/index.ts
|
|
5315
|
-
import { Command as
|
|
5464
|
+
import { Command as Command46 } from "commander";
|
|
5316
5465
|
|
|
5317
5466
|
// src/commands/linter/generate.ts
|
|
5318
|
-
import { Command as
|
|
5467
|
+
import { Command as Command44 } from "commander";
|
|
5319
5468
|
function formatGenerateError(e) {
|
|
5320
5469
|
switch (e.type) {
|
|
5321
5470
|
case "parse":
|
|
@@ -5359,7 +5508,7 @@ function handleSuccess(result, useJson) {
|
|
|
5359
5508
|
Generated ${result.rulesGenerated.length} rules to ${result.outputDir}`);
|
|
5360
5509
|
}
|
|
5361
5510
|
function createGenerateCommand2() {
|
|
5362
|
-
return new
|
|
5511
|
+
return new Command44("generate").description("Generate ESLint rules from harness-linter.yml").option("-c, --config <path>", "Path to harness-linter.yml", "./harness-linter.yml").option("-o, --output <dir>", "Override output directory").option("--clean", "Remove existing files before generating").option("--dry-run", "Preview without writing files").option("--json", "Output as JSON").option("--verbose", "Show detailed output").action(async (options) => {
|
|
5363
5512
|
try {
|
|
5364
5513
|
if (options.verbose) logger.info(`Parsing config: ${options.config}`);
|
|
5365
5514
|
const result = await generate({
|
|
@@ -5381,9 +5530,9 @@ function createGenerateCommand2() {
|
|
|
5381
5530
|
}
|
|
5382
5531
|
|
|
5383
5532
|
// src/commands/linter/validate.ts
|
|
5384
|
-
import { Command as
|
|
5533
|
+
import { Command as Command45 } from "commander";
|
|
5385
5534
|
function createValidateCommand() {
|
|
5386
|
-
return new
|
|
5535
|
+
return new Command45("validate").description("Validate harness-linter.yml config").option("-c, --config <path>", "Path to harness-linter.yml", "./harness-linter.yml").option("--json", "Output as JSON").action(async (options) => {
|
|
5387
5536
|
try {
|
|
5388
5537
|
const result = await validate({ configPath: options.config });
|
|
5389
5538
|
if (options.json) {
|
|
@@ -5402,7 +5551,7 @@ function createValidateCommand() {
|
|
|
5402
5551
|
|
|
5403
5552
|
// src/commands/linter/index.ts
|
|
5404
5553
|
function createLinterCommand() {
|
|
5405
|
-
const linter = new
|
|
5554
|
+
const linter = new Command46("linter").description(
|
|
5406
5555
|
"Generate and validate ESLint rules from YAML config"
|
|
5407
5556
|
);
|
|
5408
5557
|
linter.addCommand(createGenerateCommand2());
|
|
@@ -5411,7 +5560,7 @@ function createLinterCommand() {
|
|
|
5411
5560
|
}
|
|
5412
5561
|
|
|
5413
5562
|
// src/commands/mcp.ts
|
|
5414
|
-
import { Command as
|
|
5563
|
+
import { Command as Command47 } from "commander";
|
|
5415
5564
|
var VALID_TIERS = /* @__PURE__ */ new Set(["core", "standard", "full"]);
|
|
5416
5565
|
function parseTier(value) {
|
|
5417
5566
|
const lower = value.toLowerCase();
|
|
@@ -5428,7 +5577,7 @@ function parseBudget(value) {
|
|
|
5428
5577
|
return n;
|
|
5429
5578
|
}
|
|
5430
5579
|
function createMcpCommand() {
|
|
5431
|
-
return new
|
|
5580
|
+
return new Command47("mcp").description("Start the MCP (Model Context Protocol) server on stdio").option("--tools <tools...>", "Only register the specified tools (used by Cursor integration)").option(
|
|
5432
5581
|
"--tier <core|standard|full>",
|
|
5433
5582
|
"Load a preset tool tier instead of all tools",
|
|
5434
5583
|
parseTier
|
|
@@ -5438,7 +5587,7 @@ function createMcpCommand() {
|
|
|
5438
5587
|
parseBudget
|
|
5439
5588
|
).action(async (opts) => {
|
|
5440
5589
|
const [{ startServer: startServer2, getToolDefinitions: getToolDefinitions2 }, { selectTier }] = await Promise.all([
|
|
5441
|
-
import("./mcp-
|
|
5590
|
+
import("./mcp-KHK5KYER.js"),
|
|
5442
5591
|
import("./tool-tiers-7QGZ3FKY.js")
|
|
5443
5592
|
]);
|
|
5444
5593
|
if (opts.tools && opts.tools.length > 0) {
|
|
@@ -5459,13 +5608,13 @@ function createMcpCommand() {
|
|
|
5459
5608
|
}
|
|
5460
5609
|
|
|
5461
5610
|
// src/commands/orchestrator.ts
|
|
5462
|
-
import { Command as
|
|
5463
|
-
import * as
|
|
5611
|
+
import { Command as Command48 } from "commander";
|
|
5612
|
+
import * as path40 from "path";
|
|
5464
5613
|
import { Orchestrator, WorkflowLoader, launchTUI } from "@harness-engineering/orchestrator";
|
|
5465
5614
|
function createOrchestratorCommand() {
|
|
5466
|
-
const orchestrator = new
|
|
5615
|
+
const orchestrator = new Command48("orchestrator");
|
|
5467
5616
|
orchestrator.command("run").description("Run the orchestrator daemon").option("-w, --workflow <path>", "Path to harness.orchestrator.md", "harness.orchestrator.md").option("--headless", "Run without TUI (server-only mode for use with web dashboard)").action(async (opts) => {
|
|
5468
|
-
const workflowPath =
|
|
5617
|
+
const workflowPath = path40.resolve(process.cwd(), opts.workflow);
|
|
5469
5618
|
const loader = new WorkflowLoader();
|
|
5470
5619
|
const result = await loader.loadWorkflow(workflowPath);
|
|
5471
5620
|
if (!result.ok) {
|
|
@@ -5498,13 +5647,13 @@ function createOrchestratorCommand() {
|
|
|
5498
5647
|
|
|
5499
5648
|
// src/commands/perf.ts
|
|
5500
5649
|
init_dist();
|
|
5501
|
-
import { Command as
|
|
5502
|
-
import * as
|
|
5650
|
+
import { Command as Command49 } from "commander";
|
|
5651
|
+
import * as path41 from "path";
|
|
5503
5652
|
function registerBenchCommand(perf) {
|
|
5504
5653
|
perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob2, _opts, cmd) => {
|
|
5505
5654
|
const globalOpts = cmd.optsWithGlobals();
|
|
5506
5655
|
const cwd = process.cwd();
|
|
5507
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
5656
|
+
const { BenchmarkRunner } = await import("./dist-TG63OKA5.js");
|
|
5508
5657
|
const runner = new BenchmarkRunner();
|
|
5509
5658
|
const benchFiles = runner.discover(cwd, glob2);
|
|
5510
5659
|
if (benchFiles.length === 0) {
|
|
@@ -5568,7 +5717,7 @@ async function runBaselinesShow(globalOpts) {
|
|
|
5568
5717
|
}
|
|
5569
5718
|
async function runBaselinesUpdate(globalOpts) {
|
|
5570
5719
|
const cwd = process.cwd();
|
|
5571
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
5720
|
+
const { BenchmarkRunner } = await import("./dist-TG63OKA5.js");
|
|
5572
5721
|
const runner = new BenchmarkRunner();
|
|
5573
5722
|
const manager = new BaselineManager(cwd);
|
|
5574
5723
|
logger.info("Running benchmarks to update baselines...");
|
|
@@ -5609,9 +5758,9 @@ function registerReportCommand(perf) {
|
|
|
5609
5758
|
perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
|
|
5610
5759
|
const globalOpts = cmd.optsWithGlobals();
|
|
5611
5760
|
const cwd = process.cwd();
|
|
5612
|
-
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-
|
|
5761
|
+
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-TG63OKA5.js");
|
|
5613
5762
|
const analyzer = new EntropyAnalyzer2({
|
|
5614
|
-
rootDir:
|
|
5763
|
+
rootDir: path41.resolve(cwd),
|
|
5615
5764
|
analyze: { complexity: true, coupling: true }
|
|
5616
5765
|
});
|
|
5617
5766
|
const result = await analyzer.analyze();
|
|
@@ -5670,7 +5819,7 @@ function registerCriticalPathsCommand(perf) {
|
|
|
5670
5819
|
});
|
|
5671
5820
|
}
|
|
5672
5821
|
function createPerfCommand() {
|
|
5673
|
-
const perf = new
|
|
5822
|
+
const perf = new Command49("perf").description("Performance benchmark and baseline management");
|
|
5674
5823
|
registerBenchCommand(perf);
|
|
5675
5824
|
registerBaselinesCommands(perf);
|
|
5676
5825
|
registerReportCommand(perf);
|
|
@@ -5679,10 +5828,10 @@ function createPerfCommand() {
|
|
|
5679
5828
|
}
|
|
5680
5829
|
|
|
5681
5830
|
// src/commands/persona/index.ts
|
|
5682
|
-
import { Command as
|
|
5831
|
+
import { Command as Command52 } from "commander";
|
|
5683
5832
|
|
|
5684
5833
|
// src/commands/persona/list.ts
|
|
5685
|
-
import { Command as
|
|
5834
|
+
import { Command as Command50 } from "commander";
|
|
5686
5835
|
function printPersonaList(personas) {
|
|
5687
5836
|
if (personas.length === 0) {
|
|
5688
5837
|
logger.info("No personas found.");
|
|
@@ -5696,7 +5845,7 @@ function printPersonaList(personas) {
|
|
|
5696
5845
|
}
|
|
5697
5846
|
}
|
|
5698
5847
|
function createListCommand2() {
|
|
5699
|
-
return new
|
|
5848
|
+
return new Command50("list").description("List available agent personas").action(async (_opts, cmd) => {
|
|
5700
5849
|
const globalOpts = cmd.optsWithGlobals();
|
|
5701
5850
|
const personasDir = resolvePersonasDir();
|
|
5702
5851
|
const result = listPersonas(personasDir);
|
|
@@ -5716,17 +5865,17 @@ function createListCommand2() {
|
|
|
5716
5865
|
}
|
|
5717
5866
|
|
|
5718
5867
|
// src/commands/persona/generate.ts
|
|
5719
|
-
import { Command as
|
|
5868
|
+
import { Command as Command51 } from "commander";
|
|
5720
5869
|
import * as fs24 from "fs";
|
|
5721
|
-
import * as
|
|
5870
|
+
import * as path42 from "path";
|
|
5722
5871
|
function generatePersonaArtifacts(persona, outputDir, only) {
|
|
5723
5872
|
const slug = toKebabCase(persona.name);
|
|
5724
5873
|
const generated = [];
|
|
5725
5874
|
if (!only || only === "runtime") {
|
|
5726
5875
|
const result = generateRuntime(persona);
|
|
5727
5876
|
if (result.ok) {
|
|
5728
|
-
const outPath =
|
|
5729
|
-
fs24.mkdirSync(
|
|
5877
|
+
const outPath = path42.join(outputDir, `${slug}.runtime.json`);
|
|
5878
|
+
fs24.mkdirSync(path42.dirname(outPath), { recursive: true });
|
|
5730
5879
|
fs24.writeFileSync(outPath, result.value);
|
|
5731
5880
|
generated.push(outPath);
|
|
5732
5881
|
}
|
|
@@ -5734,7 +5883,7 @@ function generatePersonaArtifacts(persona, outputDir, only) {
|
|
|
5734
5883
|
if (!only || only === "agents-md") {
|
|
5735
5884
|
const result = generateAgentsMd(persona);
|
|
5736
5885
|
if (result.ok) {
|
|
5737
|
-
const outPath =
|
|
5886
|
+
const outPath = path42.join(outputDir, `${slug}.agents.md`);
|
|
5738
5887
|
fs24.writeFileSync(outPath, result.value);
|
|
5739
5888
|
generated.push(outPath);
|
|
5740
5889
|
}
|
|
@@ -5742,8 +5891,8 @@ function generatePersonaArtifacts(persona, outputDir, only) {
|
|
|
5742
5891
|
if (!only || only === "ci") {
|
|
5743
5892
|
const result = generateCIWorkflow(persona, "github");
|
|
5744
5893
|
if (result.ok) {
|
|
5745
|
-
const outPath =
|
|
5746
|
-
fs24.mkdirSync(
|
|
5894
|
+
const outPath = path42.join(outputDir, ".github", "workflows", `${slug}.yml`);
|
|
5895
|
+
fs24.mkdirSync(path42.dirname(outPath), { recursive: true });
|
|
5747
5896
|
fs24.writeFileSync(outPath, result.value);
|
|
5748
5897
|
generated.push(outPath);
|
|
5749
5898
|
}
|
|
@@ -5751,16 +5900,16 @@ function generatePersonaArtifacts(persona, outputDir, only) {
|
|
|
5751
5900
|
return generated;
|
|
5752
5901
|
}
|
|
5753
5902
|
function createGenerateCommand3() {
|
|
5754
|
-
return new
|
|
5903
|
+
return new Command51("generate").description("Generate artifacts from a persona config").argument("<name>", "Persona name (e.g., architecture-enforcer)").option("--output-dir <dir>", "Output directory", ".").option("--only <type>", "Generate only: ci, agents-md, runtime").action(async (name, opts, cmd) => {
|
|
5755
5904
|
const globalOpts = cmd.optsWithGlobals();
|
|
5756
|
-
const personaResult = loadPersona(
|
|
5905
|
+
const personaResult = loadPersona(path42.join(resolvePersonasDir(), `${name}.yaml`));
|
|
5757
5906
|
if (!personaResult.ok) {
|
|
5758
5907
|
logger.error(personaResult.error.message);
|
|
5759
5908
|
process.exit(ExitCode.ERROR);
|
|
5760
5909
|
}
|
|
5761
5910
|
const generated = generatePersonaArtifacts(
|
|
5762
5911
|
personaResult.value,
|
|
5763
|
-
|
|
5912
|
+
path42.resolve(opts.outputDir),
|
|
5764
5913
|
opts.only
|
|
5765
5914
|
);
|
|
5766
5915
|
if (!globalOpts.quiet) {
|
|
@@ -5773,7 +5922,7 @@ function createGenerateCommand3() {
|
|
|
5773
5922
|
|
|
5774
5923
|
// src/commands/persona/index.ts
|
|
5775
5924
|
function createPersonaCommand() {
|
|
5776
|
-
const command = new
|
|
5925
|
+
const command = new Command52("persona").description("Agent persona management commands");
|
|
5777
5926
|
command.addCommand(createListCommand2());
|
|
5778
5927
|
command.addCommand(createGenerateCommand3());
|
|
5779
5928
|
return command;
|
|
@@ -5781,8 +5930,8 @@ function createPersonaCommand() {
|
|
|
5781
5930
|
|
|
5782
5931
|
// src/commands/predict.ts
|
|
5783
5932
|
init_dist();
|
|
5784
|
-
import { Command as
|
|
5785
|
-
import
|
|
5933
|
+
import { Command as Command53 } from "commander";
|
|
5934
|
+
import chalk7 from "chalk";
|
|
5786
5935
|
var CATEGORY_ORDER = [
|
|
5787
5936
|
"circular-deps",
|
|
5788
5937
|
"layer-violations",
|
|
@@ -5803,11 +5952,11 @@ function crossingLabel(weeks) {
|
|
|
5803
5952
|
function severityPrefix(severity) {
|
|
5804
5953
|
switch (severity) {
|
|
5805
5954
|
case "critical":
|
|
5806
|
-
return
|
|
5955
|
+
return chalk7.red("[critical]");
|
|
5807
5956
|
case "warning":
|
|
5808
|
-
return
|
|
5957
|
+
return chalk7.yellow("[warning]");
|
|
5809
5958
|
case "info":
|
|
5810
|
-
return
|
|
5959
|
+
return chalk7.blue("[info]");
|
|
5811
5960
|
}
|
|
5812
5961
|
}
|
|
5813
5962
|
function printCategoryTable(result) {
|
|
@@ -5887,7 +6036,7 @@ function handlePredictError(err, mode) {
|
|
|
5887
6036
|
process.exit(ExitCode.ERROR);
|
|
5888
6037
|
}
|
|
5889
6038
|
function createPredictCommand() {
|
|
5890
|
-
const command = new
|
|
6039
|
+
const command = new Command53("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) => {
|
|
5891
6040
|
const globalOpts = cmd.optsWithGlobals();
|
|
5892
6041
|
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
5893
6042
|
try {
|
|
@@ -5911,8 +6060,8 @@ function createPredictCommand() {
|
|
|
5911
6060
|
|
|
5912
6061
|
// src/commands/publish-analyses.ts
|
|
5913
6062
|
import * as fs25 from "fs";
|
|
5914
|
-
import * as
|
|
5915
|
-
import { Command as
|
|
6063
|
+
import * as path43 from "path";
|
|
6064
|
+
import { Command as Command54 } from "commander";
|
|
5916
6065
|
init_dist();
|
|
5917
6066
|
import {
|
|
5918
6067
|
renderAnalysisComment,
|
|
@@ -5920,7 +6069,7 @@ import {
|
|
|
5920
6069
|
savePublishedIndex
|
|
5921
6070
|
} from "@harness-engineering/orchestrator";
|
|
5922
6071
|
function bootstrapTrackerCommand(opts, verb) {
|
|
5923
|
-
const projectPath =
|
|
6072
|
+
const projectPath = path43.resolve(opts.dir);
|
|
5924
6073
|
const trackerConfig = loadTrackerSyncConfig(projectPath);
|
|
5925
6074
|
if (!trackerConfig) {
|
|
5926
6075
|
logger.error(`No tracker config found in harness.config.json. Cannot ${verb}.`);
|
|
@@ -5932,7 +6081,7 @@ function bootstrapTrackerCommand(opts, verb) {
|
|
|
5932
6081
|
);
|
|
5933
6082
|
return null;
|
|
5934
6083
|
}
|
|
5935
|
-
const projectEnvPath =
|
|
6084
|
+
const projectEnvPath = path43.join(projectPath, ".env");
|
|
5936
6085
|
if (fs25.existsSync(projectEnvPath) && !process.env.GITHUB_TOKEN) {
|
|
5937
6086
|
__require("dotenv").config({ path: projectEnvPath });
|
|
5938
6087
|
}
|
|
@@ -5944,7 +6093,7 @@ function bootstrapTrackerCommand(opts, verb) {
|
|
|
5944
6093
|
return { token, projectPath, trackerConfig };
|
|
5945
6094
|
}
|
|
5946
6095
|
function buildNameToExternalIdMap(projectPath) {
|
|
5947
|
-
const roadmapFile =
|
|
6096
|
+
const roadmapFile = path43.join(projectPath, "docs", "roadmap.md");
|
|
5948
6097
|
if (!fs25.existsSync(roadmapFile)) {
|
|
5949
6098
|
logger.error("No docs/roadmap.md found. Cannot map issue hashes to external IDs.");
|
|
5950
6099
|
return null;
|
|
@@ -6000,8 +6149,8 @@ async function runPublishAnalyses(opts) {
|
|
|
6000
6149
|
const nameToExternalId = buildNameToExternalIdMap(projectPath);
|
|
6001
6150
|
if (!nameToExternalId) return process.exit(1);
|
|
6002
6151
|
const { AnalysisArchive } = await import("@harness-engineering/orchestrator");
|
|
6003
|
-
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-
|
|
6004
|
-
const archive = new AnalysisArchive(
|
|
6152
|
+
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-TG63OKA5.js");
|
|
6153
|
+
const archive = new AnalysisArchive(path43.join(projectPath, ".harness", "analyses"));
|
|
6005
6154
|
const analyses = await archive.list();
|
|
6006
6155
|
if (analyses.length === 0) {
|
|
6007
6156
|
logger.info("No analyses found to publish.");
|
|
@@ -6023,7 +6172,7 @@ async function runPublishAnalyses(opts) {
|
|
|
6023
6172
|
}
|
|
6024
6173
|
}
|
|
6025
6174
|
function createPublishAnalysesCommand() {
|
|
6026
|
-
const command = new
|
|
6175
|
+
const command = new Command54("publish-analyses").description(
|
|
6027
6176
|
"Publishes locally generated intelligence analyses to the external issue tracker (e.g., GitHub)"
|
|
6028
6177
|
).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
6029
6178
|
try {
|
|
@@ -6039,8 +6188,8 @@ function createPublishAnalysesCommand() {
|
|
|
6039
6188
|
}
|
|
6040
6189
|
|
|
6041
6190
|
// src/commands/recommend.ts
|
|
6042
|
-
import { Command as
|
|
6043
|
-
import
|
|
6191
|
+
import { Command as Command55 } from "commander";
|
|
6192
|
+
import chalk8 from "chalk";
|
|
6044
6193
|
async function resolveSnapshot(cwd, noCache) {
|
|
6045
6194
|
if (!noCache) {
|
|
6046
6195
|
const cached = loadCachedSnapshot(cwd);
|
|
@@ -6074,12 +6223,12 @@ async function runRecommend(options) {
|
|
|
6074
6223
|
function formatRecommendation(rec) {
|
|
6075
6224
|
const lines = [];
|
|
6076
6225
|
if (rec.urgency === "critical") {
|
|
6077
|
-
lines.push(` ${
|
|
6226
|
+
lines.push(` ${chalk8.red("[CRITICAL]")} ${rec.sequence}. ${rec.skillName}`);
|
|
6078
6227
|
} else {
|
|
6079
6228
|
lines.push(` ${rec.sequence}. ${rec.skillName} (${rec.score.toFixed(2)})`);
|
|
6080
6229
|
}
|
|
6081
6230
|
for (const reason of rec.reasons) {
|
|
6082
|
-
lines.push(` ${
|
|
6231
|
+
lines.push(` ${chalk8.dim("\u2192")} ${reason}`);
|
|
6083
6232
|
}
|
|
6084
6233
|
return lines.join("\n");
|
|
6085
6234
|
}
|
|
@@ -6103,7 +6252,7 @@ function printRecommendations(result) {
|
|
|
6103
6252
|
console.log("");
|
|
6104
6253
|
}
|
|
6105
6254
|
function createRecommendCommand() {
|
|
6106
|
-
const command = new
|
|
6255
|
+
const command = new Command55("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) => {
|
|
6107
6256
|
const globalOpts = cmd.optsWithGlobals();
|
|
6108
6257
|
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
6109
6258
|
try {
|
|
@@ -6140,9 +6289,9 @@ function createRecommendCommand() {
|
|
|
6140
6289
|
|
|
6141
6290
|
// src/commands/scan-config.ts
|
|
6142
6291
|
init_dist();
|
|
6143
|
-
import { Command as
|
|
6292
|
+
import { Command as Command56 } from "commander";
|
|
6144
6293
|
import { existsSync as existsSync22, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
|
|
6145
|
-
import { join as
|
|
6294
|
+
import { join as join31, relative as relative2 } from "path";
|
|
6146
6295
|
var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
|
|
6147
6296
|
function stripHighSeverityPatterns(content, injectionFindings) {
|
|
6148
6297
|
const highLines = /* @__PURE__ */ new Set();
|
|
@@ -6199,7 +6348,7 @@ async function runScanConfig(targetDir, options) {
|
|
|
6199
6348
|
const scanner = new SecurityScanner(parseSecurityConfig({}));
|
|
6200
6349
|
const results = [];
|
|
6201
6350
|
for (const configFile of CONFIG_FILES) {
|
|
6202
|
-
const result = scanSingleFile(
|
|
6351
|
+
const result = scanSingleFile(join31(targetDir, configFile), targetDir, scanner, options);
|
|
6203
6352
|
if (result) results.push(result);
|
|
6204
6353
|
}
|
|
6205
6354
|
return { exitCode: computeScanExitCode(results), results };
|
|
@@ -6229,7 +6378,7 @@ function formatTextOutput(result) {
|
|
|
6229
6378
|
}
|
|
6230
6379
|
}
|
|
6231
6380
|
function createScanConfigCommand() {
|
|
6232
|
-
const command = new
|
|
6381
|
+
const command = new Command56("scan-config").description(
|
|
6233
6382
|
"Scan CLAUDE.md, AGENTS.md, .gemini/settings.json, and skill.yaml for prompt injection patterns"
|
|
6234
6383
|
).option("--path <dir>", "Target directory to scan (default: cwd)").option("--fix", "Strip high-severity patterns from files in-place").action(async (opts, cmd) => {
|
|
6235
6384
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -6246,18 +6395,18 @@ function createScanConfigCommand() {
|
|
|
6246
6395
|
}
|
|
6247
6396
|
|
|
6248
6397
|
// src/commands/setup.ts
|
|
6249
|
-
import { Command as
|
|
6398
|
+
import { Command as Command57 } from "commander";
|
|
6250
6399
|
import * as fs28 from "fs";
|
|
6251
6400
|
import * as os7 from "os";
|
|
6252
|
-
import * as
|
|
6253
|
-
import
|
|
6401
|
+
import * as path46 from "path";
|
|
6402
|
+
import chalk10 from "chalk";
|
|
6254
6403
|
|
|
6255
6404
|
// src/utils/first-run.ts
|
|
6256
6405
|
import * as fs26 from "fs";
|
|
6257
6406
|
import * as os6 from "os";
|
|
6258
|
-
import * as
|
|
6259
|
-
var HARNESS_DIR =
|
|
6260
|
-
var MARKER_FILE =
|
|
6407
|
+
import * as path44 from "path";
|
|
6408
|
+
var HARNESS_DIR = path44.join(os6.homedir(), ".harness");
|
|
6409
|
+
var MARKER_FILE = path44.join(HARNESS_DIR, ".setup-complete");
|
|
6261
6410
|
function isFirstRun() {
|
|
6262
6411
|
return !fs26.existsSync(MARKER_FILE);
|
|
6263
6412
|
}
|
|
@@ -6277,9 +6426,9 @@ function printFirstRunWelcome() {
|
|
|
6277
6426
|
|
|
6278
6427
|
// src/commands/telemetry-wizard.ts
|
|
6279
6428
|
import * as fs27 from "fs";
|
|
6280
|
-
import * as
|
|
6429
|
+
import * as path45 from "path";
|
|
6281
6430
|
import readline from "readline";
|
|
6282
|
-
import
|
|
6431
|
+
import chalk9 from "chalk";
|
|
6283
6432
|
function prompt(question) {
|
|
6284
6433
|
const rl = readline.createInterface({
|
|
6285
6434
|
input: process.stdin,
|
|
@@ -6308,7 +6457,7 @@ function isNo(answer) {
|
|
|
6308
6457
|
return answer === "n" || answer === "no";
|
|
6309
6458
|
}
|
|
6310
6459
|
function isTelemetryConfigured(cwd) {
|
|
6311
|
-
const configPath =
|
|
6460
|
+
const configPath = path45.join(cwd, "harness.config.json");
|
|
6312
6461
|
try {
|
|
6313
6462
|
const raw = JSON.parse(fs27.readFileSync(configPath, "utf-8"));
|
|
6314
6463
|
return raw.telemetry !== void 0 && raw.adoption !== void 0;
|
|
@@ -6317,7 +6466,7 @@ function isTelemetryConfigured(cwd) {
|
|
|
6317
6466
|
}
|
|
6318
6467
|
}
|
|
6319
6468
|
function writeTelemetryConfig(cwd, result) {
|
|
6320
|
-
const configPath =
|
|
6469
|
+
const configPath = path45.join(cwd, "harness.config.json");
|
|
6321
6470
|
try {
|
|
6322
6471
|
const raw = JSON.parse(fs27.readFileSync(configPath, "utf-8"));
|
|
6323
6472
|
raw.telemetry = { enabled: result.telemetryEnabled };
|
|
@@ -6330,15 +6479,15 @@ function writeTelemetryConfig(cwd, result) {
|
|
|
6330
6479
|
}
|
|
6331
6480
|
const hasIdentity = result.identity.project || result.identity.team || result.identity.alias;
|
|
6332
6481
|
if (hasIdentity) {
|
|
6333
|
-
const harnessDir =
|
|
6482
|
+
const harnessDir = path45.join(cwd, ".harness");
|
|
6334
6483
|
fs27.mkdirSync(harnessDir, { recursive: true });
|
|
6335
|
-
const telemetryFile =
|
|
6484
|
+
const telemetryFile = path45.join(harnessDir, "telemetry.json");
|
|
6336
6485
|
fs27.writeFileSync(telemetryFile, JSON.stringify({ identity: result.identity }, null, 2) + "\n");
|
|
6337
6486
|
}
|
|
6338
6487
|
}
|
|
6339
6488
|
async function promptIdentity() {
|
|
6340
6489
|
console.log(
|
|
6341
|
-
` ${
|
|
6490
|
+
` ${chalk9.cyan("Identity")} (optional) \u2014 tag telemetry with project/team/alias for filtering.`
|
|
6342
6491
|
);
|
|
6343
6492
|
console.log(" Leave blank to keep anonymous.");
|
|
6344
6493
|
const answer = await prompt(" Set identity fields? (y/N) ");
|
|
@@ -6356,20 +6505,20 @@ async function promptIdentity() {
|
|
|
6356
6505
|
async function runTelemetryWizard() {
|
|
6357
6506
|
if (!process.stdin.isTTY) return null;
|
|
6358
6507
|
console.log("");
|
|
6359
|
-
console.log(` ${
|
|
6508
|
+
console.log(` ${chalk9.bold("Telemetry Configuration")}`);
|
|
6360
6509
|
console.log("");
|
|
6361
6510
|
console.log(" Harness can collect anonymous usage data to help improve the tool.");
|
|
6362
6511
|
console.log(" You can change these settings anytime in harness.config.json.");
|
|
6363
6512
|
console.log("");
|
|
6364
6513
|
console.log(
|
|
6365
|
-
` ${
|
|
6514
|
+
` ${chalk9.cyan("Anonymous telemetry")} \u2014 error rates, command usage, performance metrics.`
|
|
6366
6515
|
);
|
|
6367
6516
|
console.log(" No code, file contents, or personally identifiable info is sent.");
|
|
6368
6517
|
const telemetryAnswer = await prompt(" Enable anonymous telemetry? (Y/n) ");
|
|
6369
6518
|
const telemetryEnabled = !isNo(telemetryAnswer);
|
|
6370
6519
|
console.log("");
|
|
6371
6520
|
console.log(
|
|
6372
|
-
` ${
|
|
6521
|
+
` ${chalk9.cyan("Adoption tracking")} \u2014 which skills are used, how often, and success rates.`
|
|
6373
6522
|
);
|
|
6374
6523
|
console.log(" Stored locally in .harness/adoption/. Never sent externally.");
|
|
6375
6524
|
const adoptionAnswer = await prompt(" Enable local adoption tracking? (Y/n) ");
|
|
@@ -6379,7 +6528,7 @@ async function runTelemetryWizard() {
|
|
|
6379
6528
|
return { telemetryEnabled, adoptionEnabled, identity };
|
|
6380
6529
|
}
|
|
6381
6530
|
async function ensureTelemetryConfigured(cwd) {
|
|
6382
|
-
const configPath =
|
|
6531
|
+
const configPath = path45.join(cwd, "harness.config.json");
|
|
6383
6532
|
if (!fs27.existsSync(configPath)) {
|
|
6384
6533
|
return { status: "warn", message: "Not a harness project \u2014 skipped telemetry configuration" };
|
|
6385
6534
|
}
|
|
@@ -6426,7 +6575,7 @@ function runSlashCommandGeneration() {
|
|
|
6426
6575
|
}
|
|
6427
6576
|
}
|
|
6428
6577
|
function detectClient(dirName) {
|
|
6429
|
-
return fs28.existsSync(
|
|
6578
|
+
return fs28.existsSync(path46.join(os7.homedir(), dirName));
|
|
6430
6579
|
}
|
|
6431
6580
|
async function runMcpSetup(cwd) {
|
|
6432
6581
|
const results = [];
|
|
@@ -6463,12 +6612,12 @@ async function runMcpSetup(cwd) {
|
|
|
6463
6612
|
return results;
|
|
6464
6613
|
}
|
|
6465
6614
|
function formatStep(result) {
|
|
6466
|
-
const icon = result.status === "pass" ?
|
|
6615
|
+
const icon = result.status === "pass" ? chalk10.green("\u2713") : result.status === "warn" ? chalk10.yellow("\u26A0") : chalk10.red("\u2717");
|
|
6467
6616
|
return ` ${icon} ${result.message}`;
|
|
6468
6617
|
}
|
|
6469
6618
|
function configureTier0Integrations(cwd) {
|
|
6470
6619
|
try {
|
|
6471
|
-
const mcpPath =
|
|
6620
|
+
const mcpPath = path46.join(cwd, ".mcp.json");
|
|
6472
6621
|
const config = readMcpConfig(mcpPath);
|
|
6473
6622
|
const tier0 = INTEGRATION_REGISTRY.filter((i) => i.tier === 0);
|
|
6474
6623
|
const added = [];
|
|
@@ -6477,9 +6626,9 @@ function configureTier0Integrations(cwd) {
|
|
|
6477
6626
|
writeMcpEntry(mcpPath, integration.name, integration.mcpConfig);
|
|
6478
6627
|
added.push(integration.displayName);
|
|
6479
6628
|
}
|
|
6480
|
-
const geminiDir =
|
|
6629
|
+
const geminiDir = path46.join(cwd, ".gemini");
|
|
6481
6630
|
if (fs28.existsSync(geminiDir)) {
|
|
6482
|
-
const geminiPath =
|
|
6631
|
+
const geminiPath = path46.join(geminiDir, "settings.json");
|
|
6483
6632
|
const geminiConfig = readMcpConfig(geminiPath);
|
|
6484
6633
|
for (const integration of tier0) {
|
|
6485
6634
|
if (!geminiConfig.mcpServers[integration.name]) {
|
|
@@ -6500,12 +6649,12 @@ function configureTier0Integrations(cwd) {
|
|
|
6500
6649
|
}
|
|
6501
6650
|
}
|
|
6502
6651
|
function ensureHooks(cwd) {
|
|
6503
|
-
const configPath =
|
|
6652
|
+
const configPath = path46.join(cwd, "harness.config.json");
|
|
6504
6653
|
if (!fs28.existsSync(configPath)) {
|
|
6505
6654
|
return { status: "warn", message: "Not a harness project \u2014 skipped hook installation" };
|
|
6506
6655
|
}
|
|
6507
6656
|
let profile = "standard";
|
|
6508
|
-
const profilePath =
|
|
6657
|
+
const profilePath = path46.join(cwd, ".harness", "hooks", "profile.json");
|
|
6509
6658
|
try {
|
|
6510
6659
|
const data = JSON.parse(fs28.readFileSync(profilePath, "utf-8"));
|
|
6511
6660
|
if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
|
|
@@ -6526,7 +6675,7 @@ function ensureHooks(cwd) {
|
|
|
6526
6675
|
}
|
|
6527
6676
|
async function runInitialGraphScan(cwd) {
|
|
6528
6677
|
try {
|
|
6529
|
-
const { runScan: runScan2 } = await import("./scan-
|
|
6678
|
+
const { runScan: runScan2 } = await import("./scan-IJ7EYTF7.js");
|
|
6530
6679
|
const result = await runScan2(cwd);
|
|
6531
6680
|
return {
|
|
6532
6681
|
status: "pass",
|
|
@@ -6563,10 +6712,10 @@ async function runSetup(cwd) {
|
|
|
6563
6712
|
return { steps, success };
|
|
6564
6713
|
}
|
|
6565
6714
|
function createSetupCommand() {
|
|
6566
|
-
return new
|
|
6715
|
+
return new Command57("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
|
|
6567
6716
|
const cwd = process.cwd();
|
|
6568
6717
|
console.log("");
|
|
6569
|
-
console.log(` ${
|
|
6718
|
+
console.log(` ${chalk10.bold("harness setup")}`);
|
|
6570
6719
|
console.log("");
|
|
6571
6720
|
const { steps, success } = await runSetup(cwd);
|
|
6572
6721
|
for (const step of steps) {
|
|
@@ -6586,14 +6735,14 @@ function createSetupCommand() {
|
|
|
6586
6735
|
|
|
6587
6736
|
// src/commands/share.ts
|
|
6588
6737
|
init_dist();
|
|
6589
|
-
import { Command as
|
|
6738
|
+
import { Command as Command58 } from "commander";
|
|
6590
6739
|
import * as fs29 from "fs";
|
|
6591
|
-
import * as
|
|
6740
|
+
import * as path47 from "path";
|
|
6592
6741
|
import { parse as parseYaml } from "yaml";
|
|
6593
6742
|
var MANIFEST_FILENAME = "constraints.yaml";
|
|
6594
6743
|
async function runShareAction(projectPath, options) {
|
|
6595
|
-
const rootDir =
|
|
6596
|
-
const manifestPath =
|
|
6744
|
+
const rootDir = path47.resolve(projectPath);
|
|
6745
|
+
const manifestPath = path47.join(rootDir, MANIFEST_FILENAME);
|
|
6597
6746
|
if (!fs29.existsSync(manifestPath)) {
|
|
6598
6747
|
logger.error(
|
|
6599
6748
|
`No ${MANIFEST_FILENAME} found at ${manifestPath}.
|
|
@@ -6617,7 +6766,7 @@ Create a constraints.yaml in your project root to define what to share.`
|
|
|
6617
6766
|
process.exit(1);
|
|
6618
6767
|
}
|
|
6619
6768
|
const manifest = manifestResult.value;
|
|
6620
|
-
const configResult = resolveConfig(
|
|
6769
|
+
const configResult = resolveConfig(path47.join(rootDir, "harness.config.json"));
|
|
6621
6770
|
if (!configResult.ok) {
|
|
6622
6771
|
logger.error(configResult.error.message);
|
|
6623
6772
|
process.exit(1);
|
|
@@ -6635,8 +6784,8 @@ Create a constraints.yaml in your project root to define what to share.`
|
|
|
6635
6784
|
);
|
|
6636
6785
|
process.exit(1);
|
|
6637
6786
|
}
|
|
6638
|
-
const outputDir =
|
|
6639
|
-
const outputPath =
|
|
6787
|
+
const outputDir = path47.resolve(options.output);
|
|
6788
|
+
const outputPath = path47.join(outputDir, `${manifest.name}.harness-constraints.json`);
|
|
6640
6789
|
const writeResult = await writeConfig(outputPath, bundle);
|
|
6641
6790
|
if (!writeResult.ok) {
|
|
6642
6791
|
logger.error(`Failed to write bundle: ${writeResult.error.message}`);
|
|
@@ -6645,25 +6794,25 @@ Create a constraints.yaml in your project root to define what to share.`
|
|
|
6645
6794
|
logger.success(`Bundle written to ${outputPath}`);
|
|
6646
6795
|
}
|
|
6647
6796
|
function createShareCommand() {
|
|
6648
|
-
return new
|
|
6797
|
+
return new Command58("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) => {
|
|
6649
6798
|
await runShareAction(projectPath, options);
|
|
6650
6799
|
});
|
|
6651
6800
|
}
|
|
6652
6801
|
|
|
6653
6802
|
// src/commands/skill/index.ts
|
|
6654
|
-
import { Command as
|
|
6803
|
+
import { Command as Command66 } from "commander";
|
|
6655
6804
|
|
|
6656
6805
|
// src/commands/skill/list.ts
|
|
6657
|
-
import { Command as
|
|
6806
|
+
import { Command as Command59 } from "commander";
|
|
6658
6807
|
import * as fs30 from "fs";
|
|
6659
|
-
import * as
|
|
6808
|
+
import * as path48 from "path";
|
|
6660
6809
|
import { parse } from "yaml";
|
|
6661
6810
|
function scanDirectory(dirPath, source) {
|
|
6662
6811
|
if (!fs30.existsSync(dirPath)) return [];
|
|
6663
6812
|
const entries = fs30.readdirSync(dirPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
6664
6813
|
const skills = [];
|
|
6665
6814
|
for (const name of entries) {
|
|
6666
|
-
const yamlPath =
|
|
6815
|
+
const yamlPath = path48.join(dirPath, name, "skill.yaml");
|
|
6667
6816
|
if (!fs30.existsSync(yamlPath)) continue;
|
|
6668
6817
|
try {
|
|
6669
6818
|
const raw = fs30.readFileSync(yamlPath, "utf-8");
|
|
@@ -6684,10 +6833,10 @@ function scanDirectory(dirPath, source) {
|
|
|
6684
6833
|
}
|
|
6685
6834
|
function collectCommunitySkills(seen, allSkills) {
|
|
6686
6835
|
const globalDir = resolveGlobalSkillsDir();
|
|
6687
|
-
const skillsDir =
|
|
6688
|
-
const communityBase =
|
|
6689
|
-
const communityPlatformDir =
|
|
6690
|
-
const lockfilePath =
|
|
6836
|
+
const skillsDir = path48.dirname(globalDir);
|
|
6837
|
+
const communityBase = path48.join(skillsDir, "community");
|
|
6838
|
+
const communityPlatformDir = path48.join(communityBase, "claude-code");
|
|
6839
|
+
const lockfilePath = path48.join(communityBase, "skills-lock.json");
|
|
6691
6840
|
const lockfile = readLockfile2(lockfilePath);
|
|
6692
6841
|
const communitySkills = scanDirectory(communityPlatformDir, "community");
|
|
6693
6842
|
for (const skill of communitySkills) {
|
|
@@ -6757,7 +6906,7 @@ function printSkillsVerbose(skills) {
|
|
|
6757
6906
|
for (const s of skills) printSkillEntry(s);
|
|
6758
6907
|
}
|
|
6759
6908
|
function createListCommand3() {
|
|
6760
|
-
return new
|
|
6909
|
+
return new Command59("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) => {
|
|
6761
6910
|
const globalOpts = cmd.optsWithGlobals();
|
|
6762
6911
|
const skills = collectSkills({ filter: resolveFilter(opts) });
|
|
6763
6912
|
if (globalOpts.json) {
|
|
@@ -6772,9 +6921,9 @@ function createListCommand3() {
|
|
|
6772
6921
|
}
|
|
6773
6922
|
|
|
6774
6923
|
// src/commands/skill/run.ts
|
|
6775
|
-
import { Command as
|
|
6924
|
+
import { Command as Command60 } from "commander";
|
|
6776
6925
|
import * as fs31 from "fs";
|
|
6777
|
-
import * as
|
|
6926
|
+
import * as path49 from "path";
|
|
6778
6927
|
import { parse as parse2 } from "yaml";
|
|
6779
6928
|
|
|
6780
6929
|
// src/skill/complexity.ts
|
|
@@ -6870,7 +7019,7 @@ ${options.principles}`);
|
|
|
6870
7019
|
|
|
6871
7020
|
// src/commands/skill/run.ts
|
|
6872
7021
|
function loadSkillMetadata(skillDir) {
|
|
6873
|
-
const yamlPath =
|
|
7022
|
+
const yamlPath = path49.join(skillDir, "skill.yaml");
|
|
6874
7023
|
if (!fs31.existsSync(yamlPath)) return null;
|
|
6875
7024
|
try {
|
|
6876
7025
|
const result = SkillMetadataSchema.safeParse(parse2(fs31.readFileSync(yamlPath, "utf-8")));
|
|
@@ -6885,18 +7034,18 @@ function resolveComplexity(metadata, requested, projectPath) {
|
|
|
6885
7034
|
return requested;
|
|
6886
7035
|
}
|
|
6887
7036
|
function loadPrinciples(projectPath) {
|
|
6888
|
-
const principlesPath =
|
|
7037
|
+
const principlesPath = path49.join(projectPath, "docs", "principles.md");
|
|
6889
7038
|
return fs31.existsSync(principlesPath) ? fs31.readFileSync(principlesPath, "utf-8") : void 0;
|
|
6890
7039
|
}
|
|
6891
7040
|
function readMostRecentFileInDir(dirPath) {
|
|
6892
|
-
const files = fs31.readdirSync(dirPath).map((f) => ({ name: f, mtime: fs31.statSync(
|
|
6893
|
-
if (files.length > 0) return fs31.readFileSync(
|
|
7041
|
+
const files = fs31.readdirSync(dirPath).map((f) => ({ name: f, mtime: fs31.statSync(path49.join(dirPath, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
7042
|
+
if (files.length > 0) return fs31.readFileSync(path49.join(dirPath, files[0].name), "utf-8");
|
|
6894
7043
|
return void 0;
|
|
6895
7044
|
}
|
|
6896
7045
|
function loadPriorState(metadata, projectPath) {
|
|
6897
7046
|
if (!metadata?.state.persistent || metadata.state.files.length === 0) return void 0;
|
|
6898
7047
|
for (const stateFilePath of metadata.state.files) {
|
|
6899
|
-
const fullPath =
|
|
7048
|
+
const fullPath = path49.join(projectPath, stateFilePath);
|
|
6900
7049
|
if (!fs31.existsSync(fullPath)) continue;
|
|
6901
7050
|
const stat = fs31.statSync(fullPath);
|
|
6902
7051
|
if (stat.isDirectory()) return readMostRecentFileInDir(fullPath);
|
|
@@ -6920,7 +7069,7 @@ function resolvePhaseState(metadata, projectPath, phase) {
|
|
|
6920
7069
|
}
|
|
6921
7070
|
function appendProjectState(content, metadata, projectPath, hasPathOpt) {
|
|
6922
7071
|
if (!metadata?.state.persistent || !hasPathOpt) return content;
|
|
6923
|
-
const stateFile =
|
|
7072
|
+
const stateFile = path49.join(projectPath, ".harness", "state.json");
|
|
6924
7073
|
if (!fs31.existsSync(stateFile)) return content;
|
|
6925
7074
|
const stateContent = fs31.readFileSync(stateFile, "utf-8");
|
|
6926
7075
|
return content + `
|
|
@@ -6934,14 +7083,14 @@ ${stateContent}
|
|
|
6934
7083
|
}
|
|
6935
7084
|
async function runSkill(name, opts) {
|
|
6936
7085
|
const skillsDir = resolveSkillsDir();
|
|
6937
|
-
const skillDir =
|
|
7086
|
+
const skillDir = path49.join(skillsDir, name);
|
|
6938
7087
|
if (!fs31.existsSync(skillDir)) {
|
|
6939
7088
|
logger.error(`Skill not found: ${name}`);
|
|
6940
7089
|
process.exit(ExitCode.ERROR);
|
|
6941
7090
|
return;
|
|
6942
7091
|
}
|
|
6943
7092
|
const metadata = loadSkillMetadata(skillDir);
|
|
6944
|
-
const projectPath = opts.path ?
|
|
7093
|
+
const projectPath = opts.path ? path49.resolve(opts.path) : process.cwd();
|
|
6945
7094
|
const complexity = resolveComplexity(
|
|
6946
7095
|
metadata,
|
|
6947
7096
|
opts.complexity ?? "standard",
|
|
@@ -6968,7 +7117,7 @@ async function runSkill(name, opts) {
|
|
|
6968
7117
|
...stateWarning !== void 0 && { stateWarning },
|
|
6969
7118
|
...opts.party !== void 0 && { party: opts.party }
|
|
6970
7119
|
});
|
|
6971
|
-
const skillMdPath =
|
|
7120
|
+
const skillMdPath = path49.join(skillDir, "SKILL.md");
|
|
6972
7121
|
if (!fs31.existsSync(skillMdPath)) {
|
|
6973
7122
|
logger.error(`SKILL.md not found for skill: ${name}`);
|
|
6974
7123
|
process.exit(ExitCode.ERROR);
|
|
@@ -6984,13 +7133,13 @@ async function runSkill(name, opts) {
|
|
|
6984
7133
|
process.exit(ExitCode.SUCCESS);
|
|
6985
7134
|
}
|
|
6986
7135
|
function createRunCommand2() {
|
|
6987
|
-
return new
|
|
7136
|
+
return new Command60("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").action(async (name, opts) => runSkill(name, opts));
|
|
6988
7137
|
}
|
|
6989
7138
|
|
|
6990
7139
|
// src/commands/skill/validate.ts
|
|
6991
|
-
import { Command as
|
|
7140
|
+
import { Command as Command61 } from "commander";
|
|
6992
7141
|
import * as fs32 from "fs";
|
|
6993
|
-
import * as
|
|
7142
|
+
import * as path50 from "path";
|
|
6994
7143
|
import { parse as parse3 } from "yaml";
|
|
6995
7144
|
var BEHAVIORAL_REQUIRED_SECTIONS = [
|
|
6996
7145
|
"## When to Use",
|
|
@@ -7031,8 +7180,8 @@ function validateSkillMd(name, skillMdPath, skillType, errors) {
|
|
|
7031
7180
|
}
|
|
7032
7181
|
}
|
|
7033
7182
|
function validateSkillEntry(name, skillsDir, errors) {
|
|
7034
|
-
const skillDir =
|
|
7035
|
-
const yamlPath =
|
|
7183
|
+
const skillDir = path50.join(skillsDir, name);
|
|
7184
|
+
const yamlPath = path50.join(skillDir, "skill.yaml");
|
|
7036
7185
|
if (!fs32.existsSync(yamlPath)) {
|
|
7037
7186
|
errors.push(`${name}: missing skill.yaml`);
|
|
7038
7187
|
return false;
|
|
@@ -7044,7 +7193,7 @@ function validateSkillEntry(name, skillsDir, errors) {
|
|
|
7044
7193
|
errors.push(`${name}/skill.yaml: ${result.error.message}`);
|
|
7045
7194
|
return false;
|
|
7046
7195
|
}
|
|
7047
|
-
validateSkillMd(name,
|
|
7196
|
+
validateSkillMd(name, path50.join(skillDir, "SKILL.md"), result.data.type, errors);
|
|
7048
7197
|
return true;
|
|
7049
7198
|
} catch (e) {
|
|
7050
7199
|
errors.push(`${name}: parse error \u2014 ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -7052,7 +7201,7 @@ function validateSkillEntry(name, skillsDir, errors) {
|
|
|
7052
7201
|
}
|
|
7053
7202
|
}
|
|
7054
7203
|
function createValidateCommand2() {
|
|
7055
|
-
return new
|
|
7204
|
+
return new Command61("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
|
|
7056
7205
|
const globalOpts = cmd.optsWithGlobals();
|
|
7057
7206
|
const skillsDir = resolveSkillsDir();
|
|
7058
7207
|
if (!fs32.existsSync(skillsDir)) {
|
|
@@ -7082,18 +7231,18 @@ function createValidateCommand2() {
|
|
|
7082
7231
|
}
|
|
7083
7232
|
|
|
7084
7233
|
// src/commands/skill/info.ts
|
|
7085
|
-
import { Command as
|
|
7234
|
+
import { Command as Command62 } from "commander";
|
|
7086
7235
|
import * as fs33 from "fs";
|
|
7087
|
-
import * as
|
|
7236
|
+
import * as path51 from "path";
|
|
7088
7237
|
import { parse as parse4 } from "yaml";
|
|
7089
7238
|
function loadSkillMetadata2(name) {
|
|
7090
7239
|
const skillsDir = resolveSkillsDir();
|
|
7091
|
-
const skillDir =
|
|
7240
|
+
const skillDir = path51.join(skillsDir, name);
|
|
7092
7241
|
if (!fs33.existsSync(skillDir)) {
|
|
7093
7242
|
logger.error(`Skill not found: ${name}`);
|
|
7094
7243
|
return { ok: false, exitCode: ExitCode.ERROR };
|
|
7095
7244
|
}
|
|
7096
|
-
const yamlPath =
|
|
7245
|
+
const yamlPath = path51.join(skillDir, "skill.yaml");
|
|
7097
7246
|
if (!fs33.existsSync(yamlPath)) {
|
|
7098
7247
|
logger.error(`skill.yaml not found for skill: ${name}`);
|
|
7099
7248
|
return { ok: false, exitCode: ExitCode.ERROR };
|
|
@@ -7128,7 +7277,7 @@ function printSkillInfo(skill) {
|
|
|
7128
7277
|
console.log(`Persistent: ${skill.state.persistent}`);
|
|
7129
7278
|
}
|
|
7130
7279
|
function createInfoCommand() {
|
|
7131
|
-
return new
|
|
7280
|
+
return new Command62("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
|
|
7132
7281
|
const globalOpts = cmd.optsWithGlobals();
|
|
7133
7282
|
const loaded = loadSkillMetadata2(name);
|
|
7134
7283
|
if (!loaded.ok) {
|
|
@@ -7145,7 +7294,7 @@ function createInfoCommand() {
|
|
|
7145
7294
|
}
|
|
7146
7295
|
|
|
7147
7296
|
// src/commands/skill/search.ts
|
|
7148
|
-
import { Command as
|
|
7297
|
+
import { Command as Command63 } from "commander";
|
|
7149
7298
|
async function runSearch(query, opts) {
|
|
7150
7299
|
const results = await searchNpmRegistry(query, opts.registry);
|
|
7151
7300
|
return results.filter((r) => {
|
|
@@ -7190,14 +7339,14 @@ async function runSearchAction(query, opts, globalOpts) {
|
|
|
7190
7339
|
}
|
|
7191
7340
|
}
|
|
7192
7341
|
function createSearchCommand() {
|
|
7193
|
-
return new
|
|
7342
|
+
return new Command63("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) => {
|
|
7194
7343
|
await runSearchAction(query, opts, cmd.optsWithGlobals());
|
|
7195
7344
|
});
|
|
7196
7345
|
}
|
|
7197
7346
|
|
|
7198
7347
|
// src/commands/skill/create.ts
|
|
7199
|
-
import { Command as
|
|
7200
|
-
import * as
|
|
7348
|
+
import { Command as Command64 } from "commander";
|
|
7349
|
+
import * as path52 from "path";
|
|
7201
7350
|
import * as fs34 from "fs";
|
|
7202
7351
|
import YAML from "yaml";
|
|
7203
7352
|
var KEBAB_CASE_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
@@ -7282,21 +7431,21 @@ function runCreate(name, opts) {
|
|
|
7282
7431
|
if (!KEBAB_CASE_RE.test(name)) {
|
|
7283
7432
|
throw new Error(`Invalid skill name "${name}". Must be kebab-case (e.g., my-skill).`);
|
|
7284
7433
|
}
|
|
7285
|
-
const baseDir = opts.outputDir ??
|
|
7286
|
-
const skillDir =
|
|
7434
|
+
const baseDir = opts.outputDir ?? path52.join(process.cwd(), "agents", "skills", "claude-code");
|
|
7435
|
+
const skillDir = path52.join(baseDir, name);
|
|
7287
7436
|
if (fs34.existsSync(skillDir)) {
|
|
7288
7437
|
throw new Error(`Skill directory already exists: ${skillDir}`);
|
|
7289
7438
|
}
|
|
7290
7439
|
fs34.mkdirSync(skillDir, { recursive: true });
|
|
7291
7440
|
const description = opts.description || `A community skill: ${name}`;
|
|
7292
7441
|
const skillYaml = buildSkillYaml(name, opts);
|
|
7293
|
-
const skillYamlPath =
|
|
7442
|
+
const skillYamlPath = path52.join(skillDir, "skill.yaml");
|
|
7294
7443
|
fs34.writeFileSync(skillYamlPath, YAML.stringify(skillYaml));
|
|
7295
7444
|
const skillMd = buildSkillMd(name, description);
|
|
7296
|
-
const skillMdPath =
|
|
7445
|
+
const skillMdPath = path52.join(skillDir, "SKILL.md");
|
|
7297
7446
|
fs34.writeFileSync(skillMdPath, skillMd);
|
|
7298
7447
|
const readme = buildReadme(name, description);
|
|
7299
|
-
const readmePath =
|
|
7448
|
+
const readmePath = path52.join(skillDir, "README.md");
|
|
7300
7449
|
fs34.writeFileSync(readmePath, readme);
|
|
7301
7450
|
return {
|
|
7302
7451
|
name,
|
|
@@ -7311,12 +7460,12 @@ function printCreateResult(name, result) {
|
|
|
7311
7460
|
}
|
|
7312
7461
|
logger.info(`
|
|
7313
7462
|
Next steps:`);
|
|
7314
|
-
logger.info(` 1. Edit ${
|
|
7463
|
+
logger.info(` 1. Edit ${path52.join(result.directory, "SKILL.md")} with your skill content`);
|
|
7315
7464
|
logger.info(` 2. Run: harness skill validate ${name}`);
|
|
7316
7465
|
logger.info(` 3. Run: harness skills publish`);
|
|
7317
7466
|
}
|
|
7318
7467
|
function createCreateCommand() {
|
|
7319
|
-
return new
|
|
7468
|
+
return new Command64("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) => {
|
|
7320
7469
|
const globalOpts = cmd.optsWithGlobals();
|
|
7321
7470
|
try {
|
|
7322
7471
|
const result = runCreate(name, {
|
|
@@ -7339,19 +7488,19 @@ function createCreateCommand() {
|
|
|
7339
7488
|
}
|
|
7340
7489
|
|
|
7341
7490
|
// src/commands/skill/publish.ts
|
|
7342
|
-
import { Command as
|
|
7491
|
+
import { Command as Command65 } from "commander";
|
|
7343
7492
|
import * as fs36 from "fs";
|
|
7344
|
-
import * as
|
|
7493
|
+
import * as path54 from "path";
|
|
7345
7494
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
7346
7495
|
|
|
7347
7496
|
// src/registry/validator.ts
|
|
7348
7497
|
import * as fs35 from "fs";
|
|
7349
|
-
import * as
|
|
7498
|
+
import * as path53 from "path";
|
|
7350
7499
|
import { parse as parse5 } from "yaml";
|
|
7351
7500
|
import semver4 from "semver";
|
|
7352
7501
|
async function validateForPublish(skillDir, registryUrl) {
|
|
7353
7502
|
const errors = [];
|
|
7354
|
-
const skillYamlPath =
|
|
7503
|
+
const skillYamlPath = path53.join(skillDir, "skill.yaml");
|
|
7355
7504
|
if (!fs35.existsSync(skillYamlPath)) {
|
|
7356
7505
|
errors.push("skill.yaml not found. Create one with: harness skill create <name>");
|
|
7357
7506
|
return { valid: false, errors };
|
|
@@ -7380,7 +7529,7 @@ async function validateForPublish(skillDir, registryUrl) {
|
|
|
7380
7529
|
if (!skillMeta.triggers || skillMeta.triggers.length === 0) {
|
|
7381
7530
|
errors.push("At least one trigger is required. Add triggers to skill.yaml.");
|
|
7382
7531
|
}
|
|
7383
|
-
const skillMdPath =
|
|
7532
|
+
const skillMdPath = path53.join(skillDir, "SKILL.md");
|
|
7384
7533
|
if (!fs35.existsSync(skillMdPath)) {
|
|
7385
7534
|
errors.push("SKILL.md not found. Create it with content describing your skill.");
|
|
7386
7535
|
} else {
|
|
@@ -7464,11 +7613,11 @@ ${errorList}`);
|
|
|
7464
7613
|
}
|
|
7465
7614
|
const meta = validation.skillMeta;
|
|
7466
7615
|
const pkg = derivePackageJson(meta);
|
|
7467
|
-
const pkgPath =
|
|
7616
|
+
const pkgPath = path54.join(skillDir, "package.json");
|
|
7468
7617
|
fs36.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
7469
|
-
const readmePath =
|
|
7618
|
+
const readmePath = path54.join(skillDir, "README.md");
|
|
7470
7619
|
if (!fs36.existsSync(readmePath)) {
|
|
7471
|
-
const skillMdContent = fs36.readFileSync(
|
|
7620
|
+
const skillMdContent = fs36.readFileSync(path54.join(skillDir, "SKILL.md"), "utf-8");
|
|
7472
7621
|
const readme = `# ${pkg.name}
|
|
7473
7622
|
|
|
7474
7623
|
${meta.description}
|
|
@@ -7508,7 +7657,7 @@ ${skillMdContent}`;
|
|
|
7508
7657
|
};
|
|
7509
7658
|
}
|
|
7510
7659
|
function createPublishCommand() {
|
|
7511
|
-
return new
|
|
7660
|
+
return new Command65("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) => {
|
|
7512
7661
|
const globalOpts = cmd.optsWithGlobals();
|
|
7513
7662
|
const skillDir = opts.dir || process.cwd();
|
|
7514
7663
|
try {
|
|
@@ -7533,7 +7682,7 @@ function createPublishCommand() {
|
|
|
7533
7682
|
|
|
7534
7683
|
// src/commands/skill/index.ts
|
|
7535
7684
|
function createSkillCommand() {
|
|
7536
|
-
const command = new
|
|
7685
|
+
const command = new Command66("skill").description("Skill management commands");
|
|
7537
7686
|
command.addCommand(createListCommand3());
|
|
7538
7687
|
command.addCommand(createRunCommand2());
|
|
7539
7688
|
command.addCommand(createValidateCommand2());
|
|
@@ -7546,9 +7695,9 @@ function createSkillCommand() {
|
|
|
7546
7695
|
|
|
7547
7696
|
// src/commands/snapshot.ts
|
|
7548
7697
|
init_dist();
|
|
7549
|
-
import { Command as
|
|
7698
|
+
import { Command as Command67 } from "commander";
|
|
7550
7699
|
import { execSync as execSync5 } from "child_process";
|
|
7551
|
-
import
|
|
7700
|
+
import chalk11 from "chalk";
|
|
7552
7701
|
function getCommitHash3(cwd) {
|
|
7553
7702
|
try {
|
|
7554
7703
|
return execSync5("git rev-parse --short HEAD", { cwd, encoding: "utf-8" }).toString().trim();
|
|
@@ -7573,9 +7722,9 @@ function formatDelta(delta) {
|
|
|
7573
7722
|
function directionSymbol(direction) {
|
|
7574
7723
|
switch (direction) {
|
|
7575
7724
|
case "improving":
|
|
7576
|
-
return
|
|
7725
|
+
return chalk11.green("improving");
|
|
7577
7726
|
case "declining":
|
|
7578
|
-
return
|
|
7727
|
+
return chalk11.red("declining");
|
|
7579
7728
|
case "stable":
|
|
7580
7729
|
return "=";
|
|
7581
7730
|
}
|
|
@@ -7728,7 +7877,7 @@ function registerListCommand(parent) {
|
|
|
7728
7877
|
});
|
|
7729
7878
|
}
|
|
7730
7879
|
function createSnapshotCommand() {
|
|
7731
|
-
const command = new
|
|
7880
|
+
const command = new Command67("snapshot").description("Architecture timeline snapshot commands");
|
|
7732
7881
|
registerCaptureCommand(command);
|
|
7733
7882
|
registerTrendsCommand(command);
|
|
7734
7883
|
registerListCommand(command);
|
|
@@ -7736,12 +7885,12 @@ function createSnapshotCommand() {
|
|
|
7736
7885
|
}
|
|
7737
7886
|
|
|
7738
7887
|
// src/commands/state/index.ts
|
|
7739
|
-
import { Command as
|
|
7888
|
+
import { Command as Command72 } from "commander";
|
|
7740
7889
|
|
|
7741
7890
|
// src/commands/state/show.ts
|
|
7742
7891
|
init_dist();
|
|
7743
|
-
import { Command as
|
|
7744
|
-
import * as
|
|
7892
|
+
import { Command as Command68 } from "commander";
|
|
7893
|
+
import * as path55 from "path";
|
|
7745
7894
|
function printStateText(state, stream) {
|
|
7746
7895
|
if (stream) console.log(`Stream: ${stream}`);
|
|
7747
7896
|
console.log(`Schema Version: ${state.schemaVersion}`);
|
|
@@ -7765,9 +7914,9 @@ function printStateProgress(progress) {
|
|
|
7765
7914
|
}
|
|
7766
7915
|
}
|
|
7767
7916
|
function createShowCommand() {
|
|
7768
|
-
return new
|
|
7917
|
+
return new Command68("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
|
|
7769
7918
|
const globalOpts = cmd.optsWithGlobals();
|
|
7770
|
-
const result = await loadState(
|
|
7919
|
+
const result = await loadState(path55.resolve(opts.path), opts.stream);
|
|
7771
7920
|
if (!result.ok) {
|
|
7772
7921
|
logger.error(result.error.message);
|
|
7773
7922
|
process.exit(ExitCode.ERROR);
|
|
@@ -7783,9 +7932,9 @@ function createShowCommand() {
|
|
|
7783
7932
|
|
|
7784
7933
|
// src/commands/state/reset.ts
|
|
7785
7934
|
init_dist();
|
|
7786
|
-
import { Command as
|
|
7935
|
+
import { Command as Command69 } from "commander";
|
|
7787
7936
|
import * as fs37 from "fs";
|
|
7788
|
-
import * as
|
|
7937
|
+
import * as path56 from "path";
|
|
7789
7938
|
import * as readline2 from "readline";
|
|
7790
7939
|
async function resolveStatePath(projectPath, stream) {
|
|
7791
7940
|
if (stream) {
|
|
@@ -7794,9 +7943,9 @@ async function resolveStatePath(projectPath, stream) {
|
|
|
7794
7943
|
logger.error(streamResult.error.message);
|
|
7795
7944
|
process.exit(ExitCode.ERROR);
|
|
7796
7945
|
}
|
|
7797
|
-
return
|
|
7946
|
+
return path56.join(streamResult.value, "state.json");
|
|
7798
7947
|
}
|
|
7799
|
-
return
|
|
7948
|
+
return path56.join(projectPath, ".harness", "state.json");
|
|
7800
7949
|
}
|
|
7801
7950
|
async function confirmReset() {
|
|
7802
7951
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -7807,7 +7956,7 @@ async function confirmReset() {
|
|
|
7807
7956
|
return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
7808
7957
|
}
|
|
7809
7958
|
async function runReset(opts) {
|
|
7810
|
-
const projectPath =
|
|
7959
|
+
const projectPath = path56.resolve(opts.path);
|
|
7811
7960
|
const statePath = await resolveStatePath(projectPath, opts.stream);
|
|
7812
7961
|
if (!fs37.existsSync(statePath)) {
|
|
7813
7962
|
logger.info("No state file found. Nothing to reset.");
|
|
@@ -7827,16 +7976,16 @@ async function runReset(opts) {
|
|
|
7827
7976
|
process.exit(ExitCode.SUCCESS);
|
|
7828
7977
|
}
|
|
7829
7978
|
function createResetCommand() {
|
|
7830
|
-
return new
|
|
7979
|
+
return new Command69("reset").description("Reset project state (deletes .harness/state.json)").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").option("--yes", "Skip confirmation prompt").action(async (opts) => runReset(opts));
|
|
7831
7980
|
}
|
|
7832
7981
|
|
|
7833
7982
|
// src/commands/state/learn.ts
|
|
7834
7983
|
init_dist();
|
|
7835
|
-
import { Command as
|
|
7836
|
-
import * as
|
|
7984
|
+
import { Command as Command70 } from "commander";
|
|
7985
|
+
import * as path57 from "path";
|
|
7837
7986
|
function createLearnCommand() {
|
|
7838
|
-
return new
|
|
7839
|
-
const projectPath =
|
|
7987
|
+
return new Command70("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) => {
|
|
7988
|
+
const projectPath = path57.resolve(opts.path);
|
|
7840
7989
|
const result = await appendLearning(projectPath, message, void 0, void 0, opts.stream);
|
|
7841
7990
|
if (!result.ok) {
|
|
7842
7991
|
logger.error(result.error.message);
|
|
@@ -7850,10 +7999,10 @@ function createLearnCommand() {
|
|
|
7850
7999
|
|
|
7851
8000
|
// src/commands/state/streams.ts
|
|
7852
8001
|
init_dist();
|
|
7853
|
-
import { Command as
|
|
7854
|
-
import * as
|
|
8002
|
+
import { Command as Command71 } from "commander";
|
|
8003
|
+
import * as path58 from "path";
|
|
7855
8004
|
async function runListStreams(opts, globalOpts) {
|
|
7856
|
-
const projectPath =
|
|
8005
|
+
const projectPath = path58.resolve(opts.path);
|
|
7857
8006
|
const indexResult = await loadStreamIndex(projectPath);
|
|
7858
8007
|
const result = await listStreams(projectPath);
|
|
7859
8008
|
if (!result.ok) {
|
|
@@ -7874,7 +8023,7 @@ async function runListStreams(opts, globalOpts) {
|
|
|
7874
8023
|
process.exit(ExitCode.SUCCESS);
|
|
7875
8024
|
}
|
|
7876
8025
|
async function runCreateStream(name, opts) {
|
|
7877
|
-
const result = await createStream(
|
|
8026
|
+
const result = await createStream(path58.resolve(opts.path), name, opts.branch);
|
|
7878
8027
|
if (!result.ok) {
|
|
7879
8028
|
logger.error(result.error.message);
|
|
7880
8029
|
process.exit(ExitCode.ERROR);
|
|
@@ -7883,7 +8032,7 @@ async function runCreateStream(name, opts) {
|
|
|
7883
8032
|
process.exit(ExitCode.SUCCESS);
|
|
7884
8033
|
}
|
|
7885
8034
|
async function runArchiveStream(name, opts) {
|
|
7886
|
-
const result = await archiveStream(
|
|
8035
|
+
const result = await archiveStream(path58.resolve(opts.path), name);
|
|
7887
8036
|
if (!result.ok) {
|
|
7888
8037
|
logger.error(result.error.message);
|
|
7889
8038
|
process.exit(ExitCode.ERROR);
|
|
@@ -7892,7 +8041,7 @@ async function runArchiveStream(name, opts) {
|
|
|
7892
8041
|
process.exit(ExitCode.SUCCESS);
|
|
7893
8042
|
}
|
|
7894
8043
|
async function runActivateStream(name, opts) {
|
|
7895
|
-
const result = await setActiveStream(
|
|
8044
|
+
const result = await setActiveStream(path58.resolve(opts.path), name);
|
|
7896
8045
|
if (!result.ok) {
|
|
7897
8046
|
logger.error(result.error.message);
|
|
7898
8047
|
process.exit(ExitCode.ERROR);
|
|
@@ -7901,7 +8050,7 @@ async function runActivateStream(name, opts) {
|
|
|
7901
8050
|
process.exit(ExitCode.SUCCESS);
|
|
7902
8051
|
}
|
|
7903
8052
|
function createStreamsCommand() {
|
|
7904
|
-
const command = new
|
|
8053
|
+
const command = new Command71("streams").description("Manage state streams");
|
|
7905
8054
|
command.command("list").description("List all known streams").option("--path <path>", "Project root path", ".").action(async (opts, cmd) => runListStreams(opts, cmd.optsWithGlobals()));
|
|
7906
8055
|
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));
|
|
7907
8056
|
command.command("archive <name>").description("Archive a stream").option("--path <path>", "Project root path", ".").action(async (name, opts) => runArchiveStream(name, opts));
|
|
@@ -7911,7 +8060,7 @@ function createStreamsCommand() {
|
|
|
7911
8060
|
|
|
7912
8061
|
// src/commands/state/index.ts
|
|
7913
8062
|
function createStateCommand() {
|
|
7914
|
-
const command = new
|
|
8063
|
+
const command = new Command72("state").description("Project state management commands");
|
|
7915
8064
|
command.addCommand(createShowCommand());
|
|
7916
8065
|
command.addCommand(createResetCommand());
|
|
7917
8066
|
command.addCommand(createLearnCommand());
|
|
@@ -7921,8 +8070,8 @@ function createStateCommand() {
|
|
|
7921
8070
|
|
|
7922
8071
|
// src/commands/sync-analyses.ts
|
|
7923
8072
|
import * as fs38 from "fs";
|
|
7924
|
-
import * as
|
|
7925
|
-
import { Command as
|
|
8073
|
+
import * as path59 from "path";
|
|
8074
|
+
import { Command as Command73 } from "commander";
|
|
7926
8075
|
init_dist();
|
|
7927
8076
|
function isValidRecord(record) {
|
|
7928
8077
|
return typeof record.issueId === "string" && !!record.issueId && typeof record.identifier === "string" && !!record.identifier && typeof record.analyzedAt === "string" && !/[/\\]/.test(record.issueId);
|
|
@@ -7948,7 +8097,7 @@ function extractAnalysisFromComments(comments) {
|
|
|
7948
8097
|
return null;
|
|
7949
8098
|
}
|
|
7950
8099
|
function bootstrapTrackerCommand2(opts, verb) {
|
|
7951
|
-
const projectPath =
|
|
8100
|
+
const projectPath = path59.resolve(opts.dir);
|
|
7952
8101
|
const trackerConfig = loadTrackerSyncConfig(projectPath);
|
|
7953
8102
|
if (!trackerConfig) {
|
|
7954
8103
|
logger.error(`No tracker config found in harness.config.json. Cannot ${verb}.`);
|
|
@@ -7960,7 +8109,7 @@ function bootstrapTrackerCommand2(opts, verb) {
|
|
|
7960
8109
|
);
|
|
7961
8110
|
return null;
|
|
7962
8111
|
}
|
|
7963
|
-
const projectEnvPath =
|
|
8112
|
+
const projectEnvPath = path59.join(projectPath, ".env");
|
|
7964
8113
|
if (fs38.existsSync(projectEnvPath) && !process.env.GITHUB_TOKEN) {
|
|
7965
8114
|
__require("dotenv").config({ path: projectEnvPath });
|
|
7966
8115
|
}
|
|
@@ -7972,7 +8121,7 @@ function bootstrapTrackerCommand2(opts, verb) {
|
|
|
7972
8121
|
return { token, projectPath, trackerConfig };
|
|
7973
8122
|
}
|
|
7974
8123
|
function loadRoadmapFeatures(projectPath) {
|
|
7975
|
-
const roadmapFile =
|
|
8124
|
+
const roadmapFile = path59.join(projectPath, "docs", "roadmap.md");
|
|
7976
8125
|
if (!fs38.existsSync(roadmapFile)) {
|
|
7977
8126
|
logger.error("No docs/roadmap.md found. Cannot discover features with externalIds.");
|
|
7978
8127
|
return null;
|
|
@@ -8029,9 +8178,9 @@ async function runSyncAnalyses(opts) {
|
|
|
8029
8178
|
return;
|
|
8030
8179
|
}
|
|
8031
8180
|
const { AnalysisArchive, loadPublishedIndex: loadPublishedIndex2, savePublishedIndex: savePublishedIndex2 } = await import("@harness-engineering/orchestrator");
|
|
8032
|
-
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-
|
|
8181
|
+
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-TG63OKA5.js");
|
|
8033
8182
|
const adapter = new GitHubIssuesSyncAdapter2({ token, config: trackerConfig });
|
|
8034
|
-
const archive = new AnalysisArchive(
|
|
8183
|
+
const archive = new AnalysisArchive(path59.join(projectPath, ".harness", "analyses"));
|
|
8035
8184
|
const publishedIndex = loadPublishedIndex2(projectPath);
|
|
8036
8185
|
const { syncedCount, skippedCount, warnCount } = await syncFeatureAnalyses(
|
|
8037
8186
|
features,
|
|
@@ -8051,7 +8200,7 @@ async function runSyncAnalyses(opts) {
|
|
|
8051
8200
|
}
|
|
8052
8201
|
}
|
|
8053
8202
|
function createSyncAnalysesCommand() {
|
|
8054
|
-
const command = new
|
|
8203
|
+
const command = new Command73("sync-analyses").description(
|
|
8055
8204
|
"Pull published intelligence analyses from the external issue tracker into the local .harness/analyses/ directory"
|
|
8056
8205
|
).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
8057
8206
|
try {
|
|
@@ -8066,7 +8215,7 @@ function createSyncAnalysesCommand() {
|
|
|
8066
8215
|
|
|
8067
8216
|
// src/commands/taint.ts
|
|
8068
8217
|
init_dist();
|
|
8069
|
-
import { Command as
|
|
8218
|
+
import { Command as Command74 } from "commander";
|
|
8070
8219
|
function getProjectRoot() {
|
|
8071
8220
|
return process.cwd();
|
|
8072
8221
|
}
|
|
@@ -8138,26 +8287,26 @@ function registerStatusCommand(taint) {
|
|
|
8138
8287
|
});
|
|
8139
8288
|
}
|
|
8140
8289
|
function createTaintCommand() {
|
|
8141
|
-
const taint = new
|
|
8290
|
+
const taint = new Command74("taint").description("Manage sentinel session taint state");
|
|
8142
8291
|
registerClearCommand(taint);
|
|
8143
8292
|
registerStatusCommand(taint);
|
|
8144
8293
|
return taint;
|
|
8145
8294
|
}
|
|
8146
8295
|
|
|
8147
8296
|
// src/commands/telemetry/index.ts
|
|
8148
|
-
import { Command as
|
|
8297
|
+
import { Command as Command78 } from "commander";
|
|
8149
8298
|
|
|
8150
8299
|
// src/commands/telemetry/identify.ts
|
|
8151
8300
|
init_dist();
|
|
8152
|
-
import { Command as
|
|
8301
|
+
import { Command as Command75 } from "commander";
|
|
8153
8302
|
import * as fs39 from "fs";
|
|
8154
|
-
import * as
|
|
8303
|
+
import * as path60 from "path";
|
|
8155
8304
|
function telemetryFilePath(cwd) {
|
|
8156
|
-
return
|
|
8305
|
+
return path60.join(cwd, ".harness", "telemetry.json");
|
|
8157
8306
|
}
|
|
8158
8307
|
function writeTelemetryFile(cwd, data) {
|
|
8159
8308
|
const filePath = telemetryFilePath(cwd);
|
|
8160
|
-
const dir =
|
|
8309
|
+
const dir = path60.dirname(filePath);
|
|
8161
8310
|
fs39.mkdirSync(dir, { recursive: true });
|
|
8162
8311
|
fs39.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
8163
8312
|
}
|
|
@@ -8173,7 +8322,7 @@ function printIdentity(identity) {
|
|
|
8173
8322
|
}
|
|
8174
8323
|
}
|
|
8175
8324
|
function createIdentifyCommand() {
|
|
8176
|
-
const cmd = new
|
|
8325
|
+
const cmd = new Command75("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) => {
|
|
8177
8326
|
const cwd = process.cwd();
|
|
8178
8327
|
if (opts.clear) {
|
|
8179
8328
|
writeTelemetryFile(cwd, { identity: {} });
|
|
@@ -8198,7 +8347,7 @@ function createIdentifyCommand() {
|
|
|
8198
8347
|
|
|
8199
8348
|
// src/commands/telemetry/status.ts
|
|
8200
8349
|
init_dist();
|
|
8201
|
-
import { Command as
|
|
8350
|
+
import { Command as Command76 } from "commander";
|
|
8202
8351
|
function gatherEnvOverrides() {
|
|
8203
8352
|
const overrides = {};
|
|
8204
8353
|
if (process.env.DO_NOT_TRACK) overrides.DO_NOT_TRACK = process.env.DO_NOT_TRACK;
|
|
@@ -8240,7 +8389,7 @@ function printHumanStatus(result) {
|
|
|
8240
8389
|
printEnvOverrides(result.envOverrides);
|
|
8241
8390
|
}
|
|
8242
8391
|
function createStatusCommand() {
|
|
8243
|
-
const cmd = new
|
|
8392
|
+
const cmd = new Command76("status").description("Show current telemetry consent state, install ID, and identity").option("--json", "Output as JSON").action((opts) => {
|
|
8244
8393
|
const cwd = process.cwd();
|
|
8245
8394
|
const envOverrides = gatherEnvOverrides();
|
|
8246
8395
|
const consent = resolveConsent(cwd, void 0);
|
|
@@ -8273,11 +8422,11 @@ function createStatusCommand() {
|
|
|
8273
8422
|
|
|
8274
8423
|
// src/commands/telemetry/test.ts
|
|
8275
8424
|
init_dist();
|
|
8276
|
-
import { Command as
|
|
8425
|
+
import { Command as Command77 } from "commander";
|
|
8277
8426
|
|
|
8278
8427
|
// src/bin/command-telemetry.ts
|
|
8279
8428
|
import { existsSync as existsSync36, readFileSync as readFileSync25, mkdirSync as mkdirSync15, appendFileSync, writeFileSync as writeFileSync18 } from "fs";
|
|
8280
|
-
import { join as
|
|
8429
|
+
import { join as join46, parse as parsePath, resolve as resolve33 } from "path";
|
|
8281
8430
|
import { spawn as spawn2 } from "child_process";
|
|
8282
8431
|
var POSTHOG_API_KEY = "phc_wNTdCMcfJXZPgdNeDociZW6vwoGGo4nb7vqEfWThFfsG";
|
|
8283
8432
|
var EXCLUDED_COMMANDS = /* @__PURE__ */ new Set(["help", "completion"]);
|
|
@@ -8285,7 +8434,7 @@ function findProjectRoot(cwd) {
|
|
|
8285
8434
|
let dir = resolve33(cwd);
|
|
8286
8435
|
const { root } = parsePath(dir);
|
|
8287
8436
|
while (dir !== root) {
|
|
8288
|
-
if (existsSync36(
|
|
8437
|
+
if (existsSync36(join46(dir, "harness.config.json"))) return dir;
|
|
8289
8438
|
dir = resolve33(dir, "..");
|
|
8290
8439
|
}
|
|
8291
8440
|
return cwd;
|
|
@@ -8323,7 +8472,7 @@ function resolveCommandName(cmd) {
|
|
|
8323
8472
|
}
|
|
8324
8473
|
function writeCommandRecordSync(cwd, command, duration, outcome) {
|
|
8325
8474
|
try {
|
|
8326
|
-
const metricsDir =
|
|
8475
|
+
const metricsDir = join46(cwd, ".harness", "metrics");
|
|
8327
8476
|
mkdirSync15(metricsDir, { recursive: true });
|
|
8328
8477
|
const record = {
|
|
8329
8478
|
skill: command,
|
|
@@ -8333,13 +8482,13 @@ function writeCommandRecordSync(cwd, command, duration, outcome) {
|
|
|
8333
8482
|
outcome,
|
|
8334
8483
|
phasesReached: []
|
|
8335
8484
|
};
|
|
8336
|
-
const adoptionFile =
|
|
8485
|
+
const adoptionFile = join46(metricsDir, "adoption.jsonl");
|
|
8337
8486
|
appendFileSync(adoptionFile, JSON.stringify(record) + "\n");
|
|
8338
8487
|
} catch {
|
|
8339
8488
|
}
|
|
8340
8489
|
}
|
|
8341
8490
|
function isTelemetryDisabledByConfig(cwd) {
|
|
8342
|
-
const configPath =
|
|
8491
|
+
const configPath = join46(cwd, "harness.config.json");
|
|
8343
8492
|
if (!existsSync36(configPath)) return false;
|
|
8344
8493
|
try {
|
|
8345
8494
|
const config = JSON.parse(readFileSync25(configPath, "utf-8"));
|
|
@@ -8354,10 +8503,10 @@ function isTelemetryOptedOut(cwd) {
|
|
|
8354
8503
|
}
|
|
8355
8504
|
function flushTelemetryBackground(cwd) {
|
|
8356
8505
|
try {
|
|
8357
|
-
const adoptionFile =
|
|
8506
|
+
const adoptionFile = join46(cwd, ".harness", "metrics", "adoption.jsonl");
|
|
8358
8507
|
if (!existsSync36(adoptionFile)) return;
|
|
8359
8508
|
if (isTelemetryOptedOut(cwd)) return;
|
|
8360
|
-
const reporterPath =
|
|
8509
|
+
const reporterPath = join46(cwd, ".harness", "hooks", "telemetry-reporter.js");
|
|
8361
8510
|
if (!existsSync36(reporterPath)) return;
|
|
8362
8511
|
const child = spawn2(process.execPath, [reporterPath], {
|
|
8363
8512
|
cwd,
|
|
@@ -8395,7 +8544,7 @@ function reportTestSuccess(status, distinctId, identity) {
|
|
|
8395
8544
|
if (identity.team) logger.info(` team: ${identity.team}`);
|
|
8396
8545
|
}
|
|
8397
8546
|
function createTestCommand() {
|
|
8398
|
-
return new
|
|
8547
|
+
return new Command77("test").description("Send a test event to PostHog and verify connectivity").action(async () => {
|
|
8399
8548
|
const cwd = process.cwd();
|
|
8400
8549
|
const consent = resolveConsent(cwd, void 0);
|
|
8401
8550
|
if (!consent.allowed) {
|
|
@@ -8432,7 +8581,7 @@ function createTestCommand() {
|
|
|
8432
8581
|
|
|
8433
8582
|
// src/commands/telemetry/index.ts
|
|
8434
8583
|
function createTelemetryCommand() {
|
|
8435
|
-
const command = new
|
|
8584
|
+
const command = new Command78("telemetry").description("Telemetry identity and status management");
|
|
8436
8585
|
command.addCommand(createIdentifyCommand());
|
|
8437
8586
|
command.addCommand(createStatusCommand());
|
|
8438
8587
|
command.addCommand(createTestCommand());
|
|
@@ -8440,8 +8589,8 @@ function createTelemetryCommand() {
|
|
|
8440
8589
|
}
|
|
8441
8590
|
|
|
8442
8591
|
// src/commands/traceability.ts
|
|
8443
|
-
import { Command as
|
|
8444
|
-
import
|
|
8592
|
+
import { Command as Command79 } from "commander";
|
|
8593
|
+
import chalk12 from "chalk";
|
|
8445
8594
|
function confidenceLabel(maxConfidence) {
|
|
8446
8595
|
if (maxConfidence >= 0.8) return "explicit";
|
|
8447
8596
|
if (maxConfidence > 0) return "inferred";
|
|
@@ -8450,13 +8599,13 @@ function confidenceLabel(maxConfidence) {
|
|
|
8450
8599
|
function statusIcon(status) {
|
|
8451
8600
|
switch (status) {
|
|
8452
8601
|
case "full":
|
|
8453
|
-
return
|
|
8602
|
+
return chalk12.green("\u2713 full");
|
|
8454
8603
|
case "code-only":
|
|
8455
|
-
return
|
|
8604
|
+
return chalk12.yellow("\u25D0 code-only");
|
|
8456
8605
|
case "test-only":
|
|
8457
|
-
return
|
|
8606
|
+
return chalk12.yellow("\u25D0 test-only");
|
|
8458
8607
|
case "none":
|
|
8459
|
-
return
|
|
8608
|
+
return chalk12.red("\u2717 none");
|
|
8460
8609
|
default:
|
|
8461
8610
|
return status;
|
|
8462
8611
|
}
|
|
@@ -8498,14 +8647,14 @@ function handleEmptyResults(mode) {
|
|
|
8498
8647
|
}
|
|
8499
8648
|
function printResultTable(result, mode) {
|
|
8500
8649
|
const specLabel = result.specPath || result.featureName || "Unknown";
|
|
8501
|
-
console.log(` ${
|
|
8650
|
+
console.log(` ${chalk12.cyan(specLabel)} ${chalk12.dim(`(${result.summary.total} requirements)`)}`);
|
|
8502
8651
|
console.log("");
|
|
8503
8652
|
const numWidth = 4;
|
|
8504
8653
|
const nameWidth = mode === OutputMode.VERBOSE ? 44 : 36;
|
|
8505
8654
|
const codeWidth = 6;
|
|
8506
8655
|
const testWidth = 7;
|
|
8507
8656
|
const confWidth = 12;
|
|
8508
|
-
const header =
|
|
8657
|
+
const header = chalk12.dim(
|
|
8509
8658
|
` ${pad("#", numWidth)}${pad("Requirement", nameWidth)}${pad("Code", codeWidth)}${pad("Tests", testWidth)}${pad("Confidence", confWidth)}Status`
|
|
8510
8659
|
);
|
|
8511
8660
|
console.log(header);
|
|
@@ -8534,10 +8683,10 @@ function printRequirementRows(requirements, mode, cols) {
|
|
|
8534
8683
|
);
|
|
8535
8684
|
if (mode === OutputMode.VERBOSE) {
|
|
8536
8685
|
for (const f of req.codeFiles) {
|
|
8537
|
-
console.log(
|
|
8686
|
+
console.log(chalk12.dim(` code: ${f.path} (${f.method})`));
|
|
8538
8687
|
}
|
|
8539
8688
|
for (const f of req.testFiles) {
|
|
8540
|
-
console.log(
|
|
8689
|
+
console.log(chalk12.dim(` test: ${f.path} (${f.method})`));
|
|
8541
8690
|
}
|
|
8542
8691
|
}
|
|
8543
8692
|
}
|
|
@@ -8548,7 +8697,7 @@ function printCoverageSummary(summary) {
|
|
|
8548
8697
|
const codePct = s.total > 0 ? Math.round(s.withCode / s.total * 100) : 0;
|
|
8549
8698
|
const testPct = s.total > 0 ? Math.round(s.withTests / s.total * 100) : 0;
|
|
8550
8699
|
console.log(
|
|
8551
|
-
` ${
|
|
8700
|
+
` ${chalk12.bold("Coverage:")} ${fullyPct}% fully traced (${s.fullyTraced}/${s.total}), ${codePct}% with code (${s.withCode}/${s.total}), ${testPct}% with tests (${s.withTests}/${s.total})`
|
|
8552
8701
|
);
|
|
8553
8702
|
}
|
|
8554
8703
|
async function runTraceability(options) {
|
|
@@ -8556,7 +8705,7 @@ async function runTraceability(options) {
|
|
|
8556
8705
|
const projectPath = process.cwd();
|
|
8557
8706
|
const store = await loadGraphStore(projectPath);
|
|
8558
8707
|
if (!store) handleNoStore(mode);
|
|
8559
|
-
const graphModule = await import("./dist-
|
|
8708
|
+
const graphModule = await import("./dist-PGQ32ZI7.js");
|
|
8560
8709
|
const filterOptions = buildFilterOptions(options);
|
|
8561
8710
|
const results = graphModule.queryTraceability(store, filterOptions);
|
|
8562
8711
|
if (results.length === 0) handleEmptyResults(mode);
|
|
@@ -8564,14 +8713,14 @@ async function runTraceability(options) {
|
|
|
8564
8713
|
console.log(JSON.stringify(results, null, 2));
|
|
8565
8714
|
} else {
|
|
8566
8715
|
console.log("");
|
|
8567
|
-
console.log(
|
|
8716
|
+
console.log(chalk12.bold("Spec-to-Implementation Traceability"));
|
|
8568
8717
|
console.log("");
|
|
8569
8718
|
for (const result of results) printResultTable(result, mode);
|
|
8570
8719
|
}
|
|
8571
8720
|
process.exit(ExitCode.SUCCESS);
|
|
8572
8721
|
}
|
|
8573
8722
|
function createTraceabilityCommand() {
|
|
8574
|
-
return new
|
|
8723
|
+
return new Command79("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) => {
|
|
8575
8724
|
const globalOpts = cmd.optsWithGlobals();
|
|
8576
8725
|
await runTraceability({
|
|
8577
8726
|
spec: opts.spec,
|
|
@@ -8584,15 +8733,15 @@ function createTraceabilityCommand() {
|
|
|
8584
8733
|
}
|
|
8585
8734
|
|
|
8586
8735
|
// src/commands/uninstall.ts
|
|
8587
|
-
import * as
|
|
8588
|
-
import { Command as
|
|
8736
|
+
import * as path61 from "path";
|
|
8737
|
+
import { Command as Command80 } from "commander";
|
|
8589
8738
|
async function runUninstall(skillName, options) {
|
|
8590
8739
|
const packageName = resolvePackageName(skillName);
|
|
8591
8740
|
const shortName = extractSkillName(packageName);
|
|
8592
8741
|
const globalDir = resolveGlobalSkillsDir();
|
|
8593
|
-
const skillsDir =
|
|
8594
|
-
const communityBase =
|
|
8595
|
-
const lockfilePath =
|
|
8742
|
+
const skillsDir = path61.dirname(globalDir);
|
|
8743
|
+
const communityBase = path61.join(skillsDir, "community");
|
|
8744
|
+
const lockfilePath = path61.join(communityBase, "skills-lock.json");
|
|
8596
8745
|
const lockfile = readLockfile2(lockfilePath);
|
|
8597
8746
|
const entry = lockfile.skills[packageName];
|
|
8598
8747
|
if (!entry) {
|
|
@@ -8622,7 +8771,7 @@ async function runUninstall(skillName, options) {
|
|
|
8622
8771
|
return result;
|
|
8623
8772
|
}
|
|
8624
8773
|
function createUninstallCommand() {
|
|
8625
|
-
const cmd = new
|
|
8774
|
+
const cmd = new Command80("uninstall");
|
|
8626
8775
|
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) => {
|
|
8627
8776
|
try {
|
|
8628
8777
|
const result = await runUninstall(skill, opts);
|
|
@@ -8643,8 +8792,8 @@ function createUninstallCommand() {
|
|
|
8643
8792
|
// src/commands/uninstall-constraints.ts
|
|
8644
8793
|
init_dist();
|
|
8645
8794
|
import * as fs40 from "fs/promises";
|
|
8646
|
-
import * as
|
|
8647
|
-
import { Command as
|
|
8795
|
+
import * as path62 from "path";
|
|
8796
|
+
import { Command as Command81 } from "commander";
|
|
8648
8797
|
async function runUninstallConstraints(options) {
|
|
8649
8798
|
const { packageName, configPath, lockfilePath } = options;
|
|
8650
8799
|
const lockfileResult = await readLockfile(lockfilePath);
|
|
@@ -8701,11 +8850,11 @@ async function runUninstallConstraints(options) {
|
|
|
8701
8850
|
};
|
|
8702
8851
|
}
|
|
8703
8852
|
function createUninstallConstraintsCommand() {
|
|
8704
|
-
const cmd = new
|
|
8853
|
+
const cmd = new Command81("uninstall-constraints");
|
|
8705
8854
|
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) => {
|
|
8706
8855
|
let configPath;
|
|
8707
8856
|
if (opts.config) {
|
|
8708
|
-
configPath =
|
|
8857
|
+
configPath = path62.resolve(opts.config);
|
|
8709
8858
|
} else {
|
|
8710
8859
|
const found = findConfigFile();
|
|
8711
8860
|
if (!found.ok) {
|
|
@@ -8714,8 +8863,8 @@ function createUninstallConstraintsCommand() {
|
|
|
8714
8863
|
}
|
|
8715
8864
|
configPath = found.value;
|
|
8716
8865
|
}
|
|
8717
|
-
const projectRoot =
|
|
8718
|
-
const lockfilePath =
|
|
8866
|
+
const projectRoot = path62.dirname(configPath);
|
|
8867
|
+
const lockfilePath = path62.join(projectRoot, ".harness", "constraints.lock.json");
|
|
8719
8868
|
const result = await runUninstallConstraints({
|
|
8720
8869
|
packageName: name,
|
|
8721
8870
|
configPath,
|
|
@@ -8740,13 +8889,13 @@ function createUninstallConstraintsCommand() {
|
|
|
8740
8889
|
}
|
|
8741
8890
|
|
|
8742
8891
|
// src/commands/update.ts
|
|
8743
|
-
import { Command as
|
|
8892
|
+
import { Command as Command82 } from "commander";
|
|
8744
8893
|
import { execFile, execFileSync as execFileSync6 } from "child_process";
|
|
8745
8894
|
import { realpathSync, existsSync as existsSync37, readFileSync as readFileSync26 } from "fs";
|
|
8746
|
-
import { join as
|
|
8895
|
+
import { join as join49 } from "path";
|
|
8747
8896
|
import { promisify } from "util";
|
|
8748
8897
|
import readline3 from "readline";
|
|
8749
|
-
import
|
|
8898
|
+
import chalk13 from "chalk";
|
|
8750
8899
|
function detectPackageManager() {
|
|
8751
8900
|
try {
|
|
8752
8901
|
const argv1 = process.argv[1];
|
|
@@ -8827,10 +8976,10 @@ async function ensureTelemetryIfNeeded() {
|
|
|
8827
8976
|
}
|
|
8828
8977
|
function refreshHooks() {
|
|
8829
8978
|
const cwd = process.cwd();
|
|
8830
|
-
const configPath =
|
|
8979
|
+
const configPath = join49(cwd, "harness.config.json");
|
|
8831
8980
|
if (!existsSync37(configPath)) return;
|
|
8832
8981
|
let profile = "standard";
|
|
8833
|
-
const profilePath =
|
|
8982
|
+
const profilePath = join49(cwd, ".harness", "hooks", "profile.json");
|
|
8834
8983
|
try {
|
|
8835
8984
|
const data = JSON.parse(readFileSync26(profilePath, "utf-8"));
|
|
8836
8985
|
if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
|
|
@@ -8852,7 +9001,7 @@ function runLocalGraphScan() {
|
|
|
8852
9001
|
execFileSync6("harness", ["graph", "scan", "."], { stdio: "inherit" });
|
|
8853
9002
|
} catch {
|
|
8854
9003
|
logger.warn("Graph scan failed. Run manually:");
|
|
8855
|
-
console.log(` ${
|
|
9004
|
+
console.log(` ${chalk13.cyan("harness graph scan .")}`);
|
|
8856
9005
|
}
|
|
8857
9006
|
}
|
|
8858
9007
|
async function offerRegeneration() {
|
|
@@ -8869,7 +9018,7 @@ async function offerRegeneration() {
|
|
|
8869
9018
|
});
|
|
8870
9019
|
} catch {
|
|
8871
9020
|
logger.warn("Generation failed. Run manually:");
|
|
8872
|
-
console.log(` ${
|
|
9021
|
+
console.log(` ${chalk13.cyan(`harness generate${isGlobal ? " --global" : ""}`)}`);
|
|
8873
9022
|
}
|
|
8874
9023
|
if (!isGlobal) {
|
|
8875
9024
|
runLocalGraphScan();
|
|
@@ -8932,8 +9081,8 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
8932
9081
|
console.log("");
|
|
8933
9082
|
for (const { pkg, current, latest } of outdated) {
|
|
8934
9083
|
const shortName = pkg.replace("@harness-engineering/", "");
|
|
8935
|
-
const currentStr = current ?
|
|
8936
|
-
logger.info(`${shortName}: ${currentStr} \u2192 ${
|
|
9084
|
+
const currentStr = current ? chalk13.dim(`v${current}`) : chalk13.dim("not installed");
|
|
9085
|
+
logger.info(`${shortName}: ${currentStr} \u2192 ${chalk13.green(`v${latest}`)}`);
|
|
8937
9086
|
}
|
|
8938
9087
|
console.log("");
|
|
8939
9088
|
}
|
|
@@ -8949,7 +9098,7 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
8949
9098
|
} catch {
|
|
8950
9099
|
console.log("");
|
|
8951
9100
|
logger.error("Update failed. You can try manually:");
|
|
8952
|
-
console.log(` ${
|
|
9101
|
+
console.log(` ${chalk13.cyan(installCmd)}`);
|
|
8953
9102
|
process.exit(ExitCode.ERROR);
|
|
8954
9103
|
}
|
|
8955
9104
|
refreshHooks();
|
|
@@ -8958,7 +9107,7 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
8958
9107
|
process.exit(ExitCode.SUCCESS);
|
|
8959
9108
|
}
|
|
8960
9109
|
function createUpdateCommand() {
|
|
8961
|
-
return new
|
|
9110
|
+
return new Command82("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(
|
|
8962
9111
|
"--regenerate",
|
|
8963
9112
|
"Only regenerate slash commands and agent definitions (skip package updates)"
|
|
8964
9113
|
).action(async (opts, cmd) => {
|
|
@@ -8968,9 +9117,9 @@ function createUpdateCommand() {
|
|
|
8968
9117
|
}
|
|
8969
9118
|
|
|
8970
9119
|
// src/commands/usage.ts
|
|
8971
|
-
import { Command as
|
|
9120
|
+
import { Command as Command83 } from "commander";
|
|
8972
9121
|
async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
|
|
8973
|
-
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-
|
|
9122
|
+
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-TG63OKA5.js");
|
|
8974
9123
|
const records = readCostRecords(cwd);
|
|
8975
9124
|
if (includeClaudeSessions) {
|
|
8976
9125
|
const ccRecords = parseCCRecords();
|
|
@@ -9063,7 +9212,7 @@ function registerDailyCommand(usage) {
|
|
|
9063
9212
|
else logger.info("No usage data found. Run some harness sessions first.");
|
|
9064
9213
|
return;
|
|
9065
9214
|
}
|
|
9066
|
-
const { aggregateByDay } = await import("./dist-
|
|
9215
|
+
const { aggregateByDay } = await import("./dist-TG63OKA5.js");
|
|
9067
9216
|
const limited = aggregateByDay(records).slice(0, days);
|
|
9068
9217
|
if (globalOpts.json) {
|
|
9069
9218
|
console.log(
|
|
@@ -9092,7 +9241,7 @@ function registerSessionsCommand(usage) {
|
|
|
9092
9241
|
}
|
|
9093
9242
|
return;
|
|
9094
9243
|
}
|
|
9095
|
-
const { aggregateBySession } = await import("./dist-
|
|
9244
|
+
const { aggregateBySession } = await import("./dist-TG63OKA5.js");
|
|
9096
9245
|
const sessionData = aggregateBySession(records);
|
|
9097
9246
|
const limited = sessionData.slice(0, limit);
|
|
9098
9247
|
if (globalOpts.json) {
|
|
@@ -9172,7 +9321,7 @@ function registerSessionCommand(usage) {
|
|
|
9172
9321
|
cwd,
|
|
9173
9322
|
globalOpts.includeClaudeSessions
|
|
9174
9323
|
);
|
|
9175
|
-
const { aggregateBySession } = await import("./dist-
|
|
9324
|
+
const { aggregateBySession } = await import("./dist-TG63OKA5.js");
|
|
9176
9325
|
const sessionData = aggregateBySession(records);
|
|
9177
9326
|
const match = sessionData.find((s) => s.sessionId === id);
|
|
9178
9327
|
if (!match) {
|
|
@@ -9207,7 +9356,7 @@ function registerLatestCommand(usage) {
|
|
|
9207
9356
|
}
|
|
9208
9357
|
return;
|
|
9209
9358
|
}
|
|
9210
|
-
const { aggregateBySession } = await import("./dist-
|
|
9359
|
+
const { aggregateBySession } = await import("./dist-TG63OKA5.js");
|
|
9211
9360
|
const sessionData = aggregateBySession(records);
|
|
9212
9361
|
const latest = sessionData[0];
|
|
9213
9362
|
if (!latest) {
|
|
@@ -9233,7 +9382,7 @@ function registerLatestCommand(usage) {
|
|
|
9233
9382
|
});
|
|
9234
9383
|
}
|
|
9235
9384
|
function createUsageCommand() {
|
|
9236
|
-
const usage = new
|
|
9385
|
+
const usage = new Command83("usage").description("Token usage and cost tracking");
|
|
9237
9386
|
usage.option(
|
|
9238
9387
|
"--include-claude-sessions",
|
|
9239
9388
|
"Include Claude Code session data from ~/.claude/projects/"
|
|
@@ -9248,15 +9397,15 @@ function createUsageCommand() {
|
|
|
9248
9397
|
// src/commands/validate.ts
|
|
9249
9398
|
init_dist();
|
|
9250
9399
|
init_dist();
|
|
9251
|
-
import { Command as
|
|
9252
|
-
import * as
|
|
9400
|
+
import { Command as Command84 } from "commander";
|
|
9401
|
+
import * as path63 from "path";
|
|
9253
9402
|
async function runValidate(options) {
|
|
9254
9403
|
const configResult = resolveConfig(options.configPath);
|
|
9255
9404
|
if (!configResult.ok) {
|
|
9256
9405
|
return configResult;
|
|
9257
9406
|
}
|
|
9258
9407
|
const config = configResult.value;
|
|
9259
|
-
const cwd = options.cwd ?? (options.configPath ?
|
|
9408
|
+
const cwd = options.cwd ?? (options.configPath ? path63.dirname(path63.resolve(options.configPath)) : process.cwd());
|
|
9260
9409
|
const result = {
|
|
9261
9410
|
valid: true,
|
|
9262
9411
|
checks: {
|
|
@@ -9266,7 +9415,7 @@ async function runValidate(options) {
|
|
|
9266
9415
|
},
|
|
9267
9416
|
issues: []
|
|
9268
9417
|
};
|
|
9269
|
-
const agentsMapPath =
|
|
9418
|
+
const agentsMapPath = path63.resolve(cwd, config.agentsMapPath);
|
|
9270
9419
|
const agentsResult = await validateAgentsMap(agentsMapPath);
|
|
9271
9420
|
if (agentsResult.ok) {
|
|
9272
9421
|
result.checks.agentsMap = true;
|
|
@@ -9331,11 +9480,11 @@ function resolveValidateMode(globalOpts) {
|
|
|
9331
9480
|
return OutputMode.TEXT;
|
|
9332
9481
|
}
|
|
9333
9482
|
async function printCrossCheckWarnings(mode) {
|
|
9334
|
-
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-
|
|
9483
|
+
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-ULQLEOME.js");
|
|
9335
9484
|
const cwd = process.cwd();
|
|
9336
9485
|
const crossResult = await runCrossCheck2({
|
|
9337
|
-
specsDir:
|
|
9338
|
-
plansDir:
|
|
9486
|
+
specsDir: path63.join(cwd, "docs", "specs"),
|
|
9487
|
+
plansDir: path63.join(cwd, "docs", "plans"),
|
|
9339
9488
|
projectPath: cwd
|
|
9340
9489
|
});
|
|
9341
9490
|
if (!crossResult.ok || crossResult.value.warnings === 0) return;
|
|
@@ -9347,7 +9496,7 @@ async function printCrossCheckWarnings(mode) {
|
|
|
9347
9496
|
${crossResult.value.warnings} warnings`);
|
|
9348
9497
|
}
|
|
9349
9498
|
function createValidateCommand3() {
|
|
9350
|
-
const command = new
|
|
9499
|
+
const command = new Command84("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").option(
|
|
9351
9500
|
"--agent-configs",
|
|
9352
9501
|
"Validate agent configs (CLAUDE.md, hooks, skills) via agnix or built-in fallback rules"
|
|
9353
9502
|
).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()));
|
|
@@ -9425,6 +9574,7 @@ var commandCreators = [
|
|
|
9425
9574
|
createInstallCommand,
|
|
9426
9575
|
createInstallConstraintsCommand,
|
|
9427
9576
|
createIntegrationsCommand,
|
|
9577
|
+
createKnowledgePipelineCommand,
|
|
9428
9578
|
createLearningsCommand,
|
|
9429
9579
|
createLinterCommand,
|
|
9430
9580
|
createMcpCommand,
|
|
@@ -9456,7 +9606,7 @@ var commandCreators = [
|
|
|
9456
9606
|
|
|
9457
9607
|
// src/index.ts
|
|
9458
9608
|
function createProgram() {
|
|
9459
|
-
const program = new
|
|
9609
|
+
const program = new Command85();
|
|
9460
9610
|
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");
|
|
9461
9611
|
for (const creator of commandCreators) {
|
|
9462
9612
|
program.addCommand(creator());
|