@harness-engineering/cli 2.6.0 → 2.7.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/align-design-system/SKILL.md +174 -0
- package/dist/agents/skills/claude-code/align-design-system/skill.yaml +57 -0
- package/dist/agents/skills/claude-code/audit-brand-compliance/SKILL.md +189 -0
- package/dist/agents/skills/claude-code/audit-brand-compliance/skill.yaml +50 -0
- package/dist/agents/skills/claude-code/audit-component-anatomy/SKILL.md +181 -0
- package/dist/agents/skills/claude-code/audit-component-anatomy/skill.yaml +51 -0
- package/dist/agents/skills/claude-code/copy-craft/SKILL.md +192 -0
- package/dist/agents/skills/claude-code/copy-craft/skill.yaml +52 -0
- package/dist/agents/skills/claude-code/detect-design-drift/SKILL.md +139 -0
- package/dist/agents/skills/claude-code/detect-design-drift/skill.yaml +50 -0
- package/dist/agents/skills/claude-code/harness-accessibility/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-design-craft/SKILL.md +212 -0
- package/dist/agents/skills/claude-code/harness-design-craft/skill.yaml +57 -0
- package/dist/agents/skills/claude-code/harness-design-pipeline/SKILL.md +266 -0
- package/dist/agents/skills/claude-code/harness-design-pipeline/skill.yaml +70 -0
- package/dist/agents/skills/claude-code/knowledge-craft/SKILL.md +180 -0
- package/dist/agents/skills/claude-code/knowledge-craft/skill.yaml +49 -0
- package/dist/agents/skills/claude-code/naming-craft/SKILL.md +172 -0
- package/dist/agents/skills/claude-code/naming-craft/skill.yaml +51 -0
- package/dist/agents/skills/claude-code/security-craft/SKILL.md +205 -0
- package/dist/agents/skills/claude-code/security-craft/skill.yaml +58 -0
- package/dist/agents/skills/claude-code/spec-craft/SKILL.md +184 -0
- package/dist/agents/skills/claude-code/spec-craft/skill.yaml +55 -0
- package/dist/agents/skills/claude-code/test-craft/SKILL.md +212 -0
- package/dist/agents/skills/claude-code/test-craft/skill.yaml +58 -0
- package/dist/agents/skills/codex/align-design-system/SKILL.md +174 -0
- package/dist/agents/skills/codex/align-design-system/skill.yaml +57 -0
- package/dist/agents/skills/codex/audit-brand-compliance/SKILL.md +189 -0
- package/dist/agents/skills/codex/audit-brand-compliance/skill.yaml +50 -0
- package/dist/agents/skills/codex/audit-component-anatomy/SKILL.md +181 -0
- package/dist/agents/skills/codex/audit-component-anatomy/skill.yaml +51 -0
- package/dist/agents/skills/codex/copy-craft/SKILL.md +192 -0
- package/dist/agents/skills/codex/copy-craft/skill.yaml +52 -0
- package/dist/agents/skills/codex/detect-design-drift/SKILL.md +139 -0
- package/dist/agents/skills/codex/detect-design-drift/skill.yaml +50 -0
- package/dist/agents/skills/codex/harness-accessibility/SKILL.md +10 -0
- package/dist/agents/skills/codex/harness-design-craft/SKILL.md +212 -0
- package/dist/agents/skills/codex/harness-design-craft/skill.yaml +57 -0
- package/dist/agents/skills/codex/harness-design-pipeline/SKILL.md +266 -0
- package/dist/agents/skills/codex/harness-design-pipeline/skill.yaml +70 -0
- package/dist/agents/skills/codex/knowledge-craft/SKILL.md +180 -0
- package/dist/agents/skills/codex/knowledge-craft/skill.yaml +49 -0
- package/dist/agents/skills/codex/naming-craft/SKILL.md +172 -0
- package/dist/agents/skills/codex/naming-craft/skill.yaml +51 -0
- package/dist/agents/skills/codex/security-craft/SKILL.md +205 -0
- package/dist/agents/skills/codex/security-craft/skill.yaml +58 -0
- package/dist/agents/skills/codex/spec-craft/SKILL.md +184 -0
- package/dist/agents/skills/codex/spec-craft/skill.yaml +55 -0
- package/dist/agents/skills/codex/test-craft/SKILL.md +212 -0
- package/dist/agents/skills/codex/test-craft/skill.yaml +58 -0
- package/dist/agents/skills/cursor/align-design-system/SKILL.md +174 -0
- package/dist/agents/skills/cursor/align-design-system/skill.yaml +57 -0
- package/dist/agents/skills/cursor/audit-brand-compliance/SKILL.md +189 -0
- package/dist/agents/skills/cursor/audit-brand-compliance/skill.yaml +50 -0
- package/dist/agents/skills/cursor/audit-component-anatomy/SKILL.md +181 -0
- package/dist/agents/skills/cursor/audit-component-anatomy/skill.yaml +51 -0
- package/dist/agents/skills/cursor/copy-craft/SKILL.md +192 -0
- package/dist/agents/skills/cursor/copy-craft/skill.yaml +52 -0
- package/dist/agents/skills/cursor/detect-design-drift/SKILL.md +139 -0
- package/dist/agents/skills/cursor/detect-design-drift/skill.yaml +50 -0
- package/dist/agents/skills/cursor/harness-accessibility/SKILL.md +10 -0
- package/dist/agents/skills/cursor/harness-design-craft/SKILL.md +212 -0
- package/dist/agents/skills/cursor/harness-design-craft/skill.yaml +57 -0
- package/dist/agents/skills/cursor/harness-design-pipeline/SKILL.md +266 -0
- package/dist/agents/skills/cursor/harness-design-pipeline/skill.yaml +70 -0
- package/dist/agents/skills/cursor/knowledge-craft/SKILL.md +180 -0
- package/dist/agents/skills/cursor/knowledge-craft/skill.yaml +49 -0
- package/dist/agents/skills/cursor/naming-craft/SKILL.md +172 -0
- package/dist/agents/skills/cursor/naming-craft/skill.yaml +51 -0
- package/dist/agents/skills/cursor/security-craft/SKILL.md +205 -0
- package/dist/agents/skills/cursor/security-craft/skill.yaml +58 -0
- package/dist/agents/skills/cursor/spec-craft/SKILL.md +184 -0
- package/dist/agents/skills/cursor/spec-craft/skill.yaml +55 -0
- package/dist/agents/skills/cursor/test-craft/SKILL.md +212 -0
- package/dist/agents/skills/cursor/test-craft/skill.yaml +58 -0
- package/dist/agents/skills/gemini-cli/align-design-system/SKILL.md +174 -0
- package/dist/agents/skills/gemini-cli/align-design-system/skill.yaml +57 -0
- package/dist/agents/skills/gemini-cli/audit-brand-compliance/SKILL.md +189 -0
- package/dist/agents/skills/gemini-cli/audit-brand-compliance/skill.yaml +50 -0
- package/dist/agents/skills/gemini-cli/audit-component-anatomy/SKILL.md +181 -0
- package/dist/agents/skills/gemini-cli/audit-component-anatomy/skill.yaml +51 -0
- package/dist/agents/skills/gemini-cli/copy-craft/SKILL.md +192 -0
- package/dist/agents/skills/gemini-cli/copy-craft/skill.yaml +52 -0
- package/dist/agents/skills/gemini-cli/detect-design-drift/SKILL.md +139 -0
- package/dist/agents/skills/gemini-cli/detect-design-drift/skill.yaml +50 -0
- package/dist/agents/skills/gemini-cli/harness-accessibility/SKILL.md +10 -0
- package/dist/agents/skills/gemini-cli/harness-design-craft/SKILL.md +212 -0
- package/dist/agents/skills/gemini-cli/harness-design-craft/skill.yaml +57 -0
- package/dist/agents/skills/gemini-cli/harness-design-pipeline/SKILL.md +266 -0
- package/dist/agents/skills/gemini-cli/harness-design-pipeline/skill.yaml +70 -0
- package/dist/agents/skills/gemini-cli/knowledge-craft/SKILL.md +180 -0
- package/dist/agents/skills/gemini-cli/knowledge-craft/skill.yaml +49 -0
- package/dist/agents/skills/gemini-cli/naming-craft/SKILL.md +172 -0
- package/dist/agents/skills/gemini-cli/naming-craft/skill.yaml +51 -0
- package/dist/agents/skills/gemini-cli/security-craft/SKILL.md +205 -0
- package/dist/agents/skills/gemini-cli/security-craft/skill.yaml +58 -0
- package/dist/agents/skills/gemini-cli/spec-craft/SKILL.md +184 -0
- package/dist/agents/skills/gemini-cli/spec-craft/skill.yaml +55 -0
- package/dist/agents/skills/gemini-cli/test-craft/SKILL.md +212 -0
- package/dist/agents/skills/gemini-cli/test-craft/skill.yaml +58 -0
- package/dist/{agents-md-2JUQ4FE2.js → agents-md-267R2NUJ.js} +4 -4
- package/dist/{analyzer-VY6DJVOU-4AHIJLNS.js → analyzer-VY6DJVOU-WYKV3TTW.js} +2 -2
- package/dist/{architecture-CXAVNB5X.js → architecture-ZTEHGIHD.js} +6 -6
- package/dist/{assess-project-M626SSPN.js → assess-project-OKDW3YSK.js} +2 -1
- package/dist/bin/harness-mcp.js +17 -17
- package/dist/bin/harness.js +27 -27
- package/dist/{check-phase-gate-XMU6LLUQ.js → check-phase-gate-YJWFDW66.js} +5 -5
- package/dist/{chunk-ORNMAYHB.js → chunk-4EGPFB7V.js} +6196 -125
- package/dist/{chunk-HFOB2MPQ.js → chunk-67RP7MLR.js} +3 -3
- package/dist/{chunk-5JNSFYZU.js → chunk-6T5AYG5S.js} +6 -6
- package/dist/{chunk-5XLLIYYL.js → chunk-6UHDQP2N.js} +1 -1
- package/dist/{chunk-YP7I25SL.js → chunk-B3B64OPD.js} +1 -1
- package/dist/{chunk-VTTNIZJL.js → chunk-B4OLYXZ4.js} +93 -3
- package/dist/{chunk-6AX6R3LM.js → chunk-CXAHK5PJ.js} +9 -9
- package/dist/{chunk-BCFDGOMA.js → chunk-H2ZJOJ7A.js} +81 -1
- package/dist/{chunk-NX6A24DS.js → chunk-HLPY3RHE.js} +1641 -292
- package/dist/{chunk-Q6ZR2L6Q.js → chunk-HMMSWRWR.js} +2 -2
- package/dist/{chunk-YYRQCQPZ.js → chunk-IY2TZLY5.js} +176 -107
- package/dist/{chunk-I6K43QQS.js → chunk-MQG7FHXX.js} +3 -3
- package/dist/{chunk-43M3RLFQ.js → chunk-OLTVDPA2.js} +2 -2
- package/dist/{chunk-JFZOWO7D.js → chunk-OQE6ME2Z.js} +1 -1
- package/dist/{chunk-GWE5LL3R.js → chunk-P7EO7USC.js} +10 -10
- package/dist/{chunk-24KCOJJG.js → chunk-PARV3G2F.js} +1 -1
- package/dist/{chunk-QOKMDDBJ.js → chunk-QUPC37UB.js} +6 -6
- package/dist/{chunk-EPUKTTJZ.js → chunk-RC3OI5NK.js} +5 -1
- package/dist/{chunk-L5BCZ5XS.js → chunk-S7GEONXL.js} +1 -1
- package/dist/{chunk-5FDBXUFW.js → chunk-TIH53QXY.js} +1 -1
- package/dist/{chunk-OA6SWTU4.js → chunk-TIZ3L6CU.js} +11 -8
- package/dist/{chunk-GWF2OILZ.js → chunk-VG6UK6G6.js} +1 -1
- package/dist/{chunk-SZEFU6XC.js → chunk-W3PDVZ4I.js} +1 -1
- package/dist/{chunk-HYTRDAHV.js → chunk-WOXR6I3R.js} +3 -1
- package/dist/{chunk-K246XQ2L.js → chunk-XTIPZUPR.js} +1 -1
- package/dist/{chunk-HMW3VKUF.js → chunk-Z2GUITAS.js} +10 -10
- package/dist/{chunk-PFZEADQM.js → chunk-ZKA3TGYS.js} +79 -2
- package/dist/{ci-workflow-3JNDZQYD.js → ci-workflow-YGTQTNVC.js} +4 -4
- package/dist/{dist-QPWXPCPL.js → dist-R3TOOPJ7.js} +1 -1
- package/dist/{dist-OHDQBTSO.js → dist-XIJWWQ5N.js} +3 -3
- package/dist/{docs-5RYMDHN3.js → docs-KCTLXK2G.js} +6 -6
- package/dist/{engine-KZ3PPUYE.js → engine-J64WPH5K.js} +4 -4
- package/dist/{entropy-DQTAPSSE.js → entropy-M27JUL3V.js} +5 -5
- package/dist/{feedback-WH6XPQJS.js → feedback-W25QO3OL.js} +2 -2
- package/dist/{generate-agent-definitions-SZA4QIHN.js → generate-agent-definitions-RNMU5U5R.js} +5 -5
- package/dist/{glob-helper-XE2UGEOV.js → glob-helper-EX4YZKZO.js} +1 -1
- package/dist/{graph-loader-EQBOIHFZ.js → graph-loader-EIFEOUVI.js} +1 -1
- package/dist/index.d.ts +587 -6
- package/dist/index.js +27 -27
- package/dist/{loader-BNKGM23C.js → loader-HZKJ5ABV.js} +4 -4
- package/dist/{mcp-GZH4EYGD.js → mcp-NEAPIDTT.js} +17 -17
- package/dist/{performance-54TMJOEU.js → performance-3AVQUDRG.js} +6 -6
- package/dist/{review-pipeline-OTDDVPNY.js → review-pipeline-KA7SGUXJ.js} +4 -4
- package/dist/{runtime-W5THSNAL.js → runtime-IP6FVV5M.js} +4 -4
- package/dist/{scan-4PPP6ZXT.js → scan-LYKLM4EQ.js} +1 -1
- package/dist/{security-27HW7CYT.js → security-EAR4FJWI.js} +1 -1
- package/dist/{validate-QRVCD4GP.js → validate-EVH3UXIC.js} +5 -5
- package/dist/{validate-cross-check-BUAGBAPO.js → validate-cross-check-SNE3SQOB.js} +4 -4
- package/package.json +8 -7
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generateRuntime
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-S7GEONXL.js";
|
|
4
4
|
import {
|
|
5
5
|
generateAgentsMd
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OQE6ME2Z.js";
|
|
7
7
|
import {
|
|
8
8
|
generateCIWorkflow
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-B3B64OPD.js";
|
|
10
10
|
import {
|
|
11
11
|
createGenerateAgentDefinitionsCommand,
|
|
12
12
|
generateAgentDefinitions
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ZKA3TGYS.js";
|
|
14
14
|
import {
|
|
15
15
|
toKebabCase
|
|
16
16
|
} from "./chunk-KET4QQZB.js";
|
|
17
17
|
import {
|
|
18
18
|
createScanCommand,
|
|
19
19
|
loadIngestOptions
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-6UHDQP2N.js";
|
|
21
21
|
import {
|
|
22
22
|
TemplateEngine
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-WOXR6I3R.js";
|
|
24
24
|
import {
|
|
25
25
|
generate,
|
|
26
26
|
validate
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
import {
|
|
32
32
|
listPersonas,
|
|
33
33
|
loadPersona
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-XTIPZUPR.js";
|
|
35
35
|
import {
|
|
36
36
|
runPersona
|
|
37
37
|
} from "./chunk-GISMXMVL.js";
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
OutputMode,
|
|
47
47
|
createCheckPhaseGateCommand,
|
|
48
48
|
findFiles
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-OLTVDPA2.js";
|
|
50
50
|
import {
|
|
51
51
|
appendFrameworkAgents,
|
|
52
52
|
captureHealthSnapshot,
|
|
@@ -59,14 +59,26 @@ import {
|
|
|
59
59
|
isSnapshotFresh,
|
|
60
60
|
loadCachedSnapshot,
|
|
61
61
|
persistToolingConfig,
|
|
62
|
-
recommend
|
|
63
|
-
|
|
62
|
+
recommend,
|
|
63
|
+
runAlignDesignSystem,
|
|
64
|
+
runAudit,
|
|
65
|
+
runAuditBrand,
|
|
66
|
+
runCopyCraft,
|
|
67
|
+
runDesignCraft,
|
|
68
|
+
runDesignPipeline,
|
|
69
|
+
runDetectDrift,
|
|
70
|
+
runKnowledgeCraft,
|
|
71
|
+
runNamingCraft,
|
|
72
|
+
runSecurityCraft,
|
|
73
|
+
runSpecCraft,
|
|
74
|
+
runTestCraft
|
|
75
|
+
} from "./chunk-4EGPFB7V.js";
|
|
64
76
|
import {
|
|
65
77
|
VALID_PLATFORMS
|
|
66
78
|
} from "./chunk-3ISINLYT.js";
|
|
67
79
|
import {
|
|
68
80
|
loadGraphStore
|
|
69
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-TIH53QXY.js";
|
|
70
82
|
import {
|
|
71
83
|
loadOrRebuildIndex
|
|
72
84
|
} from "./chunk-27AJKSQY.js";
|
|
@@ -85,7 +97,7 @@ import {
|
|
|
85
97
|
BranchingConfigSchema,
|
|
86
98
|
findConfigFile,
|
|
87
99
|
resolveConfig
|
|
88
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-B4OLYXZ4.js";
|
|
89
101
|
import {
|
|
90
102
|
logger
|
|
91
103
|
} from "./chunk-EBJQ6N4M.js";
|
|
@@ -179,7 +191,7 @@ import {
|
|
|
179
191
|
validateSolutionsDir,
|
|
180
192
|
writeConfig,
|
|
181
193
|
writeLockfile
|
|
182
|
-
} from "./chunk-
|
|
194
|
+
} from "./chunk-IY2TZLY5.js";
|
|
183
195
|
import {
|
|
184
196
|
CLI_VERSION
|
|
185
197
|
} from "./chunk-BM3PWGXQ.js";
|
|
@@ -192,7 +204,7 @@ import {
|
|
|
192
204
|
detectDocDrift,
|
|
193
205
|
generateSuggestions,
|
|
194
206
|
validateDependencies
|
|
195
|
-
} from "./chunk-
|
|
207
|
+
} from "./chunk-W3PDVZ4I.js";
|
|
196
208
|
import {
|
|
197
209
|
Err,
|
|
198
210
|
INDEXED_FILE_KINDS,
|
|
@@ -202,8 +214,10 @@ import {
|
|
|
202
214
|
} from "./chunk-OH3NXXUY.js";
|
|
203
215
|
import {
|
|
204
216
|
DEFAULT_SKIP_DIRS,
|
|
217
|
+
DesignConstraintAdapter,
|
|
218
|
+
GraphStore,
|
|
205
219
|
init_dist as init_dist2
|
|
206
|
-
} from "./chunk-
|
|
220
|
+
} from "./chunk-H2ZJOJ7A.js";
|
|
207
221
|
import {
|
|
208
222
|
ArchConfigSchema,
|
|
209
223
|
TimelineManager
|
|
@@ -214,7 +228,7 @@ import {
|
|
|
214
228
|
} from "./chunk-KFQGP6VL.js";
|
|
215
229
|
|
|
216
230
|
// src/index.ts
|
|
217
|
-
import { Command as
|
|
231
|
+
import { Command as Command118 } from "commander";
|
|
218
232
|
|
|
219
233
|
// src/commands/add.ts
|
|
220
234
|
init_dist3();
|
|
@@ -403,7 +417,7 @@ function registerSkillsCommand(adoption) {
|
|
|
403
417
|
const globalOpts = cmd.optsWithGlobals();
|
|
404
418
|
const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
|
|
405
419
|
const cwd = process.cwd();
|
|
406
|
-
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-
|
|
420
|
+
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-XIJWWQ5N.js");
|
|
407
421
|
const records = readAdoptionRecords(cwd);
|
|
408
422
|
if (records.length === 0) {
|
|
409
423
|
if (globalOpts.json) {
|
|
@@ -439,7 +453,7 @@ function registerRecentCommand(adoption) {
|
|
|
439
453
|
const globalOpts = cmd.optsWithGlobals();
|
|
440
454
|
const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
|
|
441
455
|
const cwd = process.cwd();
|
|
442
|
-
const { readAdoptionRecords } = await import("./dist-
|
|
456
|
+
const { readAdoptionRecords } = await import("./dist-XIJWWQ5N.js");
|
|
443
457
|
const records = readAdoptionRecords(cwd);
|
|
444
458
|
if (records.length === 0) {
|
|
445
459
|
if (globalOpts.json) {
|
|
@@ -517,7 +531,7 @@ function registerSkillCommand(adoption) {
|
|
|
517
531
|
adoption.command("skill <name>").description("Show detail for a specific skill").action(async (name, _opts, cmd) => {
|
|
518
532
|
const globalOpts = cmd.optsWithGlobals();
|
|
519
533
|
const cwd = process.cwd();
|
|
520
|
-
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-
|
|
534
|
+
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-XIJWWQ5N.js");
|
|
521
535
|
const records = readAdoptionRecords(cwd);
|
|
522
536
|
const skillRecords = records.filter((r) => r.skill === name);
|
|
523
537
|
if (skillRecords.length === 0) {
|
|
@@ -807,11 +821,8 @@ function createAgentCommand() {
|
|
|
807
821
|
return command;
|
|
808
822
|
}
|
|
809
823
|
|
|
810
|
-
// src/commands/
|
|
811
|
-
init_dist3();
|
|
824
|
+
// src/commands/align-design-system.ts
|
|
812
825
|
import { Command as Command6 } from "commander";
|
|
813
|
-
import * as path3 from "path";
|
|
814
|
-
import * as fs2 from "fs";
|
|
815
826
|
|
|
816
827
|
// src/utils/output.ts
|
|
817
828
|
function resolveOutputMode(globalOpts) {
|
|
@@ -821,7 +832,115 @@ function resolveOutputMode(globalOpts) {
|
|
|
821
832
|
return OutputMode.TEXT;
|
|
822
833
|
}
|
|
823
834
|
|
|
835
|
+
// src/commands/align-design-system.ts
|
|
836
|
+
function createAlignDesignSystemCommand() {
|
|
837
|
+
return new Command6("align-design-system").description(
|
|
838
|
+
"Apply codemods for safe DRIFT-T001/T002/T003 findings and emit suggestions for DRIFT-T004 + all DRIFT-P*. Runs standalone (invokes detect-design-drift internally) or pipeline (reads pipeline.driftFindings from .harness/handoff.json)."
|
|
839
|
+
).option("--dry-run", "Compute diffs without writing files. Default: write.").option(
|
|
840
|
+
"-f, --files <files...>",
|
|
841
|
+
"Optional file/glob scope (standalone mode only \u2014 passed to detect-design-drift)."
|
|
842
|
+
).option(
|
|
843
|
+
"--mode <mode>",
|
|
844
|
+
"standalone (default) or pipeline (read findings from handoff.json)",
|
|
845
|
+
"standalone"
|
|
846
|
+
).option(
|
|
847
|
+
"--design-strictness <level>",
|
|
848
|
+
"Override design.strictness: strict | standard | permissive"
|
|
849
|
+
).action(async (opts, cmd) => {
|
|
850
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
851
|
+
const outputMode = resolveOutputMode(globalOpts);
|
|
852
|
+
const formatter = new OutputFormatter(outputMode);
|
|
853
|
+
const cwd = globalOpts.cwd ?? process.cwd();
|
|
854
|
+
const input = { path: cwd };
|
|
855
|
+
if (opts.dryRun === true) input.dryRun = true;
|
|
856
|
+
if (opts.files !== void 0) input.files = opts.files;
|
|
857
|
+
if (opts.mode !== void 0) input.mode = opts.mode;
|
|
858
|
+
if (opts.designStrictness !== void 0) input.designStrictness = opts.designStrictness;
|
|
859
|
+
let result;
|
|
860
|
+
try {
|
|
861
|
+
result = await runAlignDesignSystem(input);
|
|
862
|
+
} catch (err) {
|
|
863
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
864
|
+
if (outputMode === OutputMode.JSON) {
|
|
865
|
+
console.log(JSON.stringify({ error: message }));
|
|
866
|
+
} else {
|
|
867
|
+
logger.error(`align-design-system failed: ${message}`);
|
|
868
|
+
}
|
|
869
|
+
process.exit(ExitCode.ERROR);
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
if (outputMode === OutputMode.JSON) {
|
|
873
|
+
console.log(JSON.stringify(result, null, 2));
|
|
874
|
+
} else {
|
|
875
|
+
printAlignResult(result, outputMode, formatter);
|
|
876
|
+
}
|
|
877
|
+
if (result.summary.failed > 0) process.exit(ExitCode.ERROR);
|
|
878
|
+
process.exit(ExitCode.SUCCESS);
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
function printAlignResult(result, mode, _formatter) {
|
|
882
|
+
const verbose = mode === OutputMode.VERBOSE;
|
|
883
|
+
const { summary, outcomes, meta } = result;
|
|
884
|
+
if (outcomes.length === 0) {
|
|
885
|
+
console.log("No drift findings to align.");
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
889
|
+
for (const o of outcomes) {
|
|
890
|
+
const file = outcomeFile(o);
|
|
891
|
+
const list = byFile.get(file) ?? [];
|
|
892
|
+
list.push(o);
|
|
893
|
+
byFile.set(file, list);
|
|
894
|
+
}
|
|
895
|
+
for (const [file, fixes] of byFile) {
|
|
896
|
+
console.log(`
|
|
897
|
+
${file}`);
|
|
898
|
+
for (const o of fixes) {
|
|
899
|
+
const icon = outcomeIcon(o.kind);
|
|
900
|
+
const line = o.finding.line !== null && o.finding.line !== void 0 ? `:${o.finding.line}` : "";
|
|
901
|
+
console.log(` ${icon} ${o.finding.code}${line} \u2014 ${o.finding.message}`);
|
|
902
|
+
if (o.kind === "applied") {
|
|
903
|
+
console.log(` before: ${o.diff.before.trim()}`);
|
|
904
|
+
console.log(` after: ${o.diff.after.trim()}`);
|
|
905
|
+
} else if (o.kind === "suggestion" && verbose) {
|
|
906
|
+
console.log(` suggest: ${o.suggestion.description}`);
|
|
907
|
+
} else if (o.kind === "skipped-unsafe" && verbose) {
|
|
908
|
+
console.log(` skipped: ${o.reason}`);
|
|
909
|
+
} else if (o.kind === "failed") {
|
|
910
|
+
console.log(` error: ${o.error}`);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
console.log("");
|
|
915
|
+
console.log(
|
|
916
|
+
`Summary: ${summary.applied} applied, ${summary.suggestions} suggestions, ${summary.skipped} skipped, ${summary.failed} failed (${summary.filesModified} files modified, ${summary.durationMs}ms)`
|
|
917
|
+
);
|
|
918
|
+
if (meta.dryRun) {
|
|
919
|
+
console.log("(dry-run \u2014 no files written)");
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
function outcomeFile(o) {
|
|
923
|
+
if (o.kind === "applied") return o.diff.file;
|
|
924
|
+
return o.finding.file;
|
|
925
|
+
}
|
|
926
|
+
function outcomeIcon(kind) {
|
|
927
|
+
switch (kind) {
|
|
928
|
+
case "applied":
|
|
929
|
+
return "\u2713";
|
|
930
|
+
case "suggestion":
|
|
931
|
+
return "?";
|
|
932
|
+
case "skipped-unsafe":
|
|
933
|
+
return "\xB7";
|
|
934
|
+
case "failed":
|
|
935
|
+
return "\u2717";
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
824
939
|
// src/commands/audit-protected.ts
|
|
940
|
+
init_dist3();
|
|
941
|
+
import { Command as Command7 } from "commander";
|
|
942
|
+
import * as path3 from "path";
|
|
943
|
+
import * as fs2 from "fs";
|
|
825
944
|
import { glob } from "glob";
|
|
826
945
|
async function runAuditProtected(options) {
|
|
827
946
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -890,7 +1009,7 @@ Issues (${result.issues.length}):`);
|
|
|
890
1009
|
}
|
|
891
1010
|
}
|
|
892
1011
|
function createAuditProtectedCommand() {
|
|
893
|
-
const command = new
|
|
1012
|
+
const command = new Command7("audit-protected").description("Report all harness-ignore protected code regions").action(async (_opts, cmd) => {
|
|
894
1013
|
const globalOpts = cmd.optsWithGlobals();
|
|
895
1014
|
const mode = resolveOutputMode(globalOpts);
|
|
896
1015
|
const formatter = new OutputFormatter(mode);
|
|
@@ -916,7 +1035,7 @@ function createAuditProtectedCommand() {
|
|
|
916
1035
|
}
|
|
917
1036
|
|
|
918
1037
|
// src/commands/backfill-skill-provenance.ts
|
|
919
|
-
import { Command as
|
|
1038
|
+
import { Command as Command8 } from "commander";
|
|
920
1039
|
import * as fs3 from "fs";
|
|
921
1040
|
import * as path4 from "path";
|
|
922
1041
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
@@ -1004,7 +1123,7 @@ function runBackfillSkillProvenance(projectRoot2) {
|
|
|
1004
1123
|
return result;
|
|
1005
1124
|
}
|
|
1006
1125
|
function createBackfillSkillProvenanceCommand() {
|
|
1007
|
-
const cmd = new
|
|
1126
|
+
const cmd = new Command8("backfill-skill-provenance").description(
|
|
1008
1127
|
"Stamp `provenance: user-authored` on every catalog skill missing the field (Hermes Phase 4 one-shot)"
|
|
1009
1128
|
).option("--root <path>", "Project root containing agents/skills/", process.cwd()).action((opts) => {
|
|
1010
1129
|
const result = runBackfillSkillProvenance(opts.root);
|
|
@@ -1016,10 +1135,10 @@ function createBackfillSkillProvenanceCommand() {
|
|
|
1016
1135
|
|
|
1017
1136
|
// src/commands/blueprint.ts
|
|
1018
1137
|
init_dist3();
|
|
1019
|
-
import { Command as
|
|
1138
|
+
import { Command as Command9 } from "commander";
|
|
1020
1139
|
import * as path5 from "path";
|
|
1021
1140
|
function createBlueprintCommand() {
|
|
1022
|
-
return new
|
|
1141
|
+
return new Command9("blueprint").description("Generate a self-contained, interactive blueprint of the codebase").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory", "docs/blueprint").action(async (projectPath, options) => {
|
|
1023
1142
|
try {
|
|
1024
1143
|
const rootDir = path5.resolve(projectPath);
|
|
1025
1144
|
const outputDir = path5.resolve(options.output);
|
|
@@ -1041,7 +1160,7 @@ function createBlueprintCommand() {
|
|
|
1041
1160
|
|
|
1042
1161
|
// src/commands/check-arch.ts
|
|
1043
1162
|
init_dist3();
|
|
1044
|
-
import { Command as
|
|
1163
|
+
import { Command as Command10 } from "commander";
|
|
1045
1164
|
import { execSync as execSync2 } from "child_process";
|
|
1046
1165
|
function getCommitHash(cwd) {
|
|
1047
1166
|
try {
|
|
@@ -1170,7 +1289,7 @@ function printArchResult(value, mode, formatter) {
|
|
|
1170
1289
|
if (output) console.log(output);
|
|
1171
1290
|
}
|
|
1172
1291
|
function createCheckArchCommand() {
|
|
1173
|
-
const command = new
|
|
1292
|
+
const command = new Command10("check-arch").description("Check architecture assertions against baseline and thresholds").option("--update-baseline", "Capture current state as new baseline").option("--module <path>", "Check a single module").action(async (opts, cmd) => {
|
|
1174
1293
|
const globalOpts = cmd.optsWithGlobals();
|
|
1175
1294
|
const mode = resolveOutputMode2(globalOpts);
|
|
1176
1295
|
const formatter = new OutputFormatter(mode);
|
|
@@ -1202,7 +1321,7 @@ function createCheckArchCommand() {
|
|
|
1202
1321
|
// src/commands/check-deps.ts
|
|
1203
1322
|
init_dist3();
|
|
1204
1323
|
init_dist3();
|
|
1205
|
-
import { Command as
|
|
1324
|
+
import { Command as Command11 } from "commander";
|
|
1206
1325
|
import * as path6 from "path";
|
|
1207
1326
|
async function runCheckDeps(options) {
|
|
1208
1327
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -1294,16 +1413,352 @@ async function runCheckDepsAction(globalOpts) {
|
|
|
1294
1413
|
process.exit(result.value.valid ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
|
|
1295
1414
|
}
|
|
1296
1415
|
function createCheckDepsCommand() {
|
|
1297
|
-
const command = new
|
|
1416
|
+
const command = new Command11("check-deps").description("Validate dependency layers and detect circular dependencies").action(async (_opts, cmd) => {
|
|
1298
1417
|
await runCheckDepsAction(cmd.optsWithGlobals());
|
|
1299
1418
|
});
|
|
1300
1419
|
return command;
|
|
1301
1420
|
}
|
|
1302
1421
|
|
|
1422
|
+
// src/commands/check-design.ts
|
|
1423
|
+
init_dist3();
|
|
1424
|
+
init_dist2();
|
|
1425
|
+
import { Command as Command12 } from "commander";
|
|
1426
|
+
async function runCheckDesign(options) {
|
|
1427
|
+
const startedAt = Date.now();
|
|
1428
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1429
|
+
const mode = options.mode ?? "full";
|
|
1430
|
+
const configResult = resolveConfig(options.configPath);
|
|
1431
|
+
if (!configResult.ok) {
|
|
1432
|
+
return configResult;
|
|
1433
|
+
}
|
|
1434
|
+
const verifiersRun = [];
|
|
1435
|
+
const verifiersFailed = [];
|
|
1436
|
+
const anatomyFindings = [];
|
|
1437
|
+
const craftFindings = [];
|
|
1438
|
+
const driftFindings = [];
|
|
1439
|
+
const brandFindings = [];
|
|
1440
|
+
try {
|
|
1441
|
+
const anatomyOut = await runAudit({
|
|
1442
|
+
path: cwd,
|
|
1443
|
+
mode,
|
|
1444
|
+
...options.files !== void 0 && { files: options.files }
|
|
1445
|
+
});
|
|
1446
|
+
anatomyFindings.push(...anatomyOut.findings);
|
|
1447
|
+
verifiersRun.push("audit-anatomy");
|
|
1448
|
+
} catch (err) {
|
|
1449
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1450
|
+
verifiersFailed.push({ name: "audit-anatomy", error: message });
|
|
1451
|
+
logger.warn(`audit-anatomy verifier failed: ${message}`);
|
|
1452
|
+
}
|
|
1453
|
+
try {
|
|
1454
|
+
const craftResult = await runDesignCraft({
|
|
1455
|
+
path: cwd,
|
|
1456
|
+
mode: mode === "fast" ? "fast" : "fast",
|
|
1457
|
+
// deep mode not in MVP per design-craft spec
|
|
1458
|
+
phases: ["critique"],
|
|
1459
|
+
...options.files !== void 0 && { files: options.files }
|
|
1460
|
+
});
|
|
1461
|
+
if (craftResult.ok) {
|
|
1462
|
+
craftFindings.push(...craftResult.value.findings);
|
|
1463
|
+
verifiersRun.push("design-craft-critique");
|
|
1464
|
+
} else {
|
|
1465
|
+
verifiersFailed.push({
|
|
1466
|
+
name: "design-craft-critique",
|
|
1467
|
+
error: craftResult.error.message
|
|
1468
|
+
});
|
|
1469
|
+
logger.warn(`design-craft verifier failed: ${craftResult.error.message}`);
|
|
1470
|
+
}
|
|
1471
|
+
} catch (err) {
|
|
1472
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1473
|
+
verifiersFailed.push({ name: "design-craft-critique", error: message });
|
|
1474
|
+
logger.warn(`design-craft verifier failed: ${message}`);
|
|
1475
|
+
}
|
|
1476
|
+
try {
|
|
1477
|
+
const driftOut = await runDetectDrift({
|
|
1478
|
+
path: cwd,
|
|
1479
|
+
mode,
|
|
1480
|
+
...options.files !== void 0 && { files: options.files }
|
|
1481
|
+
});
|
|
1482
|
+
driftFindings.push(...driftOut.findings);
|
|
1483
|
+
verifiersRun.push("detect-drift");
|
|
1484
|
+
} catch (err) {
|
|
1485
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1486
|
+
verifiersFailed.push({ name: "detect-drift", error: message });
|
|
1487
|
+
logger.warn(`detect-drift verifier failed: ${message}`);
|
|
1488
|
+
}
|
|
1489
|
+
try {
|
|
1490
|
+
const brandOut = await runAuditBrand({
|
|
1491
|
+
path: cwd,
|
|
1492
|
+
mode,
|
|
1493
|
+
...options.files !== void 0 && { files: options.files }
|
|
1494
|
+
});
|
|
1495
|
+
brandFindings.push(...brandOut.findings);
|
|
1496
|
+
verifiersRun.push("audit-brand");
|
|
1497
|
+
} catch (err) {
|
|
1498
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1499
|
+
verifiersFailed.push({ name: "audit-brand", error: message });
|
|
1500
|
+
logger.warn(`audit-brand verifier failed: ${message}`);
|
|
1501
|
+
}
|
|
1502
|
+
const bySeverity = {
|
|
1503
|
+
error: 0,
|
|
1504
|
+
warn: 0,
|
|
1505
|
+
info: 0
|
|
1506
|
+
};
|
|
1507
|
+
const byCode = {};
|
|
1508
|
+
for (const f of anatomyFindings) {
|
|
1509
|
+
bySeverity[f.severity] = (bySeverity[f.severity] ?? 0) + 1;
|
|
1510
|
+
byCode[f.code] = (byCode[f.code] ?? 0) + 1;
|
|
1511
|
+
}
|
|
1512
|
+
for (const f of craftFindings) {
|
|
1513
|
+
const sev = craftTierToSeverity(f.tier);
|
|
1514
|
+
bySeverity[sev] = (bySeverity[sev] ?? 0) + 1;
|
|
1515
|
+
byCode[f.code] = (byCode[f.code] ?? 0) + 1;
|
|
1516
|
+
}
|
|
1517
|
+
for (const f of driftFindings) {
|
|
1518
|
+
bySeverity[f.severity] = (bySeverity[f.severity] ?? 0) + 1;
|
|
1519
|
+
byCode[f.code] = (byCode[f.code] ?? 0) + 1;
|
|
1520
|
+
}
|
|
1521
|
+
for (const f of brandFindings) {
|
|
1522
|
+
bySeverity[f.severity] = (bySeverity[f.severity] ?? 0) + 1;
|
|
1523
|
+
byCode[f.code] = (byCode[f.code] ?? 0) + 1;
|
|
1524
|
+
}
|
|
1525
|
+
const totalFindings = anatomyFindings.length + craftFindings.length + driftFindings.length + brandFindings.length;
|
|
1526
|
+
const graphPersisted = await persistFindings(
|
|
1527
|
+
anatomyFindings,
|
|
1528
|
+
craftFindings,
|
|
1529
|
+
driftFindings,
|
|
1530
|
+
brandFindings
|
|
1531
|
+
);
|
|
1532
|
+
const durationMs = Date.now() - startedAt;
|
|
1533
|
+
const result = {
|
|
1534
|
+
// valid is false if any error-severity finding OR any verifier failed
|
|
1535
|
+
valid: bySeverity.error === 0 && verifiersFailed.length === 0,
|
|
1536
|
+
findingsByVerifier: {
|
|
1537
|
+
anatomy: anatomyFindings,
|
|
1538
|
+
craft: craftFindings,
|
|
1539
|
+
drift: driftFindings,
|
|
1540
|
+
brand: brandFindings
|
|
1541
|
+
},
|
|
1542
|
+
summary: {
|
|
1543
|
+
totalFindings,
|
|
1544
|
+
bySeverity,
|
|
1545
|
+
byCode,
|
|
1546
|
+
verifiersRun,
|
|
1547
|
+
verifiersFailed,
|
|
1548
|
+
durationMs
|
|
1549
|
+
},
|
|
1550
|
+
graphPersisted
|
|
1551
|
+
};
|
|
1552
|
+
return Ok(result);
|
|
1553
|
+
}
|
|
1554
|
+
function craftTierToSeverity(tier) {
|
|
1555
|
+
switch (tier) {
|
|
1556
|
+
case "foundational":
|
|
1557
|
+
return "error";
|
|
1558
|
+
case "polish":
|
|
1559
|
+
return "warn";
|
|
1560
|
+
case "aspirational":
|
|
1561
|
+
return "info";
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
async function persistFindings(anatomyFindings, craftFindings, driftFindings, brandFindings) {
|
|
1565
|
+
const store = new GraphStore();
|
|
1566
|
+
const adapter = new DesignConstraintAdapter(store);
|
|
1567
|
+
const records = [
|
|
1568
|
+
...anatomyFindings.map(
|
|
1569
|
+
(f) => ({
|
|
1570
|
+
code: f.code,
|
|
1571
|
+
file: f.file,
|
|
1572
|
+
...f.line !== null && f.line !== void 0 && { line: f.line },
|
|
1573
|
+
message: f.message,
|
|
1574
|
+
severity: f.severity,
|
|
1575
|
+
evidence: f.evidence?.snippet
|
|
1576
|
+
})
|
|
1577
|
+
),
|
|
1578
|
+
...craftFindings.map(
|
|
1579
|
+
(f) => ({
|
|
1580
|
+
code: f.code,
|
|
1581
|
+
file: f.target.file,
|
|
1582
|
+
...f.target.line !== void 0 && { line: f.target.line },
|
|
1583
|
+
message: f.message,
|
|
1584
|
+
severity: craftTierToSeverity(f.tier)
|
|
1585
|
+
})
|
|
1586
|
+
),
|
|
1587
|
+
...driftFindings.map(
|
|
1588
|
+
(f) => ({
|
|
1589
|
+
code: f.code,
|
|
1590
|
+
file: f.file,
|
|
1591
|
+
...f.line !== null && f.line !== void 0 && { line: f.line },
|
|
1592
|
+
message: f.message,
|
|
1593
|
+
severity: f.severity,
|
|
1594
|
+
evidence: f.evidence?.snippet
|
|
1595
|
+
})
|
|
1596
|
+
),
|
|
1597
|
+
...brandFindings.map(
|
|
1598
|
+
(f) => ({
|
|
1599
|
+
code: f.code,
|
|
1600
|
+
file: f.file,
|
|
1601
|
+
...f.line !== null && f.line !== void 0 && { line: f.line },
|
|
1602
|
+
message: f.message,
|
|
1603
|
+
severity: f.severity,
|
|
1604
|
+
evidence: f.evidence?.snippet
|
|
1605
|
+
})
|
|
1606
|
+
)
|
|
1607
|
+
];
|
|
1608
|
+
return adapter.recordFindings(records);
|
|
1609
|
+
}
|
|
1610
|
+
function printCheckDesignResult(value, mode, formatter) {
|
|
1611
|
+
const summaryLine = `${value.summary.totalFindings} finding${value.summary.totalFindings === 1 ? "" : "s"}`;
|
|
1612
|
+
console.log(formatter.formatSummary("check-design", summaryLine, value.valid));
|
|
1613
|
+
if (mode === OutputMode.QUIET) return;
|
|
1614
|
+
printVerifierSection(
|
|
1615
|
+
"audit-anatomy",
|
|
1616
|
+
value.findingsByVerifier.anatomy.length,
|
|
1617
|
+
() => printAnatomyFindings(value.findingsByVerifier.anatomy, mode === OutputMode.VERBOSE)
|
|
1618
|
+
);
|
|
1619
|
+
printVerifierSection(
|
|
1620
|
+
"design-craft critique",
|
|
1621
|
+
value.findingsByVerifier.craft.length,
|
|
1622
|
+
() => printCraftFindings(value.findingsByVerifier.craft, mode === OutputMode.VERBOSE)
|
|
1623
|
+
);
|
|
1624
|
+
printVerifierSection(
|
|
1625
|
+
"detect-drift",
|
|
1626
|
+
value.findingsByVerifier.drift.length,
|
|
1627
|
+
() => printDriftFindings(value.findingsByVerifier.drift, mode === OutputMode.VERBOSE)
|
|
1628
|
+
);
|
|
1629
|
+
printVerifierSection(
|
|
1630
|
+
"audit-brand",
|
|
1631
|
+
value.findingsByVerifier.brand.length,
|
|
1632
|
+
() => printBrandFindings(value.findingsByVerifier.brand, mode === OutputMode.VERBOSE)
|
|
1633
|
+
);
|
|
1634
|
+
if (value.summary.verifiersFailed.length > 0) {
|
|
1635
|
+
console.log("\nVerifiers that failed:");
|
|
1636
|
+
for (const failed of value.summary.verifiersFailed) {
|
|
1637
|
+
console.log(` - ${failed.name}: ${failed.error}`);
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
console.log(
|
|
1641
|
+
`
|
|
1642
|
+
${value.summary.bySeverity.error} error, ${value.summary.bySeverity.warn} warn, ${value.summary.bySeverity.info} info`
|
|
1643
|
+
);
|
|
1644
|
+
console.log(
|
|
1645
|
+
`Graph: +${value.graphPersisted.constraintsAdded} constraint(s), +${value.graphPersisted.edgesAdded} edge(s)`
|
|
1646
|
+
);
|
|
1647
|
+
}
|
|
1648
|
+
function printVerifierSection(name, count, printer) {
|
|
1649
|
+
console.log(`
|
|
1650
|
+
${name} (${count} finding${count === 1 ? "" : "s"})`);
|
|
1651
|
+
if (count > 0) printer();
|
|
1652
|
+
}
|
|
1653
|
+
function printAnatomyFindings(findings, verbose) {
|
|
1654
|
+
const byFile = groupByFile(findings, (f) => f.file);
|
|
1655
|
+
for (const [file, fs47] of byFile) {
|
|
1656
|
+
console.log(` ${file}`);
|
|
1657
|
+
for (const f of fs47) {
|
|
1658
|
+
const line = f.line !== null && f.line !== void 0 ? `:${f.line}` : "";
|
|
1659
|
+
console.log(` ${f.code} [${f.severity}] line${line}: ${f.message}`);
|
|
1660
|
+
if (verbose) {
|
|
1661
|
+
console.log(` fix: ${f.fix.description}`);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
function printCraftFindings(findings, verbose) {
|
|
1667
|
+
const byFile = groupByFile(findings, (f) => f.target.file);
|
|
1668
|
+
for (const [file, fs47] of byFile) {
|
|
1669
|
+
console.log(` ${file}`);
|
|
1670
|
+
for (const f of fs47) {
|
|
1671
|
+
const line = f.target.line !== void 0 ? `:${f.target.line}` : "";
|
|
1672
|
+
const sev = craftTierToSeverity(f.tier);
|
|
1673
|
+
console.log(
|
|
1674
|
+
` ${f.code} [${sev} / tier:${f.tier} / impact:${f.impact} / conf:${f.confidence}] line${line}: ${f.message}`
|
|
1675
|
+
);
|
|
1676
|
+
if (verbose && f.after !== void 0) {
|
|
1677
|
+
console.log(` after: ${f.after}`);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
function printDriftFindings(findings, verbose) {
|
|
1683
|
+
const byFile = groupByFile(findings, (f) => f.file);
|
|
1684
|
+
for (const [file, fs47] of byFile) {
|
|
1685
|
+
console.log(` ${file}`);
|
|
1686
|
+
for (const f of fs47) {
|
|
1687
|
+
const line = f.line !== null && f.line !== void 0 ? `:${f.line}` : "";
|
|
1688
|
+
console.log(` ${f.code} [${f.severity}] line${line}: ${f.message}`);
|
|
1689
|
+
if (verbose) {
|
|
1690
|
+
console.log(` fix: ${f.fix.description}`);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
function printBrandFindings(findings, verbose) {
|
|
1696
|
+
const byFile = groupByFile(findings, (f) => f.file);
|
|
1697
|
+
for (const [file, fs47] of byFile) {
|
|
1698
|
+
console.log(` ${file}`);
|
|
1699
|
+
for (const f of fs47) {
|
|
1700
|
+
const line = f.line !== null && f.line !== void 0 ? `:${f.line}` : "";
|
|
1701
|
+
console.log(` ${f.code} [${f.severity}] line${line}: ${f.message}`);
|
|
1702
|
+
if (verbose) {
|
|
1703
|
+
console.log(` fix: ${f.fix.description}`);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
function groupByFile(items, getFile) {
|
|
1709
|
+
const map = /* @__PURE__ */ new Map();
|
|
1710
|
+
for (const item of items) {
|
|
1711
|
+
const f = getFile(item);
|
|
1712
|
+
const list = map.get(f) ?? [];
|
|
1713
|
+
list.push(item);
|
|
1714
|
+
map.set(f, list);
|
|
1715
|
+
}
|
|
1716
|
+
return map;
|
|
1717
|
+
}
|
|
1718
|
+
function createCheckDesignCommand() {
|
|
1719
|
+
const command = new Command12("check-design").description(
|
|
1720
|
+
"Run the design verifier suite (component-anatomy + design-craft critique). Mirrors `harness check-docs`. Single-pass; the convergence fix loop lives in the design-pipeline orchestrator (sub-project #5)."
|
|
1721
|
+
).option("-m, --mode <mode>", "Audit mode: fast | full", "full").option(
|
|
1722
|
+
"-f, --files <files...>",
|
|
1723
|
+
"Optional file/glob scoping. Defaults to all project source files."
|
|
1724
|
+
).action(async (opts, cmd) => {
|
|
1725
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1726
|
+
const mode = resolveOutputMode(globalOpts);
|
|
1727
|
+
const formatter = new OutputFormatter(mode);
|
|
1728
|
+
const result = await runCheckDesign({
|
|
1729
|
+
configPath: globalOpts.config,
|
|
1730
|
+
json: globalOpts.json,
|
|
1731
|
+
verbose: globalOpts.verbose,
|
|
1732
|
+
quiet: globalOpts.quiet,
|
|
1733
|
+
...opts.files !== void 0 && { files: opts.files },
|
|
1734
|
+
...opts.mode !== void 0 && { mode: opts.mode }
|
|
1735
|
+
});
|
|
1736
|
+
if (!result.ok) {
|
|
1737
|
+
if (mode === OutputMode.JSON) {
|
|
1738
|
+
console.log(JSON.stringify({ error: result.error.message }));
|
|
1739
|
+
} else {
|
|
1740
|
+
logger.error(result.error.message);
|
|
1741
|
+
}
|
|
1742
|
+
process.exit(result.error.exitCode);
|
|
1743
|
+
}
|
|
1744
|
+
if (mode === OutputMode.JSON) {
|
|
1745
|
+
console.log(JSON.stringify(result.value, null, 2));
|
|
1746
|
+
} else {
|
|
1747
|
+
printCheckDesignResult(result.value, mode, formatter);
|
|
1748
|
+
}
|
|
1749
|
+
const hasErrors = result.value.summary.bySeverity.error > 0;
|
|
1750
|
+
const degraded = result.value.summary.verifiersFailed.length > 0;
|
|
1751
|
+
process.exit(
|
|
1752
|
+
hasErrors ? ExitCode.VALIDATION_FAILED : degraded ? ExitCode.ERROR : ExitCode.SUCCESS
|
|
1753
|
+
);
|
|
1754
|
+
});
|
|
1755
|
+
return command;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1303
1758
|
// src/commands/check-docs.ts
|
|
1304
1759
|
init_dist3();
|
|
1305
1760
|
init_dist3();
|
|
1306
|
-
import { Command as
|
|
1761
|
+
import { Command as Command13 } from "commander";
|
|
1307
1762
|
import * as path7 from "path";
|
|
1308
1763
|
async function runCheckDocs(options) {
|
|
1309
1764
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -1381,7 +1836,7 @@ function printCheckDocsResult(value, mode, formatter) {
|
|
|
1381
1836
|
}
|
|
1382
1837
|
}
|
|
1383
1838
|
function createCheckDocsCommand() {
|
|
1384
|
-
const command = new
|
|
1839
|
+
const command = new Command13("check-docs").description("Check documentation coverage").option("--min-coverage <percent>", "Minimum coverage percentage", "80").action(async (opts, cmd) => {
|
|
1385
1840
|
const globalOpts = cmd.optsWithGlobals();
|
|
1386
1841
|
const mode = resolveOutputMode(globalOpts);
|
|
1387
1842
|
const formatter = new OutputFormatter(mode);
|
|
@@ -1412,7 +1867,7 @@ function createCheckDocsCommand() {
|
|
|
1412
1867
|
|
|
1413
1868
|
// src/commands/check-perf.ts
|
|
1414
1869
|
init_dist3();
|
|
1415
|
-
import { Command as
|
|
1870
|
+
import { Command as Command14 } from "commander";
|
|
1416
1871
|
import * as path8 from "path";
|
|
1417
1872
|
async function runCheckPerf(cwd, options) {
|
|
1418
1873
|
const runAll2 = !options.structural && !options.size && !options.coupling;
|
|
@@ -1529,7 +1984,7 @@ async function runCheckPerfAction(opts, globalOpts) {
|
|
|
1529
1984
|
process.exit(result.value.valid ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
|
|
1530
1985
|
}
|
|
1531
1986
|
function createCheckPerfCommand() {
|
|
1532
|
-
const command = new
|
|
1987
|
+
const command = new Command14("check-perf").description("Run performance checks: structural complexity, coupling, and size budgets").option("--structural", "Run structural complexity checks only").option("--coupling", "Run coupling metric checks only").option("--size", "Run size budget checks only").action(async (opts, cmd) => {
|
|
1533
1988
|
await runCheckPerfAction(opts, cmd.optsWithGlobals());
|
|
1534
1989
|
});
|
|
1535
1990
|
return command;
|
|
@@ -1537,7 +1992,7 @@ function createCheckPerfCommand() {
|
|
|
1537
1992
|
|
|
1538
1993
|
// src/commands/check-security.ts
|
|
1539
1994
|
init_dist3();
|
|
1540
|
-
import { Command as
|
|
1995
|
+
import { Command as Command15 } from "commander";
|
|
1541
1996
|
import * as path9 from "path";
|
|
1542
1997
|
import { execSync as execSync3 } from "child_process";
|
|
1543
1998
|
var SEVERITY_RANK = {
|
|
@@ -1642,7 +2097,7 @@ async function runCheckSecurityAction(opts, globalOpts) {
|
|
|
1642
2097
|
process.exit(result.value.valid ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
|
|
1643
2098
|
}
|
|
1644
2099
|
function createCheckSecurityCommand() {
|
|
1645
|
-
const command = new
|
|
2100
|
+
const command = new Command15("check-security").description("Run lightweight security scan: secrets, injection, XSS, weak crypto").option("--severity <level>", "Minimum severity threshold", "warning").hook("preAction", (thisCommand) => {
|
|
1646
2101
|
const severity = thisCommand.opts().severity;
|
|
1647
2102
|
if (!["error", "warning", "info"].includes(severity)) {
|
|
1648
2103
|
logger.error(`Invalid severity: "${severity}". Must be one of: error, warning, info`);
|
|
@@ -1655,11 +2110,11 @@ function createCheckSecurityCommand() {
|
|
|
1655
2110
|
}
|
|
1656
2111
|
|
|
1657
2112
|
// src/commands/ci/index.ts
|
|
1658
|
-
import { Command as
|
|
2113
|
+
import { Command as Command19 } from "commander";
|
|
1659
2114
|
|
|
1660
2115
|
// src/commands/ci/check.ts
|
|
1661
2116
|
init_dist3();
|
|
1662
|
-
import { Command as
|
|
2117
|
+
import { Command as Command16 } from "commander";
|
|
1663
2118
|
var VALID_CHECKS = [
|
|
1664
2119
|
"validate",
|
|
1665
2120
|
"deps",
|
|
@@ -1749,14 +2204,14 @@ async function runCheckAction(opts, globalOpts) {
|
|
|
1749
2204
|
process.exit(report.exitCode);
|
|
1750
2205
|
}
|
|
1751
2206
|
function createCheckCommand() {
|
|
1752
|
-
return new
|
|
2207
|
+
return new Command16("check").description("Run all harness checks for CI (validate, deps, docs, entropy, phase-gate, arch)").option("--skip <checks>", "Comma-separated checks to skip (e.g., entropy,docs)").option("--fail-on <severity>", "Fail on severity level: error (default) or warning", "error").action(async (opts, cmd) => {
|
|
1753
2208
|
await runCheckAction(opts, cmd.optsWithGlobals());
|
|
1754
2209
|
});
|
|
1755
2210
|
}
|
|
1756
2211
|
|
|
1757
2212
|
// src/commands/ci/init.ts
|
|
1758
2213
|
init_dist3();
|
|
1759
|
-
import { Command as
|
|
2214
|
+
import { Command as Command17 } from "commander";
|
|
1760
2215
|
import * as fs4 from "fs";
|
|
1761
2216
|
import * as path10 from "path";
|
|
1762
2217
|
var ALL_CHECKS = [
|
|
@@ -1893,14 +2348,14 @@ async function runInitAction(opts, globalOpts) {
|
|
|
1893
2348
|
}
|
|
1894
2349
|
}
|
|
1895
2350
|
function createInitCommand() {
|
|
1896
|
-
return new
|
|
2351
|
+
return new Command17("init").description("Generate CI configuration for harness checks").option("--platform <platform>", "CI platform: github, gitlab, or generic").option("--checks <list>", "Comma-separated list of checks to include").action(async (opts, cmd) => {
|
|
1897
2352
|
await runInitAction(opts, cmd.optsWithGlobals());
|
|
1898
2353
|
});
|
|
1899
2354
|
}
|
|
1900
2355
|
|
|
1901
2356
|
// src/commands/ci/notify.ts
|
|
1902
2357
|
init_dist3();
|
|
1903
|
-
import { Command as
|
|
2358
|
+
import { Command as Command18 } from "commander";
|
|
1904
2359
|
import * as fs5 from "fs";
|
|
1905
2360
|
function loadReport(reportPath) {
|
|
1906
2361
|
try {
|
|
@@ -1997,14 +2452,14 @@ async function runNotifyAction(reportPath, opts, globalOpts) {
|
|
|
1997
2452
|
}
|
|
1998
2453
|
}
|
|
1999
2454
|
function createNotifyCommand() {
|
|
2000
|
-
return new
|
|
2455
|
+
return new Command18("notify").description("Post CI check results to GitHub (PR comment or issue)").argument("<report>", "Path to CI check report JSON file (from harness ci check --json)").requiredOption("--target <target>", "Notification target: pr-comment or issue").option("--pr <number>", "PR number (required for pr-comment target)").option("--title <title>", "Custom issue title (for issue target)").option("--labels <labels>", "Comma-separated labels for created issues").action(async (reportPath, opts, cmd) => {
|
|
2001
2456
|
await runNotifyAction(reportPath, opts, cmd.optsWithGlobals());
|
|
2002
2457
|
});
|
|
2003
2458
|
}
|
|
2004
2459
|
|
|
2005
2460
|
// src/commands/ci/index.ts
|
|
2006
2461
|
function createCICommand() {
|
|
2007
|
-
const command = new
|
|
2462
|
+
const command = new Command19("ci").description("CI/CD integration commands");
|
|
2008
2463
|
command.addCommand(createCheckCommand());
|
|
2009
2464
|
command.addCommand(createInitCommand());
|
|
2010
2465
|
command.addCommand(createNotifyCommand());
|
|
@@ -2013,7 +2468,7 @@ function createCICommand() {
|
|
|
2013
2468
|
|
|
2014
2469
|
// src/commands/cleanup.ts
|
|
2015
2470
|
init_dist3();
|
|
2016
|
-
import { Command as
|
|
2471
|
+
import { Command as Command20 } from "commander";
|
|
2017
2472
|
import * as path11 from "path";
|
|
2018
2473
|
async function runCleanup(options) {
|
|
2019
2474
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -2102,7 +2557,7 @@ function printCleanupResult(value, formatter) {
|
|
|
2102
2557
|
}
|
|
2103
2558
|
}
|
|
2104
2559
|
function createCleanupCommand() {
|
|
2105
|
-
const command = new
|
|
2560
|
+
const command = new Command20("cleanup").description("Detect entropy issues (doc drift, dead code, patterns)").option("-t, --type <type>", "Issue type: drift, dead-code, patterns, all", "all").action(async (opts, cmd) => {
|
|
2106
2561
|
const globalOpts = cmd.optsWithGlobals();
|
|
2107
2562
|
const mode = resolveOutputMode(globalOpts);
|
|
2108
2563
|
const formatter = new OutputFormatter(mode);
|
|
@@ -2133,7 +2588,7 @@ function createCleanupCommand() {
|
|
|
2133
2588
|
|
|
2134
2589
|
// src/commands/cleanup-sessions.ts
|
|
2135
2590
|
init_dist3();
|
|
2136
|
-
import { Command as
|
|
2591
|
+
import { Command as Command21 } from "commander";
|
|
2137
2592
|
import * as fs6 from "fs";
|
|
2138
2593
|
import * as path12 from "path";
|
|
2139
2594
|
var STALE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -2329,7 +2784,7 @@ ${dryRun ? "Would remove" : "Removed"} ${totalRemoved} stale entry(ies) across t
|
|
|
2329
2784
|
}
|
|
2330
2785
|
}
|
|
2331
2786
|
function createCleanupSessionsCommand() {
|
|
2332
|
-
const command = new
|
|
2787
|
+
const command = new Command21("cleanup-sessions").description(
|
|
2333
2788
|
"Remove stale entries from .harness/. Default: only .harness/sessions/ (no write in 24h)."
|
|
2334
2789
|
).option("--dry-run", "List stale entries without deleting them", false).option("--path <path>", "Project root path", ".").option("--all", "Hermes Phase 2: sweep every registered .harness/ target").option(
|
|
2335
2790
|
"--include <list>",
|
|
@@ -2378,13 +2833,13 @@ async function runSessionsOnlySweep(cwd, opts, asJson) {
|
|
|
2378
2833
|
}
|
|
2379
2834
|
|
|
2380
2835
|
// src/commands/compound/index.ts
|
|
2381
|
-
import { Command as
|
|
2836
|
+
import { Command as Command23 } from "commander";
|
|
2382
2837
|
|
|
2383
2838
|
// src/commands/compound/scan-candidates.ts
|
|
2384
2839
|
init_dist3();
|
|
2385
2840
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
2386
2841
|
import { dirname as dirname2, join as join8, resolve as resolve11 } from "path";
|
|
2387
|
-
import { Command as
|
|
2842
|
+
import { Command as Command22 } from "commander";
|
|
2388
2843
|
var HOTSPOT_THRESHOLD = 7;
|
|
2389
2844
|
var DEFAULT_LOOKBACK = "7d";
|
|
2390
2845
|
async function runCompoundScanCandidatesCommand(opts) {
|
|
@@ -2439,7 +2894,7 @@ function emit(status, nonInteractive) {
|
|
|
2439
2894
|
return status;
|
|
2440
2895
|
}
|
|
2441
2896
|
function createScanCandidatesCommand() {
|
|
2442
|
-
return new
|
|
2897
|
+
return new Command22("scan-candidates").description(
|
|
2443
2898
|
"Scan recent fixes and hotspots for undocumented learnings; write candidate prompts"
|
|
2444
2899
|
).option("--lookback <window>", "Lookback window (e.g. 7d, 14d).", DEFAULT_LOOKBACK).option(
|
|
2445
2900
|
"--non-interactive",
|
|
@@ -2464,13 +2919,96 @@ function createScanCandidatesCommand() {
|
|
|
2464
2919
|
|
|
2465
2920
|
// src/commands/compound/index.ts
|
|
2466
2921
|
function createCompoundCommand() {
|
|
2467
|
-
const command = new
|
|
2922
|
+
const command = new Command23("compound").description("Compound (post-mortem playbook) commands");
|
|
2468
2923
|
command.addCommand(createScanCandidatesCommand());
|
|
2469
2924
|
return command;
|
|
2470
2925
|
}
|
|
2471
2926
|
|
|
2927
|
+
// src/commands/copy-craft.ts
|
|
2928
|
+
import { Command as Command24 } from "commander";
|
|
2929
|
+
function createCopyCraftCommand() {
|
|
2930
|
+
return new Command24("copy-craft").description(
|
|
2931
|
+
"LLM-judgment critique of prose-in-code across six surfaces: error messages, log lines, CLI output, commit subjects, PR descriptions, code comments. Third craft-pipeline ceiling skill. Graceful degradation when git/gh prereqs absent."
|
|
2932
|
+
).option("-f, --files <files...>", "Optional source file/glob scope").option(
|
|
2933
|
+
"-s, --surfaces <surfaces...>",
|
|
2934
|
+
"Restrict to: error / log / cli-output / commit / pr-description / comment"
|
|
2935
|
+
).option("--max-files <n>", "Cap source file count (default: 100)").option("--max-items-per-file <n>", "Cap per-file item sampling (default: 20)").option("--commits-since <when>", "Commit window (default: '1 month ago')").option("--pr-limit <n>", "PR count cap (default: 20)").action(async (opts, cmd) => {
|
|
2936
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2937
|
+
const outputMode = resolveOutputMode(globalOpts);
|
|
2938
|
+
const formatter = new OutputFormatter(outputMode);
|
|
2939
|
+
const cwd = globalOpts.cwd ?? process.cwd();
|
|
2940
|
+
const input = { path: cwd };
|
|
2941
|
+
if (opts.files !== void 0) input.files = opts.files;
|
|
2942
|
+
if (opts.surfaces !== void 0) input.surfaces = opts.surfaces;
|
|
2943
|
+
if (opts.maxFiles !== void 0) input.maxFiles = parseInt(opts.maxFiles, 10);
|
|
2944
|
+
if (opts.maxItemsPerFile !== void 0)
|
|
2945
|
+
input.maxItemsPerFile = parseInt(opts.maxItemsPerFile, 10);
|
|
2946
|
+
if (opts.commitsSince !== void 0) input.commitsSince = opts.commitsSince;
|
|
2947
|
+
if (opts.prLimit !== void 0) input.prLimit = parseInt(opts.prLimit, 10);
|
|
2948
|
+
let result;
|
|
2949
|
+
try {
|
|
2950
|
+
result = await runCopyCraft(input);
|
|
2951
|
+
} catch (err) {
|
|
2952
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2953
|
+
if (outputMode === OutputMode.JSON) {
|
|
2954
|
+
console.log(JSON.stringify({ error: message }));
|
|
2955
|
+
} else {
|
|
2956
|
+
logger.error(`copy-craft failed: ${message}`);
|
|
2957
|
+
}
|
|
2958
|
+
process.exit(ExitCode.ERROR);
|
|
2959
|
+
return;
|
|
2960
|
+
}
|
|
2961
|
+
if (outputMode === OutputMode.JSON) {
|
|
2962
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2963
|
+
} else {
|
|
2964
|
+
printResult2(result, outputMode, formatter);
|
|
2965
|
+
}
|
|
2966
|
+
const hasFoundational = result.findings.some((f) => f.tier === "foundational");
|
|
2967
|
+
process.exit(hasFoundational ? ExitCode.VALIDATION_FAILED : ExitCode.SUCCESS);
|
|
2968
|
+
});
|
|
2969
|
+
}
|
|
2970
|
+
function printResult2(result, mode, _formatter) {
|
|
2971
|
+
const verbose = mode === OutputMode.VERBOSE;
|
|
2972
|
+
const { findings, summary } = result;
|
|
2973
|
+
if (findings.length === 0) {
|
|
2974
|
+
console.log("No copy findings.");
|
|
2975
|
+
} else {
|
|
2976
|
+
const bySurface = /* @__PURE__ */ new Map();
|
|
2977
|
+
for (const f of findings) {
|
|
2978
|
+
const list = bySurface.get(f.target.surface) ?? [];
|
|
2979
|
+
list.push(f);
|
|
2980
|
+
bySurface.set(f.target.surface, list);
|
|
2981
|
+
}
|
|
2982
|
+
for (const [surface, fs47] of bySurface) {
|
|
2983
|
+
console.log(`
|
|
2984
|
+
[${surface}]`);
|
|
2985
|
+
for (const f of fs47) {
|
|
2986
|
+
const line = f.target.line !== void 0 ? `:${f.target.line}` : "";
|
|
2987
|
+
console.log(` ${f.code} [${f.tier}/${f.impact}/${f.confidence}] ${f.target.file}${line}`);
|
|
2988
|
+
console.log(` "${truncate(f.target.snippet, 80)}"`);
|
|
2989
|
+
console.log(` ${f.message}`);
|
|
2990
|
+
if (verbose) console.log(` source: ${f.cite.source}`);
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
console.log("");
|
|
2995
|
+
const surfaceCounts = Object.entries(summary.counts).filter(([, n]) => n > 0).map(([s, n]) => `${s}=${n}`).join(", ");
|
|
2996
|
+
console.log(
|
|
2997
|
+
`Summary: ${findings.length} findings across ${surfaceCounts || "no items"} (${summary.catalog.rubricsApplied.length} rubrics, ${summary.llmCalls.count} LLM calls, $${summary.llmCalls.costUsd.toFixed(4)}, ${summary.durationMs}ms)`
|
|
2998
|
+
);
|
|
2999
|
+
if (summary.skippedSurfaces.length > 0) {
|
|
3000
|
+
console.log(`Skipped surfaces:`);
|
|
3001
|
+
for (const s of summary.skippedSurfaces) {
|
|
3002
|
+
console.log(` - ${s.surface}: ${s.reason}`);
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
function truncate(s, n) {
|
|
3007
|
+
return s.length > n ? s.slice(0, n) + "\u2026" : s;
|
|
3008
|
+
}
|
|
3009
|
+
|
|
2472
3010
|
// src/commands/dashboard.ts
|
|
2473
|
-
import { Command as
|
|
3011
|
+
import { Command as Command25 } from "commander";
|
|
2474
3012
|
import { spawn } from "child_process";
|
|
2475
3013
|
import { existsSync as existsSync5 } from "fs";
|
|
2476
3014
|
import { createRequire } from "module";
|
|
@@ -2554,11 +3092,99 @@ function runDashboard(opts) {
|
|
|
2554
3092
|
}
|
|
2555
3093
|
}
|
|
2556
3094
|
function createDashboardCommand() {
|
|
2557
|
-
return new
|
|
3095
|
+
return new Command25("dashboard").description("Start the Harness local web dashboard").option("--port <port>", "Client dev server port", String(DEFAULT_CLIENT_PORT)).option("--api-port <port>", "API server port", String(DEFAULT_API_PORT)).option("--orchestrator-url <url>", "Orchestrator URL (default: http://localhost:8080)").option("--no-open", "Do not automatically open browser").option("--cwd <path>", "Project directory (defaults to cwd)").action((opts) => runDashboard(opts));
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3098
|
+
// src/commands/design-pipeline.ts
|
|
3099
|
+
import { Command as Command26 } from "commander";
|
|
3100
|
+
function createDesignPipelineCommand() {
|
|
3101
|
+
return new Command26("design-pipeline").description(
|
|
3102
|
+
"Run the design-pipeline orchestrator: FRESHEN \u2192 DETECT \u2192 FIX \u2192 AUDIT \u2192 FILL \u2192 REPORT. Composes detect-design-drift, align-design-system, audit-component-anatomy, audit-brand-compliance, and design-craft-elevator into a single sequential pipeline with convergence-based remediation."
|
|
3103
|
+
).option("--fix", "Enable convergence-based remediation (default: detect + report only)").option("--no-freshen", "Skip the FRESHEN phase").option("--no-fill", "Skip the FILL phase (input bootstrap + craft polish)").option("--ci", "Non-interactive: safe fixes only, no prompts").option("-f, --files <files...>", "Optional file/glob scope passed to each verifier").option("-m, --mode <mode>", "Verifier mode: fast | full", "fast").option(
|
|
3104
|
+
"--design-strictness <level>",
|
|
3105
|
+
"Override design.strictness: strict | standard | permissive"
|
|
3106
|
+
).action(async (opts, cmd) => {
|
|
3107
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
3108
|
+
const outputMode = resolveOutputMode(globalOpts);
|
|
3109
|
+
const formatter = new OutputFormatter(outputMode);
|
|
3110
|
+
const cwd = globalOpts.cwd ?? process.cwd();
|
|
3111
|
+
const input = { path: cwd };
|
|
3112
|
+
if (opts.fix === true) input.fix = true;
|
|
3113
|
+
if (opts.noFreshen === true) input.noFreshen = true;
|
|
3114
|
+
if (opts.noFill === true) input.noFill = true;
|
|
3115
|
+
if (opts.ci === true) input.ci = true;
|
|
3116
|
+
if (opts.files !== void 0) input.files = opts.files;
|
|
3117
|
+
if (opts.mode !== void 0) input.mode = opts.mode;
|
|
3118
|
+
if (opts.designStrictness !== void 0) input.designStrictness = opts.designStrictness;
|
|
3119
|
+
let result;
|
|
3120
|
+
try {
|
|
3121
|
+
result = await runDesignPipeline(input);
|
|
3122
|
+
} catch (err) {
|
|
3123
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3124
|
+
if (outputMode === OutputMode.JSON) {
|
|
3125
|
+
console.log(JSON.stringify({ error: message }));
|
|
3126
|
+
} else {
|
|
3127
|
+
logger.error(`design-pipeline failed: ${message}`);
|
|
3128
|
+
}
|
|
3129
|
+
process.exit(ExitCode.ERROR);
|
|
3130
|
+
return;
|
|
3131
|
+
}
|
|
3132
|
+
if (outputMode === OutputMode.JSON) {
|
|
3133
|
+
const serializable = { ...result, exclusions: [...result.exclusions] };
|
|
3134
|
+
console.log(JSON.stringify(serializable, null, 2));
|
|
3135
|
+
} else {
|
|
3136
|
+
printPipelineResult(result, outputMode, formatter);
|
|
3137
|
+
}
|
|
3138
|
+
const code = result.verdict === "fail" ? ExitCode.VALIDATION_FAILED : ExitCode.SUCCESS;
|
|
3139
|
+
process.exit(code);
|
|
3140
|
+
});
|
|
3141
|
+
}
|
|
3142
|
+
function printPipelineResult(result, _mode, _formatter) {
|
|
3143
|
+
console.log("");
|
|
3144
|
+
console.log(`Verdict: ${verdictBadge(result.verdict)}`);
|
|
3145
|
+
console.log("");
|
|
3146
|
+
console.log("Phases:");
|
|
3147
|
+
console.log(
|
|
3148
|
+
` FRESHEN inputs: DESIGN.md=${result.inputs.designMdExists ? "yes" : "no"} tokens.json=${result.inputs.tokensJsonExists ? "yes" : "no"} registry=${result.inputs.componentRegistryExists ? "yes" : "no"} brand=${result.inputs.brandRulesExist ? "yes" : "no"}`
|
|
3149
|
+
);
|
|
3150
|
+
console.log(` DETECT drift findings: ${result.driftFindings.length}`);
|
|
3151
|
+
console.log(
|
|
3152
|
+
` FIX iterations: ${result.summary.iterationsRun}, fixes applied: ${result.summary.fixesApplied}`
|
|
3153
|
+
);
|
|
3154
|
+
console.log(
|
|
3155
|
+
` AUDIT anatomy: ${result.auditFindings.anatomy.length}, brand: ${result.auditFindings.brand.length}`
|
|
3156
|
+
);
|
|
3157
|
+
const bootstrapped = Object.entries(result.bootstrapped).filter(([, v]) => v).map(([k]) => k);
|
|
3158
|
+
console.log(
|
|
3159
|
+
` FILL bootstrapped: ${bootstrapped.length > 0 ? bootstrapped.join(", ") : "none"}, craft suggestions: ${result.craftSuggestions}`
|
|
3160
|
+
);
|
|
3161
|
+
console.log("");
|
|
3162
|
+
console.log(
|
|
3163
|
+
`Summary: ${result.summary.totalFindings} total findings (${result.summary.bySeverity.error} error, ${result.summary.bySeverity.warn} warn, ${result.summary.bySeverity.info} info) in ${result.summary.durationMs}ms`
|
|
3164
|
+
);
|
|
3165
|
+
if (result.verifiersRun.length > 0) {
|
|
3166
|
+
console.log(`Verifiers run: ${result.verifiersRun.join(", ")}`);
|
|
3167
|
+
}
|
|
3168
|
+
if (result.verifiersFailed.length > 0) {
|
|
3169
|
+
console.log("Verifiers failed (degraded):");
|
|
3170
|
+
for (const f of result.verifiersFailed) {
|
|
3171
|
+
console.log(` - ${f.name}: ${f.error}`);
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
function verdictBadge(verdict) {
|
|
3176
|
+
switch (verdict) {
|
|
3177
|
+
case "pass":
|
|
3178
|
+
return "\u2713 pass";
|
|
3179
|
+
case "warn":
|
|
3180
|
+
return "\u26A0 warn";
|
|
3181
|
+
case "fail":
|
|
3182
|
+
return "\u2717 fail";
|
|
3183
|
+
}
|
|
2558
3184
|
}
|
|
2559
3185
|
|
|
2560
3186
|
// src/commands/doctor.ts
|
|
2561
|
-
import { Command as
|
|
3187
|
+
import { Command as Command27 } from "commander";
|
|
2562
3188
|
import * as fs8 from "fs";
|
|
2563
3189
|
import * as os from "os";
|
|
2564
3190
|
import * as path14 from "path";
|
|
@@ -3162,7 +3788,7 @@ function formatCheck(check) {
|
|
|
3162
3788
|
return line;
|
|
3163
3789
|
}
|
|
3164
3790
|
function createDoctorCommand() {
|
|
3165
|
-
return new
|
|
3791
|
+
return new Command27("doctor").description(
|
|
3166
3792
|
"Check environment health: Node, slash commands, MCP, integrations, integration credentials, hooks, baselines, sessions"
|
|
3167
3793
|
).action((_opts, cmd) => {
|
|
3168
3794
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -3190,7 +3816,7 @@ function createDoctorCommand() {
|
|
|
3190
3816
|
|
|
3191
3817
|
// src/commands/fix-drift.ts
|
|
3192
3818
|
init_dist3();
|
|
3193
|
-
import { Command as
|
|
3819
|
+
import { Command as Command28 } from "commander";
|
|
3194
3820
|
import * as path15 from "path";
|
|
3195
3821
|
async function runFixDrift(options) {
|
|
3196
3822
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -3323,7 +3949,7 @@ function printFixDriftResult(value, mode, formatter) {
|
|
|
3323
3949
|
}
|
|
3324
3950
|
}
|
|
3325
3951
|
function createFixDriftCommand() {
|
|
3326
|
-
const command = new
|
|
3952
|
+
const command = new Command28("fix-drift").description("Auto-fix entropy issues (doc drift, dead code)").option("--no-dry-run", "Actually apply fixes (default is dry-run mode)").action(async (opts, cmd) => {
|
|
3327
3953
|
const globalOpts = cmd.optsWithGlobals();
|
|
3328
3954
|
const mode = resolveOutputMode(globalOpts);
|
|
3329
3955
|
const formatter = new OutputFormatter(mode);
|
|
@@ -3353,10 +3979,10 @@ function createFixDriftCommand() {
|
|
|
3353
3979
|
}
|
|
3354
3980
|
|
|
3355
3981
|
// src/commands/gateway/index.ts
|
|
3356
|
-
import { Command as
|
|
3982
|
+
import { Command as Command31 } from "commander";
|
|
3357
3983
|
|
|
3358
3984
|
// src/commands/gateway/token.ts
|
|
3359
|
-
import { Command as
|
|
3985
|
+
import { Command as Command29 } from "commander";
|
|
3360
3986
|
import { resolve as resolve14 } from "path";
|
|
3361
3987
|
import { TokenStore } from "@harness-engineering/orchestrator";
|
|
3362
3988
|
function getStore() {
|
|
@@ -3377,7 +4003,7 @@ async function runTokenRevoke(id) {
|
|
|
3377
4003
|
return store.revoke(id);
|
|
3378
4004
|
}
|
|
3379
4005
|
function createTokenCommand() {
|
|
3380
|
-
const cmd = new
|
|
4006
|
+
const cmd = new Command29("token").description("Manage Gateway API tokens");
|
|
3381
4007
|
cmd.command("create").description("Create a new auth token. Secret is shown ONCE.").requiredOption("--name <name>", "Human label").requiredOption("--scopes <scopes>", "Comma-separated scopes").option("--bridge <kind>", "slack | discord | github-app | custom").option("--tenant <id>", "Tenant identifier").option("--expires <iso>", "Expiry ISO-8601").action(
|
|
3382
4008
|
async (opts) => {
|
|
3383
4009
|
const scopes = opts.scopes.split(",").map((s) => s.trim());
|
|
@@ -3406,7 +4032,7 @@ function createTokenCommand() {
|
|
|
3406
4032
|
}
|
|
3407
4033
|
|
|
3408
4034
|
// src/commands/gateway/deliveries.ts
|
|
3409
|
-
import { Command as
|
|
4035
|
+
import { Command as Command30 } from "commander";
|
|
3410
4036
|
import { createInterface } from "readline";
|
|
3411
4037
|
import { resolve as resolve15 } from "path";
|
|
3412
4038
|
import { WebhookQueue } from "@harness-engineering/orchestrator";
|
|
@@ -3446,7 +4072,7 @@ function promptYesNo(message) {
|
|
|
3446
4072
|
});
|
|
3447
4073
|
}
|
|
3448
4074
|
function createDeliveriesCommand() {
|
|
3449
|
-
const cmd = new
|
|
4075
|
+
const cmd = new Command30("deliveries").description("Inspect and manage webhook delivery queue");
|
|
3450
4076
|
cmd.command("list").description("List delivery queue entries (newest first; capped at 200 rows)").option("--status <status>", "Filter by status: pending|failed|delivered|dead").option("--subscription <id>", "Filter by subscription ID").action((opts) => {
|
|
3451
4077
|
const queue = getQueue();
|
|
3452
4078
|
try {
|
|
@@ -3506,14 +4132,14 @@ function createDeliveriesCommand() {
|
|
|
3506
4132
|
|
|
3507
4133
|
// src/commands/gateway/index.ts
|
|
3508
4134
|
function createGatewayCommand() {
|
|
3509
|
-
const cmd = new
|
|
4135
|
+
const cmd = new Command31("gateway").description("Gateway API administration");
|
|
3510
4136
|
cmd.addCommand(createTokenCommand());
|
|
3511
4137
|
cmd.addCommand(createDeliveriesCommand());
|
|
3512
4138
|
return cmd;
|
|
3513
4139
|
}
|
|
3514
4140
|
|
|
3515
4141
|
// src/commands/generate.ts
|
|
3516
|
-
import { Command as
|
|
4142
|
+
import { Command as Command32 } from "commander";
|
|
3517
4143
|
function validatePlatforms(platforms) {
|
|
3518
4144
|
for (const p of platforms) {
|
|
3519
4145
|
if (!VALID_PLATFORMS.includes(p)) {
|
|
@@ -3573,13 +4199,13 @@ async function runGenerateAction(opts, globalOpts) {
|
|
|
3573
4199
|
}
|
|
3574
4200
|
}
|
|
3575
4201
|
function createGenerateCommand() {
|
|
3576
|
-
return new
|
|
4202
|
+
return new Command32("generate").description("Generate all platform integrations (slash commands + agent definitions)").option("--platforms <list>", "Target platforms (comma-separated)", "claude-code,gemini-cli").option("--global", "Write to global directories", false).option("--include-global", "Include built-in global skills", false).option("--output <dir>", "Custom output directory").option("--dry-run", "Show what would change without writing", false).option("--yes", "Skip deletion confirmation prompts", false).action(async (opts, cmd) => {
|
|
3577
4203
|
await runGenerateAction(opts, cmd.optsWithGlobals());
|
|
3578
4204
|
});
|
|
3579
4205
|
}
|
|
3580
4206
|
|
|
3581
4207
|
// src/commands/graph/index.ts
|
|
3582
|
-
import { Command as
|
|
4208
|
+
import { Command as Command35 } from "commander";
|
|
3583
4209
|
|
|
3584
4210
|
// src/commands/graph/status.ts
|
|
3585
4211
|
import * as path16 from "path";
|
|
@@ -3597,7 +4223,7 @@ async function readConnectorSyncStatus(graphDir) {
|
|
|
3597
4223
|
return result;
|
|
3598
4224
|
}
|
|
3599
4225
|
async function runGraphStatus(projectPath) {
|
|
3600
|
-
const { GraphStore, loadGraphMetadata } = await import("./dist-
|
|
4226
|
+
const { GraphStore: GraphStore2, loadGraphMetadata } = await import("./dist-R3TOOPJ7.js");
|
|
3601
4227
|
const graphDir = path16.join(projectPath, ".harness", "graph");
|
|
3602
4228
|
const metaResult = await loadGraphMetadata(graphDir);
|
|
3603
4229
|
if (metaResult.status === "not_found") {
|
|
@@ -3621,7 +4247,7 @@ async function runGraphStatus(projectPath) {
|
|
|
3621
4247
|
...Object.keys(connectorSyncStatus).length > 0 ? { connectorSyncStatus } : {}
|
|
3622
4248
|
};
|
|
3623
4249
|
}
|
|
3624
|
-
const store = new
|
|
4250
|
+
const store = new GraphStore2();
|
|
3625
4251
|
const loaded = await store.load(graphDir);
|
|
3626
4252
|
if (!loaded) {
|
|
3627
4253
|
return {
|
|
@@ -3649,9 +4275,9 @@ async function runGraphStatus(projectPath) {
|
|
|
3649
4275
|
// src/commands/graph/export.ts
|
|
3650
4276
|
import * as path17 from "path";
|
|
3651
4277
|
async function runGraphExport(projectPath, format) {
|
|
3652
|
-
const { GraphStore } = await import("./dist-
|
|
4278
|
+
const { GraphStore: GraphStore2 } = await import("./dist-R3TOOPJ7.js");
|
|
3653
4279
|
const graphDir = path17.join(projectPath, ".harness", "graph");
|
|
3654
|
-
const store = new
|
|
4280
|
+
const store = new GraphStore2();
|
|
3655
4281
|
const loaded = await store.load(graphDir);
|
|
3656
4282
|
if (!loaded) throw new Error("No graph found. Run `harness scan` first.");
|
|
3657
4283
|
if (format === "json") {
|
|
@@ -3682,11 +4308,11 @@ async function runGraphExport(projectPath, format) {
|
|
|
3682
4308
|
import * as path20 from "path";
|
|
3683
4309
|
|
|
3684
4310
|
// src/commands/graph/query.ts
|
|
3685
|
-
import { Command as
|
|
4311
|
+
import { Command as Command33 } from "commander";
|
|
3686
4312
|
import * as path18 from "path";
|
|
3687
4313
|
async function runQuery(projectPath, rootNodeId, opts) {
|
|
3688
|
-
const { GraphStore, ContextQL } = await import("./dist-
|
|
3689
|
-
const store = new
|
|
4314
|
+
const { GraphStore: GraphStore2, ContextQL } = await import("./dist-R3TOOPJ7.js");
|
|
4315
|
+
const store = new GraphStore2();
|
|
3690
4316
|
const graphDir = path18.join(projectPath, ".harness", "graph");
|
|
3691
4317
|
const loaded = await store.load(graphDir);
|
|
3692
4318
|
if (!loaded) throw new Error("No graph found. Run `harness scan` first.");
|
|
@@ -3728,13 +4354,13 @@ async function runQueryAction(rootNodeId, opts, globalOpts) {
|
|
|
3728
4354
|
}
|
|
3729
4355
|
}
|
|
3730
4356
|
function createQueryCommand() {
|
|
3731
|
-
return new
|
|
4357
|
+
return new Command33("query").description("Query the knowledge graph").argument("<rootNodeId>", "Starting node ID").option("--depth <n>", "Max traversal depth", "3").option("--types <types>", "Comma-separated node types to include").option("--edges <edges>", "Comma-separated edge types to include").option("--bidirectional", "Traverse both directions").action(async (rootNodeId, opts, cmd) => {
|
|
3732
4358
|
await runQueryAction(rootNodeId, opts, cmd.optsWithGlobals());
|
|
3733
4359
|
});
|
|
3734
4360
|
}
|
|
3735
4361
|
|
|
3736
4362
|
// src/commands/graph/ingest.ts
|
|
3737
|
-
import { Command as
|
|
4363
|
+
import { Command as Command34 } from "commander";
|
|
3738
4364
|
import * as path19 from "path";
|
|
3739
4365
|
async function loadConnectorConfig(projectPath, source) {
|
|
3740
4366
|
try {
|
|
@@ -3769,7 +4395,7 @@ function mergeResults(...results) {
|
|
|
3769
4395
|
}
|
|
3770
4396
|
async function runIngest(projectPath, source, opts) {
|
|
3771
4397
|
const {
|
|
3772
|
-
GraphStore,
|
|
4398
|
+
GraphStore: GraphStore2,
|
|
3773
4399
|
CodeIngestor,
|
|
3774
4400
|
TopologicalLinker,
|
|
3775
4401
|
KnowledgeIngestor,
|
|
@@ -3782,9 +4408,9 @@ async function runIngest(projectPath, source, opts) {
|
|
|
3782
4408
|
ConfluenceConnector,
|
|
3783
4409
|
FigmaConnector,
|
|
3784
4410
|
MiroConnector
|
|
3785
|
-
} = await import("./dist-
|
|
4411
|
+
} = await import("./dist-R3TOOPJ7.js");
|
|
3786
4412
|
const graphDir = path19.join(projectPath, ".harness", "graph");
|
|
3787
|
-
const store = new
|
|
4413
|
+
const store = new GraphStore2();
|
|
3788
4414
|
await store.load(graphDir);
|
|
3789
4415
|
const ingestOptions = loadIngestOptions(projectPath);
|
|
3790
4416
|
if (opts?.all) {
|
|
@@ -3796,7 +4422,7 @@ async function runIngest(projectPath, source, opts) {
|
|
|
3796
4422
|
path19.join(projectPath, "docs", "changes")
|
|
3797
4423
|
);
|
|
3798
4424
|
const gitResult = await new GitIngestor(store).ingest(projectPath);
|
|
3799
|
-
const { createExtractionRunner } = await import("./dist-
|
|
4425
|
+
const { createExtractionRunner } = await import("./dist-R3TOOPJ7.js");
|
|
3800
4426
|
const extractedDir = path19.join(projectPath, ".harness", "knowledge", "extracted");
|
|
3801
4427
|
const signalsResult = await createExtractionRunner().run(projectPath, store, extractedDir);
|
|
3802
4428
|
const syncManager = new SyncManager(store, graphDir);
|
|
@@ -3842,7 +4468,7 @@ async function runIngest(projectPath, source, opts) {
|
|
|
3842
4468
|
);
|
|
3843
4469
|
break;
|
|
3844
4470
|
case "business-signals": {
|
|
3845
|
-
const { createExtractionRunner } = await import("./dist-
|
|
4471
|
+
const { createExtractionRunner } = await import("./dist-R3TOOPJ7.js");
|
|
3846
4472
|
const extractedDir = path19.join(projectPath, ".harness", "knowledge", "extracted");
|
|
3847
4473
|
result = await createExtractionRunner().run(projectPath, store, extractedDir);
|
|
3848
4474
|
break;
|
|
@@ -3879,7 +4505,7 @@ async function runIngest(projectPath, source, opts) {
|
|
|
3879
4505
|
return result;
|
|
3880
4506
|
}
|
|
3881
4507
|
function createIngestCommand() {
|
|
3882
|
-
return new
|
|
4508
|
+
return new Command34("ingest").description("Ingest data into the knowledge graph").option(
|
|
3883
4509
|
"--source <name>",
|
|
3884
4510
|
"Source to ingest (code, knowledge, git, requirements, business-signals, jira, slack, ci, confluence, figma, miro)"
|
|
3885
4511
|
).option("--all", "Run all sources (code, knowledge, git, and configured connectors)").option("--full", "Force full re-ingestion").action(async (opts, cmd) => {
|
|
@@ -3957,17 +4583,17 @@ async function runExportAction(opts, cmd) {
|
|
|
3957
4583
|
}
|
|
3958
4584
|
}
|
|
3959
4585
|
function createGraphCommand() {
|
|
3960
|
-
const graph = new
|
|
4586
|
+
const graph = new Command35("graph").description("Knowledge graph management");
|
|
3961
4587
|
graph.command("status").description("Show graph statistics").action(runStatusAction);
|
|
3962
4588
|
graph.command("export").description("Export graph").requiredOption("--format <format>", "Output format (json, mermaid)").action(runExportAction);
|
|
3963
4589
|
return graph;
|
|
3964
4590
|
}
|
|
3965
4591
|
|
|
3966
4592
|
// src/commands/hooks/index.ts
|
|
3967
|
-
import { Command as
|
|
4593
|
+
import { Command as Command40 } from "commander";
|
|
3968
4594
|
|
|
3969
4595
|
// src/commands/hooks/init.ts
|
|
3970
|
-
import { Command as
|
|
4596
|
+
import { Command as Command36 } from "commander";
|
|
3971
4597
|
import * as fs9 from "fs";
|
|
3972
4598
|
import * as path21 from "path";
|
|
3973
4599
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -4089,7 +4715,7 @@ function initHooks(options) {
|
|
|
4089
4715
|
return { copiedScripts, settingsPath, profilePath };
|
|
4090
4716
|
}
|
|
4091
4717
|
function createInitCommand2() {
|
|
4092
|
-
return new
|
|
4718
|
+
return new Command36("init").description("Install Claude Code hook configurations into the current project").option("--profile <profile>", "Hook profile: minimal, standard, or strict", "standard").action(async (opts, cmd) => {
|
|
4093
4719
|
const globalOpts = cmd.optsWithGlobals();
|
|
4094
4720
|
const profile = opts.profile;
|
|
4095
4721
|
if (!VALID_PROFILES.includes(profile)) {
|
|
@@ -4127,7 +4753,7 @@ function createInitCommand2() {
|
|
|
4127
4753
|
}
|
|
4128
4754
|
|
|
4129
4755
|
// src/commands/hooks/list.ts
|
|
4130
|
-
import { Command as
|
|
4756
|
+
import { Command as Command37 } from "commander";
|
|
4131
4757
|
import * as fs10 from "fs";
|
|
4132
4758
|
import * as path22 from "path";
|
|
4133
4759
|
function listHooks(projectDir) {
|
|
@@ -4160,7 +4786,7 @@ function listHooks(projectDir) {
|
|
|
4160
4786
|
return result;
|
|
4161
4787
|
}
|
|
4162
4788
|
function createListCommand() {
|
|
4163
|
-
return new
|
|
4789
|
+
return new Command37("list").description("Show installed hooks and active profile").action(async (_opts, cmd) => {
|
|
4164
4790
|
const globalOpts = cmd.optsWithGlobals();
|
|
4165
4791
|
const projectDir = process.cwd();
|
|
4166
4792
|
const result = listHooks(projectDir);
|
|
@@ -4181,7 +4807,7 @@ function createListCommand() {
|
|
|
4181
4807
|
}
|
|
4182
4808
|
|
|
4183
4809
|
// src/commands/hooks/remove.ts
|
|
4184
|
-
import { Command as
|
|
4810
|
+
import { Command as Command38 } from "commander";
|
|
4185
4811
|
import * as fs11 from "fs";
|
|
4186
4812
|
import * as path23 from "path";
|
|
4187
4813
|
function removeHooks(projectDir) {
|
|
@@ -4211,7 +4837,7 @@ function removeHooks(projectDir) {
|
|
|
4211
4837
|
return { removed, hooksDir, settingsCleaned };
|
|
4212
4838
|
}
|
|
4213
4839
|
function createRemoveCommand() {
|
|
4214
|
-
return new
|
|
4840
|
+
return new Command38("remove").description("Remove harness-managed hooks from the current project").action(async (_opts, cmd) => {
|
|
4215
4841
|
const globalOpts = cmd.optsWithGlobals();
|
|
4216
4842
|
const projectDir = process.cwd();
|
|
4217
4843
|
const result = removeHooks(projectDir);
|
|
@@ -4233,7 +4859,7 @@ function createRemoveCommand() {
|
|
|
4233
4859
|
}
|
|
4234
4860
|
|
|
4235
4861
|
// src/commands/hooks/add.ts
|
|
4236
|
-
import { Command as
|
|
4862
|
+
import { Command as Command39 } from "commander";
|
|
4237
4863
|
import * as fs12 from "fs";
|
|
4238
4864
|
import * as path24 from "path";
|
|
4239
4865
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -4290,7 +4916,7 @@ function addHooks(hookName, projectDir) {
|
|
|
4290
4916
|
return result;
|
|
4291
4917
|
}
|
|
4292
4918
|
function createAddCommand2() {
|
|
4293
|
-
return new
|
|
4919
|
+
return new Command39("add").argument("<hook-name>", "Hook name or alias (e.g., sentinel)").description("Add a hook without changing the profile").action(async (hookName, _opts, cmd) => {
|
|
4294
4920
|
const projectDir = process.cwd();
|
|
4295
4921
|
try {
|
|
4296
4922
|
const res = addHooks(hookName, projectDir);
|
|
@@ -4315,7 +4941,7 @@ function createAddCommand2() {
|
|
|
4315
4941
|
|
|
4316
4942
|
// src/commands/hooks/index.ts
|
|
4317
4943
|
function createHooksCommand() {
|
|
4318
|
-
const command = new
|
|
4944
|
+
const command = new Command40("hooks").description("Manage Claude Code hook configurations");
|
|
4319
4945
|
command.addCommand(createInitCommand2());
|
|
4320
4946
|
command.addCommand(createListCommand());
|
|
4321
4947
|
command.addCommand(createRemoveCommand());
|
|
@@ -4324,7 +4950,7 @@ function createHooksCommand() {
|
|
|
4324
4950
|
}
|
|
4325
4951
|
|
|
4326
4952
|
// src/commands/impact-preview.ts
|
|
4327
|
-
import { Command as
|
|
4953
|
+
import { Command as Command41 } from "commander";
|
|
4328
4954
|
import { execSync as execSync4 } from "child_process";
|
|
4329
4955
|
import * as path25 from "path";
|
|
4330
4956
|
import * as fs13 from "fs";
|
|
@@ -4523,7 +5149,7 @@ async function runImpactPreview(options) {
|
|
|
4523
5149
|
return formatImpactOutput(stagedFiles, acc, options);
|
|
4524
5150
|
}
|
|
4525
5151
|
function createImpactPreviewCommand() {
|
|
4526
|
-
const command = new
|
|
5152
|
+
const command = new Command41("impact-preview").description("Show blast radius of staged changes using the knowledge graph").option("--detailed", "Show all affected files instead of top items").option("--per-file", "Show impact per staged file instead of aggregate").option("--path <dir>", "Project root (default: cwd)").action(async (opts) => {
|
|
4527
5153
|
const output = await runImpactPreview({
|
|
4528
5154
|
detailed: opts.detailed,
|
|
4529
5155
|
perFile: opts.perFile,
|
|
@@ -4537,13 +5163,13 @@ function createImpactPreviewCommand() {
|
|
|
4537
5163
|
|
|
4538
5164
|
// src/commands/init.ts
|
|
4539
5165
|
init_dist3();
|
|
4540
|
-
import { Command as
|
|
5166
|
+
import { Command as Command43 } from "commander";
|
|
4541
5167
|
import chalk3 from "chalk";
|
|
4542
5168
|
import * as fs16 from "fs";
|
|
4543
5169
|
import * as path28 from "path";
|
|
4544
5170
|
|
|
4545
5171
|
// src/commands/setup-mcp.ts
|
|
4546
|
-
import { Command as
|
|
5172
|
+
import { Command as Command42 } from "commander";
|
|
4547
5173
|
import * as fs15 from "fs";
|
|
4548
5174
|
import * as path27 from "path";
|
|
4549
5175
|
import * as os2 from "os";
|
|
@@ -4715,7 +5341,31 @@ var ALL_MCP_TOOLS = [
|
|
|
4715
5341
|
"summarize_session",
|
|
4716
5342
|
"insights_summary",
|
|
4717
5343
|
// Hermes Phase 4 — agent-emitted skill proposals
|
|
4718
|
-
"emit_skill_proposal"
|
|
5344
|
+
"emit_skill_proposal",
|
|
5345
|
+
// design-pipeline #2 — component-anatomy audit (ANAT-D* findings)
|
|
5346
|
+
"audit_anatomy",
|
|
5347
|
+
// design-pipeline #6 — design-craft LLM-judgment skill (CRITIQUE / POLISH / BENCHMARK)
|
|
5348
|
+
"design_craft",
|
|
5349
|
+
// design-pipeline #1 (detect half) — design-system drift detection
|
|
5350
|
+
"detect_drift",
|
|
5351
|
+
// design-pipeline #1 (align half) — apply codemods + emit suggestions
|
|
5352
|
+
"align_design_system",
|
|
5353
|
+
// design-pipeline #3 — brand-semantics audit (BRAND-T* + BRAND-V001)
|
|
5354
|
+
"audit_brand",
|
|
5355
|
+
// design-pipeline #5 — orchestrator composing all design verifiers
|
|
5356
|
+
"run_design_pipeline",
|
|
5357
|
+
// craft-pipeline #1 — naming-craft LLM-judgment ceiling skill
|
|
5358
|
+
"naming_craft",
|
|
5359
|
+
// craft-pipeline #6 — spec-craft LLM-judgment ceiling skill
|
|
5360
|
+
"spec_craft",
|
|
5361
|
+
// craft-pipeline #5 — copy-craft LLM-judgment ceiling skill (6 surfaces)
|
|
5362
|
+
"copy_craft",
|
|
5363
|
+
// craft-pipeline #3 — test-craft LLM-judgment ceiling skill (vitest/jest/mocha/playwright)
|
|
5364
|
+
"test_craft",
|
|
5365
|
+
// craft-pipeline #9 — knowledge-craft LLM-judgment ceiling skill (docs/knowledge/ entries)
|
|
5366
|
+
"knowledge_craft",
|
|
5367
|
+
// craft-pipeline #10 — security-craft LLM-judgment ceiling skill (AST-driven, conservative-confidence)
|
|
5368
|
+
"security_craft"
|
|
4719
5369
|
];
|
|
4720
5370
|
async function runCursorToolPicker() {
|
|
4721
5371
|
try {
|
|
@@ -4888,7 +5538,7 @@ function printMcpResult(configured, skipped, trustedFolder) {
|
|
|
4888
5538
|
console.log("");
|
|
4889
5539
|
}
|
|
4890
5540
|
function createSetupMcpCommand() {
|
|
4891
|
-
return new
|
|
5541
|
+
return new Command42("setup-mcp").description("Configure MCP server for AI agent integration").option(
|
|
4892
5542
|
"--client <client>",
|
|
4893
5543
|
"Client to configure (claude, gemini, codex, cursor, opencode, all)",
|
|
4894
5544
|
"all"
|
|
@@ -5034,7 +5684,7 @@ async function runInitAction2(opts) {
|
|
|
5034
5684
|
process.exit(ExitCode.SUCCESS);
|
|
5035
5685
|
}
|
|
5036
5686
|
function createInitCommand3() {
|
|
5037
|
-
const command = new
|
|
5687
|
+
const command = new Command43("init").description("Initialize a new harness-engineering project").option("-n, --name <name>", "Project name").option("-l, --level <level>", "Adoption level (basic, intermediate, advanced)", "basic").option("-t, --template <template>", "Specific template name (e.g. orchestrator)").option("--framework <framework>", "Framework overlay (nextjs)").option("--language <language>", "Target language (typescript, python, go, rust, java)").option("-f, --force", "Overwrite existing files").option("-y, --yes", "Use defaults without prompting").action(async (opts, cmd) => {
|
|
5038
5688
|
const globalOpts = cmd.optsWithGlobals();
|
|
5039
5689
|
await runInitAction2({
|
|
5040
5690
|
name: opts.name,
|
|
@@ -5050,7 +5700,7 @@ function createInitCommand3() {
|
|
|
5050
5700
|
|
|
5051
5701
|
// src/commands/insights.ts
|
|
5052
5702
|
init_dist();
|
|
5053
|
-
import { Command as
|
|
5703
|
+
import { Command as Command44 } from "commander";
|
|
5054
5704
|
function parseSkip2(raw) {
|
|
5055
5705
|
if (!raw) return [];
|
|
5056
5706
|
const valid = new Set(INSIGHTS_KEYS);
|
|
@@ -5088,12 +5738,12 @@ function renderPretty(report) {
|
|
|
5088
5738
|
}
|
|
5089
5739
|
}
|
|
5090
5740
|
function createInsightsCommand() {
|
|
5091
|
-
return new
|
|
5741
|
+
return new Command44("insights").description(
|
|
5092
5742
|
"Composite project report \u2014 health, entropy, decay, attention, impact (Hermes Phase 1)."
|
|
5093
5743
|
).option("--json", "Emit JSON to stdout instead of pretty text").option("--skip <list>", `Comma-separated keys to skip (${INSIGHTS_KEYS.join(",")})`).action(async (opts) => {
|
|
5094
5744
|
const cwd = process.cwd();
|
|
5095
5745
|
const skip = parseSkip2(opts.skip);
|
|
5096
|
-
const { composeInsights } = await import("./dist-
|
|
5746
|
+
const { composeInsights } = await import("./dist-XIJWWQ5N.js");
|
|
5097
5747
|
const report = await composeInsights(cwd, { skip });
|
|
5098
5748
|
if (opts.json) {
|
|
5099
5749
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -5108,7 +5758,7 @@ import * as fs21 from "fs";
|
|
|
5108
5758
|
import * as os5 from "os";
|
|
5109
5759
|
import * as path33 from "path";
|
|
5110
5760
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
5111
|
-
import { Command as
|
|
5761
|
+
import { Command as Command45 } from "commander";
|
|
5112
5762
|
import { parse as yamlParse } from "yaml";
|
|
5113
5763
|
|
|
5114
5764
|
// src/registry/npm-client.ts
|
|
@@ -5669,7 +6319,7 @@ async function runInstall(skillName, options) {
|
|
|
5669
6319
|
return result;
|
|
5670
6320
|
}
|
|
5671
6321
|
function createInstallCommand() {
|
|
5672
|
-
const cmd = new
|
|
6322
|
+
const cmd = new Command45("install");
|
|
5673
6323
|
cmd.description("Install skills from npm registry, local directory, or GitHub repository").argument("<skill>", 'Skill name, @harness-skills/scoped package, or "." for bulk install').option("--version <range>", "Semver range or exact version to install").option("--force", "Force reinstall even if same version is already installed").option(
|
|
5674
6324
|
"--from <source>",
|
|
5675
6325
|
"Install from local path, directory, or GitHub (github:owner/repo, https://github.com/owner/repo)"
|
|
@@ -5705,7 +6355,7 @@ function createInstallCommand() {
|
|
|
5705
6355
|
init_dist3();
|
|
5706
6356
|
import * as fs22 from "fs/promises";
|
|
5707
6357
|
import * as path34 from "path";
|
|
5708
|
-
import { Command as
|
|
6358
|
+
import { Command as Command46 } from "commander";
|
|
5709
6359
|
import semver3 from "semver";
|
|
5710
6360
|
async function runInstallConstraints(options) {
|
|
5711
6361
|
const { source, configPath, lockfilePath } = options;
|
|
@@ -5959,17 +6609,17 @@ async function handleInstallConstraints(source, opts) {
|
|
|
5959
6609
|
logInstallResult(result.value, opts);
|
|
5960
6610
|
}
|
|
5961
6611
|
function createInstallConstraintsCommand() {
|
|
5962
|
-
const cmd = new
|
|
6612
|
+
const cmd = new Command46("install-constraints");
|
|
5963
6613
|
cmd.description("Install a constraints bundle into the local harness config").argument("<source>", "Path to a .harness-constraints.json bundle file").option("--force-local", "Resolve all conflicts by keeping local values").option("--force-package", "Resolve all conflicts by using package values").option("--dry-run", "Show what would change without writing files").option("-c, --config <path>", "Path to harness.config.json").action(handleInstallConstraints);
|
|
5964
6614
|
return cmd;
|
|
5965
6615
|
}
|
|
5966
6616
|
|
|
5967
6617
|
// src/commands/integrations/index.ts
|
|
5968
|
-
import { Command as
|
|
6618
|
+
import { Command as Command51 } from "commander";
|
|
5969
6619
|
|
|
5970
6620
|
// src/commands/integrations/add.ts
|
|
5971
6621
|
init_dist3();
|
|
5972
|
-
import { Command as
|
|
6622
|
+
import { Command as Command47 } from "commander";
|
|
5973
6623
|
import * as fs23 from "fs";
|
|
5974
6624
|
import * as path35 from "path";
|
|
5975
6625
|
import chalk4 from "chalk";
|
|
@@ -6033,7 +6683,7 @@ function printAddSuccess(value) {
|
|
|
6033
6683
|
}
|
|
6034
6684
|
}
|
|
6035
6685
|
function createAddIntegrationCommand() {
|
|
6036
|
-
return new
|
|
6686
|
+
return new Command47("add").description("Enable an MCP integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
|
|
6037
6687
|
const globalOpts = cmd.optsWithGlobals();
|
|
6038
6688
|
const result = addIntegration(process.cwd(), name);
|
|
6039
6689
|
if (!result.ok) {
|
|
@@ -6047,7 +6697,7 @@ function createAddIntegrationCommand() {
|
|
|
6047
6697
|
}
|
|
6048
6698
|
|
|
6049
6699
|
// src/commands/integrations/list.ts
|
|
6050
|
-
import { Command as
|
|
6700
|
+
import { Command as Command48 } from "commander";
|
|
6051
6701
|
import * as path36 from "path";
|
|
6052
6702
|
import chalk5 from "chalk";
|
|
6053
6703
|
function printTier0Integrations(tier0, mcpServers) {
|
|
@@ -6104,12 +6754,12 @@ async function runListIntegrations(globalOpts) {
|
|
|
6104
6754
|
process.exit(ExitCode.SUCCESS);
|
|
6105
6755
|
}
|
|
6106
6756
|
function createListIntegrationsCommand() {
|
|
6107
|
-
return new
|
|
6757
|
+
return new Command48("list").description("Show all MCP integrations with status").action(async (_opts, cmd) => runListIntegrations(cmd.optsWithGlobals()));
|
|
6108
6758
|
}
|
|
6109
6759
|
|
|
6110
6760
|
// src/commands/integrations/remove.ts
|
|
6111
6761
|
init_dist3();
|
|
6112
|
-
import { Command as
|
|
6762
|
+
import { Command as Command49 } from "commander";
|
|
6113
6763
|
import * as fs24 from "fs";
|
|
6114
6764
|
import * as path37 from "path";
|
|
6115
6765
|
function removeIntegration(cwd, name) {
|
|
@@ -6136,7 +6786,7 @@ function removeIntegration(cwd, name) {
|
|
|
6136
6786
|
return Ok(def.displayName);
|
|
6137
6787
|
}
|
|
6138
6788
|
function createRemoveIntegrationCommand() {
|
|
6139
|
-
return new
|
|
6789
|
+
return new Command49("remove").description("Remove an MCP integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
|
|
6140
6790
|
const globalOpts = cmd.optsWithGlobals();
|
|
6141
6791
|
const cwd = process.cwd();
|
|
6142
6792
|
const result = removeIntegration(cwd, name);
|
|
@@ -6158,7 +6808,7 @@ function createRemoveIntegrationCommand() {
|
|
|
6158
6808
|
|
|
6159
6809
|
// src/commands/integrations/dismiss.ts
|
|
6160
6810
|
init_dist3();
|
|
6161
|
-
import { Command as
|
|
6811
|
+
import { Command as Command50 } from "commander";
|
|
6162
6812
|
import * as path38 from "path";
|
|
6163
6813
|
function dismissIntegration(cwd, name) {
|
|
6164
6814
|
const def = INTEGRATION_REGISTRY.find((i) => i.name === name);
|
|
@@ -6180,7 +6830,7 @@ function dismissIntegration(cwd, name) {
|
|
|
6180
6830
|
return Ok(def.displayName);
|
|
6181
6831
|
}
|
|
6182
6832
|
function createDismissIntegrationCommand() {
|
|
6183
|
-
return new
|
|
6833
|
+
return new Command50("dismiss").description("Suppress doctor recommendations for an integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
|
|
6184
6834
|
const globalOpts = cmd.optsWithGlobals();
|
|
6185
6835
|
const cwd = process.cwd();
|
|
6186
6836
|
const result = dismissIntegration(cwd, name);
|
|
@@ -6204,7 +6854,7 @@ function createDismissIntegrationCommand() {
|
|
|
6204
6854
|
|
|
6205
6855
|
// src/commands/integrations/index.ts
|
|
6206
6856
|
function createIntegrationsCommand() {
|
|
6207
|
-
const command = new
|
|
6857
|
+
const command = new Command51("integrations").description(
|
|
6208
6858
|
"Manage MCP peer integrations (add, list, remove, dismiss)"
|
|
6209
6859
|
);
|
|
6210
6860
|
command.addCommand(createListIntegrationsCommand());
|
|
@@ -6214,20 +6864,87 @@ function createIntegrationsCommand() {
|
|
|
6214
6864
|
return command;
|
|
6215
6865
|
}
|
|
6216
6866
|
|
|
6867
|
+
// src/commands/knowledge-craft.ts
|
|
6868
|
+
import { Command as Command52 } from "commander";
|
|
6869
|
+
function createKnowledgeCraftCommand() {
|
|
6870
|
+
return new Command52("knowledge-craft").description(
|
|
6871
|
+
"LLM-judgment critique of knowledge-entry quality (docs/knowledge/, excluding decisions/). Fifth non-design craft-pipeline ceiling skill; 7 seed rubrics (load-bearing-fact, earns-graph-place, carries-forward-decision, \u2026). Per-file critique."
|
|
6872
|
+
).option("-f, --files <files...>", "Optional file scope (overrides discovery)").option(
|
|
6873
|
+
"--exclude-dirs <dirs...>",
|
|
6874
|
+
"Additional subdir names to skip (decisions is always excluded)"
|
|
6875
|
+
).option("--max-files <n>", "Cap entry count (default: 50)").action(async (opts, cmd) => {
|
|
6876
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
6877
|
+
const outputMode = resolveOutputMode(globalOpts);
|
|
6878
|
+
const formatter = new OutputFormatter(outputMode);
|
|
6879
|
+
const cwd = globalOpts.cwd ?? process.cwd();
|
|
6880
|
+
const input = { path: cwd };
|
|
6881
|
+
if (opts.files !== void 0) input.files = opts.files;
|
|
6882
|
+
if (opts.excludeDirs !== void 0) input.excludeDirs = opts.excludeDirs;
|
|
6883
|
+
if (opts.maxFiles !== void 0) input.maxFiles = parseInt(opts.maxFiles, 10);
|
|
6884
|
+
let result;
|
|
6885
|
+
try {
|
|
6886
|
+
result = await runKnowledgeCraft(input);
|
|
6887
|
+
} catch (err) {
|
|
6888
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6889
|
+
if (outputMode === OutputMode.JSON) {
|
|
6890
|
+
console.log(JSON.stringify({ error: message }));
|
|
6891
|
+
} else {
|
|
6892
|
+
logger.error(`knowledge-craft failed: ${message}`);
|
|
6893
|
+
}
|
|
6894
|
+
process.exit(ExitCode.ERROR);
|
|
6895
|
+
return;
|
|
6896
|
+
}
|
|
6897
|
+
if (outputMode === OutputMode.JSON) {
|
|
6898
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6899
|
+
} else {
|
|
6900
|
+
printResult3(result, outputMode, formatter);
|
|
6901
|
+
}
|
|
6902
|
+
const hasFoundational = result.findings.some((f) => f.tier === "foundational");
|
|
6903
|
+
process.exit(hasFoundational ? ExitCode.VALIDATION_FAILED : ExitCode.SUCCESS);
|
|
6904
|
+
});
|
|
6905
|
+
}
|
|
6906
|
+
function printResult3(result, mode, _formatter) {
|
|
6907
|
+
const verbose = mode === OutputMode.VERBOSE;
|
|
6908
|
+
const { findings, summary } = result;
|
|
6909
|
+
if (findings.length === 0) {
|
|
6910
|
+
console.log("No knowledge-entry findings.");
|
|
6911
|
+
} else {
|
|
6912
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
6913
|
+
for (const f of findings) {
|
|
6914
|
+
const list = byFile.get(f.target.file) ?? [];
|
|
6915
|
+
list.push(f);
|
|
6916
|
+
byFile.set(f.target.file, list);
|
|
6917
|
+
}
|
|
6918
|
+
for (const [file, fs47] of byFile) {
|
|
6919
|
+
console.log(`
|
|
6920
|
+
${file}`);
|
|
6921
|
+
for (const f of fs47) {
|
|
6922
|
+
console.log(` ${f.code} [${f.tier}/${f.impact}/${f.confidence}] ${f.target.relative}`);
|
|
6923
|
+
console.log(` ${f.message}`);
|
|
6924
|
+
if (verbose) console.log(` source: ${f.cite.source}`);
|
|
6925
|
+
}
|
|
6926
|
+
}
|
|
6927
|
+
}
|
|
6928
|
+
console.log("");
|
|
6929
|
+
console.log(
|
|
6930
|
+
`Summary: ${findings.length} findings across ${summary.counts.filesScanned} entries (${summary.counts.filesSkipped} skipped, ${summary.catalog.rubricsApplied.length} rubrics, ${summary.llmCalls.count} LLM calls, $${summary.llmCalls.costUsd.toFixed(4)}, ${summary.durationMs}ms)`
|
|
6931
|
+
);
|
|
6932
|
+
}
|
|
6933
|
+
|
|
6217
6934
|
// src/commands/knowledge-pipeline.ts
|
|
6218
|
-
import { Command as
|
|
6935
|
+
import { Command as Command53 } from "commander";
|
|
6219
6936
|
import * as path39 from "path";
|
|
6220
6937
|
import chalk6 from "chalk";
|
|
6221
6938
|
function createKnowledgePipelineCommand() {
|
|
6222
|
-
return new
|
|
6939
|
+
return new Command53("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) => {
|
|
6223
6940
|
const globalOpts = cmd.optsWithGlobals();
|
|
6224
6941
|
const projectDir = process.cwd();
|
|
6225
6942
|
try {
|
|
6226
6943
|
const graphDir = path39.join(projectDir, ".harness", "graph");
|
|
6227
6944
|
const fs47 = await import("fs/promises");
|
|
6228
6945
|
await fs47.mkdir(graphDir, { recursive: true });
|
|
6229
|
-
const { GraphStore, KnowledgePipelineRunner } = await import("./dist-
|
|
6230
|
-
const store = new
|
|
6946
|
+
const { GraphStore: GraphStore2, KnowledgePipelineRunner } = await import("./dist-R3TOOPJ7.js");
|
|
6947
|
+
const store = new GraphStore2();
|
|
6231
6948
|
try {
|
|
6232
6949
|
await store.load(graphDir);
|
|
6233
6950
|
} catch {
|
|
@@ -6383,11 +7100,11 @@ function createKnowledgePipelineCommand() {
|
|
|
6383
7100
|
}
|
|
6384
7101
|
|
|
6385
7102
|
// src/commands/learnings/index.ts
|
|
6386
|
-
import { Command as
|
|
7103
|
+
import { Command as Command55 } from "commander";
|
|
6387
7104
|
|
|
6388
7105
|
// src/commands/learnings/prune.ts
|
|
6389
7106
|
init_dist3();
|
|
6390
|
-
import { Command as
|
|
7107
|
+
import { Command as Command54 } from "commander";
|
|
6391
7108
|
import * as path40 from "path";
|
|
6392
7109
|
async function handlePrune(opts) {
|
|
6393
7110
|
const projectPath = path40.resolve(opts.path);
|
|
@@ -6429,23 +7146,23 @@ function printPatternProposals(patterns) {
|
|
|
6429
7146
|
);
|
|
6430
7147
|
}
|
|
6431
7148
|
function createPruneCommand() {
|
|
6432
|
-
return new
|
|
7149
|
+
return new Command54("prune").description(
|
|
6433
7150
|
"Analyze global learnings for patterns, present improvement proposals, and archive old entries"
|
|
6434
7151
|
).option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(handlePrune);
|
|
6435
7152
|
}
|
|
6436
7153
|
|
|
6437
7154
|
// src/commands/learnings/index.ts
|
|
6438
7155
|
function createLearningsCommand() {
|
|
6439
|
-
const command = new
|
|
7156
|
+
const command = new Command55("learnings").description("Learnings management commands");
|
|
6440
7157
|
command.addCommand(createPruneCommand());
|
|
6441
7158
|
return command;
|
|
6442
7159
|
}
|
|
6443
7160
|
|
|
6444
7161
|
// src/commands/linter/index.ts
|
|
6445
|
-
import { Command as
|
|
7162
|
+
import { Command as Command58 } from "commander";
|
|
6446
7163
|
|
|
6447
7164
|
// src/commands/linter/generate.ts
|
|
6448
|
-
import { Command as
|
|
7165
|
+
import { Command as Command56 } from "commander";
|
|
6449
7166
|
function formatGenerateError(e) {
|
|
6450
7167
|
switch (e.type) {
|
|
6451
7168
|
case "parse":
|
|
@@ -6489,7 +7206,7 @@ function handleSuccess(result, useJson) {
|
|
|
6489
7206
|
Generated ${result.rulesGenerated.length} rules to ${result.outputDir}`);
|
|
6490
7207
|
}
|
|
6491
7208
|
function createGenerateCommand2() {
|
|
6492
|
-
return new
|
|
7209
|
+
return new Command56("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) => {
|
|
6493
7210
|
try {
|
|
6494
7211
|
if (options.verbose) logger.info(`Parsing config: ${options.config}`);
|
|
6495
7212
|
const result = await generate({
|
|
@@ -6511,9 +7228,9 @@ function createGenerateCommand2() {
|
|
|
6511
7228
|
}
|
|
6512
7229
|
|
|
6513
7230
|
// src/commands/linter/validate.ts
|
|
6514
|
-
import { Command as
|
|
7231
|
+
import { Command as Command57 } from "commander";
|
|
6515
7232
|
function createValidateCommand() {
|
|
6516
|
-
return new
|
|
7233
|
+
return new Command57("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) => {
|
|
6517
7234
|
try {
|
|
6518
7235
|
const result = await validate({ configPath: options.config });
|
|
6519
7236
|
if (options.json) {
|
|
@@ -6532,7 +7249,7 @@ function createValidateCommand() {
|
|
|
6532
7249
|
|
|
6533
7250
|
// src/commands/linter/index.ts
|
|
6534
7251
|
function createLinterCommand() {
|
|
6535
|
-
const linter = new
|
|
7252
|
+
const linter = new Command58("linter").description(
|
|
6536
7253
|
"Generate and validate ESLint rules from YAML config"
|
|
6537
7254
|
);
|
|
6538
7255
|
linter.addCommand(createGenerateCommand2());
|
|
@@ -6541,7 +7258,7 @@ function createLinterCommand() {
|
|
|
6541
7258
|
}
|
|
6542
7259
|
|
|
6543
7260
|
// src/commands/maintenance.ts
|
|
6544
|
-
import { Command as
|
|
7261
|
+
import { Command as Command59 } from "commander";
|
|
6545
7262
|
import * as path41 from "path";
|
|
6546
7263
|
import * as fs25 from "fs";
|
|
6547
7264
|
import chalk7 from "chalk";
|
|
@@ -6556,6 +7273,7 @@ async function loadMaintenanceConfig(cwd) {
|
|
|
6556
7273
|
const loader = new WorkflowLoader();
|
|
6557
7274
|
const result = await loader.loadWorkflow(workflowPath);
|
|
6558
7275
|
if (!result.ok) return null;
|
|
7276
|
+
for (const w of result.value.warnings) logger.warn(w);
|
|
6559
7277
|
return result.value.config.maintenance ?? null;
|
|
6560
7278
|
}
|
|
6561
7279
|
function mergeResolvedTasks(config) {
|
|
@@ -6632,7 +7350,7 @@ function printListTable(rows) {
|
|
|
6632
7350
|
}
|
|
6633
7351
|
}
|
|
6634
7352
|
function createMaintenanceCommand() {
|
|
6635
|
-
const command = new
|
|
7353
|
+
const command = new Command59("maintenance").description(
|
|
6636
7354
|
"Hermes Phase 2 \u2014 inspect built-in + custom maintenance tasks and their persisted outputs"
|
|
6637
7355
|
);
|
|
6638
7356
|
command.command("list").description("List all resolved maintenance tasks (built-in + customTasks)").option("--json", "Emit machine-readable JSON", false).option("--path <path>", "Project root path", ".").action(async (opts) => {
|
|
@@ -6700,7 +7418,7 @@ function describeOrigin(origin) {
|
|
|
6700
7418
|
}
|
|
6701
7419
|
|
|
6702
7420
|
// src/commands/mcp.ts
|
|
6703
|
-
import { Command as
|
|
7421
|
+
import { Command as Command60 } from "commander";
|
|
6704
7422
|
var VALID_TIERS = /* @__PURE__ */ new Set(["core", "standard", "full"]);
|
|
6705
7423
|
function parseTier(value) {
|
|
6706
7424
|
const lower = value.toLowerCase();
|
|
@@ -6717,7 +7435,7 @@ function parseBudget(value) {
|
|
|
6717
7435
|
return n;
|
|
6718
7436
|
}
|
|
6719
7437
|
function createMcpCommand() {
|
|
6720
|
-
return new
|
|
7438
|
+
return new Command60("mcp").description("Start the MCP (Model Context Protocol) server on stdio").option("--tools <tools...>", "Only register the specified tools (used by Cursor integration)").option(
|
|
6721
7439
|
"--tier <core|standard|full>",
|
|
6722
7440
|
"Load a preset tool tier instead of all tools",
|
|
6723
7441
|
parseTier
|
|
@@ -6727,7 +7445,7 @@ function createMcpCommand() {
|
|
|
6727
7445
|
parseBudget
|
|
6728
7446
|
).action(async (opts) => {
|
|
6729
7447
|
const [{ startServer: startServer2, getToolDefinitions: getToolDefinitions2 }, { selectTier }] = await Promise.all([
|
|
6730
|
-
import("./mcp-
|
|
7448
|
+
import("./mcp-NEAPIDTT.js"),
|
|
6731
7449
|
import("./tool-tiers-B7JC2XC3.js")
|
|
6732
7450
|
]);
|
|
6733
7451
|
if (opts.tools && opts.tools.length > 0) {
|
|
@@ -6749,7 +7467,7 @@ function createMcpCommand() {
|
|
|
6749
7467
|
|
|
6750
7468
|
// src/commands/mcp-guard.ts
|
|
6751
7469
|
init_dist3();
|
|
6752
|
-
import { Command as
|
|
7470
|
+
import { Command as Command61 } from "commander";
|
|
6753
7471
|
import * as fs26 from "fs";
|
|
6754
7472
|
import * as path42 from "path";
|
|
6755
7473
|
import chalk8 from "chalk";
|
|
@@ -6857,7 +7575,7 @@ function formatHuman(result) {
|
|
|
6857
7575
|
}
|
|
6858
7576
|
}
|
|
6859
7577
|
function createMcpGuardCommand() {
|
|
6860
|
-
const command = new
|
|
7578
|
+
const command = new Command61("mcp-guard").description("Pre-launch OSV malware guard for MCP/npx packages").addHelpText(
|
|
6861
7579
|
"after",
|
|
6862
7580
|
'\nUse "harness mcp-guard check" before launching MCP servers to block known malicious packages.'
|
|
6863
7581
|
);
|
|
@@ -6890,7 +7608,7 @@ function createMcpGuardCommand() {
|
|
|
6890
7608
|
// src/commands/migrate.ts
|
|
6891
7609
|
init_dist3();
|
|
6892
7610
|
init_dist2();
|
|
6893
|
-
import { Command as
|
|
7611
|
+
import { Command as Command62 } from "commander";
|
|
6894
7612
|
import * as fs27 from "fs";
|
|
6895
7613
|
import * as path43 from "path";
|
|
6896
7614
|
import * as readline from "readline";
|
|
@@ -7296,7 +8014,7 @@ async function runMigrate(opts) {
|
|
|
7296
8014
|
});
|
|
7297
8015
|
}
|
|
7298
8016
|
function createMigrateCommand() {
|
|
7299
|
-
return new
|
|
8017
|
+
return new Command62("migrate").description("Migrate legacy harness artifact locations to current layout").option("--dry-run", "Show the migration plan without moving files", false).option("--yes", "Skip confirmation prompt", false).option(
|
|
7300
8018
|
"--skip-references",
|
|
7301
8019
|
"Do not update path references in docs/sessions after moves",
|
|
7302
8020
|
false
|
|
@@ -7317,12 +8035,87 @@ function createMigrateCommand() {
|
|
|
7317
8035
|
});
|
|
7318
8036
|
}
|
|
7319
8037
|
|
|
8038
|
+
// src/commands/naming-craft.ts
|
|
8039
|
+
import { Command as Command63 } from "commander";
|
|
8040
|
+
function createNamingCraftCommand() {
|
|
8041
|
+
return new Command63("naming-craft").description(
|
|
8042
|
+
"LLM-judgment critique of identifier names (variables, functions, types, files). First craft-pipeline ceiling skill; uses curated rubric catalog from Martin/Beck/Karlton."
|
|
8043
|
+
).option("-f, --files <files...>", "Optional file/glob scope").option(
|
|
8044
|
+
"-k, --kinds <kinds...>",
|
|
8045
|
+
"Restrict to variable / function / type / file (default: all)"
|
|
8046
|
+
).option("--max-files <n>", "Cap file count (default: 100)").option("--max-identifiers-per-file <n>", "Cap per-file identifier sampling (default: 15)").action(async (opts, cmd) => {
|
|
8047
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
8048
|
+
const outputMode = resolveOutputMode(globalOpts);
|
|
8049
|
+
const formatter = new OutputFormatter(outputMode);
|
|
8050
|
+
const cwd = globalOpts.cwd ?? process.cwd();
|
|
8051
|
+
const input = { path: cwd };
|
|
8052
|
+
if (opts.files !== void 0) input.files = opts.files;
|
|
8053
|
+
if (opts.kinds !== void 0) input.kinds = opts.kinds;
|
|
8054
|
+
if (opts.maxFiles !== void 0) input.maxFiles = parseInt(opts.maxFiles, 10);
|
|
8055
|
+
if (opts.maxIdentifiersPerFile !== void 0)
|
|
8056
|
+
input.maxIdentifiersPerFile = parseInt(opts.maxIdentifiersPerFile, 10);
|
|
8057
|
+
let result;
|
|
8058
|
+
try {
|
|
8059
|
+
result = await runNamingCraft(input);
|
|
8060
|
+
} catch (err) {
|
|
8061
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8062
|
+
if (outputMode === OutputMode.JSON) {
|
|
8063
|
+
console.log(JSON.stringify({ error: message }));
|
|
8064
|
+
} else {
|
|
8065
|
+
logger.error(`naming-craft failed: ${message}`);
|
|
8066
|
+
}
|
|
8067
|
+
process.exit(ExitCode.ERROR);
|
|
8068
|
+
return;
|
|
8069
|
+
}
|
|
8070
|
+
if (outputMode === OutputMode.JSON) {
|
|
8071
|
+
console.log(JSON.stringify(result, null, 2));
|
|
8072
|
+
} else {
|
|
8073
|
+
printResult4(result, outputMode, formatter);
|
|
8074
|
+
}
|
|
8075
|
+
const hasError = result.findings.some((f) => f.tier === "foundational");
|
|
8076
|
+
process.exit(hasError ? ExitCode.VALIDATION_FAILED : ExitCode.SUCCESS);
|
|
8077
|
+
});
|
|
8078
|
+
}
|
|
8079
|
+
function printResult4(result, mode, _formatter) {
|
|
8080
|
+
const verbose = mode === OutputMode.VERBOSE;
|
|
8081
|
+
const { findings, summary } = result;
|
|
8082
|
+
if (findings.length === 0) {
|
|
8083
|
+
console.log("No naming findings.");
|
|
8084
|
+
} else {
|
|
8085
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
8086
|
+
for (const f of findings) {
|
|
8087
|
+
const list = byFile.get(f.target.file) ?? [];
|
|
8088
|
+
list.push(f);
|
|
8089
|
+
byFile.set(f.target.file, list);
|
|
8090
|
+
}
|
|
8091
|
+
for (const [file, fs47] of byFile) {
|
|
8092
|
+
console.log(`
|
|
8093
|
+
${file}`);
|
|
8094
|
+
for (const f of fs47) {
|
|
8095
|
+
const line = f.target.line !== void 0 ? `:${f.target.line}` : "";
|
|
8096
|
+
console.log(
|
|
8097
|
+
` ${f.code} [${f.tier}/${f.impact}/${f.confidence}] ${f.target.kind} ${f.target.identifier}${line}`
|
|
8098
|
+
);
|
|
8099
|
+
console.log(` ${f.message}`);
|
|
8100
|
+
if (verbose) console.log(` source: ${f.cite.source}`);
|
|
8101
|
+
}
|
|
8102
|
+
}
|
|
8103
|
+
}
|
|
8104
|
+
console.log("");
|
|
8105
|
+
console.log(
|
|
8106
|
+
`Summary: ${findings.length} findings (rubrics: ${summary.catalog.rubricsApplied.length}, LLM calls: ${summary.llmCalls.count}, cost: $${summary.llmCalls.costUsd.toFixed(4)}, ${summary.durationMs}ms)`
|
|
8107
|
+
);
|
|
8108
|
+
console.log(
|
|
8109
|
+
`Convention: vars=${summary.convention.variables ?? "?"}, funcs=${summary.convention.functions ?? "?"}, types=${summary.convention.types ?? "?"}, files=${summary.convention.files ?? "?"}`
|
|
8110
|
+
);
|
|
8111
|
+
}
|
|
8112
|
+
|
|
7320
8113
|
// src/commands/notifications/index.ts
|
|
7321
|
-
import { Command as
|
|
8114
|
+
import { Command as Command65 } from "commander";
|
|
7322
8115
|
|
|
7323
8116
|
// src/commands/notifications/test.ts
|
|
7324
8117
|
init_dist3();
|
|
7325
|
-
import { Command as
|
|
8118
|
+
import { Command as Command64 } from "commander";
|
|
7326
8119
|
import { randomBytes } from "crypto";
|
|
7327
8120
|
import { resolve as resolve28 } from "path";
|
|
7328
8121
|
import { SinkRegistry, SinkConfigError, wrapAsEnvelope } from "@harness-engineering/orchestrator";
|
|
@@ -7374,7 +8167,7 @@ async function runNotificationsTest(sinkId, opts, projectRoot2 = process.cwd())
|
|
|
7374
8167
|
return { ok: false, error: result.error };
|
|
7375
8168
|
}
|
|
7376
8169
|
function createNotificationsTestSubcommand() {
|
|
7377
|
-
return new
|
|
8170
|
+
return new Command64("test").description("Send a synthetic notification.test event through the named sink").argument("<sink-id>", "Sink id from harness.config.json `notifications.sinks[].id`").option("--message <text>", "Override the default test message").action(async (sinkId, opts, cmd) => {
|
|
7378
8171
|
const globalOpts = cmd.optsWithGlobals();
|
|
7379
8172
|
const projectRoot2 = typeof globalOpts["cwd"] === "string" ? resolve28(globalOpts["cwd"]) : process.cwd();
|
|
7380
8173
|
const result = await runNotificationsTest(sinkId, opts, projectRoot2);
|
|
@@ -7391,7 +8184,7 @@ function createNotificationsTestSubcommand() {
|
|
|
7391
8184
|
|
|
7392
8185
|
// src/commands/notifications/index.ts
|
|
7393
8186
|
function createNotificationsCommand() {
|
|
7394
|
-
const cmd = new
|
|
8187
|
+
const cmd = new Command65("notifications").description(
|
|
7395
8188
|
"Manage notification sinks (Slack and others)"
|
|
7396
8189
|
);
|
|
7397
8190
|
cmd.addCommand(createNotificationsTestSubcommand());
|
|
@@ -7399,11 +8192,11 @@ function createNotificationsCommand() {
|
|
|
7399
8192
|
}
|
|
7400
8193
|
|
|
7401
8194
|
// src/commands/orchestrator.ts
|
|
7402
|
-
import { Command as
|
|
8195
|
+
import { Command as Command66 } from "commander";
|
|
7403
8196
|
import * as path44 from "path";
|
|
7404
8197
|
import { Orchestrator, WorkflowLoader as WorkflowLoader2, launchTUI } from "@harness-engineering/orchestrator";
|
|
7405
8198
|
function createOrchestratorCommand() {
|
|
7406
|
-
const orchestrator = new
|
|
8199
|
+
const orchestrator = new Command66("orchestrator");
|
|
7407
8200
|
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) => {
|
|
7408
8201
|
const workflowPath = path44.resolve(process.cwd(), opts.workflow);
|
|
7409
8202
|
const loader = new WorkflowLoader2();
|
|
@@ -7412,7 +8205,8 @@ function createOrchestratorCommand() {
|
|
|
7412
8205
|
logger.error(`Failed to load workflow: ${result.error.message}`);
|
|
7413
8206
|
process.exit(ExitCode.ERROR);
|
|
7414
8207
|
}
|
|
7415
|
-
const { config, promptTemplate } = result.value;
|
|
8208
|
+
const { config, promptTemplate, warnings } = result.value;
|
|
8209
|
+
for (const w of warnings) logger.warn(w);
|
|
7416
8210
|
const daemon = new Orchestrator(config, promptTemplate);
|
|
7417
8211
|
const shutdown = () => {
|
|
7418
8212
|
daemon.stop();
|
|
@@ -7438,13 +8232,13 @@ function createOrchestratorCommand() {
|
|
|
7438
8232
|
|
|
7439
8233
|
// src/commands/perf.ts
|
|
7440
8234
|
init_dist3();
|
|
7441
|
-
import { Command as
|
|
8235
|
+
import { Command as Command67 } from "commander";
|
|
7442
8236
|
import * as path45 from "path";
|
|
7443
8237
|
function registerBenchCommand(perf) {
|
|
7444
8238
|
perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob2, _opts, cmd) => {
|
|
7445
8239
|
const globalOpts = cmd.optsWithGlobals();
|
|
7446
8240
|
const cwd = process.cwd();
|
|
7447
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
8241
|
+
const { BenchmarkRunner } = await import("./dist-XIJWWQ5N.js");
|
|
7448
8242
|
const runner = new BenchmarkRunner();
|
|
7449
8243
|
const benchFiles = runner.discover(cwd, glob2);
|
|
7450
8244
|
if (benchFiles.length === 0) {
|
|
@@ -7508,7 +8302,7 @@ async function runBaselinesShow(globalOpts) {
|
|
|
7508
8302
|
}
|
|
7509
8303
|
async function runBaselinesUpdate(globalOpts) {
|
|
7510
8304
|
const cwd = process.cwd();
|
|
7511
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
8305
|
+
const { BenchmarkRunner } = await import("./dist-XIJWWQ5N.js");
|
|
7512
8306
|
const runner = new BenchmarkRunner();
|
|
7513
8307
|
const manager = new BaselineManager(cwd);
|
|
7514
8308
|
logger.info("Running benchmarks to update baselines...");
|
|
@@ -7549,7 +8343,7 @@ function registerReportCommand(perf) {
|
|
|
7549
8343
|
perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
|
|
7550
8344
|
const globalOpts = cmd.optsWithGlobals();
|
|
7551
8345
|
const cwd = process.cwd();
|
|
7552
|
-
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-
|
|
8346
|
+
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-XIJWWQ5N.js");
|
|
7553
8347
|
const analyzer = new EntropyAnalyzer2({
|
|
7554
8348
|
rootDir: path45.resolve(cwd),
|
|
7555
8349
|
analyze: { complexity: true, coupling: true }
|
|
@@ -7610,7 +8404,7 @@ function registerCriticalPathsCommand(perf) {
|
|
|
7610
8404
|
});
|
|
7611
8405
|
}
|
|
7612
8406
|
function createPerfCommand() {
|
|
7613
|
-
const perf = new
|
|
8407
|
+
const perf = new Command67("perf").description("Performance benchmark and baseline management");
|
|
7614
8408
|
registerBenchCommand(perf);
|
|
7615
8409
|
registerBaselinesCommands(perf);
|
|
7616
8410
|
registerReportCommand(perf);
|
|
@@ -7619,10 +8413,10 @@ function createPerfCommand() {
|
|
|
7619
8413
|
}
|
|
7620
8414
|
|
|
7621
8415
|
// src/commands/persona/index.ts
|
|
7622
|
-
import { Command as
|
|
8416
|
+
import { Command as Command70 } from "commander";
|
|
7623
8417
|
|
|
7624
8418
|
// src/commands/persona/list.ts
|
|
7625
|
-
import { Command as
|
|
8419
|
+
import { Command as Command68 } from "commander";
|
|
7626
8420
|
function printPersonaList(personas) {
|
|
7627
8421
|
if (personas.length === 0) {
|
|
7628
8422
|
logger.info("No personas found.");
|
|
@@ -7636,7 +8430,7 @@ function printPersonaList(personas) {
|
|
|
7636
8430
|
}
|
|
7637
8431
|
}
|
|
7638
8432
|
function createListCommand2() {
|
|
7639
|
-
return new
|
|
8433
|
+
return new Command68("list").description("List available agent personas").action(async (_opts, cmd) => {
|
|
7640
8434
|
const globalOpts = cmd.optsWithGlobals();
|
|
7641
8435
|
const personasDir = resolvePersonasDir();
|
|
7642
8436
|
const result = listPersonas(personasDir);
|
|
@@ -7656,7 +8450,7 @@ function createListCommand2() {
|
|
|
7656
8450
|
}
|
|
7657
8451
|
|
|
7658
8452
|
// src/commands/persona/generate.ts
|
|
7659
|
-
import { Command as
|
|
8453
|
+
import { Command as Command69 } from "commander";
|
|
7660
8454
|
import * as fs28 from "fs";
|
|
7661
8455
|
import * as path46 from "path";
|
|
7662
8456
|
function generatePersonaArtifacts(persona, outputDir, only) {
|
|
@@ -7691,7 +8485,7 @@ function generatePersonaArtifacts(persona, outputDir, only) {
|
|
|
7691
8485
|
return generated;
|
|
7692
8486
|
}
|
|
7693
8487
|
function createGenerateCommand3() {
|
|
7694
|
-
return new
|
|
8488
|
+
return new Command69("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) => {
|
|
7695
8489
|
const globalOpts = cmd.optsWithGlobals();
|
|
7696
8490
|
const personaResult = loadPersona(path46.join(resolvePersonasDir(), `${name}.yaml`));
|
|
7697
8491
|
if (!personaResult.ok) {
|
|
@@ -7713,7 +8507,7 @@ function createGenerateCommand3() {
|
|
|
7713
8507
|
|
|
7714
8508
|
// src/commands/persona/index.ts
|
|
7715
8509
|
function createPersonaCommand() {
|
|
7716
|
-
const command = new
|
|
8510
|
+
const command = new Command70("persona").description("Agent persona management commands");
|
|
7717
8511
|
command.addCommand(createListCommand2());
|
|
7718
8512
|
command.addCommand(createGenerateCommand3());
|
|
7719
8513
|
return command;
|
|
@@ -7721,7 +8515,7 @@ function createPersonaCommand() {
|
|
|
7721
8515
|
|
|
7722
8516
|
// src/commands/predict.ts
|
|
7723
8517
|
init_dist3();
|
|
7724
|
-
import { Command as
|
|
8518
|
+
import { Command as Command71 } from "commander";
|
|
7725
8519
|
import chalk10 from "chalk";
|
|
7726
8520
|
var CATEGORY_ORDER = [
|
|
7727
8521
|
"circular-deps",
|
|
@@ -7827,7 +8621,7 @@ function handlePredictError(err, mode) {
|
|
|
7827
8621
|
process.exit(ExitCode.ERROR);
|
|
7828
8622
|
}
|
|
7829
8623
|
function createPredictCommand() {
|
|
7830
|
-
const command = new
|
|
8624
|
+
const command = new Command71("predict").description("Predict which architectural constraints will break and when").option("--category <name>", "Filter to a single metric category").option("--no-roadmap", "Baseline only \u2014 skip roadmap spec impact").option("--horizon <weeks>", "Forecast horizon in weeks (default: 12)", "12").action(async (opts, cmd) => {
|
|
7831
8625
|
const globalOpts = cmd.optsWithGlobals();
|
|
7832
8626
|
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
7833
8627
|
try {
|
|
@@ -7851,7 +8645,7 @@ function createPredictCommand() {
|
|
|
7851
8645
|
|
|
7852
8646
|
// src/commands/proposals.ts
|
|
7853
8647
|
init_dist3();
|
|
7854
|
-
import { Command as
|
|
8648
|
+
import { Command as Command72 } from "commander";
|
|
7855
8649
|
import { resolve as resolve32 } from "path";
|
|
7856
8650
|
function projectRoot() {
|
|
7857
8651
|
return resolve32(process.env["HARNESS_PROJECT_ROOT"] ?? process.cwd());
|
|
@@ -7946,7 +8740,7 @@ async function actApproveCommand(id) {
|
|
|
7946
8740
|
}
|
|
7947
8741
|
}
|
|
7948
8742
|
function createProposalsCommand() {
|
|
7949
|
-
const cmd = new
|
|
8743
|
+
const cmd = new Command72("proposals").description("Skill-proposal review queue (Hermes Phase 4)");
|
|
7950
8744
|
cmd.command("list").description("List skill proposals in the local queue").option(
|
|
7951
8745
|
"--status <status>",
|
|
7952
8746
|
`Filter by status \u2014 one of ${ALLOWED_STATUSES.join(" | ")}`,
|
|
@@ -7963,7 +8757,7 @@ function createProposalsCommand() {
|
|
|
7963
8757
|
// src/commands/publish-analyses.ts
|
|
7964
8758
|
import * as fs29 from "fs";
|
|
7965
8759
|
import * as path47 from "path";
|
|
7966
|
-
import { Command as
|
|
8760
|
+
import { Command as Command73 } from "commander";
|
|
7967
8761
|
init_dist3();
|
|
7968
8762
|
import {
|
|
7969
8763
|
renderAnalysisComment,
|
|
@@ -8076,7 +8870,7 @@ async function runPublishAnalyses(opts) {
|
|
|
8076
8870
|
const nameToExternalId = await buildNameToExternalIdMap(projectPath);
|
|
8077
8871
|
if (!nameToExternalId) return process.exit(1);
|
|
8078
8872
|
const { AnalysisArchive } = await import("@harness-engineering/orchestrator");
|
|
8079
|
-
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-
|
|
8873
|
+
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-XIJWWQ5N.js");
|
|
8080
8874
|
const archive = new AnalysisArchive(path47.join(projectPath, ".harness", "analyses"));
|
|
8081
8875
|
const analyses = await archive.list();
|
|
8082
8876
|
if (analyses.length === 0) {
|
|
@@ -8099,7 +8893,7 @@ async function runPublishAnalyses(opts) {
|
|
|
8099
8893
|
}
|
|
8100
8894
|
}
|
|
8101
8895
|
function createPublishAnalysesCommand() {
|
|
8102
|
-
const command = new
|
|
8896
|
+
const command = new Command73("publish-analyses").description(
|
|
8103
8897
|
"Publishes locally generated intelligence analyses to the external issue tracker (e.g., GitHub)"
|
|
8104
8898
|
).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
8105
8899
|
try {
|
|
@@ -8115,13 +8909,13 @@ function createPublishAnalysesCommand() {
|
|
|
8115
8909
|
}
|
|
8116
8910
|
|
|
8117
8911
|
// src/commands/pulse/index.ts
|
|
8118
|
-
import { Command as
|
|
8912
|
+
import { Command as Command75 } from "commander";
|
|
8119
8913
|
|
|
8120
8914
|
// src/commands/pulse/run.ts
|
|
8121
8915
|
init_dist3();
|
|
8122
8916
|
import { readFileSync as readFileSync18, mkdirSync as mkdirSync13, writeFileSync as writeFileSync15 } from "fs";
|
|
8123
8917
|
import { dirname as dirname17, join as join38, resolve as resolve34 } from "path";
|
|
8124
|
-
import { Command as
|
|
8918
|
+
import { Command as Command74 } from "commander";
|
|
8125
8919
|
async function runPulseRunCommand(opts) {
|
|
8126
8920
|
const startedAt = Date.now();
|
|
8127
8921
|
let raw;
|
|
@@ -8186,7 +8980,7 @@ function emit2(status, nonInteractive) {
|
|
|
8186
8980
|
return status;
|
|
8187
8981
|
}
|
|
8188
8982
|
function createRunCommand2() {
|
|
8189
|
-
return new
|
|
8983
|
+
return new Command74("run").description("Run a pulse: query configured adapters, sanitize, assemble single-page report").option(
|
|
8190
8984
|
"--lookback <window>",
|
|
8191
8985
|
"Lookback window (e.g. 24h, 7d). Defaults to pulse.lookbackDefault."
|
|
8192
8986
|
).option(
|
|
@@ -8210,13 +9004,13 @@ function createRunCommand2() {
|
|
|
8210
9004
|
|
|
8211
9005
|
// src/commands/pulse/index.ts
|
|
8212
9006
|
function createPulseCommand() {
|
|
8213
|
-
const command = new
|
|
9007
|
+
const command = new Command75("pulse").description("Pulse (read-side observability) commands");
|
|
8214
9008
|
command.addCommand(createRunCommand2());
|
|
8215
9009
|
return command;
|
|
8216
9010
|
}
|
|
8217
9011
|
|
|
8218
9012
|
// src/commands/recommend.ts
|
|
8219
|
-
import { Command as
|
|
9013
|
+
import { Command as Command76 } from "commander";
|
|
8220
9014
|
import chalk11 from "chalk";
|
|
8221
9015
|
async function resolveSnapshot(cwd, noCache) {
|
|
8222
9016
|
if (!noCache) {
|
|
@@ -8280,7 +9074,7 @@ function printRecommendations(result) {
|
|
|
8280
9074
|
console.log("");
|
|
8281
9075
|
}
|
|
8282
9076
|
function createRecommendCommand() {
|
|
8283
|
-
const command = new
|
|
9077
|
+
const command = new Command76("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) => {
|
|
8284
9078
|
const globalOpts = cmd.optsWithGlobals();
|
|
8285
9079
|
const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
|
|
8286
9080
|
try {
|
|
@@ -8316,11 +9110,11 @@ function createRecommendCommand() {
|
|
|
8316
9110
|
}
|
|
8317
9111
|
|
|
8318
9112
|
// src/commands/roadmap/index.ts
|
|
8319
|
-
import { Command as
|
|
9113
|
+
import { Command as Command78 } from "commander";
|
|
8320
9114
|
|
|
8321
9115
|
// src/commands/roadmap/migrate.ts
|
|
8322
9116
|
init_dist3();
|
|
8323
|
-
import { Command as
|
|
9117
|
+
import { Command as Command77 } from "commander";
|
|
8324
9118
|
import * as fs31 from "fs";
|
|
8325
9119
|
import * as path49 from "path";
|
|
8326
9120
|
import chalk12 from "chalk";
|
|
@@ -8578,61 +9372,296 @@ async function runRoadmapMigrate(opts) {
|
|
|
8578
9372
|
if (!reportR.ok) {
|
|
8579
9373
|
return Err(new CLIError(`migration failed: ${reportR.error.message}`));
|
|
8580
9374
|
}
|
|
8581
|
-
if (isJson) {
|
|
8582
|
-
const exitCode = reportToExitCode(reportR.value);
|
|
8583
|
-
console.log(JSON.stringify(buildJsonOutput(plan, reportR.value, void 0, exitCode)));
|
|
8584
|
-
} else {
|
|
8585
|
-
printReport(reportR.value);
|
|
9375
|
+
if (isJson) {
|
|
9376
|
+
const exitCode = reportToExitCode(reportR.value);
|
|
9377
|
+
console.log(JSON.stringify(buildJsonOutput(plan, reportR.value, void 0, exitCode)));
|
|
9378
|
+
} else {
|
|
9379
|
+
printReport(reportR.value);
|
|
9380
|
+
}
|
|
9381
|
+
return Ok(reportR.value);
|
|
9382
|
+
} finally {
|
|
9383
|
+
lockResult.release();
|
|
9384
|
+
}
|
|
9385
|
+
}
|
|
9386
|
+
function createRoadmapMigrateCommand() {
|
|
9387
|
+
return new Command77("migrate").description("Migrate the project roadmap to a different storage mode").requiredOption("--to <target>", 'Migration target (only "file-less" supported today)').option("--dry-run", "Print the migration plan without making any changes", false).option(
|
|
9388
|
+
"--format <fmt>",
|
|
9389
|
+
'Output format: "human" (default) or "json" (single JSON object for CI consumers)',
|
|
9390
|
+
"human"
|
|
9391
|
+
).action(async (options) => {
|
|
9392
|
+
const format = options.format === "json" ? "json" : "human";
|
|
9393
|
+
const result = await runRoadmapMigrate({
|
|
9394
|
+
to: options.to,
|
|
9395
|
+
dryRun: Boolean(options.dryRun),
|
|
9396
|
+
format
|
|
9397
|
+
});
|
|
9398
|
+
if (!result.ok) {
|
|
9399
|
+
if (format === "json") {
|
|
9400
|
+
console.log(
|
|
9401
|
+
JSON.stringify(
|
|
9402
|
+
buildJsonOutput(
|
|
9403
|
+
void 0,
|
|
9404
|
+
void 0,
|
|
9405
|
+
result.error.message,
|
|
9406
|
+
MigrateExitCode.CONFIG_ERROR
|
|
9407
|
+
)
|
|
9408
|
+
)
|
|
9409
|
+
);
|
|
9410
|
+
} else {
|
|
9411
|
+
logger.error(result.error.message);
|
|
9412
|
+
}
|
|
9413
|
+
process.exit(format === "json" ? MigrateExitCode.CONFIG_ERROR : result.error.exitCode);
|
|
9414
|
+
}
|
|
9415
|
+
const exitCode = reportToExitCode(result.value);
|
|
9416
|
+
process.exit(exitCode);
|
|
9417
|
+
});
|
|
9418
|
+
}
|
|
9419
|
+
|
|
9420
|
+
// src/commands/roadmap/index.ts
|
|
9421
|
+
function createRoadmapCommand() {
|
|
9422
|
+
const roadmap = new Command78("roadmap").description("Roadmap management");
|
|
9423
|
+
roadmap.addCommand(createRoadmapMigrateCommand());
|
|
9424
|
+
return roadmap;
|
|
9425
|
+
}
|
|
9426
|
+
|
|
9427
|
+
// src/commands/routing/index.ts
|
|
9428
|
+
import { Command as Command82 } from "commander";
|
|
9429
|
+
|
|
9430
|
+
// src/commands/routing/config.ts
|
|
9431
|
+
import { Command as Command79 } from "commander";
|
|
9432
|
+
|
|
9433
|
+
// src/commands/routing/http-client.ts
|
|
9434
|
+
function orchestratorBase() {
|
|
9435
|
+
return process.env["HARNESS_ORCHESTRATOR_URL"] ?? "http://127.0.0.1:8080";
|
|
9436
|
+
}
|
|
9437
|
+
function authHeader() {
|
|
9438
|
+
const tok = process.env["HARNESS_API_TOKEN"];
|
|
9439
|
+
return tok ? { Authorization: `Bearer ${tok}` } : {};
|
|
9440
|
+
}
|
|
9441
|
+
async function getJson(path71) {
|
|
9442
|
+
try {
|
|
9443
|
+
const res = await fetch(`${orchestratorBase()}${path71}`, {
|
|
9444
|
+
headers: { ...authHeader() }
|
|
9445
|
+
});
|
|
9446
|
+
const text = await res.text();
|
|
9447
|
+
if (!res.ok) return { ok: false, status: res.status, body: null, error: text };
|
|
9448
|
+
return { ok: true, status: res.status, body: text ? JSON.parse(text) : null };
|
|
9449
|
+
} catch (err) {
|
|
9450
|
+
return {
|
|
9451
|
+
ok: false,
|
|
9452
|
+
status: 0,
|
|
9453
|
+
body: null,
|
|
9454
|
+
error: err instanceof Error ? err.message : String(err)
|
|
9455
|
+
};
|
|
9456
|
+
}
|
|
9457
|
+
}
|
|
9458
|
+
async function postJson(path71, body) {
|
|
9459
|
+
try {
|
|
9460
|
+
const res = await fetch(`${orchestratorBase()}${path71}`, {
|
|
9461
|
+
method: "POST",
|
|
9462
|
+
headers: { "Content-Type": "application/json", ...authHeader() },
|
|
9463
|
+
body: JSON.stringify(body)
|
|
9464
|
+
});
|
|
9465
|
+
const text = await res.text();
|
|
9466
|
+
if (!res.ok) return { ok: false, status: res.status, body: null, error: text };
|
|
9467
|
+
return { ok: true, status: res.status, body: text ? JSON.parse(text) : null };
|
|
9468
|
+
} catch (err) {
|
|
9469
|
+
return {
|
|
9470
|
+
ok: false,
|
|
9471
|
+
status: 0,
|
|
9472
|
+
body: null,
|
|
9473
|
+
error: err instanceof Error ? err.message : String(err)
|
|
9474
|
+
};
|
|
9475
|
+
}
|
|
9476
|
+
}
|
|
9477
|
+
|
|
9478
|
+
// src/commands/routing/config.ts
|
|
9479
|
+
function renderHuman(data) {
|
|
9480
|
+
console.log("Backends:");
|
|
9481
|
+
for (const b of data.backends) console.log(` - ${b}`);
|
|
9482
|
+
console.log("");
|
|
9483
|
+
console.log("Resolved Chains:");
|
|
9484
|
+
const keys = Object.keys(data.resolvedChains);
|
|
9485
|
+
if (keys.length === 0) {
|
|
9486
|
+
console.log(" (none)");
|
|
9487
|
+
return;
|
|
9488
|
+
}
|
|
9489
|
+
for (const key of keys) {
|
|
9490
|
+
const chain = data.resolvedChains[key] ?? [];
|
|
9491
|
+
const rendered = chain.map((c) => c.exists ? c.candidate : `${c.candidate}(MISSING)`).join(" -> ");
|
|
9492
|
+
console.log(` ${key}: ${rendered}`);
|
|
9493
|
+
}
|
|
9494
|
+
}
|
|
9495
|
+
function createConfigCommand() {
|
|
9496
|
+
return new Command79("config").description("Print active routing config and resolved fallback chains").option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
|
|
9497
|
+
const r = await getJson("/api/v1/routing/config");
|
|
9498
|
+
if (!r.ok) {
|
|
9499
|
+
if (r.status === 0) {
|
|
9500
|
+
logger.error(
|
|
9501
|
+
`Failed to reach orchestrator at ${orchestratorBase()}: ${r.error ?? "unknown error"}`
|
|
9502
|
+
);
|
|
9503
|
+
} else if (r.status === 503) {
|
|
9504
|
+
logger.error(
|
|
9505
|
+
"Routing observability not available \u2014 orchestrator has no BackendRouter (legacy single-backend config)"
|
|
9506
|
+
);
|
|
9507
|
+
} else {
|
|
9508
|
+
logger.error(`Request failed (${r.status}): ${r.error ?? ""}`);
|
|
9509
|
+
}
|
|
9510
|
+
process.exit(ExitCode.ERROR);
|
|
9511
|
+
return;
|
|
9512
|
+
}
|
|
9513
|
+
if (opts.json) {
|
|
9514
|
+
console.log(JSON.stringify(r.body, null, 2));
|
|
9515
|
+
return;
|
|
8586
9516
|
}
|
|
8587
|
-
|
|
8588
|
-
}
|
|
8589
|
-
|
|
9517
|
+
if (r.body) renderHuman(r.body);
|
|
9518
|
+
});
|
|
9519
|
+
}
|
|
9520
|
+
|
|
9521
|
+
// src/commands/routing/trace.ts
|
|
9522
|
+
import { Command as Command80 } from "commander";
|
|
9523
|
+
function buildUseCase(opts) {
|
|
9524
|
+
if (opts.skill) {
|
|
9525
|
+
return opts.mode ? { kind: "skill", skillName: opts.skill, cognitiveMode: opts.mode } : { kind: "skill", skillName: opts.skill };
|
|
8590
9526
|
}
|
|
9527
|
+
if (opts.mode) return { kind: "mode", cognitiveMode: opts.mode };
|
|
9528
|
+
return null;
|
|
8591
9529
|
}
|
|
8592
|
-
function
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
9530
|
+
function renderHuman2(r) {
|
|
9531
|
+
console.log(`Backend: ${r.decision.backendName} (type: ${r.def.type})`);
|
|
9532
|
+
console.log(`Duration: ${r.decision.durationMs.toFixed(2)} ms`);
|
|
9533
|
+
console.log("Resolution path:");
|
|
9534
|
+
if (r.decision.resolutionPath.length === 0) {
|
|
9535
|
+
console.log(" (empty)");
|
|
9536
|
+
return;
|
|
9537
|
+
}
|
|
9538
|
+
for (const step of r.decision.resolutionPath) {
|
|
9539
|
+
console.log(` ${step.source}:${step.candidate} -> ${step.outcome}`);
|
|
9540
|
+
}
|
|
9541
|
+
}
|
|
9542
|
+
function createTraceCommand() {
|
|
9543
|
+
return new Command80("trace").description("Dry-run a routing decision without dispatching (Spec B F7)").option("--skill <name>", "Skill name to trace").option("--mode <m>", "Cognitive mode to trace (or attach to --skill per spec D12)").option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
|
|
9544
|
+
const useCase = buildUseCase(opts);
|
|
9545
|
+
if (!useCase) {
|
|
9546
|
+
logger.error("Either --skill <name> or --mode <m> is required");
|
|
9547
|
+
process.exit(ExitCode.ERROR);
|
|
9548
|
+
return;
|
|
9549
|
+
}
|
|
9550
|
+
const r = await postJson("/api/v1/routing/trace", { useCase });
|
|
9551
|
+
if (!r.ok) {
|
|
9552
|
+
if (r.status === 0) {
|
|
9553
|
+
logger.error(
|
|
9554
|
+
`Failed to reach orchestrator at ${orchestratorBase()}: ${r.error ?? "unknown error"}`
|
|
9555
|
+
);
|
|
9556
|
+
} else if (r.status === 503) {
|
|
9557
|
+
logger.error(
|
|
9558
|
+
"Routing observability not available \u2014 orchestrator has no BackendRouter (legacy single-backend config)"
|
|
8615
9559
|
);
|
|
8616
9560
|
} else {
|
|
8617
|
-
logger.error(
|
|
9561
|
+
logger.error(`Trace failed (${r.status}): ${r.error ?? ""}`);
|
|
8618
9562
|
}
|
|
8619
|
-
process.exit(
|
|
9563
|
+
process.exit(ExitCode.ERROR);
|
|
9564
|
+
return;
|
|
8620
9565
|
}
|
|
8621
|
-
|
|
8622
|
-
|
|
9566
|
+
if (opts.json) {
|
|
9567
|
+
console.log(JSON.stringify(r.body, null, 2));
|
|
9568
|
+
return;
|
|
9569
|
+
}
|
|
9570
|
+
if (r.body) renderHuman2(r.body);
|
|
8623
9571
|
});
|
|
8624
9572
|
}
|
|
8625
9573
|
|
|
8626
|
-
// src/commands/
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
|
|
8630
|
-
|
|
9574
|
+
// src/commands/routing/decisions.ts
|
|
9575
|
+
import { Command as Command81 } from "commander";
|
|
9576
|
+
function summarizeUseCase(uc) {
|
|
9577
|
+
switch (uc.kind) {
|
|
9578
|
+
case "skill":
|
|
9579
|
+
return uc.cognitiveMode ? `skill:${uc.skillName}/${uc.cognitiveMode}` : `skill:${uc.skillName}`;
|
|
9580
|
+
case "mode":
|
|
9581
|
+
return `mode:${uc.cognitiveMode}`;
|
|
9582
|
+
case "tier":
|
|
9583
|
+
return `tier:${uc.tier}`;
|
|
9584
|
+
case "intelligence":
|
|
9585
|
+
return `intelligence:${uc.layer}`;
|
|
9586
|
+
case "isolation":
|
|
9587
|
+
return `isolation:${uc.tier}`;
|
|
9588
|
+
case "maintenance":
|
|
9589
|
+
return "maintenance";
|
|
9590
|
+
case "chat":
|
|
9591
|
+
return "chat";
|
|
9592
|
+
}
|
|
9593
|
+
}
|
|
9594
|
+
function shortIso(iso) {
|
|
9595
|
+
const parts = iso.split("T");
|
|
9596
|
+
const tail = parts[1] ?? iso;
|
|
9597
|
+
return tail.replace("Z", "");
|
|
9598
|
+
}
|
|
9599
|
+
function renderHuman3(data) {
|
|
9600
|
+
if (data.decisions.length === 0) {
|
|
9601
|
+
console.log("(no decisions in buffer)");
|
|
9602
|
+
return;
|
|
9603
|
+
}
|
|
9604
|
+
console.log("TIMESTAMP USE-CASE BACKEND DURATION");
|
|
9605
|
+
for (const d of data.decisions) {
|
|
9606
|
+
const ts = shortIso(d.timestamp).padEnd(13);
|
|
9607
|
+
const uc = summarizeUseCase(d.useCase).padEnd(38);
|
|
9608
|
+
const be = d.backendName.padEnd(14);
|
|
9609
|
+
const dur = `${d.durationMs.toFixed(2)} ms`;
|
|
9610
|
+
console.log(`${ts} ${uc} ${be} ${dur}`);
|
|
9611
|
+
}
|
|
9612
|
+
}
|
|
9613
|
+
function buildQuery(opts) {
|
|
9614
|
+
const p = new URLSearchParams();
|
|
9615
|
+
if (opts.skill) p.set("skill", opts.skill);
|
|
9616
|
+
if (opts.mode) p.set("mode", opts.mode);
|
|
9617
|
+
if (opts.backend) p.set("backend", opts.backend);
|
|
9618
|
+
if (opts.last) p.set("limit", opts.last);
|
|
9619
|
+
const q = p.toString();
|
|
9620
|
+
return q ? `?${q}` : "";
|
|
9621
|
+
}
|
|
9622
|
+
function createDecisionsCommand() {
|
|
9623
|
+
return new Command81("decisions").description("List recent routing decisions from the orchestrator ring buffer (Spec B F8)").option("--skill <name>", "Filter by useCase.skillName").option("--mode <m>", "Filter by useCase.cognitiveMode").option("--backend <name>", "Filter by chosen backendName").option("--last <N>", "Limit to the N most recent decisions").option("--json", "Emit JSON to stdout instead of human-readable text").action(
|
|
9624
|
+
async (opts) => {
|
|
9625
|
+
const query = buildQuery(opts);
|
|
9626
|
+
const r = await getJson(`/api/v1/routing/decisions${query}`);
|
|
9627
|
+
if (!r.ok) {
|
|
9628
|
+
if (r.status === 0) {
|
|
9629
|
+
logger.error(
|
|
9630
|
+
`Failed to reach orchestrator at ${orchestratorBase()}: ${r.error ?? "unknown error"}`
|
|
9631
|
+
);
|
|
9632
|
+
} else if (r.status === 503) {
|
|
9633
|
+
logger.error(
|
|
9634
|
+
"Routing observability not available \u2014 orchestrator has no BackendRouter (legacy single-backend config)"
|
|
9635
|
+
);
|
|
9636
|
+
} else {
|
|
9637
|
+
logger.error(`Request failed (${r.status}): ${r.error ?? ""}`);
|
|
9638
|
+
}
|
|
9639
|
+
process.exit(ExitCode.ERROR);
|
|
9640
|
+
return;
|
|
9641
|
+
}
|
|
9642
|
+
if (opts.json) {
|
|
9643
|
+
console.log(JSON.stringify(r.body, null, 2));
|
|
9644
|
+
return;
|
|
9645
|
+
}
|
|
9646
|
+
if (r.body) renderHuman3(r.body);
|
|
9647
|
+
}
|
|
9648
|
+
);
|
|
9649
|
+
}
|
|
9650
|
+
|
|
9651
|
+
// src/commands/routing/index.ts
|
|
9652
|
+
function createRoutingCommand() {
|
|
9653
|
+
const cmd = new Command82("routing").description(
|
|
9654
|
+
"Inspect routing config, trace decisions, and read recent dispatches"
|
|
9655
|
+
);
|
|
9656
|
+
cmd.addCommand(createConfigCommand());
|
|
9657
|
+
cmd.addCommand(createTraceCommand());
|
|
9658
|
+
cmd.addCommand(createDecisionsCommand());
|
|
9659
|
+
return cmd;
|
|
8631
9660
|
}
|
|
8632
9661
|
|
|
8633
9662
|
// src/commands/scan-config.ts
|
|
8634
9663
|
init_dist3();
|
|
8635
|
-
import { Command as
|
|
9664
|
+
import { Command as Command83 } from "commander";
|
|
8636
9665
|
import { existsSync as existsSync28, readFileSync as readFileSync21, writeFileSync as writeFileSync18 } from "fs";
|
|
8637
9666
|
import { join as join41, relative as relative3 } from "path";
|
|
8638
9667
|
var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
|
|
@@ -8721,7 +9750,7 @@ function formatTextOutput(result) {
|
|
|
8721
9750
|
}
|
|
8722
9751
|
}
|
|
8723
9752
|
function createScanConfigCommand() {
|
|
8724
|
-
const command = new
|
|
9753
|
+
const command = new Command83("scan-config").description(
|
|
8725
9754
|
"Scan CLAUDE.md, AGENTS.md, .gemini/settings.json, and skill.yaml for prompt injection patterns"
|
|
8726
9755
|
).option("--path <dir>", "Target directory to scan (default: cwd)").option("--fix", "Strip high-severity patterns from files in-place").action(async (opts, cmd) => {
|
|
8727
9756
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -8739,7 +9768,7 @@ function createScanConfigCommand() {
|
|
|
8739
9768
|
|
|
8740
9769
|
// src/commands/search.ts
|
|
8741
9770
|
init_dist();
|
|
8742
|
-
import { Command as
|
|
9771
|
+
import { Command as Command84 } from "commander";
|
|
8743
9772
|
function parseFileKinds(raw) {
|
|
8744
9773
|
if (!raw) return void 0;
|
|
8745
9774
|
const set = /* @__PURE__ */ new Set();
|
|
@@ -8760,7 +9789,7 @@ function fmtBytes(n) {
|
|
|
8760
9789
|
return n.toFixed(0);
|
|
8761
9790
|
}
|
|
8762
9791
|
function createSearchCommand() {
|
|
8763
|
-
return new
|
|
9792
|
+
return new Command84("search").description("Full-text search over archived + live session content (Hermes Phase 1).").argument(
|
|
8764
9793
|
"<query>",
|
|
8765
9794
|
"FTS5 query (bare words AND-joined; quotes/AND/OR/NOT/column: for advanced syntax)"
|
|
8766
9795
|
).option("-n, --limit <n>", "Max results", "20").option("--archived-only", "Skip live sessions, only search archived ones").option("--json", "Emit JSON to stdout instead of pretty text").option(
|
|
@@ -8819,8 +9848,76 @@ function createSearchCommand() {
|
|
|
8819
9848
|
});
|
|
8820
9849
|
}
|
|
8821
9850
|
|
|
9851
|
+
// src/commands/security-craft.ts
|
|
9852
|
+
import { Command as Command85 } from "commander";
|
|
9853
|
+
function createSecurityCraftCommand() {
|
|
9854
|
+
return new Command85("security-craft").description(
|
|
9855
|
+
"LLM-judgment critique of security posture (TS/JS source). Sixth non-design craft-pipeline ceiling skill (the final sub-project). AST-driven signal detection fires only on files with security-relevant constructs; conservative confidence defaults manage the FP risk inherent in judgment-based security."
|
|
9856
|
+
).option("-f, --files <files...>", "Optional file scope (overrides discovery)").option("-p, --packages <names...>", "Restrict to specific packages under packages/").option("--max-files <n>", "Cap source-file count (default: 100)").option("--max-signals-per-file <n>", "Cap per-file signal critique (default: 10)").action(async (opts, cmd) => {
|
|
9857
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
9858
|
+
const outputMode = resolveOutputMode(globalOpts);
|
|
9859
|
+
const formatter = new OutputFormatter(outputMode);
|
|
9860
|
+
const cwd = globalOpts.cwd ?? process.cwd();
|
|
9861
|
+
const input = { path: cwd };
|
|
9862
|
+
if (opts.files !== void 0) input.files = opts.files;
|
|
9863
|
+
if (opts.packages !== void 0) input.packages = opts.packages;
|
|
9864
|
+
if (opts.maxFiles !== void 0) input.maxFiles = parseInt(opts.maxFiles, 10);
|
|
9865
|
+
if (opts.maxSignalsPerFile !== void 0)
|
|
9866
|
+
input.maxSignalsPerFile = parseInt(opts.maxSignalsPerFile, 10);
|
|
9867
|
+
let result;
|
|
9868
|
+
try {
|
|
9869
|
+
result = await runSecurityCraft(input);
|
|
9870
|
+
} catch (err) {
|
|
9871
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
9872
|
+
if (outputMode === OutputMode.JSON) {
|
|
9873
|
+
console.log(JSON.stringify({ error: message }));
|
|
9874
|
+
} else {
|
|
9875
|
+
logger.error(`security-craft failed: ${message}`);
|
|
9876
|
+
}
|
|
9877
|
+
process.exit(ExitCode.ERROR);
|
|
9878
|
+
return;
|
|
9879
|
+
}
|
|
9880
|
+
if (outputMode === OutputMode.JSON) {
|
|
9881
|
+
console.log(JSON.stringify(result, null, 2));
|
|
9882
|
+
} else {
|
|
9883
|
+
printResult5(result, outputMode, formatter);
|
|
9884
|
+
}
|
|
9885
|
+
const hasFoundational = result.findings.some((f) => f.tier === "foundational");
|
|
9886
|
+
process.exit(hasFoundational ? ExitCode.VALIDATION_FAILED : ExitCode.SUCCESS);
|
|
9887
|
+
});
|
|
9888
|
+
}
|
|
9889
|
+
function printResult5(result, mode, _formatter) {
|
|
9890
|
+
const verbose = mode === OutputMode.VERBOSE;
|
|
9891
|
+
const { findings, summary } = result;
|
|
9892
|
+
if (findings.length === 0) {
|
|
9893
|
+
console.log("No security findings.");
|
|
9894
|
+
} else {
|
|
9895
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
9896
|
+
for (const f of findings) {
|
|
9897
|
+
const list = byFile.get(f.target.file) ?? [];
|
|
9898
|
+
list.push(f);
|
|
9899
|
+
byFile.set(f.target.file, list);
|
|
9900
|
+
}
|
|
9901
|
+
for (const [file, fs47] of byFile) {
|
|
9902
|
+
console.log(`
|
|
9903
|
+
${file}`);
|
|
9904
|
+
for (const f of fs47) {
|
|
9905
|
+
console.log(
|
|
9906
|
+
` ${f.code} [${f.tier}/${f.impact}/${f.confidence}] ${f.target.signal}:${f.target.line}`
|
|
9907
|
+
);
|
|
9908
|
+
console.log(` ${f.message}`);
|
|
9909
|
+
if (verbose) console.log(` source: ${f.cite.source}`);
|
|
9910
|
+
}
|
|
9911
|
+
}
|
|
9912
|
+
}
|
|
9913
|
+
console.log("");
|
|
9914
|
+
console.log(
|
|
9915
|
+
`Summary: ${findings.length} findings across ${summary.counts.filesScanned} files (${summary.counts.filesSkippedNoSignal} skipped, ${summary.counts.signalsDetected} signals, ${summary.catalog.rubricsApplied.length} rubrics, ${summary.llmCalls.count} LLM calls, $${summary.llmCalls.costUsd.toFixed(4)}, ${summary.durationMs}ms)`
|
|
9916
|
+
);
|
|
9917
|
+
}
|
|
9918
|
+
|
|
8822
9919
|
// src/commands/setup.ts
|
|
8823
|
-
import { Command as
|
|
9920
|
+
import { Command as Command86 } from "commander";
|
|
8824
9921
|
import * as fs34 from "fs";
|
|
8825
9922
|
import * as os8 from "os";
|
|
8826
9923
|
import * as path52 from "path";
|
|
@@ -9126,7 +10223,7 @@ async function detectLegacyLayout(cwd) {
|
|
|
9126
10223
|
}
|
|
9127
10224
|
async function runInitialGraphScan(cwd) {
|
|
9128
10225
|
try {
|
|
9129
|
-
const { runScan: runScan2 } = await import("./scan-
|
|
10226
|
+
const { runScan: runScan2 } = await import("./scan-LYKLM4EQ.js");
|
|
9130
10227
|
const result = await runScan2(cwd);
|
|
9131
10228
|
return {
|
|
9132
10229
|
status: "pass",
|
|
@@ -9165,7 +10262,7 @@ async function runSetup(cwd) {
|
|
|
9165
10262
|
return { steps, success };
|
|
9166
10263
|
}
|
|
9167
10264
|
function createSetupCommand() {
|
|
9168
|
-
return new
|
|
10265
|
+
return new Command86("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
|
|
9169
10266
|
const cwd = process.cwd();
|
|
9170
10267
|
console.log("");
|
|
9171
10268
|
console.log(` ${chalk14.bold("harness setup")}`);
|
|
@@ -9188,7 +10285,7 @@ function createSetupCommand() {
|
|
|
9188
10285
|
|
|
9189
10286
|
// src/commands/share.ts
|
|
9190
10287
|
init_dist3();
|
|
9191
|
-
import { Command as
|
|
10288
|
+
import { Command as Command87 } from "commander";
|
|
9192
10289
|
import * as fs35 from "fs";
|
|
9193
10290
|
import * as path53 from "path";
|
|
9194
10291
|
import { parse as parseYaml2 } from "yaml";
|
|
@@ -9247,16 +10344,16 @@ Create a constraints.yaml in your project root to define what to share.`
|
|
|
9247
10344
|
logger.success(`Bundle written to ${outputPath}`);
|
|
9248
10345
|
}
|
|
9249
10346
|
function createShareCommand() {
|
|
9250
|
-
return new
|
|
10347
|
+
return new Command87("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) => {
|
|
9251
10348
|
await runShareAction(projectPath, options);
|
|
9252
10349
|
});
|
|
9253
10350
|
}
|
|
9254
10351
|
|
|
9255
10352
|
// src/commands/skill/index.ts
|
|
9256
|
-
import { Command as
|
|
10353
|
+
import { Command as Command95 } from "commander";
|
|
9257
10354
|
|
|
9258
10355
|
// src/commands/skill/list.ts
|
|
9259
|
-
import { Command as
|
|
10356
|
+
import { Command as Command88 } from "commander";
|
|
9260
10357
|
import * as fs36 from "fs";
|
|
9261
10358
|
import * as path54 from "path";
|
|
9262
10359
|
import { parse } from "yaml";
|
|
@@ -9359,7 +10456,7 @@ function printSkillsVerbose(skills) {
|
|
|
9359
10456
|
for (const s of skills) printSkillEntry(s);
|
|
9360
10457
|
}
|
|
9361
10458
|
function createListCommand3() {
|
|
9362
|
-
return new
|
|
10459
|
+
return new Command88("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) => {
|
|
9363
10460
|
const globalOpts = cmd.optsWithGlobals();
|
|
9364
10461
|
const skills = collectSkills({ filter: resolveFilter(opts) });
|
|
9365
10462
|
if (globalOpts.json) {
|
|
@@ -9374,7 +10471,7 @@ function createListCommand3() {
|
|
|
9374
10471
|
}
|
|
9375
10472
|
|
|
9376
10473
|
// src/commands/skill/run.ts
|
|
9377
|
-
import { Command as
|
|
10474
|
+
import { Command as Command89 } from "commander";
|
|
9378
10475
|
import * as fs37 from "fs";
|
|
9379
10476
|
import * as path55 from "path";
|
|
9380
10477
|
import { parse as parse2 } from "yaml";
|
|
@@ -9582,15 +10679,20 @@ async function runSkill(name, opts) {
|
|
|
9582
10679
|
projectPath,
|
|
9583
10680
|
!!opts.path
|
|
9584
10681
|
);
|
|
9585
|
-
|
|
10682
|
+
const overrideHint = opts.backend ? `<!-- HARNESS_BACKEND_OVERRIDE=${opts.backend} -->
|
|
10683
|
+
` : "";
|
|
10684
|
+
process.stdout.write(overrideHint + preamble + content);
|
|
9586
10685
|
process.exit(ExitCode.SUCCESS);
|
|
9587
10686
|
}
|
|
9588
10687
|
function createRunCommand3() {
|
|
9589
|
-
return new
|
|
10688
|
+
return new Command89("run").description("Run a skill (outputs SKILL.md content with context preamble)").argument("<name>", "Skill name (e.g., harness-tdd)").option("--path <path>", "Project root path for context injection").option("--complexity <level>", "Rigor level: fast, standard, thorough", "standard").option("--phase <name>", "Start at a specific phase (for re-entry)").option("--party", "Enable multi-perspective evaluation").option(
|
|
10689
|
+
"--backend <name>",
|
|
10690
|
+
"Spec B: one-shot routing override forwarded to the orchestrator as HARNESS_BACKEND_OVERRIDE"
|
|
10691
|
+
).action(async (name, opts) => runSkill(name, opts));
|
|
9590
10692
|
}
|
|
9591
10693
|
|
|
9592
10694
|
// src/commands/skill/validate.ts
|
|
9593
|
-
import { Command as
|
|
10695
|
+
import { Command as Command90 } from "commander";
|
|
9594
10696
|
import * as fs38 from "fs";
|
|
9595
10697
|
import * as path56 from "path";
|
|
9596
10698
|
import { parse as parse3 } from "yaml";
|
|
@@ -9654,7 +10756,7 @@ function validateSkillEntry(name, skillsDir, errors) {
|
|
|
9654
10756
|
}
|
|
9655
10757
|
}
|
|
9656
10758
|
function createValidateCommand2() {
|
|
9657
|
-
return new
|
|
10759
|
+
return new Command90("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
|
|
9658
10760
|
const globalOpts = cmd.optsWithGlobals();
|
|
9659
10761
|
const skillsDir = resolveSkillsDir();
|
|
9660
10762
|
if (!fs38.existsSync(skillsDir)) {
|
|
@@ -9684,7 +10786,7 @@ function createValidateCommand2() {
|
|
|
9684
10786
|
}
|
|
9685
10787
|
|
|
9686
10788
|
// src/commands/skill/info.ts
|
|
9687
|
-
import { Command as
|
|
10789
|
+
import { Command as Command91 } from "commander";
|
|
9688
10790
|
import * as fs39 from "fs";
|
|
9689
10791
|
import * as path57 from "path";
|
|
9690
10792
|
import { parse as parse4 } from "yaml";
|
|
@@ -9730,7 +10832,7 @@ function printSkillInfo(skill) {
|
|
|
9730
10832
|
console.log(`Persistent: ${skill.state.persistent}`);
|
|
9731
10833
|
}
|
|
9732
10834
|
function createInfoCommand() {
|
|
9733
|
-
return new
|
|
10835
|
+
return new Command91("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
|
|
9734
10836
|
const globalOpts = cmd.optsWithGlobals();
|
|
9735
10837
|
const loaded = loadSkillMetadata2(name);
|
|
9736
10838
|
if (!loaded.ok) {
|
|
@@ -9747,7 +10849,7 @@ function createInfoCommand() {
|
|
|
9747
10849
|
}
|
|
9748
10850
|
|
|
9749
10851
|
// src/commands/skill/search.ts
|
|
9750
|
-
import { Command as
|
|
10852
|
+
import { Command as Command92 } from "commander";
|
|
9751
10853
|
async function runSearch(query, opts) {
|
|
9752
10854
|
const results = await searchNpmRegistry(query, opts.registry);
|
|
9753
10855
|
return results.filter((r) => {
|
|
@@ -9792,13 +10894,13 @@ async function runSearchAction(query, opts, globalOpts) {
|
|
|
9792
10894
|
}
|
|
9793
10895
|
}
|
|
9794
10896
|
function createSearchCommand2() {
|
|
9795
|
-
return new
|
|
10897
|
+
return new Command92("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) => {
|
|
9796
10898
|
await runSearchAction(query, opts, cmd.optsWithGlobals());
|
|
9797
10899
|
});
|
|
9798
10900
|
}
|
|
9799
10901
|
|
|
9800
10902
|
// src/commands/skill/create.ts
|
|
9801
|
-
import { Command as
|
|
10903
|
+
import { Command as Command93 } from "commander";
|
|
9802
10904
|
import * as path58 from "path";
|
|
9803
10905
|
import * as fs40 from "fs";
|
|
9804
10906
|
import YAML from "yaml";
|
|
@@ -9918,7 +11020,7 @@ Next steps:`);
|
|
|
9918
11020
|
logger.info(` 3. Run: harness skills publish`);
|
|
9919
11021
|
}
|
|
9920
11022
|
function createCreateCommand() {
|
|
9921
|
-
return new
|
|
11023
|
+
return new Command93("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) => {
|
|
9922
11024
|
const globalOpts = cmd.optsWithGlobals();
|
|
9923
11025
|
try {
|
|
9924
11026
|
const result = runCreate(name, {
|
|
@@ -9941,7 +11043,7 @@ function createCreateCommand() {
|
|
|
9941
11043
|
}
|
|
9942
11044
|
|
|
9943
11045
|
// src/commands/skill/publish.ts
|
|
9944
|
-
import { Command as
|
|
11046
|
+
import { Command as Command94 } from "commander";
|
|
9945
11047
|
import * as fs42 from "fs";
|
|
9946
11048
|
import * as path60 from "path";
|
|
9947
11049
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
@@ -10110,7 +11212,7 @@ ${skillMdContent}`;
|
|
|
10110
11212
|
};
|
|
10111
11213
|
}
|
|
10112
11214
|
function createPublishCommand() {
|
|
10113
|
-
return new
|
|
11215
|
+
return new Command94("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) => {
|
|
10114
11216
|
const globalOpts = cmd.optsWithGlobals();
|
|
10115
11217
|
const skillDir = opts.dir || process.cwd();
|
|
10116
11218
|
try {
|
|
@@ -10135,7 +11237,7 @@ function createPublishCommand() {
|
|
|
10135
11237
|
|
|
10136
11238
|
// src/commands/skill/index.ts
|
|
10137
11239
|
function createSkillCommand() {
|
|
10138
|
-
const command = new
|
|
11240
|
+
const command = new Command95("skill").description("Skill management commands");
|
|
10139
11241
|
command.addCommand(createListCommand3());
|
|
10140
11242
|
command.addCommand(createRunCommand3());
|
|
10141
11243
|
command.addCommand(createValidateCommand2());
|
|
@@ -10148,7 +11250,7 @@ function createSkillCommand() {
|
|
|
10148
11250
|
|
|
10149
11251
|
// src/commands/snapshot.ts
|
|
10150
11252
|
init_dist3();
|
|
10151
|
-
import { Command as
|
|
11253
|
+
import { Command as Command96 } from "commander";
|
|
10152
11254
|
import { execSync as execSync5 } from "child_process";
|
|
10153
11255
|
import chalk15 from "chalk";
|
|
10154
11256
|
function getCommitHash3(cwd) {
|
|
@@ -10330,19 +11432,88 @@ function registerListCommand(parent) {
|
|
|
10330
11432
|
});
|
|
10331
11433
|
}
|
|
10332
11434
|
function createSnapshotCommand() {
|
|
10333
|
-
const command = new
|
|
11435
|
+
const command = new Command96("snapshot").description("Architecture timeline snapshot commands");
|
|
10334
11436
|
registerCaptureCommand(command);
|
|
10335
11437
|
registerTrendsCommand(command);
|
|
10336
11438
|
registerListCommand(command);
|
|
10337
11439
|
return command;
|
|
10338
11440
|
}
|
|
10339
11441
|
|
|
11442
|
+
// src/commands/spec-craft.ts
|
|
11443
|
+
import { Command as Command97 } from "commander";
|
|
11444
|
+
function createSpecCraftCommand() {
|
|
11445
|
+
return new Command97("spec-craft").description(
|
|
11446
|
+
"LLM-judgment critique of spec quality (proposals + ADRs). Second craft-pipeline ceiling skill; 7 seed rubrics from the spec-quality canon. Per-section critique."
|
|
11447
|
+
).option("-f, --files <files...>", "Optional spec file/glob scope").option("-k, --kinds <kinds...>", "Restrict to proposal / adr (default: both)").option("-s, --sections <names...>", "Restrict to specific canonical section names").option("--max-files <n>", "Cap doc count (default: 50)").option("--max-sections-per-file <n>", "Cap per-doc section critique (default: 10)").action(async (opts, cmd) => {
|
|
11448
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
11449
|
+
const outputMode = resolveOutputMode(globalOpts);
|
|
11450
|
+
const formatter = new OutputFormatter(outputMode);
|
|
11451
|
+
const cwd = globalOpts.cwd ?? process.cwd();
|
|
11452
|
+
const input = { path: cwd };
|
|
11453
|
+
if (opts.files !== void 0) input.files = opts.files;
|
|
11454
|
+
if (opts.kinds !== void 0) input.kinds = opts.kinds;
|
|
11455
|
+
if (opts.sections !== void 0) input.sections = opts.sections;
|
|
11456
|
+
if (opts.maxFiles !== void 0) input.maxFiles = parseInt(opts.maxFiles, 10);
|
|
11457
|
+
if (opts.maxSectionsPerFile !== void 0)
|
|
11458
|
+
input.maxSectionsPerFile = parseInt(opts.maxSectionsPerFile, 10);
|
|
11459
|
+
let result;
|
|
11460
|
+
try {
|
|
11461
|
+
result = await runSpecCraft(input);
|
|
11462
|
+
} catch (err) {
|
|
11463
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11464
|
+
if (outputMode === OutputMode.JSON) {
|
|
11465
|
+
console.log(JSON.stringify({ error: message }));
|
|
11466
|
+
} else {
|
|
11467
|
+
logger.error(`spec-craft failed: ${message}`);
|
|
11468
|
+
}
|
|
11469
|
+
process.exit(ExitCode.ERROR);
|
|
11470
|
+
return;
|
|
11471
|
+
}
|
|
11472
|
+
if (outputMode === OutputMode.JSON) {
|
|
11473
|
+
console.log(JSON.stringify(result, null, 2));
|
|
11474
|
+
} else {
|
|
11475
|
+
printResult6(result, outputMode, formatter);
|
|
11476
|
+
}
|
|
11477
|
+
const hasFoundational = result.findings.some((f) => f.tier === "foundational");
|
|
11478
|
+
process.exit(hasFoundational ? ExitCode.VALIDATION_FAILED : ExitCode.SUCCESS);
|
|
11479
|
+
});
|
|
11480
|
+
}
|
|
11481
|
+
function printResult6(result, mode, _formatter) {
|
|
11482
|
+
const verbose = mode === OutputMode.VERBOSE;
|
|
11483
|
+
const { findings, summary } = result;
|
|
11484
|
+
if (findings.length === 0) {
|
|
11485
|
+
console.log("No spec findings.");
|
|
11486
|
+
} else {
|
|
11487
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
11488
|
+
for (const f of findings) {
|
|
11489
|
+
const list = byFile.get(f.target.file) ?? [];
|
|
11490
|
+
list.push(f);
|
|
11491
|
+
byFile.set(f.target.file, list);
|
|
11492
|
+
}
|
|
11493
|
+
for (const [file, fs47] of byFile) {
|
|
11494
|
+
console.log(`
|
|
11495
|
+
${file}`);
|
|
11496
|
+
for (const f of fs47) {
|
|
11497
|
+
console.log(
|
|
11498
|
+
` ${f.code} [${f.tier}/${f.impact}/${f.confidence}] ## ${f.target.section}:${f.target.line}`
|
|
11499
|
+
);
|
|
11500
|
+
console.log(` ${f.message}`);
|
|
11501
|
+
if (verbose) console.log(` source: ${f.cite.source}`);
|
|
11502
|
+
}
|
|
11503
|
+
}
|
|
11504
|
+
}
|
|
11505
|
+
console.log("");
|
|
11506
|
+
console.log(
|
|
11507
|
+
`Summary: ${findings.length} findings across ${summary.docsScanned} docs (${summary.sectionsScanned} sections, ${summary.catalog.rubricsApplied.length} rubrics, ${summary.llmCalls.count} LLM calls, $${summary.llmCalls.costUsd.toFixed(4)}, ${summary.durationMs}ms)`
|
|
11508
|
+
);
|
|
11509
|
+
}
|
|
11510
|
+
|
|
10340
11511
|
// src/commands/state/index.ts
|
|
10341
|
-
import { Command as
|
|
11512
|
+
import { Command as Command102 } from "commander";
|
|
10342
11513
|
|
|
10343
11514
|
// src/commands/state/show.ts
|
|
10344
11515
|
init_dist3();
|
|
10345
|
-
import { Command as
|
|
11516
|
+
import { Command as Command98 } from "commander";
|
|
10346
11517
|
import * as path61 from "path";
|
|
10347
11518
|
function printStateText(state, stream) {
|
|
10348
11519
|
if (stream) console.log(`Stream: ${stream}`);
|
|
@@ -10367,7 +11538,7 @@ function printStateProgress(progress) {
|
|
|
10367
11538
|
}
|
|
10368
11539
|
}
|
|
10369
11540
|
function createShowCommand() {
|
|
10370
|
-
return new
|
|
11541
|
+
return new Command98("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
|
|
10371
11542
|
const globalOpts = cmd.optsWithGlobals();
|
|
10372
11543
|
const result = await loadState(path61.resolve(opts.path), opts.stream);
|
|
10373
11544
|
if (!result.ok) {
|
|
@@ -10385,7 +11556,7 @@ function createShowCommand() {
|
|
|
10385
11556
|
|
|
10386
11557
|
// src/commands/state/reset.ts
|
|
10387
11558
|
init_dist3();
|
|
10388
|
-
import { Command as
|
|
11559
|
+
import { Command as Command99 } from "commander";
|
|
10389
11560
|
import * as fs43 from "fs";
|
|
10390
11561
|
import * as path62 from "path";
|
|
10391
11562
|
import * as readline3 from "readline";
|
|
@@ -10429,15 +11600,15 @@ async function runReset(opts) {
|
|
|
10429
11600
|
process.exit(ExitCode.SUCCESS);
|
|
10430
11601
|
}
|
|
10431
11602
|
function createResetCommand() {
|
|
10432
|
-
return new
|
|
11603
|
+
return new Command99("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));
|
|
10433
11604
|
}
|
|
10434
11605
|
|
|
10435
11606
|
// src/commands/state/learn.ts
|
|
10436
11607
|
init_dist3();
|
|
10437
|
-
import { Command as
|
|
11608
|
+
import { Command as Command100 } from "commander";
|
|
10438
11609
|
import * as path63 from "path";
|
|
10439
11610
|
function createLearnCommand() {
|
|
10440
|
-
return new
|
|
11611
|
+
return new Command100("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) => {
|
|
10441
11612
|
const projectPath = path63.resolve(opts.path);
|
|
10442
11613
|
const result = await appendLearning(projectPath, message, void 0, void 0, opts.stream);
|
|
10443
11614
|
if (!result.ok) {
|
|
@@ -10452,7 +11623,7 @@ function createLearnCommand() {
|
|
|
10452
11623
|
|
|
10453
11624
|
// src/commands/state/streams.ts
|
|
10454
11625
|
init_dist3();
|
|
10455
|
-
import { Command as
|
|
11626
|
+
import { Command as Command101 } from "commander";
|
|
10456
11627
|
import * as path64 from "path";
|
|
10457
11628
|
async function runListStreams(opts, globalOpts) {
|
|
10458
11629
|
const projectPath = path64.resolve(opts.path);
|
|
@@ -10503,7 +11674,7 @@ async function runActivateStream(name, opts) {
|
|
|
10503
11674
|
process.exit(ExitCode.SUCCESS);
|
|
10504
11675
|
}
|
|
10505
11676
|
function createStreamsCommand() {
|
|
10506
|
-
const command = new
|
|
11677
|
+
const command = new Command101("streams").description("Manage state streams");
|
|
10507
11678
|
command.command("list").description("List all known streams").option("--path <path>", "Project root path", ".").action(async (opts, cmd) => runListStreams(opts, cmd.optsWithGlobals()));
|
|
10508
11679
|
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));
|
|
10509
11680
|
command.command("archive <name>").description("Archive a stream").option("--path <path>", "Project root path", ".").action(async (name, opts) => runArchiveStream(name, opts));
|
|
@@ -10513,7 +11684,7 @@ function createStreamsCommand() {
|
|
|
10513
11684
|
|
|
10514
11685
|
// src/commands/state/index.ts
|
|
10515
11686
|
function createStateCommand() {
|
|
10516
|
-
const command = new
|
|
11687
|
+
const command = new Command102("state").description("Project state management commands");
|
|
10517
11688
|
command.addCommand(createShowCommand());
|
|
10518
11689
|
command.addCommand(createResetCommand());
|
|
10519
11690
|
command.addCommand(createLearnCommand());
|
|
@@ -10524,7 +11695,7 @@ function createStateCommand() {
|
|
|
10524
11695
|
// src/commands/sync-analyses.ts
|
|
10525
11696
|
import * as fs44 from "fs";
|
|
10526
11697
|
import * as path65 from "path";
|
|
10527
|
-
import { Command as
|
|
11698
|
+
import { Command as Command103 } from "commander";
|
|
10528
11699
|
init_dist3();
|
|
10529
11700
|
function isValidRecord(record) {
|
|
10530
11701
|
return typeof record.issueId === "string" && !!record.issueId && typeof record.identifier === "string" && !!record.identifier && typeof record.analyzedAt === "string" && !/[/\\]/.test(record.issueId);
|
|
@@ -10650,7 +11821,7 @@ async function runSyncAnalyses(opts) {
|
|
|
10650
11821
|
return;
|
|
10651
11822
|
}
|
|
10652
11823
|
const { AnalysisArchive, loadPublishedIndex: loadPublishedIndex2, savePublishedIndex: savePublishedIndex2 } = await import("@harness-engineering/orchestrator");
|
|
10653
|
-
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-
|
|
11824
|
+
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-XIJWWQ5N.js");
|
|
10654
11825
|
const adapter = new GitHubIssuesSyncAdapter2({ token, config: trackerConfig });
|
|
10655
11826
|
const archive = new AnalysisArchive(path65.join(projectPath, ".harness", "analyses"));
|
|
10656
11827
|
const publishedIndex = loadPublishedIndex2(projectPath);
|
|
@@ -10672,7 +11843,7 @@ async function runSyncAnalyses(opts) {
|
|
|
10672
11843
|
}
|
|
10673
11844
|
}
|
|
10674
11845
|
function createSyncAnalysesCommand() {
|
|
10675
|
-
const command = new
|
|
11846
|
+
const command = new Command103("sync-analyses").description(
|
|
10676
11847
|
"Pull published intelligence analyses from the external issue tracker into the local .harness/analyses/ directory"
|
|
10677
11848
|
).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
10678
11849
|
try {
|
|
@@ -10686,7 +11857,7 @@ function createSyncAnalysesCommand() {
|
|
|
10686
11857
|
}
|
|
10687
11858
|
|
|
10688
11859
|
// src/commands/sync-main.ts
|
|
10689
|
-
import { Command as
|
|
11860
|
+
import { Command as Command104 } from "commander";
|
|
10690
11861
|
import * as path66 from "path";
|
|
10691
11862
|
import {
|
|
10692
11863
|
syncMain as defaultSyncMain
|
|
@@ -10717,7 +11888,7 @@ function formatHuman2(r) {
|
|
|
10717
11888
|
}
|
|
10718
11889
|
}
|
|
10719
11890
|
function createSyncMainCommand() {
|
|
10720
|
-
return new
|
|
11891
|
+
return new Command104("sync-main").description("Fast-forward the local default branch from origin (no-op on conflict)").option("--json", "Emit a SyncMainResult JSON object", false).option("--path <path>", "Project root path", ".").action(async (opts) => {
|
|
10721
11892
|
const cwd = path66.resolve(opts.path ?? ".");
|
|
10722
11893
|
const exitCode = await runSyncMain({ cwd, json: Boolean(opts.json) });
|
|
10723
11894
|
process.exit(exitCode);
|
|
@@ -10726,7 +11897,7 @@ function createSyncMainCommand() {
|
|
|
10726
11897
|
|
|
10727
11898
|
// src/commands/taint.ts
|
|
10728
11899
|
init_dist3();
|
|
10729
|
-
import { Command as
|
|
11900
|
+
import { Command as Command105 } from "commander";
|
|
10730
11901
|
function getProjectRoot() {
|
|
10731
11902
|
return process.cwd();
|
|
10732
11903
|
}
|
|
@@ -10798,18 +11969,18 @@ function registerStatusCommand(taint) {
|
|
|
10798
11969
|
});
|
|
10799
11970
|
}
|
|
10800
11971
|
function createTaintCommand() {
|
|
10801
|
-
const taint = new
|
|
11972
|
+
const taint = new Command105("taint").description("Manage sentinel session taint state");
|
|
10802
11973
|
registerClearCommand(taint);
|
|
10803
11974
|
registerStatusCommand(taint);
|
|
10804
11975
|
return taint;
|
|
10805
11976
|
}
|
|
10806
11977
|
|
|
10807
11978
|
// src/commands/telemetry/index.ts
|
|
10808
|
-
import { Command as
|
|
11979
|
+
import { Command as Command109 } from "commander";
|
|
10809
11980
|
|
|
10810
11981
|
// src/commands/telemetry/identify.ts
|
|
10811
11982
|
init_dist3();
|
|
10812
|
-
import { Command as
|
|
11983
|
+
import { Command as Command106 } from "commander";
|
|
10813
11984
|
import * as fs45 from "fs";
|
|
10814
11985
|
import * as path67 from "path";
|
|
10815
11986
|
function telemetryFilePath(cwd) {
|
|
@@ -10833,7 +12004,7 @@ function printIdentity(identity) {
|
|
|
10833
12004
|
}
|
|
10834
12005
|
}
|
|
10835
12006
|
function createIdentifyCommand() {
|
|
10836
|
-
const cmd = new
|
|
12007
|
+
const cmd = new Command106("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) => {
|
|
10837
12008
|
const cwd = process.cwd();
|
|
10838
12009
|
if (opts.clear) {
|
|
10839
12010
|
writeTelemetryFile(cwd, { identity: {} });
|
|
@@ -10858,7 +12029,7 @@ function createIdentifyCommand() {
|
|
|
10858
12029
|
|
|
10859
12030
|
// src/commands/telemetry/status.ts
|
|
10860
12031
|
init_dist3();
|
|
10861
|
-
import { Command as
|
|
12032
|
+
import { Command as Command107 } from "commander";
|
|
10862
12033
|
function gatherEnvOverrides() {
|
|
10863
12034
|
const overrides = {};
|
|
10864
12035
|
if (process.env.DO_NOT_TRACK) overrides.DO_NOT_TRACK = process.env.DO_NOT_TRACK;
|
|
@@ -10900,7 +12071,7 @@ function printHumanStatus(result) {
|
|
|
10900
12071
|
printEnvOverrides(result.envOverrides);
|
|
10901
12072
|
}
|
|
10902
12073
|
function createStatusCommand() {
|
|
10903
|
-
const cmd = new
|
|
12074
|
+
const cmd = new Command107("status").description("Show current telemetry consent state, install ID, and identity").option("--json", "Output as JSON").action((opts) => {
|
|
10904
12075
|
const cwd = process.cwd();
|
|
10905
12076
|
const envOverrides = gatherEnvOverrides();
|
|
10906
12077
|
const consent = resolveConsent(cwd, void 0);
|
|
@@ -10933,7 +12104,7 @@ function createStatusCommand() {
|
|
|
10933
12104
|
|
|
10934
12105
|
// src/commands/telemetry/test.ts
|
|
10935
12106
|
init_dist3();
|
|
10936
|
-
import { Command as
|
|
12107
|
+
import { Command as Command108 } from "commander";
|
|
10937
12108
|
|
|
10938
12109
|
// src/bin/command-telemetry.ts
|
|
10939
12110
|
import { existsSync as existsSync42, readFileSync as readFileSync32, mkdirSync as mkdirSync19, appendFileSync, writeFileSync as writeFileSync24 } from "fs";
|
|
@@ -11055,7 +12226,7 @@ function reportTestSuccess(status, distinctId, identity) {
|
|
|
11055
12226
|
if (identity.team) logger.info(` team: ${identity.team}`);
|
|
11056
12227
|
}
|
|
11057
12228
|
function createTestCommand() {
|
|
11058
|
-
return new
|
|
12229
|
+
return new Command108("test").description("Send a test event to PostHog and verify connectivity").action(async () => {
|
|
11059
12230
|
const cwd = process.cwd();
|
|
11060
12231
|
const consent = resolveConsent(cwd, void 0);
|
|
11061
12232
|
if (!consent.allowed) {
|
|
@@ -11092,15 +12263,87 @@ function createTestCommand() {
|
|
|
11092
12263
|
|
|
11093
12264
|
// src/commands/telemetry/index.ts
|
|
11094
12265
|
function createTelemetryCommand() {
|
|
11095
|
-
const command = new
|
|
12266
|
+
const command = new Command109("telemetry").description("Telemetry identity and status management");
|
|
11096
12267
|
command.addCommand(createIdentifyCommand());
|
|
11097
12268
|
command.addCommand(createStatusCommand());
|
|
11098
12269
|
command.addCommand(createTestCommand());
|
|
11099
12270
|
return command;
|
|
11100
12271
|
}
|
|
11101
12272
|
|
|
12273
|
+
// src/commands/test-craft.ts
|
|
12274
|
+
import { Command as Command110 } from "commander";
|
|
12275
|
+
function createTestCraftCommand() {
|
|
12276
|
+
return new Command110("test-craft").description(
|
|
12277
|
+
"LLM-judgment critique of test quality across vitest/jest/mocha/playwright. Fourth craft-pipeline ceiling skill. Per-test critique with best-effort source pairing."
|
|
12278
|
+
).option("-f, --files <files...>", "Optional test file/glob scope").option("--frameworks <names...>", "Restrict to: vitest / jest / mocha / playwright").option("--max-files <n>", "Cap test file count (default: 100)").option("--max-tests-per-file <n>", "Cap per-file test critique (default: 20)").option("--no-source-pair", "Skip source-pairing resolution").action(async (opts, cmd) => {
|
|
12279
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
12280
|
+
const outputMode = resolveOutputMode(globalOpts);
|
|
12281
|
+
const formatter = new OutputFormatter(outputMode);
|
|
12282
|
+
const cwd = globalOpts.cwd ?? process.cwd();
|
|
12283
|
+
const input = { path: cwd };
|
|
12284
|
+
if (opts.files !== void 0) input.files = opts.files;
|
|
12285
|
+
if (opts.frameworks !== void 0) input.frameworks = opts.frameworks;
|
|
12286
|
+
if (opts.maxFiles !== void 0) input.maxFiles = parseInt(opts.maxFiles, 10);
|
|
12287
|
+
if (opts.maxTestsPerFile !== void 0)
|
|
12288
|
+
input.maxTestsPerFile = parseInt(opts.maxTestsPerFile, 10);
|
|
12289
|
+
if (opts.noSourcePair === true) input.sourcePair = false;
|
|
12290
|
+
let result;
|
|
12291
|
+
try {
|
|
12292
|
+
result = await runTestCraft(input);
|
|
12293
|
+
} catch (err) {
|
|
12294
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12295
|
+
if (outputMode === OutputMode.JSON) {
|
|
12296
|
+
console.log(JSON.stringify({ error: message }));
|
|
12297
|
+
} else {
|
|
12298
|
+
logger.error(`test-craft failed: ${message}`);
|
|
12299
|
+
}
|
|
12300
|
+
process.exit(ExitCode.ERROR);
|
|
12301
|
+
return;
|
|
12302
|
+
}
|
|
12303
|
+
if (outputMode === OutputMode.JSON) {
|
|
12304
|
+
console.log(JSON.stringify(result, null, 2));
|
|
12305
|
+
} else {
|
|
12306
|
+
printResult7(result, outputMode, formatter);
|
|
12307
|
+
}
|
|
12308
|
+
const hasFoundational = result.findings.some((f) => f.tier === "foundational");
|
|
12309
|
+
process.exit(hasFoundational ? ExitCode.VALIDATION_FAILED : ExitCode.SUCCESS);
|
|
12310
|
+
});
|
|
12311
|
+
}
|
|
12312
|
+
function printResult7(result, mode, _formatter) {
|
|
12313
|
+
const verbose = mode === OutputMode.VERBOSE;
|
|
12314
|
+
const { findings, summary } = result;
|
|
12315
|
+
if (findings.length === 0) {
|
|
12316
|
+
console.log("No test findings.");
|
|
12317
|
+
} else {
|
|
12318
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
12319
|
+
for (const f of findings) {
|
|
12320
|
+
const list = byFile.get(f.target.file) ?? [];
|
|
12321
|
+
list.push(f);
|
|
12322
|
+
byFile.set(f.target.file, list);
|
|
12323
|
+
}
|
|
12324
|
+
for (const [file, fs47] of byFile) {
|
|
12325
|
+
console.log(`
|
|
12326
|
+
${file}`);
|
|
12327
|
+
for (const f of fs47) {
|
|
12328
|
+
const nestingStr = f.target.nesting.length > 0 ? f.target.nesting.join(" > ") + " > " : "";
|
|
12329
|
+
console.log(
|
|
12330
|
+
` ${f.code} [${f.tier}/${f.impact}/${f.confidence}] ${f.target.framework}:${f.target.line}`
|
|
12331
|
+
);
|
|
12332
|
+
console.log(` ${nestingStr}${f.target.testName}`);
|
|
12333
|
+
console.log(` ${f.message}`);
|
|
12334
|
+
if (verbose) console.log(` source: ${f.cite.source}`);
|
|
12335
|
+
}
|
|
12336
|
+
}
|
|
12337
|
+
}
|
|
12338
|
+
console.log("");
|
|
12339
|
+
const frameworksStr = Object.entries(summary.frameworksDetected).filter(([, n]) => n > 0).map(([k, n]) => `${k}=${n}`).join(", ");
|
|
12340
|
+
console.log(
|
|
12341
|
+
`Summary: ${findings.length} findings across ${summary.counts.testsExtracted} tests (${summary.counts.filesScanned} files, frameworks: ${frameworksStr || "none"}, paired: ${summary.counts.sourcePaired}, ${summary.llmCalls.count} LLM calls, $${summary.llmCalls.costUsd.toFixed(4)}, ${summary.durationMs}ms)`
|
|
12342
|
+
);
|
|
12343
|
+
}
|
|
12344
|
+
|
|
11102
12345
|
// src/commands/traceability.ts
|
|
11103
|
-
import { Command as
|
|
12346
|
+
import { Command as Command111 } from "commander";
|
|
11104
12347
|
import chalk16 from "chalk";
|
|
11105
12348
|
function confidenceLabel(maxConfidence) {
|
|
11106
12349
|
if (maxConfidence >= 0.8) return "explicit";
|
|
@@ -11121,7 +12364,7 @@ function statusIcon(status) {
|
|
|
11121
12364
|
return status;
|
|
11122
12365
|
}
|
|
11123
12366
|
}
|
|
11124
|
-
function
|
|
12367
|
+
function truncate2(str, max) {
|
|
11125
12368
|
if (str.length <= max) return str;
|
|
11126
12369
|
return str.slice(0, max - 3) + "...";
|
|
11127
12370
|
}
|
|
@@ -11189,7 +12432,7 @@ function printRequirementRows(requirements, mode, cols) {
|
|
|
11189
12432
|
const { numWidth, nameWidth, codeWidth, testWidth, confWidth } = cols;
|
|
11190
12433
|
for (const req of requirements) {
|
|
11191
12434
|
const num = `${req.index}.`;
|
|
11192
|
-
const name =
|
|
12435
|
+
const name = truncate2(req.requirementName, nameWidth - 2);
|
|
11193
12436
|
const code = String(req.codeFiles.length);
|
|
11194
12437
|
const tests = String(req.testFiles.length);
|
|
11195
12438
|
const conf = confidenceLabel(req.maxConfidence);
|
|
@@ -11221,7 +12464,7 @@ async function runTraceability(options) {
|
|
|
11221
12464
|
const projectPath = process.cwd();
|
|
11222
12465
|
const store = await loadGraphStore(projectPath);
|
|
11223
12466
|
if (!store) handleNoStore(mode);
|
|
11224
|
-
const graphModule = await import("./dist-
|
|
12467
|
+
const graphModule = await import("./dist-R3TOOPJ7.js");
|
|
11225
12468
|
const filterOptions = buildFilterOptions(options);
|
|
11226
12469
|
const results = graphModule.queryTraceability(store, filterOptions);
|
|
11227
12470
|
if (results.length === 0) handleEmptyResults(mode);
|
|
@@ -11236,7 +12479,7 @@ async function runTraceability(options) {
|
|
|
11236
12479
|
process.exit(ExitCode.SUCCESS);
|
|
11237
12480
|
}
|
|
11238
12481
|
function createTraceabilityCommand() {
|
|
11239
|
-
return new
|
|
12482
|
+
return new Command111("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) => {
|
|
11240
12483
|
const globalOpts = cmd.optsWithGlobals();
|
|
11241
12484
|
await runTraceability({
|
|
11242
12485
|
spec: opts.spec,
|
|
@@ -11250,7 +12493,7 @@ function createTraceabilityCommand() {
|
|
|
11250
12493
|
|
|
11251
12494
|
// src/commands/uninstall.ts
|
|
11252
12495
|
import * as path68 from "path";
|
|
11253
|
-
import { Command as
|
|
12496
|
+
import { Command as Command112 } from "commander";
|
|
11254
12497
|
async function runUninstall(skillName, options) {
|
|
11255
12498
|
const packageName = resolvePackageName(skillName);
|
|
11256
12499
|
const shortName = extractSkillName(packageName);
|
|
@@ -11287,7 +12530,7 @@ async function runUninstall(skillName, options) {
|
|
|
11287
12530
|
return result;
|
|
11288
12531
|
}
|
|
11289
12532
|
function createUninstallCommand() {
|
|
11290
|
-
const cmd = new
|
|
12533
|
+
const cmd = new Command112("uninstall");
|
|
11291
12534
|
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) => {
|
|
11292
12535
|
try {
|
|
11293
12536
|
const result = await runUninstall(skill, opts);
|
|
@@ -11309,7 +12552,7 @@ function createUninstallCommand() {
|
|
|
11309
12552
|
init_dist3();
|
|
11310
12553
|
import * as fs46 from "fs/promises";
|
|
11311
12554
|
import * as path69 from "path";
|
|
11312
|
-
import { Command as
|
|
12555
|
+
import { Command as Command113 } from "commander";
|
|
11313
12556
|
async function runUninstallConstraints(options) {
|
|
11314
12557
|
const { packageName, configPath, lockfilePath } = options;
|
|
11315
12558
|
const lockfileResult = await readLockfile(lockfilePath);
|
|
@@ -11366,7 +12609,7 @@ async function runUninstallConstraints(options) {
|
|
|
11366
12609
|
};
|
|
11367
12610
|
}
|
|
11368
12611
|
function createUninstallConstraintsCommand() {
|
|
11369
|
-
const cmd = new
|
|
12612
|
+
const cmd = new Command113("uninstall-constraints");
|
|
11370
12613
|
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) => {
|
|
11371
12614
|
let configPath;
|
|
11372
12615
|
if (opts.config) {
|
|
@@ -11406,7 +12649,7 @@ function createUninstallConstraintsCommand() {
|
|
|
11406
12649
|
|
|
11407
12650
|
// src/commands/update.ts
|
|
11408
12651
|
init_dist3();
|
|
11409
|
-
import { Command as
|
|
12652
|
+
import { Command as Command114 } from "commander";
|
|
11410
12653
|
import { execFile, execFileSync as execFileSync7 } from "child_process";
|
|
11411
12654
|
import { realpathSync, existsSync as existsSync43, readFileSync as readFileSync33 } from "fs";
|
|
11412
12655
|
import { dirname as dirname22, join as join59 } from "path";
|
|
@@ -11774,7 +13017,7 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
11774
13017
|
process.exit(ExitCode.SUCCESS);
|
|
11775
13018
|
}
|
|
11776
13019
|
function createUpdateCommand() {
|
|
11777
|
-
return new
|
|
13020
|
+
return new Command114("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(
|
|
11778
13021
|
"--regenerate",
|
|
11779
13022
|
"Only regenerate slash commands and agent definitions (skip package updates)"
|
|
11780
13023
|
).action(async (opts, cmd) => {
|
|
@@ -11784,9 +13027,9 @@ function createUpdateCommand() {
|
|
|
11784
13027
|
}
|
|
11785
13028
|
|
|
11786
13029
|
// src/commands/usage.ts
|
|
11787
|
-
import { Command as
|
|
13030
|
+
import { Command as Command115 } from "commander";
|
|
11788
13031
|
async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
|
|
11789
|
-
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-
|
|
13032
|
+
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-XIJWWQ5N.js");
|
|
11790
13033
|
const records = readCostRecords(cwd);
|
|
11791
13034
|
if (includeClaudeSessions) {
|
|
11792
13035
|
const ccRecords = parseCCRecords();
|
|
@@ -11879,7 +13122,7 @@ function registerDailyCommand(usage) {
|
|
|
11879
13122
|
else logger.info("No usage data found. Run some harness sessions first.");
|
|
11880
13123
|
return;
|
|
11881
13124
|
}
|
|
11882
|
-
const { aggregateByDay } = await import("./dist-
|
|
13125
|
+
const { aggregateByDay } = await import("./dist-XIJWWQ5N.js");
|
|
11883
13126
|
const limited = aggregateByDay(records).slice(0, days);
|
|
11884
13127
|
if (globalOpts.json) {
|
|
11885
13128
|
console.log(
|
|
@@ -11908,7 +13151,7 @@ function registerSessionsCommand(usage) {
|
|
|
11908
13151
|
}
|
|
11909
13152
|
return;
|
|
11910
13153
|
}
|
|
11911
|
-
const { aggregateBySession } = await import("./dist-
|
|
13154
|
+
const { aggregateBySession } = await import("./dist-XIJWWQ5N.js");
|
|
11912
13155
|
const sessionData = aggregateBySession(records);
|
|
11913
13156
|
const limited = sessionData.slice(0, limit);
|
|
11914
13157
|
if (globalOpts.json) {
|
|
@@ -11988,7 +13231,7 @@ function registerSessionCommand(usage) {
|
|
|
11988
13231
|
cwd,
|
|
11989
13232
|
globalOpts.includeClaudeSessions
|
|
11990
13233
|
);
|
|
11991
|
-
const { aggregateBySession } = await import("./dist-
|
|
13234
|
+
const { aggregateBySession } = await import("./dist-XIJWWQ5N.js");
|
|
11992
13235
|
const sessionData = aggregateBySession(records);
|
|
11993
13236
|
const match = sessionData.find((s) => s.sessionId === id);
|
|
11994
13237
|
if (!match) {
|
|
@@ -12023,7 +13266,7 @@ function registerLatestCommand(usage) {
|
|
|
12023
13266
|
}
|
|
12024
13267
|
return;
|
|
12025
13268
|
}
|
|
12026
|
-
const { aggregateBySession } = await import("./dist-
|
|
13269
|
+
const { aggregateBySession } = await import("./dist-XIJWWQ5N.js");
|
|
12027
13270
|
const sessionData = aggregateBySession(records);
|
|
12028
13271
|
const latest = sessionData[0];
|
|
12029
13272
|
if (!latest) {
|
|
@@ -12049,7 +13292,7 @@ function registerLatestCommand(usage) {
|
|
|
12049
13292
|
});
|
|
12050
13293
|
}
|
|
12051
13294
|
function createUsageCommand() {
|
|
12052
|
-
const usage = new
|
|
13295
|
+
const usage = new Command115("usage").description("Token usage and cost tracking");
|
|
12053
13296
|
usage.option(
|
|
12054
13297
|
"--include-claude-sessions",
|
|
12055
13298
|
"Include Claude Code session data from ~/.claude/projects/"
|
|
@@ -12064,7 +13307,7 @@ function createUsageCommand() {
|
|
|
12064
13307
|
// src/commands/validate.ts
|
|
12065
13308
|
init_dist3();
|
|
12066
13309
|
init_dist3();
|
|
12067
|
-
import { Command as
|
|
13310
|
+
import { Command as Command116 } from "commander";
|
|
12068
13311
|
import * as path70 from "path";
|
|
12069
13312
|
async function runValidate(options) {
|
|
12070
13313
|
const configResult = resolveConfig(options.configPath);
|
|
@@ -12163,6 +13406,102 @@ async function runValidate(options) {
|
|
|
12163
13406
|
}
|
|
12164
13407
|
});
|
|
12165
13408
|
}
|
|
13409
|
+
const anatomyEnabled = config.design?.audit?.componentAnatomy?.enabled !== false;
|
|
13410
|
+
if (anatomyEnabled) {
|
|
13411
|
+
try {
|
|
13412
|
+
const strictness = config.design?.strictness ?? "standard";
|
|
13413
|
+
const auditOutput = await runAudit({
|
|
13414
|
+
path: cwd,
|
|
13415
|
+
mode: "fast",
|
|
13416
|
+
designStrictness: strictness
|
|
13417
|
+
});
|
|
13418
|
+
result.checks.componentAnatomy = true;
|
|
13419
|
+
for (const finding of auditOutput.findings) {
|
|
13420
|
+
const severity = finding.severity === "warn" ? "warning" : finding.severity;
|
|
13421
|
+
if (severity === "error") result.valid = false;
|
|
13422
|
+
result.issues.push({
|
|
13423
|
+
check: "componentAnatomy",
|
|
13424
|
+
file: finding.file,
|
|
13425
|
+
...finding.line !== null && finding.line !== void 0 && { line: finding.line },
|
|
13426
|
+
ruleId: finding.code,
|
|
13427
|
+
severity,
|
|
13428
|
+
message: finding.message,
|
|
13429
|
+
suggestion: finding.fix.description
|
|
13430
|
+
});
|
|
13431
|
+
}
|
|
13432
|
+
} catch (err) {
|
|
13433
|
+
result.checks.componentAnatomy = false;
|
|
13434
|
+
result.issues.push({
|
|
13435
|
+
check: "componentAnatomy",
|
|
13436
|
+
severity: "warning",
|
|
13437
|
+
message: `Component-anatomy audit skipped: ${err.message}`
|
|
13438
|
+
});
|
|
13439
|
+
}
|
|
13440
|
+
}
|
|
13441
|
+
const driftEnabled = config.design?.audit?.driftDetection?.enabled !== false;
|
|
13442
|
+
if (driftEnabled) {
|
|
13443
|
+
try {
|
|
13444
|
+
const strictness = config.design?.strictness ?? "standard";
|
|
13445
|
+
const driftOutput = await runDetectDrift({
|
|
13446
|
+
path: cwd,
|
|
13447
|
+
mode: "fast",
|
|
13448
|
+
designStrictness: strictness
|
|
13449
|
+
});
|
|
13450
|
+
result.checks.driftDetection = true;
|
|
13451
|
+
for (const finding of driftOutput.findings) {
|
|
13452
|
+
const severity = finding.severity === "warn" ? "warning" : finding.severity;
|
|
13453
|
+
if (severity === "error") result.valid = false;
|
|
13454
|
+
result.issues.push({
|
|
13455
|
+
check: "driftDetection",
|
|
13456
|
+
file: finding.file,
|
|
13457
|
+
...finding.line !== null && finding.line !== void 0 && { line: finding.line },
|
|
13458
|
+
ruleId: finding.code,
|
|
13459
|
+
severity,
|
|
13460
|
+
message: finding.message,
|
|
13461
|
+
suggestion: finding.fix.description
|
|
13462
|
+
});
|
|
13463
|
+
}
|
|
13464
|
+
} catch (err) {
|
|
13465
|
+
result.checks.driftDetection = false;
|
|
13466
|
+
result.issues.push({
|
|
13467
|
+
check: "driftDetection",
|
|
13468
|
+
severity: "warning",
|
|
13469
|
+
message: `Drift detection skipped: ${err.message}`
|
|
13470
|
+
});
|
|
13471
|
+
}
|
|
13472
|
+
}
|
|
13473
|
+
const brandEnabled = config.design?.audit?.brandCompliance?.enabled !== false;
|
|
13474
|
+
if (brandEnabled) {
|
|
13475
|
+
try {
|
|
13476
|
+
const strictness = config.design?.strictness ?? "standard";
|
|
13477
|
+
const brandOutput = await runAuditBrand({
|
|
13478
|
+
path: cwd,
|
|
13479
|
+
mode: "fast",
|
|
13480
|
+
designStrictness: strictness
|
|
13481
|
+
});
|
|
13482
|
+
result.checks.brandCompliance = true;
|
|
13483
|
+
for (const finding of brandOutput.findings) {
|
|
13484
|
+
const severity = finding.severity === "warn" ? "warning" : finding.severity;
|
|
13485
|
+
if (severity === "error") result.valid = false;
|
|
13486
|
+
result.issues.push({
|
|
13487
|
+
check: "brandCompliance",
|
|
13488
|
+
file: finding.file,
|
|
13489
|
+
...finding.line !== null && finding.line !== void 0 && { line: finding.line },
|
|
13490
|
+
ruleId: finding.code,
|
|
13491
|
+
severity,
|
|
13492
|
+
message: finding.message,
|
|
13493
|
+
suggestion: finding.fix.description
|
|
13494
|
+
});
|
|
13495
|
+
}
|
|
13496
|
+
} catch (err) {
|
|
13497
|
+
result.checks.brandCompliance = false;
|
|
13498
|
+
result.issues.push({
|
|
13499
|
+
check: "brandCompliance",
|
|
13500
|
+
severity: "warning",
|
|
13501
|
+
message: `Brand compliance audit skipped: ${err.message}`
|
|
13502
|
+
});
|
|
13503
|
+
}
|
|
13504
|
+
}
|
|
12166
13505
|
if (options.agentConfigs) {
|
|
12167
13506
|
const agentCfg = await validateAgentConfigs(cwd, {
|
|
12168
13507
|
strict: options.strict === true,
|
|
@@ -12192,7 +13531,7 @@ function resolveValidateMode(globalOpts) {
|
|
|
12192
13531
|
return OutputMode.TEXT;
|
|
12193
13532
|
}
|
|
12194
13533
|
async function printCrossCheckWarnings(mode) {
|
|
12195
|
-
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-
|
|
13534
|
+
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-SNE3SQOB.js");
|
|
12196
13535
|
const cwd = process.cwd();
|
|
12197
13536
|
const crossResult = await runCrossCheck2({
|
|
12198
13537
|
specsDir: path70.join(cwd, "docs", "specs"),
|
|
@@ -12208,7 +13547,7 @@ async function printCrossCheckWarnings(mode) {
|
|
|
12208
13547
|
${crossResult.value.warnings} warnings`);
|
|
12209
13548
|
}
|
|
12210
13549
|
function createValidateCommand3() {
|
|
12211
|
-
const command = new
|
|
13550
|
+
const command = new Command116("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").option(
|
|
12212
13551
|
"--agent-configs",
|
|
12213
13552
|
"Validate agent configs (CLAUDE.md, hooks, skills) via agnix or built-in fallback rules"
|
|
12214
13553
|
).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()));
|
|
@@ -12257,7 +13596,7 @@ Agent configs checked via ${engineLabel}${note}`);
|
|
|
12257
13596
|
|
|
12258
13597
|
// src/commands/verify.ts
|
|
12259
13598
|
init_dist3();
|
|
12260
|
-
import { Command as
|
|
13599
|
+
import { Command as Command117 } from "commander";
|
|
12261
13600
|
import { execSync as execSync6 } from "child_process";
|
|
12262
13601
|
function loadBranchingConfig(configPath) {
|
|
12263
13602
|
const shouldLoad = configPath !== void 0 || findConfigFile().ok;
|
|
@@ -12320,7 +13659,7 @@ async function runVerify(options) {
|
|
|
12320
13659
|
process.exit(ExitCode.VALIDATION_FAILED);
|
|
12321
13660
|
}
|
|
12322
13661
|
function createVerifyCommand() {
|
|
12323
|
-
return new
|
|
13662
|
+
return new Command117("verify").description(
|
|
12324
13663
|
"Verify project conventions (currently: branch naming). Works with or without a harness.config.json."
|
|
12325
13664
|
).option(
|
|
12326
13665
|
"--branch <name>",
|
|
@@ -12341,11 +13680,13 @@ var commandCreators = [
|
|
|
12341
13680
|
createAdoptionCommand,
|
|
12342
13681
|
createAdviseSkillsCommand,
|
|
12343
13682
|
createAgentCommand,
|
|
13683
|
+
createAlignDesignSystemCommand,
|
|
12344
13684
|
createAuditProtectedCommand,
|
|
12345
13685
|
createBackfillSkillProvenanceCommand,
|
|
12346
13686
|
createBlueprintCommand,
|
|
12347
13687
|
createCheckArchCommand,
|
|
12348
13688
|
createCheckDepsCommand,
|
|
13689
|
+
createCheckDesignCommand,
|
|
12349
13690
|
createCheckDocsCommand,
|
|
12350
13691
|
createCheckPerfCommand,
|
|
12351
13692
|
createCheckPhaseGateCommand,
|
|
@@ -12354,8 +13695,10 @@ var commandCreators = [
|
|
|
12354
13695
|
createCleanupCommand,
|
|
12355
13696
|
createCleanupSessionsCommand,
|
|
12356
13697
|
createCompoundCommand,
|
|
13698
|
+
createCopyCraftCommand,
|
|
12357
13699
|
createCreateSkillCommand,
|
|
12358
13700
|
createDashboardCommand,
|
|
13701
|
+
createDesignPipelineCommand,
|
|
12359
13702
|
createDoctorCommand,
|
|
12360
13703
|
createFixDriftCommand,
|
|
12361
13704
|
createGatewayCommand,
|
|
@@ -12371,6 +13714,7 @@ var commandCreators = [
|
|
|
12371
13714
|
createInstallCommand,
|
|
12372
13715
|
createInstallConstraintsCommand,
|
|
12373
13716
|
createIntegrationsCommand,
|
|
13717
|
+
createKnowledgeCraftCommand,
|
|
12374
13718
|
createKnowledgePipelineCommand,
|
|
12375
13719
|
createLearningsCommand,
|
|
12376
13720
|
createLinterCommand,
|
|
@@ -12378,6 +13722,7 @@ var commandCreators = [
|
|
|
12378
13722
|
createMcpCommand,
|
|
12379
13723
|
createMcpGuardCommand,
|
|
12380
13724
|
createMigrateCommand,
|
|
13725
|
+
createNamingCraftCommand,
|
|
12381
13726
|
createNotificationsCommand,
|
|
12382
13727
|
createOrchestratorCommand,
|
|
12383
13728
|
createPerfCommand,
|
|
@@ -12389,19 +13734,23 @@ var commandCreators = [
|
|
|
12389
13734
|
createQueryCommand,
|
|
12390
13735
|
createRecommendCommand,
|
|
12391
13736
|
createRoadmapCommand,
|
|
13737
|
+
createRoutingCommand,
|
|
12392
13738
|
createScanCommand,
|
|
12393
13739
|
createScanConfigCommand,
|
|
12394
13740
|
createSearchCommand,
|
|
13741
|
+
createSecurityCraftCommand,
|
|
12395
13742
|
createSetupCommand,
|
|
12396
13743
|
createSetupMcpCommand,
|
|
12397
13744
|
createShareCommand,
|
|
12398
13745
|
createSkillCommand,
|
|
12399
13746
|
createSnapshotCommand,
|
|
13747
|
+
createSpecCraftCommand,
|
|
12400
13748
|
createStateCommand,
|
|
12401
13749
|
createSyncAnalysesCommand,
|
|
12402
13750
|
createSyncMainCommand,
|
|
12403
13751
|
createTaintCommand,
|
|
12404
13752
|
createTelemetryCommand,
|
|
13753
|
+
createTestCraftCommand,
|
|
12405
13754
|
createTraceabilityCommand,
|
|
12406
13755
|
createUninstallCommand,
|
|
12407
13756
|
createUninstallConstraintsCommand,
|
|
@@ -12413,7 +13762,7 @@ var commandCreators = [
|
|
|
12413
13762
|
|
|
12414
13763
|
// src/index.ts
|
|
12415
13764
|
function createProgram() {
|
|
12416
|
-
const program = new
|
|
13765
|
+
const program = new Command118();
|
|
12417
13766
|
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");
|
|
12418
13767
|
for (const creator of commandCreators) {
|
|
12419
13768
|
program.addCommand(creator());
|