@harness-engineering/cli 1.25.6 → 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-2PYJM2MK.js → agents-md-OPOZA5L7.js} +3 -3
- package/dist/{architecture-VCLB7A23.js → architecture-PMVMO6SF.js} +4 -4
- package/dist/{assess-project-64C6LIKN.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-RT6PGEHY.js → check-phase-gate-NTLAU3LO.js} +4 -4
- package/dist/{chunk-JUXFYB2K.js → chunk-4KSKV5MK.js} +1 -1
- package/dist/{chunk-7BAGSY5Q.js → chunk-6SCA4NEZ.js} +1 -1
- package/dist/{chunk-42ZZLMYD.js → chunk-77EZGPSR.js} +1 -1
- package/dist/{chunk-CBZECDCW.js → chunk-7JNZXJKY.js} +5 -5
- package/dist/{chunk-43VBX44J.js → chunk-CAS3TS4Y.js} +110 -92
- package/dist/{chunk-FL6A72LV.js → chunk-EXTWTJRF.js} +1 -1
- package/dist/{chunk-XLO4AXXM.js → chunk-FI3D6D7U.js} +9 -9
- package/dist/{chunk-ZAKUCM7O.js → chunk-G6SYTGOH.js} +2 -2
- package/dist/{chunk-RKZW3FDF.js → chunk-HAOBHL3W.js} +1 -1
- package/dist/{chunk-4YEBV2FT.js → chunk-IFHAUFJX.js} +2 -2
- package/dist/{chunk-XMEEYMGE.js → chunk-J3O64D2A.js} +1 -1
- package/dist/{chunk-WEOGCL7B.js → chunk-JBJ4AVE4.js} +3 -3
- package/dist/{chunk-VELT5VAG.js → chunk-JWSVLC4I.js} +1 -1
- package/dist/{chunk-BUJOMC3O.js → chunk-JZ6GORAK.js} +38 -2
- package/dist/{chunk-JQCS75DY.js → chunk-KFE2X7LG.js} +4 -4
- package/dist/{chunk-U2OMWI7Z.js → chunk-KSFUJT5B.js} +1 -1
- package/dist/{chunk-Y5JA4J2M.js → chunk-KXIAHHHP.js} +2 -2
- package/dist/{chunk-R2BI5UPK.js → chunk-NIOB6FTG.js} +1 -1
- package/dist/{chunk-X2JJ3CPG.js → chunk-NVGQO4VM.js} +8 -8
- package/dist/{chunk-EY6F2QXW.js → chunk-QYSWNPXZ.js} +1 -1
- package/dist/{chunk-SZZ5UQL7.js → chunk-RNAGPTKF.js} +6 -6
- package/dist/{chunk-KJC4SE7C.js → chunk-UBRD5FH4.js} +9 -9
- package/dist/{chunk-RDQGCHKD.js → chunk-VV2PJT4K.js} +3358 -227
- package/dist/{chunk-SMY35HJM.js → chunk-Z2JORLRT.js} +1 -1
- package/dist/{chunk-R7P2FMJT.js → chunk-ZBQ3ZY75.js} +436 -284
- package/dist/{ci-workflow-SZL3KVUK.js → ci-workflow-H52EMCL6.js} +3 -3
- package/dist/{dist-GRW3X2ZQ.js → dist-PGQ32ZI7.js} +41 -1
- package/dist/{dist-T3DGV5UN.js → dist-TG63OKA5.js} +2 -2
- package/dist/{docs-WDLJORLK.js → docs-GP4VUSIB.js} +4 -4
- package/dist/{engine-2YWYRCKK.js → engine-KQG5RVXX.js} +3 -3
- package/dist/{entropy-PJGTOORX.js → entropy-RXESIYKC.js} +3 -3
- package/dist/{feedback-M5KCJKL2.js → feedback-HS7ZYXOU.js} +1 -1
- package/dist/{generate-agent-definitions-MFDW6LZT.js → generate-agent-definitions-I4B7CVOB.js} +4 -4
- package/dist/{graph-loader-QMKXT454.js → graph-loader-TIVI6NQ7.js} +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +25 -25
- package/dist/{loader-6O52FYHE.js → loader-CWAH6B4H.js} +3 -3
- package/dist/{mcp-GGNFWKVC.js → mcp-KHK5KYER.js} +15 -15
- package/dist/{performance-337U5URQ.js → performance-WDW5WS3J.js} +4 -4
- package/dist/{review-pipeline-DB5RD4SN.js → review-pipeline-QOZGWCTY.js} +3 -3
- package/dist/{runtime-B74EN2WD.js → runtime-SFEFRPLX.js} +3 -3
- package/dist/{scan-DXQUHGTT.js → scan-IJ7EYTF7.js} +1 -1
- package/dist/{security-3AYN6FVU.js → security-2K7UUK6T.js} +1 -1
- package/dist/{validate-35CD7VWN.js → validate-HXM6DXRZ.js} +4 -4
- package/dist/{validate-cross-check-LJKXBQYH.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");
|
|
@@ -4071,9 +4086,11 @@ function scaffoldProject(engine, ctx) {
|
|
|
4071
4086
|
...language !== void 0 && { language }
|
|
4072
4087
|
});
|
|
4073
4088
|
if (!renderResult.ok) return Err(new CLIError(renderResult.error.message, ExitCode.ERROR));
|
|
4089
|
+
const existingProject = !force && engine.isExistingProject(cwd);
|
|
4074
4090
|
const writeResult = engine.write(renderResult.value, cwd, {
|
|
4075
4091
|
overwrite: force,
|
|
4076
|
-
...language !== void 0 && { language }
|
|
4092
|
+
...language !== void 0 && { language },
|
|
4093
|
+
existingProject
|
|
4077
4094
|
});
|
|
4078
4095
|
if (!writeResult.ok) return Err(new CLIError(writeResult.error.message, ExitCode.ERROR));
|
|
4079
4096
|
if (writeResult.value.skippedConfigs.length > 0) {
|
|
@@ -5250,15 +5267,149 @@ function createIntegrationsCommand() {
|
|
|
5250
5267
|
return command;
|
|
5251
5268
|
}
|
|
5252
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
|
+
|
|
5253
5404
|
// src/commands/learnings/index.ts
|
|
5254
|
-
import { Command as
|
|
5405
|
+
import { Command as Command43 } from "commander";
|
|
5255
5406
|
|
|
5256
5407
|
// src/commands/learnings/prune.ts
|
|
5257
5408
|
init_dist();
|
|
5258
|
-
import { Command as
|
|
5259
|
-
import * as
|
|
5409
|
+
import { Command as Command42 } from "commander";
|
|
5410
|
+
import * as path39 from "path";
|
|
5260
5411
|
async function handlePrune(opts) {
|
|
5261
|
-
const projectPath =
|
|
5412
|
+
const projectPath = path39.resolve(opts.path);
|
|
5262
5413
|
const result = await pruneLearnings(projectPath, opts.stream);
|
|
5263
5414
|
if (!result.ok) {
|
|
5264
5415
|
logger.error(result.error.message);
|
|
@@ -5297,23 +5448,23 @@ function printPatternProposals(patterns) {
|
|
|
5297
5448
|
);
|
|
5298
5449
|
}
|
|
5299
5450
|
function createPruneCommand() {
|
|
5300
|
-
return new
|
|
5451
|
+
return new Command42("prune").description(
|
|
5301
5452
|
"Analyze global learnings for patterns, present improvement proposals, and archive old entries"
|
|
5302
5453
|
).option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(handlePrune);
|
|
5303
5454
|
}
|
|
5304
5455
|
|
|
5305
5456
|
// src/commands/learnings/index.ts
|
|
5306
5457
|
function createLearningsCommand() {
|
|
5307
|
-
const command = new
|
|
5458
|
+
const command = new Command43("learnings").description("Learnings management commands");
|
|
5308
5459
|
command.addCommand(createPruneCommand());
|
|
5309
5460
|
return command;
|
|
5310
5461
|
}
|
|
5311
5462
|
|
|
5312
5463
|
// src/commands/linter/index.ts
|
|
5313
|
-
import { Command as
|
|
5464
|
+
import { Command as Command46 } from "commander";
|
|
5314
5465
|
|
|
5315
5466
|
// src/commands/linter/generate.ts
|
|
5316
|
-
import { Command as
|
|
5467
|
+
import { Command as Command44 } from "commander";
|
|
5317
5468
|
function formatGenerateError(e) {
|
|
5318
5469
|
switch (e.type) {
|
|
5319
5470
|
case "parse":
|
|
@@ -5357,7 +5508,7 @@ function handleSuccess(result, useJson) {
|
|
|
5357
5508
|
Generated ${result.rulesGenerated.length} rules to ${result.outputDir}`);
|
|
5358
5509
|
}
|
|
5359
5510
|
function createGenerateCommand2() {
|
|
5360
|
-
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) => {
|
|
5361
5512
|
try {
|
|
5362
5513
|
if (options.verbose) logger.info(`Parsing config: ${options.config}`);
|
|
5363
5514
|
const result = await generate({
|
|
@@ -5379,9 +5530,9 @@ function createGenerateCommand2() {
|
|
|
5379
5530
|
}
|
|
5380
5531
|
|
|
5381
5532
|
// src/commands/linter/validate.ts
|
|
5382
|
-
import { Command as
|
|
5533
|
+
import { Command as Command45 } from "commander";
|
|
5383
5534
|
function createValidateCommand() {
|
|
5384
|
-
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) => {
|
|
5385
5536
|
try {
|
|
5386
5537
|
const result = await validate({ configPath: options.config });
|
|
5387
5538
|
if (options.json) {
|
|
@@ -5400,7 +5551,7 @@ function createValidateCommand() {
|
|
|
5400
5551
|
|
|
5401
5552
|
// src/commands/linter/index.ts
|
|
5402
5553
|
function createLinterCommand() {
|
|
5403
|
-
const linter = new
|
|
5554
|
+
const linter = new Command46("linter").description(
|
|
5404
5555
|
"Generate and validate ESLint rules from YAML config"
|
|
5405
5556
|
);
|
|
5406
5557
|
linter.addCommand(createGenerateCommand2());
|
|
@@ -5409,7 +5560,7 @@ function createLinterCommand() {
|
|
|
5409
5560
|
}
|
|
5410
5561
|
|
|
5411
5562
|
// src/commands/mcp.ts
|
|
5412
|
-
import { Command as
|
|
5563
|
+
import { Command as Command47 } from "commander";
|
|
5413
5564
|
var VALID_TIERS = /* @__PURE__ */ new Set(["core", "standard", "full"]);
|
|
5414
5565
|
function parseTier(value) {
|
|
5415
5566
|
const lower = value.toLowerCase();
|
|
@@ -5426,7 +5577,7 @@ function parseBudget(value) {
|
|
|
5426
5577
|
return n;
|
|
5427
5578
|
}
|
|
5428
5579
|
function createMcpCommand() {
|
|
5429
|
-
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(
|
|
5430
5581
|
"--tier <core|standard|full>",
|
|
5431
5582
|
"Load a preset tool tier instead of all tools",
|
|
5432
5583
|
parseTier
|
|
@@ -5436,7 +5587,7 @@ function createMcpCommand() {
|
|
|
5436
5587
|
parseBudget
|
|
5437
5588
|
).action(async (opts) => {
|
|
5438
5589
|
const [{ startServer: startServer2, getToolDefinitions: getToolDefinitions2 }, { selectTier }] = await Promise.all([
|
|
5439
|
-
import("./mcp-
|
|
5590
|
+
import("./mcp-KHK5KYER.js"),
|
|
5440
5591
|
import("./tool-tiers-7QGZ3FKY.js")
|
|
5441
5592
|
]);
|
|
5442
5593
|
if (opts.tools && opts.tools.length > 0) {
|
|
@@ -5457,13 +5608,13 @@ function createMcpCommand() {
|
|
|
5457
5608
|
}
|
|
5458
5609
|
|
|
5459
5610
|
// src/commands/orchestrator.ts
|
|
5460
|
-
import { Command as
|
|
5461
|
-
import * as
|
|
5611
|
+
import { Command as Command48 } from "commander";
|
|
5612
|
+
import * as path40 from "path";
|
|
5462
5613
|
import { Orchestrator, WorkflowLoader, launchTUI } from "@harness-engineering/orchestrator";
|
|
5463
5614
|
function createOrchestratorCommand() {
|
|
5464
|
-
const orchestrator = new
|
|
5615
|
+
const orchestrator = new Command48("orchestrator");
|
|
5465
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) => {
|
|
5466
|
-
const workflowPath =
|
|
5617
|
+
const workflowPath = path40.resolve(process.cwd(), opts.workflow);
|
|
5467
5618
|
const loader = new WorkflowLoader();
|
|
5468
5619
|
const result = await loader.loadWorkflow(workflowPath);
|
|
5469
5620
|
if (!result.ok) {
|
|
@@ -5496,13 +5647,13 @@ function createOrchestratorCommand() {
|
|
|
5496
5647
|
|
|
5497
5648
|
// src/commands/perf.ts
|
|
5498
5649
|
init_dist();
|
|
5499
|
-
import { Command as
|
|
5500
|
-
import * as
|
|
5650
|
+
import { Command as Command49 } from "commander";
|
|
5651
|
+
import * as path41 from "path";
|
|
5501
5652
|
function registerBenchCommand(perf) {
|
|
5502
5653
|
perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob2, _opts, cmd) => {
|
|
5503
5654
|
const globalOpts = cmd.optsWithGlobals();
|
|
5504
5655
|
const cwd = process.cwd();
|
|
5505
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
5656
|
+
const { BenchmarkRunner } = await import("./dist-TG63OKA5.js");
|
|
5506
5657
|
const runner = new BenchmarkRunner();
|
|
5507
5658
|
const benchFiles = runner.discover(cwd, glob2);
|
|
5508
5659
|
if (benchFiles.length === 0) {
|
|
@@ -5566,7 +5717,7 @@ async function runBaselinesShow(globalOpts) {
|
|
|
5566
5717
|
}
|
|
5567
5718
|
async function runBaselinesUpdate(globalOpts) {
|
|
5568
5719
|
const cwd = process.cwd();
|
|
5569
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
5720
|
+
const { BenchmarkRunner } = await import("./dist-TG63OKA5.js");
|
|
5570
5721
|
const runner = new BenchmarkRunner();
|
|
5571
5722
|
const manager = new BaselineManager(cwd);
|
|
5572
5723
|
logger.info("Running benchmarks to update baselines...");
|
|
@@ -5607,9 +5758,9 @@ function registerReportCommand(perf) {
|
|
|
5607
5758
|
perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
|
|
5608
5759
|
const globalOpts = cmd.optsWithGlobals();
|
|
5609
5760
|
const cwd = process.cwd();
|
|
5610
|
-
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-
|
|
5761
|
+
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-TG63OKA5.js");
|
|
5611
5762
|
const analyzer = new EntropyAnalyzer2({
|
|
5612
|
-
rootDir:
|
|
5763
|
+
rootDir: path41.resolve(cwd),
|
|
5613
5764
|
analyze: { complexity: true, coupling: true }
|
|
5614
5765
|
});
|
|
5615
5766
|
const result = await analyzer.analyze();
|
|
@@ -5668,7 +5819,7 @@ function registerCriticalPathsCommand(perf) {
|
|
|
5668
5819
|
});
|
|
5669
5820
|
}
|
|
5670
5821
|
function createPerfCommand() {
|
|
5671
|
-
const perf = new
|
|
5822
|
+
const perf = new Command49("perf").description("Performance benchmark and baseline management");
|
|
5672
5823
|
registerBenchCommand(perf);
|
|
5673
5824
|
registerBaselinesCommands(perf);
|
|
5674
5825
|
registerReportCommand(perf);
|
|
@@ -5677,10 +5828,10 @@ function createPerfCommand() {
|
|
|
5677
5828
|
}
|
|
5678
5829
|
|
|
5679
5830
|
// src/commands/persona/index.ts
|
|
5680
|
-
import { Command as
|
|
5831
|
+
import { Command as Command52 } from "commander";
|
|
5681
5832
|
|
|
5682
5833
|
// src/commands/persona/list.ts
|
|
5683
|
-
import { Command as
|
|
5834
|
+
import { Command as Command50 } from "commander";
|
|
5684
5835
|
function printPersonaList(personas) {
|
|
5685
5836
|
if (personas.length === 0) {
|
|
5686
5837
|
logger.info("No personas found.");
|
|
@@ -5694,7 +5845,7 @@ function printPersonaList(personas) {
|
|
|
5694
5845
|
}
|
|
5695
5846
|
}
|
|
5696
5847
|
function createListCommand2() {
|
|
5697
|
-
return new
|
|
5848
|
+
return new Command50("list").description("List available agent personas").action(async (_opts, cmd) => {
|
|
5698
5849
|
const globalOpts = cmd.optsWithGlobals();
|
|
5699
5850
|
const personasDir = resolvePersonasDir();
|
|
5700
5851
|
const result = listPersonas(personasDir);
|
|
@@ -5714,17 +5865,17 @@ function createListCommand2() {
|
|
|
5714
5865
|
}
|
|
5715
5866
|
|
|
5716
5867
|
// src/commands/persona/generate.ts
|
|
5717
|
-
import { Command as
|
|
5868
|
+
import { Command as Command51 } from "commander";
|
|
5718
5869
|
import * as fs24 from "fs";
|
|
5719
|
-
import * as
|
|
5870
|
+
import * as path42 from "path";
|
|
5720
5871
|
function generatePersonaArtifacts(persona, outputDir, only) {
|
|
5721
5872
|
const slug = toKebabCase(persona.name);
|
|
5722
5873
|
const generated = [];
|
|
5723
5874
|
if (!only || only === "runtime") {
|
|
5724
5875
|
const result = generateRuntime(persona);
|
|
5725
5876
|
if (result.ok) {
|
|
5726
|
-
const outPath =
|
|
5727
|
-
fs24.mkdirSync(
|
|
5877
|
+
const outPath = path42.join(outputDir, `${slug}.runtime.json`);
|
|
5878
|
+
fs24.mkdirSync(path42.dirname(outPath), { recursive: true });
|
|
5728
5879
|
fs24.writeFileSync(outPath, result.value);
|
|
5729
5880
|
generated.push(outPath);
|
|
5730
5881
|
}
|
|
@@ -5732,7 +5883,7 @@ function generatePersonaArtifacts(persona, outputDir, only) {
|
|
|
5732
5883
|
if (!only || only === "agents-md") {
|
|
5733
5884
|
const result = generateAgentsMd(persona);
|
|
5734
5885
|
if (result.ok) {
|
|
5735
|
-
const outPath =
|
|
5886
|
+
const outPath = path42.join(outputDir, `${slug}.agents.md`);
|
|
5736
5887
|
fs24.writeFileSync(outPath, result.value);
|
|
5737
5888
|
generated.push(outPath);
|
|
5738
5889
|
}
|
|
@@ -5740,8 +5891,8 @@ function generatePersonaArtifacts(persona, outputDir, only) {
|
|
|
5740
5891
|
if (!only || only === "ci") {
|
|
5741
5892
|
const result = generateCIWorkflow(persona, "github");
|
|
5742
5893
|
if (result.ok) {
|
|
5743
|
-
const outPath =
|
|
5744
|
-
fs24.mkdirSync(
|
|
5894
|
+
const outPath = path42.join(outputDir, ".github", "workflows", `${slug}.yml`);
|
|
5895
|
+
fs24.mkdirSync(path42.dirname(outPath), { recursive: true });
|
|
5745
5896
|
fs24.writeFileSync(outPath, result.value);
|
|
5746
5897
|
generated.push(outPath);
|
|
5747
5898
|
}
|
|
@@ -5749,16 +5900,16 @@ function generatePersonaArtifacts(persona, outputDir, only) {
|
|
|
5749
5900
|
return generated;
|
|
5750
5901
|
}
|
|
5751
5902
|
function createGenerateCommand3() {
|
|
5752
|
-
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) => {
|
|
5753
5904
|
const globalOpts = cmd.optsWithGlobals();
|
|
5754
|
-
const personaResult = loadPersona(
|
|
5905
|
+
const personaResult = loadPersona(path42.join(resolvePersonasDir(), `${name}.yaml`));
|
|
5755
5906
|
if (!personaResult.ok) {
|
|
5756
5907
|
logger.error(personaResult.error.message);
|
|
5757
5908
|
process.exit(ExitCode.ERROR);
|
|
5758
5909
|
}
|
|
5759
5910
|
const generated = generatePersonaArtifacts(
|
|
5760
5911
|
personaResult.value,
|
|
5761
|
-
|
|
5912
|
+
path42.resolve(opts.outputDir),
|
|
5762
5913
|
opts.only
|
|
5763
5914
|
);
|
|
5764
5915
|
if (!globalOpts.quiet) {
|
|
@@ -5771,7 +5922,7 @@ function createGenerateCommand3() {
|
|
|
5771
5922
|
|
|
5772
5923
|
// src/commands/persona/index.ts
|
|
5773
5924
|
function createPersonaCommand() {
|
|
5774
|
-
const command = new
|
|
5925
|
+
const command = new Command52("persona").description("Agent persona management commands");
|
|
5775
5926
|
command.addCommand(createListCommand2());
|
|
5776
5927
|
command.addCommand(createGenerateCommand3());
|
|
5777
5928
|
return command;
|
|
@@ -5779,8 +5930,8 @@ function createPersonaCommand() {
|
|
|
5779
5930
|
|
|
5780
5931
|
// src/commands/predict.ts
|
|
5781
5932
|
init_dist();
|
|
5782
|
-
import { Command as
|
|
5783
|
-
import
|
|
5933
|
+
import { Command as Command53 } from "commander";
|
|
5934
|
+
import chalk7 from "chalk";
|
|
5784
5935
|
var CATEGORY_ORDER = [
|
|
5785
5936
|
"circular-deps",
|
|
5786
5937
|
"layer-violations",
|
|
@@ -5801,11 +5952,11 @@ function crossingLabel(weeks) {
|
|
|
5801
5952
|
function severityPrefix(severity) {
|
|
5802
5953
|
switch (severity) {
|
|
5803
5954
|
case "critical":
|
|
5804
|
-
return
|
|
5955
|
+
return chalk7.red("[critical]");
|
|
5805
5956
|
case "warning":
|
|
5806
|
-
return
|
|
5957
|
+
return chalk7.yellow("[warning]");
|
|
5807
5958
|
case "info":
|
|
5808
|
-
return
|
|
5959
|
+
return chalk7.blue("[info]");
|
|
5809
5960
|
}
|
|
5810
5961
|
}
|
|
5811
5962
|
function printCategoryTable(result) {
|
|
@@ -5885,7 +6036,7 @@ function handlePredictError(err, mode) {
|
|
|
5885
6036
|
process.exit(ExitCode.ERROR);
|
|
5886
6037
|
}
|
|
5887
6038
|
function createPredictCommand() {
|
|
5888
|
-
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) => {
|
|
5889
6040
|
const globalOpts = cmd.optsWithGlobals();
|
|
5890
6041
|
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
5891
6042
|
try {
|
|
@@ -5909,8 +6060,8 @@ function createPredictCommand() {
|
|
|
5909
6060
|
|
|
5910
6061
|
// src/commands/publish-analyses.ts
|
|
5911
6062
|
import * as fs25 from "fs";
|
|
5912
|
-
import * as
|
|
5913
|
-
import { Command as
|
|
6063
|
+
import * as path43 from "path";
|
|
6064
|
+
import { Command as Command54 } from "commander";
|
|
5914
6065
|
init_dist();
|
|
5915
6066
|
import {
|
|
5916
6067
|
renderAnalysisComment,
|
|
@@ -5918,7 +6069,7 @@ import {
|
|
|
5918
6069
|
savePublishedIndex
|
|
5919
6070
|
} from "@harness-engineering/orchestrator";
|
|
5920
6071
|
function bootstrapTrackerCommand(opts, verb) {
|
|
5921
|
-
const projectPath =
|
|
6072
|
+
const projectPath = path43.resolve(opts.dir);
|
|
5922
6073
|
const trackerConfig = loadTrackerSyncConfig(projectPath);
|
|
5923
6074
|
if (!trackerConfig) {
|
|
5924
6075
|
logger.error(`No tracker config found in harness.config.json. Cannot ${verb}.`);
|
|
@@ -5930,7 +6081,7 @@ function bootstrapTrackerCommand(opts, verb) {
|
|
|
5930
6081
|
);
|
|
5931
6082
|
return null;
|
|
5932
6083
|
}
|
|
5933
|
-
const projectEnvPath =
|
|
6084
|
+
const projectEnvPath = path43.join(projectPath, ".env");
|
|
5934
6085
|
if (fs25.existsSync(projectEnvPath) && !process.env.GITHUB_TOKEN) {
|
|
5935
6086
|
__require("dotenv").config({ path: projectEnvPath });
|
|
5936
6087
|
}
|
|
@@ -5942,7 +6093,7 @@ function bootstrapTrackerCommand(opts, verb) {
|
|
|
5942
6093
|
return { token, projectPath, trackerConfig };
|
|
5943
6094
|
}
|
|
5944
6095
|
function buildNameToExternalIdMap(projectPath) {
|
|
5945
|
-
const roadmapFile =
|
|
6096
|
+
const roadmapFile = path43.join(projectPath, "docs", "roadmap.md");
|
|
5946
6097
|
if (!fs25.existsSync(roadmapFile)) {
|
|
5947
6098
|
logger.error("No docs/roadmap.md found. Cannot map issue hashes to external IDs.");
|
|
5948
6099
|
return null;
|
|
@@ -5998,8 +6149,8 @@ async function runPublishAnalyses(opts) {
|
|
|
5998
6149
|
const nameToExternalId = buildNameToExternalIdMap(projectPath);
|
|
5999
6150
|
if (!nameToExternalId) return process.exit(1);
|
|
6000
6151
|
const { AnalysisArchive } = await import("@harness-engineering/orchestrator");
|
|
6001
|
-
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-
|
|
6002
|
-
const archive = new AnalysisArchive(
|
|
6152
|
+
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-TG63OKA5.js");
|
|
6153
|
+
const archive = new AnalysisArchive(path43.join(projectPath, ".harness", "analyses"));
|
|
6003
6154
|
const analyses = await archive.list();
|
|
6004
6155
|
if (analyses.length === 0) {
|
|
6005
6156
|
logger.info("No analyses found to publish.");
|
|
@@ -6021,7 +6172,7 @@ async function runPublishAnalyses(opts) {
|
|
|
6021
6172
|
}
|
|
6022
6173
|
}
|
|
6023
6174
|
function createPublishAnalysesCommand() {
|
|
6024
|
-
const command = new
|
|
6175
|
+
const command = new Command54("publish-analyses").description(
|
|
6025
6176
|
"Publishes locally generated intelligence analyses to the external issue tracker (e.g., GitHub)"
|
|
6026
6177
|
).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
6027
6178
|
try {
|
|
@@ -6037,8 +6188,8 @@ function createPublishAnalysesCommand() {
|
|
|
6037
6188
|
}
|
|
6038
6189
|
|
|
6039
6190
|
// src/commands/recommend.ts
|
|
6040
|
-
import { Command as
|
|
6041
|
-
import
|
|
6191
|
+
import { Command as Command55 } from "commander";
|
|
6192
|
+
import chalk8 from "chalk";
|
|
6042
6193
|
async function resolveSnapshot(cwd, noCache) {
|
|
6043
6194
|
if (!noCache) {
|
|
6044
6195
|
const cached = loadCachedSnapshot(cwd);
|
|
@@ -6072,12 +6223,12 @@ async function runRecommend(options) {
|
|
|
6072
6223
|
function formatRecommendation(rec) {
|
|
6073
6224
|
const lines = [];
|
|
6074
6225
|
if (rec.urgency === "critical") {
|
|
6075
|
-
lines.push(` ${
|
|
6226
|
+
lines.push(` ${chalk8.red("[CRITICAL]")} ${rec.sequence}. ${rec.skillName}`);
|
|
6076
6227
|
} else {
|
|
6077
6228
|
lines.push(` ${rec.sequence}. ${rec.skillName} (${rec.score.toFixed(2)})`);
|
|
6078
6229
|
}
|
|
6079
6230
|
for (const reason of rec.reasons) {
|
|
6080
|
-
lines.push(` ${
|
|
6231
|
+
lines.push(` ${chalk8.dim("\u2192")} ${reason}`);
|
|
6081
6232
|
}
|
|
6082
6233
|
return lines.join("\n");
|
|
6083
6234
|
}
|
|
@@ -6101,7 +6252,7 @@ function printRecommendations(result) {
|
|
|
6101
6252
|
console.log("");
|
|
6102
6253
|
}
|
|
6103
6254
|
function createRecommendCommand() {
|
|
6104
|
-
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) => {
|
|
6105
6256
|
const globalOpts = cmd.optsWithGlobals();
|
|
6106
6257
|
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
6107
6258
|
try {
|
|
@@ -6138,9 +6289,9 @@ function createRecommendCommand() {
|
|
|
6138
6289
|
|
|
6139
6290
|
// src/commands/scan-config.ts
|
|
6140
6291
|
init_dist();
|
|
6141
|
-
import { Command as
|
|
6292
|
+
import { Command as Command56 } from "commander";
|
|
6142
6293
|
import { existsSync as existsSync22, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
|
|
6143
|
-
import { join as
|
|
6294
|
+
import { join as join31, relative as relative2 } from "path";
|
|
6144
6295
|
var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
|
|
6145
6296
|
function stripHighSeverityPatterns(content, injectionFindings) {
|
|
6146
6297
|
const highLines = /* @__PURE__ */ new Set();
|
|
@@ -6197,7 +6348,7 @@ async function runScanConfig(targetDir, options) {
|
|
|
6197
6348
|
const scanner = new SecurityScanner(parseSecurityConfig({}));
|
|
6198
6349
|
const results = [];
|
|
6199
6350
|
for (const configFile of CONFIG_FILES) {
|
|
6200
|
-
const result = scanSingleFile(
|
|
6351
|
+
const result = scanSingleFile(join31(targetDir, configFile), targetDir, scanner, options);
|
|
6201
6352
|
if (result) results.push(result);
|
|
6202
6353
|
}
|
|
6203
6354
|
return { exitCode: computeScanExitCode(results), results };
|
|
@@ -6227,7 +6378,7 @@ function formatTextOutput(result) {
|
|
|
6227
6378
|
}
|
|
6228
6379
|
}
|
|
6229
6380
|
function createScanConfigCommand() {
|
|
6230
|
-
const command = new
|
|
6381
|
+
const command = new Command56("scan-config").description(
|
|
6231
6382
|
"Scan CLAUDE.md, AGENTS.md, .gemini/settings.json, and skill.yaml for prompt injection patterns"
|
|
6232
6383
|
).option("--path <dir>", "Target directory to scan (default: cwd)").option("--fix", "Strip high-severity patterns from files in-place").action(async (opts, cmd) => {
|
|
6233
6384
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -6244,18 +6395,18 @@ function createScanConfigCommand() {
|
|
|
6244
6395
|
}
|
|
6245
6396
|
|
|
6246
6397
|
// src/commands/setup.ts
|
|
6247
|
-
import { Command as
|
|
6398
|
+
import { Command as Command57 } from "commander";
|
|
6248
6399
|
import * as fs28 from "fs";
|
|
6249
6400
|
import * as os7 from "os";
|
|
6250
|
-
import * as
|
|
6251
|
-
import
|
|
6401
|
+
import * as path46 from "path";
|
|
6402
|
+
import chalk10 from "chalk";
|
|
6252
6403
|
|
|
6253
6404
|
// src/utils/first-run.ts
|
|
6254
6405
|
import * as fs26 from "fs";
|
|
6255
6406
|
import * as os6 from "os";
|
|
6256
|
-
import * as
|
|
6257
|
-
var HARNESS_DIR =
|
|
6258
|
-
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");
|
|
6259
6410
|
function isFirstRun() {
|
|
6260
6411
|
return !fs26.existsSync(MARKER_FILE);
|
|
6261
6412
|
}
|
|
@@ -6275,9 +6426,9 @@ function printFirstRunWelcome() {
|
|
|
6275
6426
|
|
|
6276
6427
|
// src/commands/telemetry-wizard.ts
|
|
6277
6428
|
import * as fs27 from "fs";
|
|
6278
|
-
import * as
|
|
6429
|
+
import * as path45 from "path";
|
|
6279
6430
|
import readline from "readline";
|
|
6280
|
-
import
|
|
6431
|
+
import chalk9 from "chalk";
|
|
6281
6432
|
function prompt(question) {
|
|
6282
6433
|
const rl = readline.createInterface({
|
|
6283
6434
|
input: process.stdin,
|
|
@@ -6306,7 +6457,7 @@ function isNo(answer) {
|
|
|
6306
6457
|
return answer === "n" || answer === "no";
|
|
6307
6458
|
}
|
|
6308
6459
|
function isTelemetryConfigured(cwd) {
|
|
6309
|
-
const configPath =
|
|
6460
|
+
const configPath = path45.join(cwd, "harness.config.json");
|
|
6310
6461
|
try {
|
|
6311
6462
|
const raw = JSON.parse(fs27.readFileSync(configPath, "utf-8"));
|
|
6312
6463
|
return raw.telemetry !== void 0 && raw.adoption !== void 0;
|
|
@@ -6315,7 +6466,7 @@ function isTelemetryConfigured(cwd) {
|
|
|
6315
6466
|
}
|
|
6316
6467
|
}
|
|
6317
6468
|
function writeTelemetryConfig(cwd, result) {
|
|
6318
|
-
const configPath =
|
|
6469
|
+
const configPath = path45.join(cwd, "harness.config.json");
|
|
6319
6470
|
try {
|
|
6320
6471
|
const raw = JSON.parse(fs27.readFileSync(configPath, "utf-8"));
|
|
6321
6472
|
raw.telemetry = { enabled: result.telemetryEnabled };
|
|
@@ -6328,15 +6479,15 @@ function writeTelemetryConfig(cwd, result) {
|
|
|
6328
6479
|
}
|
|
6329
6480
|
const hasIdentity = result.identity.project || result.identity.team || result.identity.alias;
|
|
6330
6481
|
if (hasIdentity) {
|
|
6331
|
-
const harnessDir =
|
|
6482
|
+
const harnessDir = path45.join(cwd, ".harness");
|
|
6332
6483
|
fs27.mkdirSync(harnessDir, { recursive: true });
|
|
6333
|
-
const telemetryFile =
|
|
6484
|
+
const telemetryFile = path45.join(harnessDir, "telemetry.json");
|
|
6334
6485
|
fs27.writeFileSync(telemetryFile, JSON.stringify({ identity: result.identity }, null, 2) + "\n");
|
|
6335
6486
|
}
|
|
6336
6487
|
}
|
|
6337
6488
|
async function promptIdentity() {
|
|
6338
6489
|
console.log(
|
|
6339
|
-
` ${
|
|
6490
|
+
` ${chalk9.cyan("Identity")} (optional) \u2014 tag telemetry with project/team/alias for filtering.`
|
|
6340
6491
|
);
|
|
6341
6492
|
console.log(" Leave blank to keep anonymous.");
|
|
6342
6493
|
const answer = await prompt(" Set identity fields? (y/N) ");
|
|
@@ -6354,20 +6505,20 @@ async function promptIdentity() {
|
|
|
6354
6505
|
async function runTelemetryWizard() {
|
|
6355
6506
|
if (!process.stdin.isTTY) return null;
|
|
6356
6507
|
console.log("");
|
|
6357
|
-
console.log(` ${
|
|
6508
|
+
console.log(` ${chalk9.bold("Telemetry Configuration")}`);
|
|
6358
6509
|
console.log("");
|
|
6359
6510
|
console.log(" Harness can collect anonymous usage data to help improve the tool.");
|
|
6360
6511
|
console.log(" You can change these settings anytime in harness.config.json.");
|
|
6361
6512
|
console.log("");
|
|
6362
6513
|
console.log(
|
|
6363
|
-
` ${
|
|
6514
|
+
` ${chalk9.cyan("Anonymous telemetry")} \u2014 error rates, command usage, performance metrics.`
|
|
6364
6515
|
);
|
|
6365
6516
|
console.log(" No code, file contents, or personally identifiable info is sent.");
|
|
6366
6517
|
const telemetryAnswer = await prompt(" Enable anonymous telemetry? (Y/n) ");
|
|
6367
6518
|
const telemetryEnabled = !isNo(telemetryAnswer);
|
|
6368
6519
|
console.log("");
|
|
6369
6520
|
console.log(
|
|
6370
|
-
` ${
|
|
6521
|
+
` ${chalk9.cyan("Adoption tracking")} \u2014 which skills are used, how often, and success rates.`
|
|
6371
6522
|
);
|
|
6372
6523
|
console.log(" Stored locally in .harness/adoption/. Never sent externally.");
|
|
6373
6524
|
const adoptionAnswer = await prompt(" Enable local adoption tracking? (Y/n) ");
|
|
@@ -6377,7 +6528,7 @@ async function runTelemetryWizard() {
|
|
|
6377
6528
|
return { telemetryEnabled, adoptionEnabled, identity };
|
|
6378
6529
|
}
|
|
6379
6530
|
async function ensureTelemetryConfigured(cwd) {
|
|
6380
|
-
const configPath =
|
|
6531
|
+
const configPath = path45.join(cwd, "harness.config.json");
|
|
6381
6532
|
if (!fs27.existsSync(configPath)) {
|
|
6382
6533
|
return { status: "warn", message: "Not a harness project \u2014 skipped telemetry configuration" };
|
|
6383
6534
|
}
|
|
@@ -6424,7 +6575,7 @@ function runSlashCommandGeneration() {
|
|
|
6424
6575
|
}
|
|
6425
6576
|
}
|
|
6426
6577
|
function detectClient(dirName) {
|
|
6427
|
-
return fs28.existsSync(
|
|
6578
|
+
return fs28.existsSync(path46.join(os7.homedir(), dirName));
|
|
6428
6579
|
}
|
|
6429
6580
|
async function runMcpSetup(cwd) {
|
|
6430
6581
|
const results = [];
|
|
@@ -6461,12 +6612,12 @@ async function runMcpSetup(cwd) {
|
|
|
6461
6612
|
return results;
|
|
6462
6613
|
}
|
|
6463
6614
|
function formatStep(result) {
|
|
6464
|
-
const icon = result.status === "pass" ?
|
|
6615
|
+
const icon = result.status === "pass" ? chalk10.green("\u2713") : result.status === "warn" ? chalk10.yellow("\u26A0") : chalk10.red("\u2717");
|
|
6465
6616
|
return ` ${icon} ${result.message}`;
|
|
6466
6617
|
}
|
|
6467
6618
|
function configureTier0Integrations(cwd) {
|
|
6468
6619
|
try {
|
|
6469
|
-
const mcpPath =
|
|
6620
|
+
const mcpPath = path46.join(cwd, ".mcp.json");
|
|
6470
6621
|
const config = readMcpConfig(mcpPath);
|
|
6471
6622
|
const tier0 = INTEGRATION_REGISTRY.filter((i) => i.tier === 0);
|
|
6472
6623
|
const added = [];
|
|
@@ -6475,9 +6626,9 @@ function configureTier0Integrations(cwd) {
|
|
|
6475
6626
|
writeMcpEntry(mcpPath, integration.name, integration.mcpConfig);
|
|
6476
6627
|
added.push(integration.displayName);
|
|
6477
6628
|
}
|
|
6478
|
-
const geminiDir =
|
|
6629
|
+
const geminiDir = path46.join(cwd, ".gemini");
|
|
6479
6630
|
if (fs28.existsSync(geminiDir)) {
|
|
6480
|
-
const geminiPath =
|
|
6631
|
+
const geminiPath = path46.join(geminiDir, "settings.json");
|
|
6481
6632
|
const geminiConfig = readMcpConfig(geminiPath);
|
|
6482
6633
|
for (const integration of tier0) {
|
|
6483
6634
|
if (!geminiConfig.mcpServers[integration.name]) {
|
|
@@ -6498,12 +6649,12 @@ function configureTier0Integrations(cwd) {
|
|
|
6498
6649
|
}
|
|
6499
6650
|
}
|
|
6500
6651
|
function ensureHooks(cwd) {
|
|
6501
|
-
const configPath =
|
|
6652
|
+
const configPath = path46.join(cwd, "harness.config.json");
|
|
6502
6653
|
if (!fs28.existsSync(configPath)) {
|
|
6503
6654
|
return { status: "warn", message: "Not a harness project \u2014 skipped hook installation" };
|
|
6504
6655
|
}
|
|
6505
6656
|
let profile = "standard";
|
|
6506
|
-
const profilePath =
|
|
6657
|
+
const profilePath = path46.join(cwd, ".harness", "hooks", "profile.json");
|
|
6507
6658
|
try {
|
|
6508
6659
|
const data = JSON.parse(fs28.readFileSync(profilePath, "utf-8"));
|
|
6509
6660
|
if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
|
|
@@ -6524,7 +6675,7 @@ function ensureHooks(cwd) {
|
|
|
6524
6675
|
}
|
|
6525
6676
|
async function runInitialGraphScan(cwd) {
|
|
6526
6677
|
try {
|
|
6527
|
-
const { runScan: runScan2 } = await import("./scan-
|
|
6678
|
+
const { runScan: runScan2 } = await import("./scan-IJ7EYTF7.js");
|
|
6528
6679
|
const result = await runScan2(cwd);
|
|
6529
6680
|
return {
|
|
6530
6681
|
status: "pass",
|
|
@@ -6561,10 +6712,10 @@ async function runSetup(cwd) {
|
|
|
6561
6712
|
return { steps, success };
|
|
6562
6713
|
}
|
|
6563
6714
|
function createSetupCommand() {
|
|
6564
|
-
return new
|
|
6715
|
+
return new Command57("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
|
|
6565
6716
|
const cwd = process.cwd();
|
|
6566
6717
|
console.log("");
|
|
6567
|
-
console.log(` ${
|
|
6718
|
+
console.log(` ${chalk10.bold("harness setup")}`);
|
|
6568
6719
|
console.log("");
|
|
6569
6720
|
const { steps, success } = await runSetup(cwd);
|
|
6570
6721
|
for (const step of steps) {
|
|
@@ -6584,14 +6735,14 @@ function createSetupCommand() {
|
|
|
6584
6735
|
|
|
6585
6736
|
// src/commands/share.ts
|
|
6586
6737
|
init_dist();
|
|
6587
|
-
import { Command as
|
|
6738
|
+
import { Command as Command58 } from "commander";
|
|
6588
6739
|
import * as fs29 from "fs";
|
|
6589
|
-
import * as
|
|
6740
|
+
import * as path47 from "path";
|
|
6590
6741
|
import { parse as parseYaml } from "yaml";
|
|
6591
6742
|
var MANIFEST_FILENAME = "constraints.yaml";
|
|
6592
6743
|
async function runShareAction(projectPath, options) {
|
|
6593
|
-
const rootDir =
|
|
6594
|
-
const manifestPath =
|
|
6744
|
+
const rootDir = path47.resolve(projectPath);
|
|
6745
|
+
const manifestPath = path47.join(rootDir, MANIFEST_FILENAME);
|
|
6595
6746
|
if (!fs29.existsSync(manifestPath)) {
|
|
6596
6747
|
logger.error(
|
|
6597
6748
|
`No ${MANIFEST_FILENAME} found at ${manifestPath}.
|
|
@@ -6615,7 +6766,7 @@ Create a constraints.yaml in your project root to define what to share.`
|
|
|
6615
6766
|
process.exit(1);
|
|
6616
6767
|
}
|
|
6617
6768
|
const manifest = manifestResult.value;
|
|
6618
|
-
const configResult = resolveConfig(
|
|
6769
|
+
const configResult = resolveConfig(path47.join(rootDir, "harness.config.json"));
|
|
6619
6770
|
if (!configResult.ok) {
|
|
6620
6771
|
logger.error(configResult.error.message);
|
|
6621
6772
|
process.exit(1);
|
|
@@ -6633,8 +6784,8 @@ Create a constraints.yaml in your project root to define what to share.`
|
|
|
6633
6784
|
);
|
|
6634
6785
|
process.exit(1);
|
|
6635
6786
|
}
|
|
6636
|
-
const outputDir =
|
|
6637
|
-
const outputPath =
|
|
6787
|
+
const outputDir = path47.resolve(options.output);
|
|
6788
|
+
const outputPath = path47.join(outputDir, `${manifest.name}.harness-constraints.json`);
|
|
6638
6789
|
const writeResult = await writeConfig(outputPath, bundle);
|
|
6639
6790
|
if (!writeResult.ok) {
|
|
6640
6791
|
logger.error(`Failed to write bundle: ${writeResult.error.message}`);
|
|
@@ -6643,25 +6794,25 @@ Create a constraints.yaml in your project root to define what to share.`
|
|
|
6643
6794
|
logger.success(`Bundle written to ${outputPath}`);
|
|
6644
6795
|
}
|
|
6645
6796
|
function createShareCommand() {
|
|
6646
|
-
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) => {
|
|
6647
6798
|
await runShareAction(projectPath, options);
|
|
6648
6799
|
});
|
|
6649
6800
|
}
|
|
6650
6801
|
|
|
6651
6802
|
// src/commands/skill/index.ts
|
|
6652
|
-
import { Command as
|
|
6803
|
+
import { Command as Command66 } from "commander";
|
|
6653
6804
|
|
|
6654
6805
|
// src/commands/skill/list.ts
|
|
6655
|
-
import { Command as
|
|
6806
|
+
import { Command as Command59 } from "commander";
|
|
6656
6807
|
import * as fs30 from "fs";
|
|
6657
|
-
import * as
|
|
6808
|
+
import * as path48 from "path";
|
|
6658
6809
|
import { parse } from "yaml";
|
|
6659
6810
|
function scanDirectory(dirPath, source) {
|
|
6660
6811
|
if (!fs30.existsSync(dirPath)) return [];
|
|
6661
6812
|
const entries = fs30.readdirSync(dirPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
6662
6813
|
const skills = [];
|
|
6663
6814
|
for (const name of entries) {
|
|
6664
|
-
const yamlPath =
|
|
6815
|
+
const yamlPath = path48.join(dirPath, name, "skill.yaml");
|
|
6665
6816
|
if (!fs30.existsSync(yamlPath)) continue;
|
|
6666
6817
|
try {
|
|
6667
6818
|
const raw = fs30.readFileSync(yamlPath, "utf-8");
|
|
@@ -6682,10 +6833,10 @@ function scanDirectory(dirPath, source) {
|
|
|
6682
6833
|
}
|
|
6683
6834
|
function collectCommunitySkills(seen, allSkills) {
|
|
6684
6835
|
const globalDir = resolveGlobalSkillsDir();
|
|
6685
|
-
const skillsDir =
|
|
6686
|
-
const communityBase =
|
|
6687
|
-
const communityPlatformDir =
|
|
6688
|
-
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");
|
|
6689
6840
|
const lockfile = readLockfile2(lockfilePath);
|
|
6690
6841
|
const communitySkills = scanDirectory(communityPlatformDir, "community");
|
|
6691
6842
|
for (const skill of communitySkills) {
|
|
@@ -6755,7 +6906,7 @@ function printSkillsVerbose(skills) {
|
|
|
6755
6906
|
for (const s of skills) printSkillEntry(s);
|
|
6756
6907
|
}
|
|
6757
6908
|
function createListCommand3() {
|
|
6758
|
-
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) => {
|
|
6759
6910
|
const globalOpts = cmd.optsWithGlobals();
|
|
6760
6911
|
const skills = collectSkills({ filter: resolveFilter(opts) });
|
|
6761
6912
|
if (globalOpts.json) {
|
|
@@ -6770,9 +6921,9 @@ function createListCommand3() {
|
|
|
6770
6921
|
}
|
|
6771
6922
|
|
|
6772
6923
|
// src/commands/skill/run.ts
|
|
6773
|
-
import { Command as
|
|
6924
|
+
import { Command as Command60 } from "commander";
|
|
6774
6925
|
import * as fs31 from "fs";
|
|
6775
|
-
import * as
|
|
6926
|
+
import * as path49 from "path";
|
|
6776
6927
|
import { parse as parse2 } from "yaml";
|
|
6777
6928
|
|
|
6778
6929
|
// src/skill/complexity.ts
|
|
@@ -6868,7 +7019,7 @@ ${options.principles}`);
|
|
|
6868
7019
|
|
|
6869
7020
|
// src/commands/skill/run.ts
|
|
6870
7021
|
function loadSkillMetadata(skillDir) {
|
|
6871
|
-
const yamlPath =
|
|
7022
|
+
const yamlPath = path49.join(skillDir, "skill.yaml");
|
|
6872
7023
|
if (!fs31.existsSync(yamlPath)) return null;
|
|
6873
7024
|
try {
|
|
6874
7025
|
const result = SkillMetadataSchema.safeParse(parse2(fs31.readFileSync(yamlPath, "utf-8")));
|
|
@@ -6883,18 +7034,18 @@ function resolveComplexity(metadata, requested, projectPath) {
|
|
|
6883
7034
|
return requested;
|
|
6884
7035
|
}
|
|
6885
7036
|
function loadPrinciples(projectPath) {
|
|
6886
|
-
const principlesPath =
|
|
7037
|
+
const principlesPath = path49.join(projectPath, "docs", "principles.md");
|
|
6887
7038
|
return fs31.existsSync(principlesPath) ? fs31.readFileSync(principlesPath, "utf-8") : void 0;
|
|
6888
7039
|
}
|
|
6889
7040
|
function readMostRecentFileInDir(dirPath) {
|
|
6890
|
-
const files = fs31.readdirSync(dirPath).map((f) => ({ name: f, mtime: fs31.statSync(
|
|
6891
|
-
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");
|
|
6892
7043
|
return void 0;
|
|
6893
7044
|
}
|
|
6894
7045
|
function loadPriorState(metadata, projectPath) {
|
|
6895
7046
|
if (!metadata?.state.persistent || metadata.state.files.length === 0) return void 0;
|
|
6896
7047
|
for (const stateFilePath of metadata.state.files) {
|
|
6897
|
-
const fullPath =
|
|
7048
|
+
const fullPath = path49.join(projectPath, stateFilePath);
|
|
6898
7049
|
if (!fs31.existsSync(fullPath)) continue;
|
|
6899
7050
|
const stat = fs31.statSync(fullPath);
|
|
6900
7051
|
if (stat.isDirectory()) return readMostRecentFileInDir(fullPath);
|
|
@@ -6918,7 +7069,7 @@ function resolvePhaseState(metadata, projectPath, phase) {
|
|
|
6918
7069
|
}
|
|
6919
7070
|
function appendProjectState(content, metadata, projectPath, hasPathOpt) {
|
|
6920
7071
|
if (!metadata?.state.persistent || !hasPathOpt) return content;
|
|
6921
|
-
const stateFile =
|
|
7072
|
+
const stateFile = path49.join(projectPath, ".harness", "state.json");
|
|
6922
7073
|
if (!fs31.existsSync(stateFile)) return content;
|
|
6923
7074
|
const stateContent = fs31.readFileSync(stateFile, "utf-8");
|
|
6924
7075
|
return content + `
|
|
@@ -6932,14 +7083,14 @@ ${stateContent}
|
|
|
6932
7083
|
}
|
|
6933
7084
|
async function runSkill(name, opts) {
|
|
6934
7085
|
const skillsDir = resolveSkillsDir();
|
|
6935
|
-
const skillDir =
|
|
7086
|
+
const skillDir = path49.join(skillsDir, name);
|
|
6936
7087
|
if (!fs31.existsSync(skillDir)) {
|
|
6937
7088
|
logger.error(`Skill not found: ${name}`);
|
|
6938
7089
|
process.exit(ExitCode.ERROR);
|
|
6939
7090
|
return;
|
|
6940
7091
|
}
|
|
6941
7092
|
const metadata = loadSkillMetadata(skillDir);
|
|
6942
|
-
const projectPath = opts.path ?
|
|
7093
|
+
const projectPath = opts.path ? path49.resolve(opts.path) : process.cwd();
|
|
6943
7094
|
const complexity = resolveComplexity(
|
|
6944
7095
|
metadata,
|
|
6945
7096
|
opts.complexity ?? "standard",
|
|
@@ -6966,7 +7117,7 @@ async function runSkill(name, opts) {
|
|
|
6966
7117
|
...stateWarning !== void 0 && { stateWarning },
|
|
6967
7118
|
...opts.party !== void 0 && { party: opts.party }
|
|
6968
7119
|
});
|
|
6969
|
-
const skillMdPath =
|
|
7120
|
+
const skillMdPath = path49.join(skillDir, "SKILL.md");
|
|
6970
7121
|
if (!fs31.existsSync(skillMdPath)) {
|
|
6971
7122
|
logger.error(`SKILL.md not found for skill: ${name}`);
|
|
6972
7123
|
process.exit(ExitCode.ERROR);
|
|
@@ -6982,13 +7133,13 @@ async function runSkill(name, opts) {
|
|
|
6982
7133
|
process.exit(ExitCode.SUCCESS);
|
|
6983
7134
|
}
|
|
6984
7135
|
function createRunCommand2() {
|
|
6985
|
-
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));
|
|
6986
7137
|
}
|
|
6987
7138
|
|
|
6988
7139
|
// src/commands/skill/validate.ts
|
|
6989
|
-
import { Command as
|
|
7140
|
+
import { Command as Command61 } from "commander";
|
|
6990
7141
|
import * as fs32 from "fs";
|
|
6991
|
-
import * as
|
|
7142
|
+
import * as path50 from "path";
|
|
6992
7143
|
import { parse as parse3 } from "yaml";
|
|
6993
7144
|
var BEHAVIORAL_REQUIRED_SECTIONS = [
|
|
6994
7145
|
"## When to Use",
|
|
@@ -7029,8 +7180,8 @@ function validateSkillMd(name, skillMdPath, skillType, errors) {
|
|
|
7029
7180
|
}
|
|
7030
7181
|
}
|
|
7031
7182
|
function validateSkillEntry(name, skillsDir, errors) {
|
|
7032
|
-
const skillDir =
|
|
7033
|
-
const yamlPath =
|
|
7183
|
+
const skillDir = path50.join(skillsDir, name);
|
|
7184
|
+
const yamlPath = path50.join(skillDir, "skill.yaml");
|
|
7034
7185
|
if (!fs32.existsSync(yamlPath)) {
|
|
7035
7186
|
errors.push(`${name}: missing skill.yaml`);
|
|
7036
7187
|
return false;
|
|
@@ -7042,7 +7193,7 @@ function validateSkillEntry(name, skillsDir, errors) {
|
|
|
7042
7193
|
errors.push(`${name}/skill.yaml: ${result.error.message}`);
|
|
7043
7194
|
return false;
|
|
7044
7195
|
}
|
|
7045
|
-
validateSkillMd(name,
|
|
7196
|
+
validateSkillMd(name, path50.join(skillDir, "SKILL.md"), result.data.type, errors);
|
|
7046
7197
|
return true;
|
|
7047
7198
|
} catch (e) {
|
|
7048
7199
|
errors.push(`${name}: parse error \u2014 ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -7050,7 +7201,7 @@ function validateSkillEntry(name, skillsDir, errors) {
|
|
|
7050
7201
|
}
|
|
7051
7202
|
}
|
|
7052
7203
|
function createValidateCommand2() {
|
|
7053
|
-
return new
|
|
7204
|
+
return new Command61("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
|
|
7054
7205
|
const globalOpts = cmd.optsWithGlobals();
|
|
7055
7206
|
const skillsDir = resolveSkillsDir();
|
|
7056
7207
|
if (!fs32.existsSync(skillsDir)) {
|
|
@@ -7080,18 +7231,18 @@ function createValidateCommand2() {
|
|
|
7080
7231
|
}
|
|
7081
7232
|
|
|
7082
7233
|
// src/commands/skill/info.ts
|
|
7083
|
-
import { Command as
|
|
7234
|
+
import { Command as Command62 } from "commander";
|
|
7084
7235
|
import * as fs33 from "fs";
|
|
7085
|
-
import * as
|
|
7236
|
+
import * as path51 from "path";
|
|
7086
7237
|
import { parse as parse4 } from "yaml";
|
|
7087
7238
|
function loadSkillMetadata2(name) {
|
|
7088
7239
|
const skillsDir = resolveSkillsDir();
|
|
7089
|
-
const skillDir =
|
|
7240
|
+
const skillDir = path51.join(skillsDir, name);
|
|
7090
7241
|
if (!fs33.existsSync(skillDir)) {
|
|
7091
7242
|
logger.error(`Skill not found: ${name}`);
|
|
7092
7243
|
return { ok: false, exitCode: ExitCode.ERROR };
|
|
7093
7244
|
}
|
|
7094
|
-
const yamlPath =
|
|
7245
|
+
const yamlPath = path51.join(skillDir, "skill.yaml");
|
|
7095
7246
|
if (!fs33.existsSync(yamlPath)) {
|
|
7096
7247
|
logger.error(`skill.yaml not found for skill: ${name}`);
|
|
7097
7248
|
return { ok: false, exitCode: ExitCode.ERROR };
|
|
@@ -7126,7 +7277,7 @@ function printSkillInfo(skill) {
|
|
|
7126
7277
|
console.log(`Persistent: ${skill.state.persistent}`);
|
|
7127
7278
|
}
|
|
7128
7279
|
function createInfoCommand() {
|
|
7129
|
-
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) => {
|
|
7130
7281
|
const globalOpts = cmd.optsWithGlobals();
|
|
7131
7282
|
const loaded = loadSkillMetadata2(name);
|
|
7132
7283
|
if (!loaded.ok) {
|
|
@@ -7143,7 +7294,7 @@ function createInfoCommand() {
|
|
|
7143
7294
|
}
|
|
7144
7295
|
|
|
7145
7296
|
// src/commands/skill/search.ts
|
|
7146
|
-
import { Command as
|
|
7297
|
+
import { Command as Command63 } from "commander";
|
|
7147
7298
|
async function runSearch(query, opts) {
|
|
7148
7299
|
const results = await searchNpmRegistry(query, opts.registry);
|
|
7149
7300
|
return results.filter((r) => {
|
|
@@ -7188,14 +7339,14 @@ async function runSearchAction(query, opts, globalOpts) {
|
|
|
7188
7339
|
}
|
|
7189
7340
|
}
|
|
7190
7341
|
function createSearchCommand() {
|
|
7191
|
-
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) => {
|
|
7192
7343
|
await runSearchAction(query, opts, cmd.optsWithGlobals());
|
|
7193
7344
|
});
|
|
7194
7345
|
}
|
|
7195
7346
|
|
|
7196
7347
|
// src/commands/skill/create.ts
|
|
7197
|
-
import { Command as
|
|
7198
|
-
import * as
|
|
7348
|
+
import { Command as Command64 } from "commander";
|
|
7349
|
+
import * as path52 from "path";
|
|
7199
7350
|
import * as fs34 from "fs";
|
|
7200
7351
|
import YAML from "yaml";
|
|
7201
7352
|
var KEBAB_CASE_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
@@ -7280,21 +7431,21 @@ function runCreate(name, opts) {
|
|
|
7280
7431
|
if (!KEBAB_CASE_RE.test(name)) {
|
|
7281
7432
|
throw new Error(`Invalid skill name "${name}". Must be kebab-case (e.g., my-skill).`);
|
|
7282
7433
|
}
|
|
7283
|
-
const baseDir = opts.outputDir ??
|
|
7284
|
-
const skillDir =
|
|
7434
|
+
const baseDir = opts.outputDir ?? path52.join(process.cwd(), "agents", "skills", "claude-code");
|
|
7435
|
+
const skillDir = path52.join(baseDir, name);
|
|
7285
7436
|
if (fs34.existsSync(skillDir)) {
|
|
7286
7437
|
throw new Error(`Skill directory already exists: ${skillDir}`);
|
|
7287
7438
|
}
|
|
7288
7439
|
fs34.mkdirSync(skillDir, { recursive: true });
|
|
7289
7440
|
const description = opts.description || `A community skill: ${name}`;
|
|
7290
7441
|
const skillYaml = buildSkillYaml(name, opts);
|
|
7291
|
-
const skillYamlPath =
|
|
7442
|
+
const skillYamlPath = path52.join(skillDir, "skill.yaml");
|
|
7292
7443
|
fs34.writeFileSync(skillYamlPath, YAML.stringify(skillYaml));
|
|
7293
7444
|
const skillMd = buildSkillMd(name, description);
|
|
7294
|
-
const skillMdPath =
|
|
7445
|
+
const skillMdPath = path52.join(skillDir, "SKILL.md");
|
|
7295
7446
|
fs34.writeFileSync(skillMdPath, skillMd);
|
|
7296
7447
|
const readme = buildReadme(name, description);
|
|
7297
|
-
const readmePath =
|
|
7448
|
+
const readmePath = path52.join(skillDir, "README.md");
|
|
7298
7449
|
fs34.writeFileSync(readmePath, readme);
|
|
7299
7450
|
return {
|
|
7300
7451
|
name,
|
|
@@ -7309,12 +7460,12 @@ function printCreateResult(name, result) {
|
|
|
7309
7460
|
}
|
|
7310
7461
|
logger.info(`
|
|
7311
7462
|
Next steps:`);
|
|
7312
|
-
logger.info(` 1. Edit ${
|
|
7463
|
+
logger.info(` 1. Edit ${path52.join(result.directory, "SKILL.md")} with your skill content`);
|
|
7313
7464
|
logger.info(` 2. Run: harness skill validate ${name}`);
|
|
7314
7465
|
logger.info(` 3. Run: harness skills publish`);
|
|
7315
7466
|
}
|
|
7316
7467
|
function createCreateCommand() {
|
|
7317
|
-
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) => {
|
|
7318
7469
|
const globalOpts = cmd.optsWithGlobals();
|
|
7319
7470
|
try {
|
|
7320
7471
|
const result = runCreate(name, {
|
|
@@ -7337,19 +7488,19 @@ function createCreateCommand() {
|
|
|
7337
7488
|
}
|
|
7338
7489
|
|
|
7339
7490
|
// src/commands/skill/publish.ts
|
|
7340
|
-
import { Command as
|
|
7491
|
+
import { Command as Command65 } from "commander";
|
|
7341
7492
|
import * as fs36 from "fs";
|
|
7342
|
-
import * as
|
|
7493
|
+
import * as path54 from "path";
|
|
7343
7494
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
7344
7495
|
|
|
7345
7496
|
// src/registry/validator.ts
|
|
7346
7497
|
import * as fs35 from "fs";
|
|
7347
|
-
import * as
|
|
7498
|
+
import * as path53 from "path";
|
|
7348
7499
|
import { parse as parse5 } from "yaml";
|
|
7349
7500
|
import semver4 from "semver";
|
|
7350
7501
|
async function validateForPublish(skillDir, registryUrl) {
|
|
7351
7502
|
const errors = [];
|
|
7352
|
-
const skillYamlPath =
|
|
7503
|
+
const skillYamlPath = path53.join(skillDir, "skill.yaml");
|
|
7353
7504
|
if (!fs35.existsSync(skillYamlPath)) {
|
|
7354
7505
|
errors.push("skill.yaml not found. Create one with: harness skill create <name>");
|
|
7355
7506
|
return { valid: false, errors };
|
|
@@ -7378,7 +7529,7 @@ async function validateForPublish(skillDir, registryUrl) {
|
|
|
7378
7529
|
if (!skillMeta.triggers || skillMeta.triggers.length === 0) {
|
|
7379
7530
|
errors.push("At least one trigger is required. Add triggers to skill.yaml.");
|
|
7380
7531
|
}
|
|
7381
|
-
const skillMdPath =
|
|
7532
|
+
const skillMdPath = path53.join(skillDir, "SKILL.md");
|
|
7382
7533
|
if (!fs35.existsSync(skillMdPath)) {
|
|
7383
7534
|
errors.push("SKILL.md not found. Create it with content describing your skill.");
|
|
7384
7535
|
} else {
|
|
@@ -7462,11 +7613,11 @@ ${errorList}`);
|
|
|
7462
7613
|
}
|
|
7463
7614
|
const meta = validation.skillMeta;
|
|
7464
7615
|
const pkg = derivePackageJson(meta);
|
|
7465
|
-
const pkgPath =
|
|
7616
|
+
const pkgPath = path54.join(skillDir, "package.json");
|
|
7466
7617
|
fs36.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
7467
|
-
const readmePath =
|
|
7618
|
+
const readmePath = path54.join(skillDir, "README.md");
|
|
7468
7619
|
if (!fs36.existsSync(readmePath)) {
|
|
7469
|
-
const skillMdContent = fs36.readFileSync(
|
|
7620
|
+
const skillMdContent = fs36.readFileSync(path54.join(skillDir, "SKILL.md"), "utf-8");
|
|
7470
7621
|
const readme = `# ${pkg.name}
|
|
7471
7622
|
|
|
7472
7623
|
${meta.description}
|
|
@@ -7506,7 +7657,7 @@ ${skillMdContent}`;
|
|
|
7506
7657
|
};
|
|
7507
7658
|
}
|
|
7508
7659
|
function createPublishCommand() {
|
|
7509
|
-
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) => {
|
|
7510
7661
|
const globalOpts = cmd.optsWithGlobals();
|
|
7511
7662
|
const skillDir = opts.dir || process.cwd();
|
|
7512
7663
|
try {
|
|
@@ -7531,7 +7682,7 @@ function createPublishCommand() {
|
|
|
7531
7682
|
|
|
7532
7683
|
// src/commands/skill/index.ts
|
|
7533
7684
|
function createSkillCommand() {
|
|
7534
|
-
const command = new
|
|
7685
|
+
const command = new Command66("skill").description("Skill management commands");
|
|
7535
7686
|
command.addCommand(createListCommand3());
|
|
7536
7687
|
command.addCommand(createRunCommand2());
|
|
7537
7688
|
command.addCommand(createValidateCommand2());
|
|
@@ -7544,9 +7695,9 @@ function createSkillCommand() {
|
|
|
7544
7695
|
|
|
7545
7696
|
// src/commands/snapshot.ts
|
|
7546
7697
|
init_dist();
|
|
7547
|
-
import { Command as
|
|
7698
|
+
import { Command as Command67 } from "commander";
|
|
7548
7699
|
import { execSync as execSync5 } from "child_process";
|
|
7549
|
-
import
|
|
7700
|
+
import chalk11 from "chalk";
|
|
7550
7701
|
function getCommitHash3(cwd) {
|
|
7551
7702
|
try {
|
|
7552
7703
|
return execSync5("git rev-parse --short HEAD", { cwd, encoding: "utf-8" }).toString().trim();
|
|
@@ -7571,9 +7722,9 @@ function formatDelta(delta) {
|
|
|
7571
7722
|
function directionSymbol(direction) {
|
|
7572
7723
|
switch (direction) {
|
|
7573
7724
|
case "improving":
|
|
7574
|
-
return
|
|
7725
|
+
return chalk11.green("improving");
|
|
7575
7726
|
case "declining":
|
|
7576
|
-
return
|
|
7727
|
+
return chalk11.red("declining");
|
|
7577
7728
|
case "stable":
|
|
7578
7729
|
return "=";
|
|
7579
7730
|
}
|
|
@@ -7726,7 +7877,7 @@ function registerListCommand(parent) {
|
|
|
7726
7877
|
});
|
|
7727
7878
|
}
|
|
7728
7879
|
function createSnapshotCommand() {
|
|
7729
|
-
const command = new
|
|
7880
|
+
const command = new Command67("snapshot").description("Architecture timeline snapshot commands");
|
|
7730
7881
|
registerCaptureCommand(command);
|
|
7731
7882
|
registerTrendsCommand(command);
|
|
7732
7883
|
registerListCommand(command);
|
|
@@ -7734,12 +7885,12 @@ function createSnapshotCommand() {
|
|
|
7734
7885
|
}
|
|
7735
7886
|
|
|
7736
7887
|
// src/commands/state/index.ts
|
|
7737
|
-
import { Command as
|
|
7888
|
+
import { Command as Command72 } from "commander";
|
|
7738
7889
|
|
|
7739
7890
|
// src/commands/state/show.ts
|
|
7740
7891
|
init_dist();
|
|
7741
|
-
import { Command as
|
|
7742
|
-
import * as
|
|
7892
|
+
import { Command as Command68 } from "commander";
|
|
7893
|
+
import * as path55 from "path";
|
|
7743
7894
|
function printStateText(state, stream) {
|
|
7744
7895
|
if (stream) console.log(`Stream: ${stream}`);
|
|
7745
7896
|
console.log(`Schema Version: ${state.schemaVersion}`);
|
|
@@ -7763,9 +7914,9 @@ function printStateProgress(progress) {
|
|
|
7763
7914
|
}
|
|
7764
7915
|
}
|
|
7765
7916
|
function createShowCommand() {
|
|
7766
|
-
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) => {
|
|
7767
7918
|
const globalOpts = cmd.optsWithGlobals();
|
|
7768
|
-
const result = await loadState(
|
|
7919
|
+
const result = await loadState(path55.resolve(opts.path), opts.stream);
|
|
7769
7920
|
if (!result.ok) {
|
|
7770
7921
|
logger.error(result.error.message);
|
|
7771
7922
|
process.exit(ExitCode.ERROR);
|
|
@@ -7781,9 +7932,9 @@ function createShowCommand() {
|
|
|
7781
7932
|
|
|
7782
7933
|
// src/commands/state/reset.ts
|
|
7783
7934
|
init_dist();
|
|
7784
|
-
import { Command as
|
|
7935
|
+
import { Command as Command69 } from "commander";
|
|
7785
7936
|
import * as fs37 from "fs";
|
|
7786
|
-
import * as
|
|
7937
|
+
import * as path56 from "path";
|
|
7787
7938
|
import * as readline2 from "readline";
|
|
7788
7939
|
async function resolveStatePath(projectPath, stream) {
|
|
7789
7940
|
if (stream) {
|
|
@@ -7792,9 +7943,9 @@ async function resolveStatePath(projectPath, stream) {
|
|
|
7792
7943
|
logger.error(streamResult.error.message);
|
|
7793
7944
|
process.exit(ExitCode.ERROR);
|
|
7794
7945
|
}
|
|
7795
|
-
return
|
|
7946
|
+
return path56.join(streamResult.value, "state.json");
|
|
7796
7947
|
}
|
|
7797
|
-
return
|
|
7948
|
+
return path56.join(projectPath, ".harness", "state.json");
|
|
7798
7949
|
}
|
|
7799
7950
|
async function confirmReset() {
|
|
7800
7951
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -7805,7 +7956,7 @@ async function confirmReset() {
|
|
|
7805
7956
|
return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
7806
7957
|
}
|
|
7807
7958
|
async function runReset(opts) {
|
|
7808
|
-
const projectPath =
|
|
7959
|
+
const projectPath = path56.resolve(opts.path);
|
|
7809
7960
|
const statePath = await resolveStatePath(projectPath, opts.stream);
|
|
7810
7961
|
if (!fs37.existsSync(statePath)) {
|
|
7811
7962
|
logger.info("No state file found. Nothing to reset.");
|
|
@@ -7825,16 +7976,16 @@ async function runReset(opts) {
|
|
|
7825
7976
|
process.exit(ExitCode.SUCCESS);
|
|
7826
7977
|
}
|
|
7827
7978
|
function createResetCommand() {
|
|
7828
|
-
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));
|
|
7829
7980
|
}
|
|
7830
7981
|
|
|
7831
7982
|
// src/commands/state/learn.ts
|
|
7832
7983
|
init_dist();
|
|
7833
|
-
import { Command as
|
|
7834
|
-
import * as
|
|
7984
|
+
import { Command as Command70 } from "commander";
|
|
7985
|
+
import * as path57 from "path";
|
|
7835
7986
|
function createLearnCommand() {
|
|
7836
|
-
return new
|
|
7837
|
-
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);
|
|
7838
7989
|
const result = await appendLearning(projectPath, message, void 0, void 0, opts.stream);
|
|
7839
7990
|
if (!result.ok) {
|
|
7840
7991
|
logger.error(result.error.message);
|
|
@@ -7848,10 +7999,10 @@ function createLearnCommand() {
|
|
|
7848
7999
|
|
|
7849
8000
|
// src/commands/state/streams.ts
|
|
7850
8001
|
init_dist();
|
|
7851
|
-
import { Command as
|
|
7852
|
-
import * as
|
|
8002
|
+
import { Command as Command71 } from "commander";
|
|
8003
|
+
import * as path58 from "path";
|
|
7853
8004
|
async function runListStreams(opts, globalOpts) {
|
|
7854
|
-
const projectPath =
|
|
8005
|
+
const projectPath = path58.resolve(opts.path);
|
|
7855
8006
|
const indexResult = await loadStreamIndex(projectPath);
|
|
7856
8007
|
const result = await listStreams(projectPath);
|
|
7857
8008
|
if (!result.ok) {
|
|
@@ -7872,7 +8023,7 @@ async function runListStreams(opts, globalOpts) {
|
|
|
7872
8023
|
process.exit(ExitCode.SUCCESS);
|
|
7873
8024
|
}
|
|
7874
8025
|
async function runCreateStream(name, opts) {
|
|
7875
|
-
const result = await createStream(
|
|
8026
|
+
const result = await createStream(path58.resolve(opts.path), name, opts.branch);
|
|
7876
8027
|
if (!result.ok) {
|
|
7877
8028
|
logger.error(result.error.message);
|
|
7878
8029
|
process.exit(ExitCode.ERROR);
|
|
@@ -7881,7 +8032,7 @@ async function runCreateStream(name, opts) {
|
|
|
7881
8032
|
process.exit(ExitCode.SUCCESS);
|
|
7882
8033
|
}
|
|
7883
8034
|
async function runArchiveStream(name, opts) {
|
|
7884
|
-
const result = await archiveStream(
|
|
8035
|
+
const result = await archiveStream(path58.resolve(opts.path), name);
|
|
7885
8036
|
if (!result.ok) {
|
|
7886
8037
|
logger.error(result.error.message);
|
|
7887
8038
|
process.exit(ExitCode.ERROR);
|
|
@@ -7890,7 +8041,7 @@ async function runArchiveStream(name, opts) {
|
|
|
7890
8041
|
process.exit(ExitCode.SUCCESS);
|
|
7891
8042
|
}
|
|
7892
8043
|
async function runActivateStream(name, opts) {
|
|
7893
|
-
const result = await setActiveStream(
|
|
8044
|
+
const result = await setActiveStream(path58.resolve(opts.path), name);
|
|
7894
8045
|
if (!result.ok) {
|
|
7895
8046
|
logger.error(result.error.message);
|
|
7896
8047
|
process.exit(ExitCode.ERROR);
|
|
@@ -7899,7 +8050,7 @@ async function runActivateStream(name, opts) {
|
|
|
7899
8050
|
process.exit(ExitCode.SUCCESS);
|
|
7900
8051
|
}
|
|
7901
8052
|
function createStreamsCommand() {
|
|
7902
|
-
const command = new
|
|
8053
|
+
const command = new Command71("streams").description("Manage state streams");
|
|
7903
8054
|
command.command("list").description("List all known streams").option("--path <path>", "Project root path", ".").action(async (opts, cmd) => runListStreams(opts, cmd.optsWithGlobals()));
|
|
7904
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));
|
|
7905
8056
|
command.command("archive <name>").description("Archive a stream").option("--path <path>", "Project root path", ".").action(async (name, opts) => runArchiveStream(name, opts));
|
|
@@ -7909,7 +8060,7 @@ function createStreamsCommand() {
|
|
|
7909
8060
|
|
|
7910
8061
|
// src/commands/state/index.ts
|
|
7911
8062
|
function createStateCommand() {
|
|
7912
|
-
const command = new
|
|
8063
|
+
const command = new Command72("state").description("Project state management commands");
|
|
7913
8064
|
command.addCommand(createShowCommand());
|
|
7914
8065
|
command.addCommand(createResetCommand());
|
|
7915
8066
|
command.addCommand(createLearnCommand());
|
|
@@ -7919,8 +8070,8 @@ function createStateCommand() {
|
|
|
7919
8070
|
|
|
7920
8071
|
// src/commands/sync-analyses.ts
|
|
7921
8072
|
import * as fs38 from "fs";
|
|
7922
|
-
import * as
|
|
7923
|
-
import { Command as
|
|
8073
|
+
import * as path59 from "path";
|
|
8074
|
+
import { Command as Command73 } from "commander";
|
|
7924
8075
|
init_dist();
|
|
7925
8076
|
function isValidRecord(record) {
|
|
7926
8077
|
return typeof record.issueId === "string" && !!record.issueId && typeof record.identifier === "string" && !!record.identifier && typeof record.analyzedAt === "string" && !/[/\\]/.test(record.issueId);
|
|
@@ -7946,7 +8097,7 @@ function extractAnalysisFromComments(comments) {
|
|
|
7946
8097
|
return null;
|
|
7947
8098
|
}
|
|
7948
8099
|
function bootstrapTrackerCommand2(opts, verb) {
|
|
7949
|
-
const projectPath =
|
|
8100
|
+
const projectPath = path59.resolve(opts.dir);
|
|
7950
8101
|
const trackerConfig = loadTrackerSyncConfig(projectPath);
|
|
7951
8102
|
if (!trackerConfig) {
|
|
7952
8103
|
logger.error(`No tracker config found in harness.config.json. Cannot ${verb}.`);
|
|
@@ -7958,7 +8109,7 @@ function bootstrapTrackerCommand2(opts, verb) {
|
|
|
7958
8109
|
);
|
|
7959
8110
|
return null;
|
|
7960
8111
|
}
|
|
7961
|
-
const projectEnvPath =
|
|
8112
|
+
const projectEnvPath = path59.join(projectPath, ".env");
|
|
7962
8113
|
if (fs38.existsSync(projectEnvPath) && !process.env.GITHUB_TOKEN) {
|
|
7963
8114
|
__require("dotenv").config({ path: projectEnvPath });
|
|
7964
8115
|
}
|
|
@@ -7970,7 +8121,7 @@ function bootstrapTrackerCommand2(opts, verb) {
|
|
|
7970
8121
|
return { token, projectPath, trackerConfig };
|
|
7971
8122
|
}
|
|
7972
8123
|
function loadRoadmapFeatures(projectPath) {
|
|
7973
|
-
const roadmapFile =
|
|
8124
|
+
const roadmapFile = path59.join(projectPath, "docs", "roadmap.md");
|
|
7974
8125
|
if (!fs38.existsSync(roadmapFile)) {
|
|
7975
8126
|
logger.error("No docs/roadmap.md found. Cannot discover features with externalIds.");
|
|
7976
8127
|
return null;
|
|
@@ -8027,9 +8178,9 @@ async function runSyncAnalyses(opts) {
|
|
|
8027
8178
|
return;
|
|
8028
8179
|
}
|
|
8029
8180
|
const { AnalysisArchive, loadPublishedIndex: loadPublishedIndex2, savePublishedIndex: savePublishedIndex2 } = await import("@harness-engineering/orchestrator");
|
|
8030
|
-
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-
|
|
8181
|
+
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-TG63OKA5.js");
|
|
8031
8182
|
const adapter = new GitHubIssuesSyncAdapter2({ token, config: trackerConfig });
|
|
8032
|
-
const archive = new AnalysisArchive(
|
|
8183
|
+
const archive = new AnalysisArchive(path59.join(projectPath, ".harness", "analyses"));
|
|
8033
8184
|
const publishedIndex = loadPublishedIndex2(projectPath);
|
|
8034
8185
|
const { syncedCount, skippedCount, warnCount } = await syncFeatureAnalyses(
|
|
8035
8186
|
features,
|
|
@@ -8049,7 +8200,7 @@ async function runSyncAnalyses(opts) {
|
|
|
8049
8200
|
}
|
|
8050
8201
|
}
|
|
8051
8202
|
function createSyncAnalysesCommand() {
|
|
8052
|
-
const command = new
|
|
8203
|
+
const command = new Command73("sync-analyses").description(
|
|
8053
8204
|
"Pull published intelligence analyses from the external issue tracker into the local .harness/analyses/ directory"
|
|
8054
8205
|
).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
8055
8206
|
try {
|
|
@@ -8064,7 +8215,7 @@ function createSyncAnalysesCommand() {
|
|
|
8064
8215
|
|
|
8065
8216
|
// src/commands/taint.ts
|
|
8066
8217
|
init_dist();
|
|
8067
|
-
import { Command as
|
|
8218
|
+
import { Command as Command74 } from "commander";
|
|
8068
8219
|
function getProjectRoot() {
|
|
8069
8220
|
return process.cwd();
|
|
8070
8221
|
}
|
|
@@ -8136,26 +8287,26 @@ function registerStatusCommand(taint) {
|
|
|
8136
8287
|
});
|
|
8137
8288
|
}
|
|
8138
8289
|
function createTaintCommand() {
|
|
8139
|
-
const taint = new
|
|
8290
|
+
const taint = new Command74("taint").description("Manage sentinel session taint state");
|
|
8140
8291
|
registerClearCommand(taint);
|
|
8141
8292
|
registerStatusCommand(taint);
|
|
8142
8293
|
return taint;
|
|
8143
8294
|
}
|
|
8144
8295
|
|
|
8145
8296
|
// src/commands/telemetry/index.ts
|
|
8146
|
-
import { Command as
|
|
8297
|
+
import { Command as Command78 } from "commander";
|
|
8147
8298
|
|
|
8148
8299
|
// src/commands/telemetry/identify.ts
|
|
8149
8300
|
init_dist();
|
|
8150
|
-
import { Command as
|
|
8301
|
+
import { Command as Command75 } from "commander";
|
|
8151
8302
|
import * as fs39 from "fs";
|
|
8152
|
-
import * as
|
|
8303
|
+
import * as path60 from "path";
|
|
8153
8304
|
function telemetryFilePath(cwd) {
|
|
8154
|
-
return
|
|
8305
|
+
return path60.join(cwd, ".harness", "telemetry.json");
|
|
8155
8306
|
}
|
|
8156
8307
|
function writeTelemetryFile(cwd, data) {
|
|
8157
8308
|
const filePath = telemetryFilePath(cwd);
|
|
8158
|
-
const dir =
|
|
8309
|
+
const dir = path60.dirname(filePath);
|
|
8159
8310
|
fs39.mkdirSync(dir, { recursive: true });
|
|
8160
8311
|
fs39.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
8161
8312
|
}
|
|
@@ -8171,7 +8322,7 @@ function printIdentity(identity) {
|
|
|
8171
8322
|
}
|
|
8172
8323
|
}
|
|
8173
8324
|
function createIdentifyCommand() {
|
|
8174
|
-
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) => {
|
|
8175
8326
|
const cwd = process.cwd();
|
|
8176
8327
|
if (opts.clear) {
|
|
8177
8328
|
writeTelemetryFile(cwd, { identity: {} });
|
|
@@ -8196,7 +8347,7 @@ function createIdentifyCommand() {
|
|
|
8196
8347
|
|
|
8197
8348
|
// src/commands/telemetry/status.ts
|
|
8198
8349
|
init_dist();
|
|
8199
|
-
import { Command as
|
|
8350
|
+
import { Command as Command76 } from "commander";
|
|
8200
8351
|
function gatherEnvOverrides() {
|
|
8201
8352
|
const overrides = {};
|
|
8202
8353
|
if (process.env.DO_NOT_TRACK) overrides.DO_NOT_TRACK = process.env.DO_NOT_TRACK;
|
|
@@ -8238,7 +8389,7 @@ function printHumanStatus(result) {
|
|
|
8238
8389
|
printEnvOverrides(result.envOverrides);
|
|
8239
8390
|
}
|
|
8240
8391
|
function createStatusCommand() {
|
|
8241
|
-
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) => {
|
|
8242
8393
|
const cwd = process.cwd();
|
|
8243
8394
|
const envOverrides = gatherEnvOverrides();
|
|
8244
8395
|
const consent = resolveConsent(cwd, void 0);
|
|
@@ -8271,11 +8422,11 @@ function createStatusCommand() {
|
|
|
8271
8422
|
|
|
8272
8423
|
// src/commands/telemetry/test.ts
|
|
8273
8424
|
init_dist();
|
|
8274
|
-
import { Command as
|
|
8425
|
+
import { Command as Command77 } from "commander";
|
|
8275
8426
|
|
|
8276
8427
|
// src/bin/command-telemetry.ts
|
|
8277
8428
|
import { existsSync as existsSync36, readFileSync as readFileSync25, mkdirSync as mkdirSync15, appendFileSync, writeFileSync as writeFileSync18 } from "fs";
|
|
8278
|
-
import { join as
|
|
8429
|
+
import { join as join46, parse as parsePath, resolve as resolve33 } from "path";
|
|
8279
8430
|
import { spawn as spawn2 } from "child_process";
|
|
8280
8431
|
var POSTHOG_API_KEY = "phc_wNTdCMcfJXZPgdNeDociZW6vwoGGo4nb7vqEfWThFfsG";
|
|
8281
8432
|
var EXCLUDED_COMMANDS = /* @__PURE__ */ new Set(["help", "completion"]);
|
|
@@ -8283,7 +8434,7 @@ function findProjectRoot(cwd) {
|
|
|
8283
8434
|
let dir = resolve33(cwd);
|
|
8284
8435
|
const { root } = parsePath(dir);
|
|
8285
8436
|
while (dir !== root) {
|
|
8286
|
-
if (existsSync36(
|
|
8437
|
+
if (existsSync36(join46(dir, "harness.config.json"))) return dir;
|
|
8287
8438
|
dir = resolve33(dir, "..");
|
|
8288
8439
|
}
|
|
8289
8440
|
return cwd;
|
|
@@ -8321,7 +8472,7 @@ function resolveCommandName(cmd) {
|
|
|
8321
8472
|
}
|
|
8322
8473
|
function writeCommandRecordSync(cwd, command, duration, outcome) {
|
|
8323
8474
|
try {
|
|
8324
|
-
const metricsDir =
|
|
8475
|
+
const metricsDir = join46(cwd, ".harness", "metrics");
|
|
8325
8476
|
mkdirSync15(metricsDir, { recursive: true });
|
|
8326
8477
|
const record = {
|
|
8327
8478
|
skill: command,
|
|
@@ -8331,13 +8482,13 @@ function writeCommandRecordSync(cwd, command, duration, outcome) {
|
|
|
8331
8482
|
outcome,
|
|
8332
8483
|
phasesReached: []
|
|
8333
8484
|
};
|
|
8334
|
-
const adoptionFile =
|
|
8485
|
+
const adoptionFile = join46(metricsDir, "adoption.jsonl");
|
|
8335
8486
|
appendFileSync(adoptionFile, JSON.stringify(record) + "\n");
|
|
8336
8487
|
} catch {
|
|
8337
8488
|
}
|
|
8338
8489
|
}
|
|
8339
8490
|
function isTelemetryDisabledByConfig(cwd) {
|
|
8340
|
-
const configPath =
|
|
8491
|
+
const configPath = join46(cwd, "harness.config.json");
|
|
8341
8492
|
if (!existsSync36(configPath)) return false;
|
|
8342
8493
|
try {
|
|
8343
8494
|
const config = JSON.parse(readFileSync25(configPath, "utf-8"));
|
|
@@ -8352,10 +8503,10 @@ function isTelemetryOptedOut(cwd) {
|
|
|
8352
8503
|
}
|
|
8353
8504
|
function flushTelemetryBackground(cwd) {
|
|
8354
8505
|
try {
|
|
8355
|
-
const adoptionFile =
|
|
8506
|
+
const adoptionFile = join46(cwd, ".harness", "metrics", "adoption.jsonl");
|
|
8356
8507
|
if (!existsSync36(adoptionFile)) return;
|
|
8357
8508
|
if (isTelemetryOptedOut(cwd)) return;
|
|
8358
|
-
const reporterPath =
|
|
8509
|
+
const reporterPath = join46(cwd, ".harness", "hooks", "telemetry-reporter.js");
|
|
8359
8510
|
if (!existsSync36(reporterPath)) return;
|
|
8360
8511
|
const child = spawn2(process.execPath, [reporterPath], {
|
|
8361
8512
|
cwd,
|
|
@@ -8393,7 +8544,7 @@ function reportTestSuccess(status, distinctId, identity) {
|
|
|
8393
8544
|
if (identity.team) logger.info(` team: ${identity.team}`);
|
|
8394
8545
|
}
|
|
8395
8546
|
function createTestCommand() {
|
|
8396
|
-
return new
|
|
8547
|
+
return new Command77("test").description("Send a test event to PostHog and verify connectivity").action(async () => {
|
|
8397
8548
|
const cwd = process.cwd();
|
|
8398
8549
|
const consent = resolveConsent(cwd, void 0);
|
|
8399
8550
|
if (!consent.allowed) {
|
|
@@ -8430,7 +8581,7 @@ function createTestCommand() {
|
|
|
8430
8581
|
|
|
8431
8582
|
// src/commands/telemetry/index.ts
|
|
8432
8583
|
function createTelemetryCommand() {
|
|
8433
|
-
const command = new
|
|
8584
|
+
const command = new Command78("telemetry").description("Telemetry identity and status management");
|
|
8434
8585
|
command.addCommand(createIdentifyCommand());
|
|
8435
8586
|
command.addCommand(createStatusCommand());
|
|
8436
8587
|
command.addCommand(createTestCommand());
|
|
@@ -8438,8 +8589,8 @@ function createTelemetryCommand() {
|
|
|
8438
8589
|
}
|
|
8439
8590
|
|
|
8440
8591
|
// src/commands/traceability.ts
|
|
8441
|
-
import { Command as
|
|
8442
|
-
import
|
|
8592
|
+
import { Command as Command79 } from "commander";
|
|
8593
|
+
import chalk12 from "chalk";
|
|
8443
8594
|
function confidenceLabel(maxConfidence) {
|
|
8444
8595
|
if (maxConfidence >= 0.8) return "explicit";
|
|
8445
8596
|
if (maxConfidence > 0) return "inferred";
|
|
@@ -8448,13 +8599,13 @@ function confidenceLabel(maxConfidence) {
|
|
|
8448
8599
|
function statusIcon(status) {
|
|
8449
8600
|
switch (status) {
|
|
8450
8601
|
case "full":
|
|
8451
|
-
return
|
|
8602
|
+
return chalk12.green("\u2713 full");
|
|
8452
8603
|
case "code-only":
|
|
8453
|
-
return
|
|
8604
|
+
return chalk12.yellow("\u25D0 code-only");
|
|
8454
8605
|
case "test-only":
|
|
8455
|
-
return
|
|
8606
|
+
return chalk12.yellow("\u25D0 test-only");
|
|
8456
8607
|
case "none":
|
|
8457
|
-
return
|
|
8608
|
+
return chalk12.red("\u2717 none");
|
|
8458
8609
|
default:
|
|
8459
8610
|
return status;
|
|
8460
8611
|
}
|
|
@@ -8496,14 +8647,14 @@ function handleEmptyResults(mode) {
|
|
|
8496
8647
|
}
|
|
8497
8648
|
function printResultTable(result, mode) {
|
|
8498
8649
|
const specLabel = result.specPath || result.featureName || "Unknown";
|
|
8499
|
-
console.log(` ${
|
|
8650
|
+
console.log(` ${chalk12.cyan(specLabel)} ${chalk12.dim(`(${result.summary.total} requirements)`)}`);
|
|
8500
8651
|
console.log("");
|
|
8501
8652
|
const numWidth = 4;
|
|
8502
8653
|
const nameWidth = mode === OutputMode.VERBOSE ? 44 : 36;
|
|
8503
8654
|
const codeWidth = 6;
|
|
8504
8655
|
const testWidth = 7;
|
|
8505
8656
|
const confWidth = 12;
|
|
8506
|
-
const header =
|
|
8657
|
+
const header = chalk12.dim(
|
|
8507
8658
|
` ${pad("#", numWidth)}${pad("Requirement", nameWidth)}${pad("Code", codeWidth)}${pad("Tests", testWidth)}${pad("Confidence", confWidth)}Status`
|
|
8508
8659
|
);
|
|
8509
8660
|
console.log(header);
|
|
@@ -8532,10 +8683,10 @@ function printRequirementRows(requirements, mode, cols) {
|
|
|
8532
8683
|
);
|
|
8533
8684
|
if (mode === OutputMode.VERBOSE) {
|
|
8534
8685
|
for (const f of req.codeFiles) {
|
|
8535
|
-
console.log(
|
|
8686
|
+
console.log(chalk12.dim(` code: ${f.path} (${f.method})`));
|
|
8536
8687
|
}
|
|
8537
8688
|
for (const f of req.testFiles) {
|
|
8538
|
-
console.log(
|
|
8689
|
+
console.log(chalk12.dim(` test: ${f.path} (${f.method})`));
|
|
8539
8690
|
}
|
|
8540
8691
|
}
|
|
8541
8692
|
}
|
|
@@ -8546,7 +8697,7 @@ function printCoverageSummary(summary) {
|
|
|
8546
8697
|
const codePct = s.total > 0 ? Math.round(s.withCode / s.total * 100) : 0;
|
|
8547
8698
|
const testPct = s.total > 0 ? Math.round(s.withTests / s.total * 100) : 0;
|
|
8548
8699
|
console.log(
|
|
8549
|
-
` ${
|
|
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})`
|
|
8550
8701
|
);
|
|
8551
8702
|
}
|
|
8552
8703
|
async function runTraceability(options) {
|
|
@@ -8554,7 +8705,7 @@ async function runTraceability(options) {
|
|
|
8554
8705
|
const projectPath = process.cwd();
|
|
8555
8706
|
const store = await loadGraphStore(projectPath);
|
|
8556
8707
|
if (!store) handleNoStore(mode);
|
|
8557
|
-
const graphModule = await import("./dist-
|
|
8708
|
+
const graphModule = await import("./dist-PGQ32ZI7.js");
|
|
8558
8709
|
const filterOptions = buildFilterOptions(options);
|
|
8559
8710
|
const results = graphModule.queryTraceability(store, filterOptions);
|
|
8560
8711
|
if (results.length === 0) handleEmptyResults(mode);
|
|
@@ -8562,14 +8713,14 @@ async function runTraceability(options) {
|
|
|
8562
8713
|
console.log(JSON.stringify(results, null, 2));
|
|
8563
8714
|
} else {
|
|
8564
8715
|
console.log("");
|
|
8565
|
-
console.log(
|
|
8716
|
+
console.log(chalk12.bold("Spec-to-Implementation Traceability"));
|
|
8566
8717
|
console.log("");
|
|
8567
8718
|
for (const result of results) printResultTable(result, mode);
|
|
8568
8719
|
}
|
|
8569
8720
|
process.exit(ExitCode.SUCCESS);
|
|
8570
8721
|
}
|
|
8571
8722
|
function createTraceabilityCommand() {
|
|
8572
|
-
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) => {
|
|
8573
8724
|
const globalOpts = cmd.optsWithGlobals();
|
|
8574
8725
|
await runTraceability({
|
|
8575
8726
|
spec: opts.spec,
|
|
@@ -8582,15 +8733,15 @@ function createTraceabilityCommand() {
|
|
|
8582
8733
|
}
|
|
8583
8734
|
|
|
8584
8735
|
// src/commands/uninstall.ts
|
|
8585
|
-
import * as
|
|
8586
|
-
import { Command as
|
|
8736
|
+
import * as path61 from "path";
|
|
8737
|
+
import { Command as Command80 } from "commander";
|
|
8587
8738
|
async function runUninstall(skillName, options) {
|
|
8588
8739
|
const packageName = resolvePackageName(skillName);
|
|
8589
8740
|
const shortName = extractSkillName(packageName);
|
|
8590
8741
|
const globalDir = resolveGlobalSkillsDir();
|
|
8591
|
-
const skillsDir =
|
|
8592
|
-
const communityBase =
|
|
8593
|
-
const lockfilePath =
|
|
8742
|
+
const skillsDir = path61.dirname(globalDir);
|
|
8743
|
+
const communityBase = path61.join(skillsDir, "community");
|
|
8744
|
+
const lockfilePath = path61.join(communityBase, "skills-lock.json");
|
|
8594
8745
|
const lockfile = readLockfile2(lockfilePath);
|
|
8595
8746
|
const entry = lockfile.skills[packageName];
|
|
8596
8747
|
if (!entry) {
|
|
@@ -8620,7 +8771,7 @@ async function runUninstall(skillName, options) {
|
|
|
8620
8771
|
return result;
|
|
8621
8772
|
}
|
|
8622
8773
|
function createUninstallCommand() {
|
|
8623
|
-
const cmd = new
|
|
8774
|
+
const cmd = new Command80("uninstall");
|
|
8624
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) => {
|
|
8625
8776
|
try {
|
|
8626
8777
|
const result = await runUninstall(skill, opts);
|
|
@@ -8641,8 +8792,8 @@ function createUninstallCommand() {
|
|
|
8641
8792
|
// src/commands/uninstall-constraints.ts
|
|
8642
8793
|
init_dist();
|
|
8643
8794
|
import * as fs40 from "fs/promises";
|
|
8644
|
-
import * as
|
|
8645
|
-
import { Command as
|
|
8795
|
+
import * as path62 from "path";
|
|
8796
|
+
import { Command as Command81 } from "commander";
|
|
8646
8797
|
async function runUninstallConstraints(options) {
|
|
8647
8798
|
const { packageName, configPath, lockfilePath } = options;
|
|
8648
8799
|
const lockfileResult = await readLockfile(lockfilePath);
|
|
@@ -8699,11 +8850,11 @@ async function runUninstallConstraints(options) {
|
|
|
8699
8850
|
};
|
|
8700
8851
|
}
|
|
8701
8852
|
function createUninstallConstraintsCommand() {
|
|
8702
|
-
const cmd = new
|
|
8853
|
+
const cmd = new Command81("uninstall-constraints");
|
|
8703
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) => {
|
|
8704
8855
|
let configPath;
|
|
8705
8856
|
if (opts.config) {
|
|
8706
|
-
configPath =
|
|
8857
|
+
configPath = path62.resolve(opts.config);
|
|
8707
8858
|
} else {
|
|
8708
8859
|
const found = findConfigFile();
|
|
8709
8860
|
if (!found.ok) {
|
|
@@ -8712,8 +8863,8 @@ function createUninstallConstraintsCommand() {
|
|
|
8712
8863
|
}
|
|
8713
8864
|
configPath = found.value;
|
|
8714
8865
|
}
|
|
8715
|
-
const projectRoot =
|
|
8716
|
-
const lockfilePath =
|
|
8866
|
+
const projectRoot = path62.dirname(configPath);
|
|
8867
|
+
const lockfilePath = path62.join(projectRoot, ".harness", "constraints.lock.json");
|
|
8717
8868
|
const result = await runUninstallConstraints({
|
|
8718
8869
|
packageName: name,
|
|
8719
8870
|
configPath,
|
|
@@ -8738,13 +8889,13 @@ function createUninstallConstraintsCommand() {
|
|
|
8738
8889
|
}
|
|
8739
8890
|
|
|
8740
8891
|
// src/commands/update.ts
|
|
8741
|
-
import { Command as
|
|
8892
|
+
import { Command as Command82 } from "commander";
|
|
8742
8893
|
import { execFile, execFileSync as execFileSync6 } from "child_process";
|
|
8743
8894
|
import { realpathSync, existsSync as existsSync37, readFileSync as readFileSync26 } from "fs";
|
|
8744
|
-
import { join as
|
|
8895
|
+
import { join as join49 } from "path";
|
|
8745
8896
|
import { promisify } from "util";
|
|
8746
8897
|
import readline3 from "readline";
|
|
8747
|
-
import
|
|
8898
|
+
import chalk13 from "chalk";
|
|
8748
8899
|
function detectPackageManager() {
|
|
8749
8900
|
try {
|
|
8750
8901
|
const argv1 = process.argv[1];
|
|
@@ -8825,10 +8976,10 @@ async function ensureTelemetryIfNeeded() {
|
|
|
8825
8976
|
}
|
|
8826
8977
|
function refreshHooks() {
|
|
8827
8978
|
const cwd = process.cwd();
|
|
8828
|
-
const configPath =
|
|
8979
|
+
const configPath = join49(cwd, "harness.config.json");
|
|
8829
8980
|
if (!existsSync37(configPath)) return;
|
|
8830
8981
|
let profile = "standard";
|
|
8831
|
-
const profilePath =
|
|
8982
|
+
const profilePath = join49(cwd, ".harness", "hooks", "profile.json");
|
|
8832
8983
|
try {
|
|
8833
8984
|
const data = JSON.parse(readFileSync26(profilePath, "utf-8"));
|
|
8834
8985
|
if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
|
|
@@ -8850,7 +9001,7 @@ function runLocalGraphScan() {
|
|
|
8850
9001
|
execFileSync6("harness", ["graph", "scan", "."], { stdio: "inherit" });
|
|
8851
9002
|
} catch {
|
|
8852
9003
|
logger.warn("Graph scan failed. Run manually:");
|
|
8853
|
-
console.log(` ${
|
|
9004
|
+
console.log(` ${chalk13.cyan("harness graph scan .")}`);
|
|
8854
9005
|
}
|
|
8855
9006
|
}
|
|
8856
9007
|
async function offerRegeneration() {
|
|
@@ -8867,7 +9018,7 @@ async function offerRegeneration() {
|
|
|
8867
9018
|
});
|
|
8868
9019
|
} catch {
|
|
8869
9020
|
logger.warn("Generation failed. Run manually:");
|
|
8870
|
-
console.log(` ${
|
|
9021
|
+
console.log(` ${chalk13.cyan(`harness generate${isGlobal ? " --global" : ""}`)}`);
|
|
8871
9022
|
}
|
|
8872
9023
|
if (!isGlobal) {
|
|
8873
9024
|
runLocalGraphScan();
|
|
@@ -8930,8 +9081,8 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
8930
9081
|
console.log("");
|
|
8931
9082
|
for (const { pkg, current, latest } of outdated) {
|
|
8932
9083
|
const shortName = pkg.replace("@harness-engineering/", "");
|
|
8933
|
-
const currentStr = current ?
|
|
8934
|
-
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}`)}`);
|
|
8935
9086
|
}
|
|
8936
9087
|
console.log("");
|
|
8937
9088
|
}
|
|
@@ -8947,7 +9098,7 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
8947
9098
|
} catch {
|
|
8948
9099
|
console.log("");
|
|
8949
9100
|
logger.error("Update failed. You can try manually:");
|
|
8950
|
-
console.log(` ${
|
|
9101
|
+
console.log(` ${chalk13.cyan(installCmd)}`);
|
|
8951
9102
|
process.exit(ExitCode.ERROR);
|
|
8952
9103
|
}
|
|
8953
9104
|
refreshHooks();
|
|
@@ -8956,7 +9107,7 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
8956
9107
|
process.exit(ExitCode.SUCCESS);
|
|
8957
9108
|
}
|
|
8958
9109
|
function createUpdateCommand() {
|
|
8959
|
-
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(
|
|
8960
9111
|
"--regenerate",
|
|
8961
9112
|
"Only regenerate slash commands and agent definitions (skip package updates)"
|
|
8962
9113
|
).action(async (opts, cmd) => {
|
|
@@ -8966,9 +9117,9 @@ function createUpdateCommand() {
|
|
|
8966
9117
|
}
|
|
8967
9118
|
|
|
8968
9119
|
// src/commands/usage.ts
|
|
8969
|
-
import { Command as
|
|
9120
|
+
import { Command as Command83 } from "commander";
|
|
8970
9121
|
async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
|
|
8971
|
-
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-
|
|
9122
|
+
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-TG63OKA5.js");
|
|
8972
9123
|
const records = readCostRecords(cwd);
|
|
8973
9124
|
if (includeClaudeSessions) {
|
|
8974
9125
|
const ccRecords = parseCCRecords();
|
|
@@ -9061,7 +9212,7 @@ function registerDailyCommand(usage) {
|
|
|
9061
9212
|
else logger.info("No usage data found. Run some harness sessions first.");
|
|
9062
9213
|
return;
|
|
9063
9214
|
}
|
|
9064
|
-
const { aggregateByDay } = await import("./dist-
|
|
9215
|
+
const { aggregateByDay } = await import("./dist-TG63OKA5.js");
|
|
9065
9216
|
const limited = aggregateByDay(records).slice(0, days);
|
|
9066
9217
|
if (globalOpts.json) {
|
|
9067
9218
|
console.log(
|
|
@@ -9090,7 +9241,7 @@ function registerSessionsCommand(usage) {
|
|
|
9090
9241
|
}
|
|
9091
9242
|
return;
|
|
9092
9243
|
}
|
|
9093
|
-
const { aggregateBySession } = await import("./dist-
|
|
9244
|
+
const { aggregateBySession } = await import("./dist-TG63OKA5.js");
|
|
9094
9245
|
const sessionData = aggregateBySession(records);
|
|
9095
9246
|
const limited = sessionData.slice(0, limit);
|
|
9096
9247
|
if (globalOpts.json) {
|
|
@@ -9170,7 +9321,7 @@ function registerSessionCommand(usage) {
|
|
|
9170
9321
|
cwd,
|
|
9171
9322
|
globalOpts.includeClaudeSessions
|
|
9172
9323
|
);
|
|
9173
|
-
const { aggregateBySession } = await import("./dist-
|
|
9324
|
+
const { aggregateBySession } = await import("./dist-TG63OKA5.js");
|
|
9174
9325
|
const sessionData = aggregateBySession(records);
|
|
9175
9326
|
const match = sessionData.find((s) => s.sessionId === id);
|
|
9176
9327
|
if (!match) {
|
|
@@ -9205,7 +9356,7 @@ function registerLatestCommand(usage) {
|
|
|
9205
9356
|
}
|
|
9206
9357
|
return;
|
|
9207
9358
|
}
|
|
9208
|
-
const { aggregateBySession } = await import("./dist-
|
|
9359
|
+
const { aggregateBySession } = await import("./dist-TG63OKA5.js");
|
|
9209
9360
|
const sessionData = aggregateBySession(records);
|
|
9210
9361
|
const latest = sessionData[0];
|
|
9211
9362
|
if (!latest) {
|
|
@@ -9231,7 +9382,7 @@ function registerLatestCommand(usage) {
|
|
|
9231
9382
|
});
|
|
9232
9383
|
}
|
|
9233
9384
|
function createUsageCommand() {
|
|
9234
|
-
const usage = new
|
|
9385
|
+
const usage = new Command83("usage").description("Token usage and cost tracking");
|
|
9235
9386
|
usage.option(
|
|
9236
9387
|
"--include-claude-sessions",
|
|
9237
9388
|
"Include Claude Code session data from ~/.claude/projects/"
|
|
@@ -9246,15 +9397,15 @@ function createUsageCommand() {
|
|
|
9246
9397
|
// src/commands/validate.ts
|
|
9247
9398
|
init_dist();
|
|
9248
9399
|
init_dist();
|
|
9249
|
-
import { Command as
|
|
9250
|
-
import * as
|
|
9400
|
+
import { Command as Command84 } from "commander";
|
|
9401
|
+
import * as path63 from "path";
|
|
9251
9402
|
async function runValidate(options) {
|
|
9252
9403
|
const configResult = resolveConfig(options.configPath);
|
|
9253
9404
|
if (!configResult.ok) {
|
|
9254
9405
|
return configResult;
|
|
9255
9406
|
}
|
|
9256
9407
|
const config = configResult.value;
|
|
9257
|
-
const cwd = options.cwd ?? (options.configPath ?
|
|
9408
|
+
const cwd = options.cwd ?? (options.configPath ? path63.dirname(path63.resolve(options.configPath)) : process.cwd());
|
|
9258
9409
|
const result = {
|
|
9259
9410
|
valid: true,
|
|
9260
9411
|
checks: {
|
|
@@ -9264,7 +9415,7 @@ async function runValidate(options) {
|
|
|
9264
9415
|
},
|
|
9265
9416
|
issues: []
|
|
9266
9417
|
};
|
|
9267
|
-
const agentsMapPath =
|
|
9418
|
+
const agentsMapPath = path63.resolve(cwd, config.agentsMapPath);
|
|
9268
9419
|
const agentsResult = await validateAgentsMap(agentsMapPath);
|
|
9269
9420
|
if (agentsResult.ok) {
|
|
9270
9421
|
result.checks.agentsMap = true;
|
|
@@ -9329,11 +9480,11 @@ function resolveValidateMode(globalOpts) {
|
|
|
9329
9480
|
return OutputMode.TEXT;
|
|
9330
9481
|
}
|
|
9331
9482
|
async function printCrossCheckWarnings(mode) {
|
|
9332
|
-
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-
|
|
9483
|
+
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-ULQLEOME.js");
|
|
9333
9484
|
const cwd = process.cwd();
|
|
9334
9485
|
const crossResult = await runCrossCheck2({
|
|
9335
|
-
specsDir:
|
|
9336
|
-
plansDir:
|
|
9486
|
+
specsDir: path63.join(cwd, "docs", "specs"),
|
|
9487
|
+
plansDir: path63.join(cwd, "docs", "plans"),
|
|
9337
9488
|
projectPath: cwd
|
|
9338
9489
|
});
|
|
9339
9490
|
if (!crossResult.ok || crossResult.value.warnings === 0) return;
|
|
@@ -9345,7 +9496,7 @@ async function printCrossCheckWarnings(mode) {
|
|
|
9345
9496
|
${crossResult.value.warnings} warnings`);
|
|
9346
9497
|
}
|
|
9347
9498
|
function createValidateCommand3() {
|
|
9348
|
-
const command = new
|
|
9499
|
+
const command = new Command84("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").option(
|
|
9349
9500
|
"--agent-configs",
|
|
9350
9501
|
"Validate agent configs (CLAUDE.md, hooks, skills) via agnix or built-in fallback rules"
|
|
9351
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()));
|
|
@@ -9423,6 +9574,7 @@ var commandCreators = [
|
|
|
9423
9574
|
createInstallCommand,
|
|
9424
9575
|
createInstallConstraintsCommand,
|
|
9425
9576
|
createIntegrationsCommand,
|
|
9577
|
+
createKnowledgePipelineCommand,
|
|
9426
9578
|
createLearningsCommand,
|
|
9427
9579
|
createLinterCommand,
|
|
9428
9580
|
createMcpCommand,
|
|
@@ -9454,7 +9606,7 @@ var commandCreators = [
|
|
|
9454
9606
|
|
|
9455
9607
|
// src/index.ts
|
|
9456
9608
|
function createProgram() {
|
|
9457
|
-
const program = new
|
|
9609
|
+
const program = new Command85();
|
|
9458
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");
|
|
9459
9611
|
for (const creator of commandCreators) {
|
|
9460
9612
|
program.addCommand(creator());
|