@harness-engineering/cli 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +35 -0
- package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +33 -44
- package/dist/agents/skills/codex/harness-execution/SKILL.md +35 -0
- package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +33 -44
- package/dist/agents/skills/cursor/harness-execution/SKILL.md +35 -0
- package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +33 -44
- package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +35 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +33 -44
- package/dist/{agents-md-XOJE5ETA.js → agents-md-YYCLGMBF.js} +2 -2
- package/dist/{architecture-JEZPJ725.js → architecture-5KPP4ID4.js} +3 -3
- package/dist/{assess-project-RHXOQNMM.js → assess-project-B6ENHUAU.js} +1 -1
- package/dist/bin/harness-mcp.js +13 -13
- package/dist/bin/harness.js +22 -22
- package/dist/{check-phase-gate-GNDOMS35.js → check-phase-gate-REG3HWYC.js} +3 -3
- package/dist/{chunk-N24HCQA4.js → chunk-A65QO5KN.js} +132 -46
- package/dist/{chunk-UX3PQKVZ.js → chunk-BXKNWSG4.js} +1 -1
- package/dist/{chunk-XX4OLNWQ.js → chunk-C2ZGWMTN.js} +2 -2
- package/dist/{chunk-HEIMJJI4.js → chunk-DNX35Q5K.js} +2 -2
- package/dist/{chunk-BYVT5LVO.js → chunk-ERZCC5VH.js} +3 -3
- package/dist/{chunk-XFU6SB2Q.js → chunk-FL5SLUKZ.js} +62 -27
- package/dist/{chunk-NWLGL3IR.js → chunk-FUH4J43G.js} +1 -1
- package/dist/{chunk-MGUPSE6D.js → chunk-HIPBU2Q4.js} +5 -5
- package/dist/{chunk-3ISHDWO7.js → chunk-IF3JK3G5.js} +1 -1
- package/dist/{chunk-KAJOS3BA.js → chunk-LMZ2JTNP.js} +2 -2
- package/dist/{chunk-527G27VI.js → chunk-OQFEFVIN.js} +2 -2
- package/dist/{chunk-Z4AWEIBY.js → chunk-PZX2Y3RV.js} +3 -3
- package/dist/{chunk-ONCPJGHY.js → chunk-RGQXHCCH.js} +6 -6
- package/dist/{chunk-QBC7DI4Q.js → chunk-TCVQVHEF.js} +1 -1
- package/dist/{chunk-PC2R5RUJ.js → chunk-TE5YHHHZ.js} +1 -1
- package/dist/{chunk-HWTUUQOW.js → chunk-UBTMPO5H.js} +3 -3
- package/dist/{chunk-GSP2XIVS.js → chunk-XEOSSKIB.js} +1 -1
- package/dist/{chunk-DE5U6KOL.js → chunk-XZ2Q4UTW.js} +1 -1
- package/dist/{chunk-YQSYCBAH.js → chunk-YF3AY6KS.js} +6 -6
- package/dist/{chunk-GGKRA7A7.js → chunk-YQAFKOOL.js} +1 -1
- package/dist/{chunk-WWEVS7RO.js → chunk-ZOUJP3EY.js} +106 -80
- package/dist/{chunk-6WQCLCBO.js → chunk-ZRKFDE6M.js} +1 -1
- package/dist/{ci-workflow-ORZ4F45F.js → ci-workflow-JEYYCBOC.js} +2 -2
- package/dist/{dist-LHINSVK4.js → dist-3HW4LCHE.js} +15 -1
- package/dist/{docs-AU3DXFFO.js → docs-YRMW7UED.js} +3 -3
- package/dist/{engine-6GPWOYQH.js → engine-E7H5U3AC.js} +2 -2
- package/dist/{entropy-VLKDRMRT.js → entropy-3JBKCGJJ.js} +2 -2
- package/dist/{feedback-YXYY44ZC.js → feedback-U6VJ6AUJ.js} +1 -1
- package/dist/{generate-agent-definitions-XIHQPKG3.js → generate-agent-definitions-S2FRZF4Y.js} +3 -3
- package/dist/hooks/format-check.js +202 -0
- package/dist/hooks/quality-warner.js +32 -0
- package/dist/hooks/strict-quality-gate.js +48 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.js +22 -22
- package/dist/{loader-YAN56MT3.js → loader-RGQJYERV.js} +2 -2
- package/dist/{mcp-RK3SFVYB.js → mcp-NDTFZXWF.js} +13 -13
- package/dist/{performance-64DPTLLQ.js → performance-FPWKC4CN.js} +3 -3
- package/dist/{review-pipeline-NENG6LW7.js → review-pipeline-WUHG7PHO.js} +2 -2
- package/dist/{runtime-FFIIRT2T.js → runtime-Q3ORD7LW.js} +2 -2
- package/dist/{security-3PIBN35B.js → security-JDHTRBGC.js} +1 -1
- package/dist/{validate-7IAF2ES3.js → validate-G3LKBOYA.js} +3 -3
- package/dist/{validate-cross-check-QPSAOZKD.js → validate-cross-check-4ITA72DF.js} +2 -2
- package/package.json +8 -8
- package/dist/hooks/quality-gate.js +0 -131
|
@@ -190,6 +190,7 @@ import {
|
|
|
190
190
|
assertPortUsable,
|
|
191
191
|
assertSanitized,
|
|
192
192
|
assignFeature,
|
|
193
|
+
assigneeInvariantHolds,
|
|
193
194
|
buildCiReviewVerdict,
|
|
194
195
|
buildExclusionSet,
|
|
195
196
|
buildProjectContext,
|
|
@@ -202,6 +203,7 @@ import {
|
|
|
202
203
|
checkOverlap,
|
|
203
204
|
checkRoadmapHealth,
|
|
204
205
|
checkTaint,
|
|
206
|
+
claim,
|
|
205
207
|
classifyConfidence,
|
|
206
208
|
classifyFinding,
|
|
207
209
|
clearEventHashCache,
|
|
@@ -309,7 +311,9 @@ import {
|
|
|
309
311
|
insecureDefaultsRules,
|
|
310
312
|
invalidateCheckState,
|
|
311
313
|
isBadPort,
|
|
314
|
+
isClaimableBy,
|
|
312
315
|
isDuplicateFinding,
|
|
316
|
+
isMachineAssignee,
|
|
313
317
|
isRegression,
|
|
314
318
|
isSanitizedResult,
|
|
315
319
|
isSmallSuggestion,
|
|
@@ -378,6 +382,7 @@ import {
|
|
|
378
382
|
promoteSessionLearnings,
|
|
379
383
|
proposalsDir,
|
|
380
384
|
pruneLearnings,
|
|
385
|
+
pushAssigneeToExternal,
|
|
381
386
|
reactRules,
|
|
382
387
|
readAdoptionRecords,
|
|
383
388
|
readCheckState,
|
|
@@ -389,6 +394,7 @@ import {
|
|
|
389
394
|
readTaint,
|
|
390
395
|
registerMockAdapter,
|
|
391
396
|
registerPulseAdapter,
|
|
397
|
+
release,
|
|
392
398
|
removeContributions,
|
|
393
399
|
removeProvenance,
|
|
394
400
|
requestMultiplePeerReviews,
|
|
@@ -438,6 +444,7 @@ import {
|
|
|
438
444
|
serializeRoadmap,
|
|
439
445
|
serializeStrategyDoc,
|
|
440
446
|
setActiveStream,
|
|
447
|
+
setStatus,
|
|
441
448
|
sharpEdgesRules,
|
|
442
449
|
shouldRunCheck,
|
|
443
450
|
spawnBackgroundCheck,
|
|
@@ -481,7 +488,7 @@ import {
|
|
|
481
488
|
writeStrategyDoc,
|
|
482
489
|
writeTaint,
|
|
483
490
|
xssRules
|
|
484
|
-
} from "./chunk-
|
|
491
|
+
} from "./chunk-A65QO5KN.js";
|
|
485
492
|
import {
|
|
486
493
|
EXTENSION_MAP,
|
|
487
494
|
EntropyAnalyzer,
|
|
@@ -843,6 +850,7 @@ export {
|
|
|
843
850
|
assertPortUsable,
|
|
844
851
|
assertSanitized,
|
|
845
852
|
assignFeature,
|
|
853
|
+
assigneeInvariantHolds,
|
|
846
854
|
buildCiReviewVerdict,
|
|
847
855
|
buildDependencyGraph,
|
|
848
856
|
buildExclusionSet,
|
|
@@ -857,6 +865,7 @@ export {
|
|
|
857
865
|
checkOverlap,
|
|
858
866
|
checkRoadmapHealth,
|
|
859
867
|
checkTaint,
|
|
868
|
+
claim,
|
|
860
869
|
classifyConfidence,
|
|
861
870
|
classifyFinding,
|
|
862
871
|
clearEventHashCache,
|
|
@@ -977,8 +986,10 @@ export {
|
|
|
977
986
|
insecureDefaultsRules,
|
|
978
987
|
invalidateCheckState,
|
|
979
988
|
isBadPort,
|
|
989
|
+
isClaimableBy,
|
|
980
990
|
isDuplicateFinding,
|
|
981
991
|
isErr,
|
|
992
|
+
isMachineAssignee,
|
|
982
993
|
isOk,
|
|
983
994
|
isRegression,
|
|
984
995
|
isSanitizedResult,
|
|
@@ -1050,6 +1061,7 @@ export {
|
|
|
1050
1061
|
promoteSessionLearnings,
|
|
1051
1062
|
proposalsDir,
|
|
1052
1063
|
pruneLearnings,
|
|
1064
|
+
pushAssigneeToExternal,
|
|
1053
1065
|
reactRules,
|
|
1054
1066
|
readAdoptionRecords,
|
|
1055
1067
|
readCheckState,
|
|
@@ -1061,6 +1073,7 @@ export {
|
|
|
1061
1073
|
readTaint,
|
|
1062
1074
|
registerMockAdapter,
|
|
1063
1075
|
registerPulseAdapter,
|
|
1076
|
+
release,
|
|
1064
1077
|
removeContributions,
|
|
1065
1078
|
removeProvenance,
|
|
1066
1079
|
requestMultiplePeerReviews,
|
|
@@ -1112,6 +1125,7 @@ export {
|
|
|
1112
1125
|
serializeRoadmap,
|
|
1113
1126
|
serializeStrategyDoc,
|
|
1114
1127
|
setActiveStream,
|
|
1128
|
+
setStatus,
|
|
1115
1129
|
sharpEdgesRules,
|
|
1116
1130
|
shouldRunCheck,
|
|
1117
1131
|
spawnBackgroundCheck,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
checkDocsDefinition,
|
|
3
3
|
handleCheckDocs
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HIPBU2Q4.js";
|
|
5
5
|
import "./chunk-RC3OI5NK.js";
|
|
6
6
|
import "./chunk-W6Y7ZW3Y.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-YQAFKOOL.js";
|
|
8
8
|
import "./chunk-ZCZD7FHU.js";
|
|
9
9
|
import "./chunk-3WGJMBKH.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-A65QO5KN.js";
|
|
11
11
|
import "./chunk-N55WOGN3.js";
|
|
12
12
|
import "./chunk-BDGTZRZ6.js";
|
|
13
13
|
import "./chunk-PP6ZRL5T.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
detectEntropyDefinition,
|
|
3
3
|
handleDetectEntropy
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PZX2Y3RV.js";
|
|
5
5
|
import "./chunk-RC3OI5NK.js";
|
|
6
6
|
import "./chunk-W6Y7ZW3Y.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-A65QO5KN.js";
|
|
8
8
|
import "./chunk-N55WOGN3.js";
|
|
9
9
|
import "./chunk-BDGTZRZ6.js";
|
|
10
10
|
import "./chunk-PP6ZRL5T.js";
|
package/dist/{generate-agent-definitions-XIHQPKG3.js → generate-agent-definitions-S2FRZF4Y.js}
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createGenerateAgentDefinitionsCommand,
|
|
3
3
|
generateAgentDefinitions
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FUH4J43G.js";
|
|
5
5
|
import "./chunk-KET4QQZB.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-TE5YHHHZ.js";
|
|
7
7
|
import "./chunk-3ISINLYT.js";
|
|
8
8
|
import "./chunk-6B6UN6SG.js";
|
|
9
9
|
import "./chunk-3WGJMBKH.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-A65QO5KN.js";
|
|
11
11
|
import "./chunk-N55WOGN3.js";
|
|
12
12
|
import "./chunk-BDGTZRZ6.js";
|
|
13
13
|
import "./chunk-PP6ZRL5T.js";
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// format-check.js — shared detection core for the format/lint hooks.
|
|
2
|
+
//
|
|
3
|
+
// Single source of truth for formatter detection and execution, imported by
|
|
4
|
+
// both `quality-warner.js` (warn-only) and `strict-quality-gate.js` (blocking).
|
|
5
|
+
// Takes NO opinion on exit codes — it returns a structured result and lets each
|
|
6
|
+
// entrypoint decide what to do with it.
|
|
7
|
+
//
|
|
8
|
+
// Result shape:
|
|
9
|
+
// { status: 'clean' | 'violations' | 'infra-error', name, output, message }
|
|
10
|
+
//
|
|
11
|
+
// Disambiguation contract (load-bearing): `violations` (the formatter spawned
|
|
12
|
+
// and reported real format/lint problems) MUST be distinguishable from
|
|
13
|
+
// `infra-error` (the tool is absent, timed out, or could not run). The strict
|
|
14
|
+
// gate blocks only on `violations`; everything ambiguous defaults to
|
|
15
|
+
// `infra-error` so the gate fails open rather than walling off every edit.
|
|
16
|
+
|
|
17
|
+
import { accessSync, readFileSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { execFileSync } from 'node:child_process';
|
|
20
|
+
|
|
21
|
+
// Detection order: first match wins
|
|
22
|
+
const DETECTORS = [
|
|
23
|
+
{
|
|
24
|
+
configs: ['biome.json', 'biome.jsonc'],
|
|
25
|
+
cmd: 'npx',
|
|
26
|
+
args: ['biome', 'check'],
|
|
27
|
+
name: 'Biome',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
configs: [
|
|
31
|
+
'.prettierrc',
|
|
32
|
+
'.prettierrc.json',
|
|
33
|
+
'.prettierrc.yml',
|
|
34
|
+
'.prettierrc.yaml',
|
|
35
|
+
'.prettierrc.js',
|
|
36
|
+
'.prettierrc.cjs',
|
|
37
|
+
'.prettierrc.mjs',
|
|
38
|
+
'prettier.config.js',
|
|
39
|
+
'prettier.config.cjs',
|
|
40
|
+
'prettier.config.mjs',
|
|
41
|
+
],
|
|
42
|
+
cmd: 'npx',
|
|
43
|
+
args: ['prettier', '--check'],
|
|
44
|
+
name: 'Prettier',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
configs: ['.ruff.toml', 'ruff.toml'],
|
|
48
|
+
cmd: 'ruff',
|
|
49
|
+
args: ['check'],
|
|
50
|
+
name: 'Ruff',
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
export function detectFormatter(cwd) {
|
|
55
|
+
for (const detector of DETECTORS) {
|
|
56
|
+
for (const config of detector.configs) {
|
|
57
|
+
try {
|
|
58
|
+
accessSync(join(cwd, config));
|
|
59
|
+
return detector;
|
|
60
|
+
} catch {
|
|
61
|
+
// Config not found, try next
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Concatenate whatever a failed execFileSync left on stdout/stderr. */
|
|
69
|
+
function errorOutput(err) {
|
|
70
|
+
return `${err?.stdout ?? ''}${err?.stderr ?? ''}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Classify a non-zero formatter exit as a real `violations` result or an
|
|
75
|
+
* `infra-error`. The detector's exit code alone is ambiguous (linters exit
|
|
76
|
+
* non-zero both for genuine violations and for usage/spawn failures), so we
|
|
77
|
+
* default to `infra-error` (fail open) unless we can positively identify
|
|
78
|
+
* parseable violation output.
|
|
79
|
+
*/
|
|
80
|
+
function classifyError(err) {
|
|
81
|
+
// The command binary itself is missing / not spawnable.
|
|
82
|
+
if (err?.code === 'ENOENT') return 'infra-error';
|
|
83
|
+
// Killed by a signal — almost always our own timeout.
|
|
84
|
+
if (err?.signal) return 'infra-error';
|
|
85
|
+
|
|
86
|
+
const output = errorOutput(err);
|
|
87
|
+
|
|
88
|
+
// npx/npm could not locate or run the underlying tool, or the tool was
|
|
89
|
+
// invoked without a target it requires (e.g. `prettier --check` with no
|
|
90
|
+
// file). These are usage/infra failures, NOT format violations.
|
|
91
|
+
if (
|
|
92
|
+
/could not determine executable|npm error|command not found|not found|ENOENT|expected at least one|no files matching|usage:/i.test(
|
|
93
|
+
output
|
|
94
|
+
)
|
|
95
|
+
) {
|
|
96
|
+
return 'infra-error';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Spawned, exited non-zero, and produced parseable output → real violations.
|
|
100
|
+
if (typeof err?.status === 'number' && output.trim()) return 'violations';
|
|
101
|
+
|
|
102
|
+
// Non-zero but nothing to parse — treat as infra and fail open.
|
|
103
|
+
return 'infra-error';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Run the project's formatter/linter for the edited file and classify the
|
|
108
|
+
* outcome. Performs detection only — never calls process.exit.
|
|
109
|
+
*
|
|
110
|
+
* @param {{ tool_input?: { file_path?: string } }} input Parsed hook stdin.
|
|
111
|
+
* @param {string} cwd Project root.
|
|
112
|
+
* @returns {{ status: 'clean'|'violations'|'infra-error', name: string|null, output: string, message: string }}
|
|
113
|
+
*/
|
|
114
|
+
export function runFormatCheck(input, cwd) {
|
|
115
|
+
const filePath = input?.tool_input?.file_path ?? '';
|
|
116
|
+
|
|
117
|
+
// Special case: .go files use `gofmt -l`, which lists files needing formatting.
|
|
118
|
+
if (typeof filePath === 'string' && filePath.endsWith('.go')) {
|
|
119
|
+
try {
|
|
120
|
+
const result = execFileSync('gofmt', ['-l', filePath], {
|
|
121
|
+
encoding: 'utf-8',
|
|
122
|
+
cwd,
|
|
123
|
+
timeout: 10000,
|
|
124
|
+
});
|
|
125
|
+
if (result.trim()) {
|
|
126
|
+
return {
|
|
127
|
+
status: 'violations',
|
|
128
|
+
name: 'gofmt',
|
|
129
|
+
output: result.trim(),
|
|
130
|
+
message: `gofmt found formatting issues in: ${result.trim()}`,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return { status: 'clean', name: 'gofmt', output: '', message: 'gofmt check passed' };
|
|
134
|
+
} catch (err) {
|
|
135
|
+
// gofmt not available or failed to run — fail open.
|
|
136
|
+
return {
|
|
137
|
+
status: 'infra-error',
|
|
138
|
+
name: 'gofmt',
|
|
139
|
+
output: errorOutput(err),
|
|
140
|
+
message: 'gofmt check failed (tool may not be installed)',
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const detector = detectFormatter(cwd);
|
|
146
|
+
if (!detector) {
|
|
147
|
+
// No formatter detected — nothing to check.
|
|
148
|
+
return { status: 'clean', name: null, output: '', message: 'No formatter detected' };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
execFileSync(detector.cmd, detector.args, {
|
|
153
|
+
encoding: 'utf-8',
|
|
154
|
+
cwd,
|
|
155
|
+
timeout: 30000,
|
|
156
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
157
|
+
});
|
|
158
|
+
return {
|
|
159
|
+
status: 'clean',
|
|
160
|
+
name: detector.name,
|
|
161
|
+
output: '',
|
|
162
|
+
message: `${detector.name} check passed`,
|
|
163
|
+
};
|
|
164
|
+
} catch (err) {
|
|
165
|
+
const output = errorOutput(err).slice(0, 500);
|
|
166
|
+
if (classifyError(err) === 'violations') {
|
|
167
|
+
return {
|
|
168
|
+
status: 'violations',
|
|
169
|
+
name: detector.name,
|
|
170
|
+
output,
|
|
171
|
+
message: `${detector.name} check reported issues:\n${output}`,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
status: 'infra-error',
|
|
176
|
+
name: detector.name,
|
|
177
|
+
output,
|
|
178
|
+
message: `${detector.name} check could not run (treated as non-blocking):\n${output}`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Read and parse hook stdin (the JSON event payload). Returns null when stdin
|
|
185
|
+
* is empty or malformed so callers can fail open.
|
|
186
|
+
*
|
|
187
|
+
* @param {number} fd File descriptor to read (0 = stdin).
|
|
188
|
+
*/
|
|
189
|
+
export function readHookInput(fd) {
|
|
190
|
+
let raw;
|
|
191
|
+
try {
|
|
192
|
+
raw = readFileSync(fd, 'utf-8');
|
|
193
|
+
} catch {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
if (!raw.trim()) return null;
|
|
197
|
+
try {
|
|
198
|
+
return JSON.parse(raw);
|
|
199
|
+
} catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// quality-warner.js — PostToolUse:Edit/Write hook (standard profile)
|
|
3
|
+
// Runs the project formatter/linter after edits and WARNS on violations.
|
|
4
|
+
// Never blocks (always exits 0). Warnings go to stderr.
|
|
5
|
+
// Exit codes: 0 = allow (always)
|
|
6
|
+
//
|
|
7
|
+
// This is the warn-tier sibling of strict-quality-gate.js. Both obtain their
|
|
8
|
+
// detection from format-check.js; only the exit-code policy differs.
|
|
9
|
+
|
|
10
|
+
import process from 'node:process';
|
|
11
|
+
import { runFormatCheck, readHookInput } from './format-check.js';
|
|
12
|
+
|
|
13
|
+
function main() {
|
|
14
|
+
const input = readHookInput(0);
|
|
15
|
+
if (!input) {
|
|
16
|
+
process.exit(0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const result = runFormatCheck(input, process.cwd());
|
|
21
|
+
// Warn-only: surface every outcome on stderr, never block.
|
|
22
|
+
if (result.status !== 'clean' || result.name) {
|
|
23
|
+
process.stderr.write(`[quality-warner] ${result.message}\n`);
|
|
24
|
+
}
|
|
25
|
+
process.exit(0);
|
|
26
|
+
} catch {
|
|
27
|
+
// Unexpected error — fail open.
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
main();
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// strict-quality-gate.js — PostToolUse:Edit/Write hook (strict profile only)
|
|
3
|
+
// Runs the project formatter/linter after edits and BLOCKS on real violations.
|
|
4
|
+
// Exit codes:
|
|
5
|
+
// 0 = allow (clean, or infra-error → fail open)
|
|
6
|
+
// 2 = block (genuine format/lint violations; stderr is fed back to Claude)
|
|
7
|
+
//
|
|
8
|
+
// A PostToolUse hook that exits 2 surfaces its stderr to Claude as a must-fix:
|
|
9
|
+
// the edit already landed, so the model is told to correct the violation.
|
|
10
|
+
//
|
|
11
|
+
// Fail-open contract: when the formatter is absent, times out, or its output is
|
|
12
|
+
// unparseable (status 'infra-error'), this hook writes a loud warning and exits
|
|
13
|
+
// 0 — a missing formatter must not wall off every edit. See format-check.js.
|
|
14
|
+
|
|
15
|
+
import process from 'node:process';
|
|
16
|
+
import { runFormatCheck, readHookInput } from './format-check.js';
|
|
17
|
+
|
|
18
|
+
function main() {
|
|
19
|
+
const input = readHookInput(0);
|
|
20
|
+
if (!input) {
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const result = runFormatCheck(input, process.cwd());
|
|
26
|
+
|
|
27
|
+
if (result.status === 'violations') {
|
|
28
|
+
process.stderr.write(
|
|
29
|
+
`[strict-quality-gate] BLOCKED — ${result.message}\n` +
|
|
30
|
+
`Fix the formatting/lint violations above before continuing.\n`
|
|
31
|
+
);
|
|
32
|
+
process.exit(2);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (result.status === 'infra-error') {
|
|
36
|
+
process.stderr.write(`[strict-quality-gate] WARNING (failing open) — ${result.message}\n`);
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// clean
|
|
41
|
+
process.exit(0);
|
|
42
|
+
} catch {
|
|
43
|
+
// Unexpected error — fail open.
|
|
44
|
+
process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
main();
|
package/dist/index.d.ts
CHANGED
|
@@ -1576,14 +1576,14 @@ declare const HarnessConfigSchema: z.ZodObject<{
|
|
|
1576
1576
|
modules: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodEnum<["circular-deps", "layer-violations", "complexity", "coupling", "forbidden-imports", "module-size", "dependency-depth"]>, z.ZodUnion<[z.ZodNumber, z.ZodRecord<z.ZodString, z.ZodNumber>]>>>>;
|
|
1577
1577
|
}, "strip", z.ZodTypeAny, {
|
|
1578
1578
|
enabled: boolean;
|
|
1579
|
-
thresholds: Partial<Record<"complexity" | "coupling" | "circular-deps" | "layer-violations" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>;
|
|
1580
|
-
modules: Record<string, Partial<Record<"complexity" | "coupling" | "circular-deps" | "layer-violations" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>>;
|
|
1581
1579
|
baselinePath: string;
|
|
1580
|
+
thresholds: Partial<Record<"circular-deps" | "layer-violations" | "complexity" | "coupling" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>;
|
|
1581
|
+
modules: Record<string, Partial<Record<"circular-deps" | "layer-violations" | "complexity" | "coupling" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>>;
|
|
1582
1582
|
}, {
|
|
1583
1583
|
enabled?: boolean | undefined;
|
|
1584
|
-
thresholds?: Partial<Record<"complexity" | "coupling" | "circular-deps" | "layer-violations" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>> | undefined;
|
|
1585
|
-
modules?: Record<string, Partial<Record<"complexity" | "coupling" | "circular-deps" | "layer-violations" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>> | undefined;
|
|
1586
1584
|
baselinePath?: string | undefined;
|
|
1585
|
+
thresholds?: Partial<Record<"circular-deps" | "layer-violations" | "complexity" | "coupling" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>> | undefined;
|
|
1586
|
+
modules?: Record<string, Partial<Record<"circular-deps" | "layer-violations" | "complexity" | "coupling" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>> | undefined;
|
|
1587
1587
|
}>>;
|
|
1588
1588
|
/** Skill loading, suggestion, and tier override settings */
|
|
1589
1589
|
skills: z.ZodOptional<z.ZodObject<{
|
|
@@ -2235,9 +2235,9 @@ declare const HarnessConfigSchema: z.ZodObject<{
|
|
|
2235
2235
|
} | undefined;
|
|
2236
2236
|
architecture?: {
|
|
2237
2237
|
enabled: boolean;
|
|
2238
|
-
thresholds: Partial<Record<"complexity" | "coupling" | "circular-deps" | "layer-violations" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>;
|
|
2239
|
-
modules: Record<string, Partial<Record<"complexity" | "coupling" | "circular-deps" | "layer-violations" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>>;
|
|
2240
2238
|
baselinePath: string;
|
|
2239
|
+
thresholds: Partial<Record<"circular-deps" | "layer-violations" | "complexity" | "coupling" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>;
|
|
2240
|
+
modules: Record<string, Partial<Record<"circular-deps" | "layer-violations" | "complexity" | "coupling" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>>;
|
|
2241
2241
|
} | undefined;
|
|
2242
2242
|
traceability?: {
|
|
2243
2243
|
enabled: boolean;
|
|
@@ -2553,9 +2553,9 @@ declare const HarnessConfigSchema: z.ZodObject<{
|
|
|
2553
2553
|
} | undefined;
|
|
2554
2554
|
architecture?: {
|
|
2555
2555
|
enabled?: boolean | undefined;
|
|
2556
|
-
thresholds?: Partial<Record<"complexity" | "coupling" | "circular-deps" | "layer-violations" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>> | undefined;
|
|
2557
|
-
modules?: Record<string, Partial<Record<"complexity" | "coupling" | "circular-deps" | "layer-violations" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>> | undefined;
|
|
2558
2556
|
baselinePath?: string | undefined;
|
|
2557
|
+
thresholds?: Partial<Record<"circular-deps" | "layer-violations" | "complexity" | "coupling" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>> | undefined;
|
|
2558
|
+
modules?: Record<string, Partial<Record<"circular-deps" | "layer-violations" | "complexity" | "coupling" | "forbidden-imports" | "module-size" | "dependency-depth", number | Record<string, number>>>> | undefined;
|
|
2559
2559
|
} | undefined;
|
|
2560
2560
|
traceability?: {
|
|
2561
2561
|
enabled?: boolean | undefined;
|
package/dist/index.js
CHANGED
|
@@ -12,19 +12,19 @@ import {
|
|
|
12
12
|
runSnapshotCapture,
|
|
13
13
|
runUninstall,
|
|
14
14
|
runUninstallConstraints
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-FL5SLUKZ.js";
|
|
16
16
|
import {
|
|
17
17
|
generateRuntime
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-ZRKFDE6M.js";
|
|
19
19
|
import {
|
|
20
20
|
generateAgentsMd
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-TCVQVHEF.js";
|
|
22
22
|
import {
|
|
23
23
|
generateCIWorkflow
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-XEOSSKIB.js";
|
|
25
25
|
import {
|
|
26
26
|
runCrossCheck
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-IF3JK3G5.js";
|
|
28
28
|
import {
|
|
29
29
|
AGENT_DESCRIPTIONS,
|
|
30
30
|
DEFAULT_TOOLS,
|
|
@@ -33,14 +33,14 @@ import {
|
|
|
33
33
|
generateAgentDefinitions,
|
|
34
34
|
renderClaudeCodeAgent,
|
|
35
35
|
renderGeminiAgent
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-FUH4J43G.js";
|
|
37
37
|
import "./chunk-KET4QQZB.js";
|
|
38
38
|
import {
|
|
39
39
|
runScan
|
|
40
40
|
} from "./chunk-2N4OENGE.js";
|
|
41
41
|
import {
|
|
42
42
|
TemplateEngine
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-BXKNWSG4.js";
|
|
44
44
|
import "./chunk-CQ553GZO.js";
|
|
45
45
|
import {
|
|
46
46
|
generateSkillFiles
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
import {
|
|
49
49
|
listPersonas,
|
|
50
50
|
loadPersona
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-TE5YHHHZ.js";
|
|
52
52
|
import {
|
|
53
53
|
detectTrigger,
|
|
54
54
|
runPersona
|
|
@@ -63,26 +63,26 @@ import {
|
|
|
63
63
|
OutputFormatter,
|
|
64
64
|
OutputMode,
|
|
65
65
|
runCheckPhaseGate
|
|
66
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-LMZ2JTNP.js";
|
|
67
67
|
import {
|
|
68
68
|
createHarnessServer,
|
|
69
69
|
generateSlashCommands,
|
|
70
70
|
getToolDefinitions,
|
|
71
71
|
startServer
|
|
72
|
-
} from "./chunk-
|
|
73
|
-
import "./chunk-
|
|
74
|
-
import "./chunk-
|
|
75
|
-
import "./chunk-
|
|
76
|
-
import "./chunk-
|
|
77
|
-
import "./chunk-
|
|
72
|
+
} from "./chunk-ZOUJP3EY.js";
|
|
73
|
+
import "./chunk-DNX35Q5K.js";
|
|
74
|
+
import "./chunk-C2ZGWMTN.js";
|
|
75
|
+
import "./chunk-YF3AY6KS.js";
|
|
76
|
+
import "./chunk-PZX2Y3RV.js";
|
|
77
|
+
import "./chunk-RGQXHCCH.js";
|
|
78
78
|
import "./chunk-IOW3MW2K.js";
|
|
79
|
-
import "./chunk-
|
|
79
|
+
import "./chunk-ERZCC5VH.js";
|
|
80
80
|
import "./chunk-3ISINLYT.js";
|
|
81
81
|
import "./chunk-CLI4K2CH.js";
|
|
82
|
-
import "./chunk-
|
|
83
|
-
import "./chunk-
|
|
84
|
-
import "./chunk-
|
|
85
|
-
import "./chunk-
|
|
82
|
+
import "./chunk-UBTMPO5H.js";
|
|
83
|
+
import "./chunk-OQFEFVIN.js";
|
|
84
|
+
import "./chunk-XZ2Q4UTW.js";
|
|
85
|
+
import "./chunk-HIPBU2Q4.js";
|
|
86
86
|
import "./chunk-RC3OI5NK.js";
|
|
87
87
|
import "./chunk-W6Y7ZW3Y.js";
|
|
88
88
|
import "./chunk-27AJKSQY.js";
|
|
@@ -92,7 +92,7 @@ import {
|
|
|
92
92
|
findConfigFile,
|
|
93
93
|
loadConfig,
|
|
94
94
|
resolveConfig
|
|
95
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-YQAFKOOL.js";
|
|
96
96
|
import "./chunk-ZCZD7FHU.js";
|
|
97
97
|
import {
|
|
98
98
|
logger
|
|
@@ -102,7 +102,7 @@ import {
|
|
|
102
102
|
ExitCode,
|
|
103
103
|
handleError
|
|
104
104
|
} from "./chunk-3WGJMBKH.js";
|
|
105
|
-
import "./chunk-
|
|
105
|
+
import "./chunk-A65QO5KN.js";
|
|
106
106
|
import "./chunk-BM3PWGXQ.js";
|
|
107
107
|
import "./chunk-N55WOGN3.js";
|
|
108
108
|
import "./chunk-BDGTZRZ6.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
listPersonas,
|
|
3
3
|
loadPersona
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-TE5YHHHZ.js";
|
|
5
|
+
import "./chunk-A65QO5KN.js";
|
|
6
6
|
import "./chunk-N55WOGN3.js";
|
|
7
7
|
import "./chunk-BDGTZRZ6.js";
|
|
8
8
|
import "./chunk-PP6ZRL5T.js";
|