dsh-doublecheck 0.8.0 → 0.9.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/CHANGELOG.md +6 -0
- package/README.es.md +13 -0
- package/README.hi.md +13 -0
- package/README.md +14 -1
- package/README.pt.md +13 -0
- package/README.zh.md +13 -0
- package/lib/ci.d.ts +19 -0
- package/lib/ci.js +73 -0
- package/lib/domain/gate.d.ts +47 -0
- package/lib/domain/gate.js +84 -0
- package/lib/guard/gate.js +15 -4
- package/package.json +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to dsh-doublecheck are recorded here, newest first.
|
|
4
4
|
|
|
5
|
+
## [0.9.0] - 2026-08-26
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Headless CI gate report (JSON/SARIF).** `/gate run` now also writes a `gate-report.json` next to `gate-report.md` — the same settled `GateState` as lossless JSON. The new `doublecheck-gate` CLI serializes that state to JSON or SARIF 2.1.0 for GitHub Actions PR comments/status checks (`doublecheck-gate --format json|sarif --input gate-report.json`), exiting `0` on `deliverable` and `1` on `rework`. The CLI never re-runs the four-phase gate or the evidence folds — it only serializes the already-settled state.
|
|
10
|
+
|
|
5
11
|
## [0.8.0] - 2026-08-23
|
|
6
12
|
|
|
7
13
|
### Added
|
package/README.es.md
CHANGED
|
@@ -192,6 +192,19 @@ Las luces rojas son comprobaciones fallidas (un spec ausente, una última ejecuc
|
|
|
192
192
|
- counts, ids, and verdicts only: no file contents or session text are embedded, and recognized secrets are redacted.
|
|
193
193
|
````
|
|
194
194
|
|
|
195
|
+
## Salida de CI
|
|
196
|
+
|
|
197
|
+
`/gate run` también escribe un `gate-report.json` (el mismo estado asentado que el JSON sin pérdida, junto a `gate-report.md`). El CLI `doublecheck-gate` convierte ese archivo en salida legible por máquina para GitHub Actions:
|
|
198
|
+
|
|
199
|
+
```sh
|
|
200
|
+
# JSON (comentario de PR / payload de estado)
|
|
201
|
+
doublecheck-gate --format json --input gate-report.json
|
|
202
|
+
# SARIF 2.1.0 (subida de code-scanning / verificación de estado)
|
|
203
|
+
doublecheck-gate --format sarif < gate-report.json
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
El CLI solo serializa el `GateState` ya asentado — nunca vuelve a ejecutar la puerta de cuatro fases ni los pliegues de evidencia. Su código de salida mapea el veredicto: `0` = entregable, `1` = retrabajo, `2` = error de uso/análisis.
|
|
207
|
+
|
|
195
208
|
## Permisos y datos
|
|
196
209
|
|
|
197
210
|
- **Lee**: el registro de sesión (`tool/call` / `tool/result` / `tool/code-dispatch`, fuentes `user/message` inyectadas y los registros de veredicto ajenos `autoReview/*`) solo en proceso; el estado opcional del servicio de modo plan.
|
package/README.hi.md
CHANGED
|
@@ -192,6 +192,19 @@ dsh --profile web --dump-config | grep -E -A3 'id: doublecheck-(grill|guard)'
|
|
|
192
192
|
- counts, ids, and verdicts only: no file contents or session text are embedded, and recognized secrets are redacted.
|
|
193
193
|
````
|
|
194
194
|
|
|
195
|
+
## CI आउटपुट
|
|
196
|
+
|
|
197
|
+
`/gate run` एक `gate-report.json` भी लिखता है (दोषरहित JSON जैसी ही स्थापित स्थिति, `gate-report.md` के पास)। `doublecheck-gate` CLI उस फ़ाइल को GitHub Actions के लिए मशीन-पठनीय आउटपुट में बदलता है:
|
|
198
|
+
|
|
199
|
+
```sh
|
|
200
|
+
# JSON (PR टिप्पणी / स्थिति पेलोड)
|
|
201
|
+
doublecheck-gate --format json --input gate-report.json
|
|
202
|
+
# SARIF 2.1.0 (code-scanning अपलोड / स्थिति जाँच)
|
|
203
|
+
doublecheck-gate --format sarif < gate-report.json
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
CLI केवल पहले से स्थापित `GateState` को क्रमबद्ध करता है — यह कभी चार-चरणीय द्वार या साक्ष्य तहों को दोबारा नहीं चलाता। इसका निकास कोड निर्णय को मैप करता है: `0` = डिलीवर करने योग्य, `1` = पुनः कार्य, `2` = उपयोग/पार्स त्रुटि।
|
|
207
|
+
|
|
195
208
|
## अनुमतियाँ और डेटा
|
|
196
209
|
|
|
197
210
|
- **पढ़ता है**: सत्र लॉग (`tool/call` / `tool/result` / `tool/code-dispatch`, इंजेक्ट किए गए `user/message` स्रोत, और बाहरी `autoReview/*` निर्णय रिकॉर्ड) केवल प्रक्रिया के भीतर; वैकल्पिक प्लान-मोड सेवा स्थिति।
|
package/README.md
CHANGED
|
@@ -193,10 +193,23 @@ Red lights are failed checks (a missing spec, a failing latest run, coverage bel
|
|
|
193
193
|
- counts, ids, and verdicts only: no file contents or session text are embedded, and recognized secrets are redacted.
|
|
194
194
|
````
|
|
195
195
|
|
|
196
|
+
## CI output
|
|
197
|
+
|
|
198
|
+
`/gate run` also writes a `gate-report.json` (the same settled state as lossless JSON, next to `gate-report.md`). The `doublecheck-gate` CLI turns that file into machine-readable output for GitHub Actions:
|
|
199
|
+
|
|
200
|
+
```sh
|
|
201
|
+
# JSON (PR comment / status payload)
|
|
202
|
+
doublecheck-gate --format json --input gate-report.json
|
|
203
|
+
# SARIF 2.1.0 (code-scanning upload / status check)
|
|
204
|
+
doublecheck-gate --format sarif < gate-report.json
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The CLI only serializes the already-settled `GateState` — it never re-runs the four-phase gate or the evidence folds. Its exit code maps the verdict: `0` = deliverable, `1` = rework, `2` = usage/parse error.
|
|
208
|
+
|
|
196
209
|
## Permissions & data
|
|
197
210
|
|
|
198
211
|
- **Reads**: the session log (`tool/call` / `tool/result` / `tool/code-dispatch`, injected `user/message` sources, and the foreign `autoReview/*` verdict records) in-process only; the optional plan-mode service state.
|
|
199
|
-
- **Writes**: `doublecheck-spec.md`, `doublecheck-report.md`, and `gate-report.
|
|
212
|
+
- **Writes**: `doublecheck-spec.md`, `doublecheck-report.md`, `gate-report.md`, and `gate-report.json` in the session workspace (paths configurable) through the `ctx.fs` seam; the durable `doublecheck/state` and `doublecheck/gate` session events.
|
|
200
213
|
- **Model calls**: the gate's consistency and local-review phases (one subagent each per `/gate run`), the optional adversary review, and the `doublecheck_report` verification workflow start subagent runs; nothing else calls a model or the network.
|
|
201
214
|
- **Never touched**: credentials, environment variables, or any file outside the session workspace. The workshop manifest declares `filesystem:read` and `filesystem:write` only. Gate reports carry counts, ids, and verdicts only; recognized secrets in reviewer texts are redacted before storage or display.
|
|
202
215
|
|
package/README.pt.md
CHANGED
|
@@ -192,6 +192,19 @@ As luzes vermelhas são verificações que falharam (um spec ausente, uma últim
|
|
|
192
192
|
- counts, ids, and verdicts only: no file contents or session text are embedded, and recognized secrets are redacted.
|
|
193
193
|
````
|
|
194
194
|
|
|
195
|
+
## Saída do CI
|
|
196
|
+
|
|
197
|
+
`/gate run` também grava um `gate-report.json` (o mesmo estado assentado que o JSON sem perda, ao lado de `gate-report.md`). O CLI `doublecheck-gate` converte esse arquivo em saída legível por máquina para o GitHub Actions:
|
|
198
|
+
|
|
199
|
+
```sh
|
|
200
|
+
# JSON (comentário de PR / payload de status)
|
|
201
|
+
doublecheck-gate --format json --input gate-report.json
|
|
202
|
+
# SARIF 2.1.0 (upload de code-scanning / verificação de status)
|
|
203
|
+
doublecheck-gate --format sarif < gate-report.json
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
O CLI apenas serializa o `GateState` já assentado — nunca reexecuta a porta de quatro fases nem as dobras de evidência. Seu código de saída mapeia o veredicto: `0` = entregável, `1` = retrabalho, `2` = erro de uso/análise.
|
|
207
|
+
|
|
195
208
|
## Permissões e dados
|
|
196
209
|
|
|
197
210
|
- **Lê**: o registro de sessão (`tool/call` / `tool/result` / `tool/code-dispatch`, fontes `user/message` injetadas e os registros de veredicto alheios `autoReview/*`) somente em processo; o estado opcional do serviço de modo plano.
|
package/README.zh.md
CHANGED
|
@@ -192,6 +192,19 @@ dsh --profile web --dump-config | grep -E -A3 'id: doublecheck-(grill|guard)'
|
|
|
192
192
|
- counts, ids, and verdicts only: no file contents or session text are embedded, and recognized secrets are redacted.
|
|
193
193
|
````
|
|
194
194
|
|
|
195
|
+
## CI 输出
|
|
196
|
+
|
|
197
|
+
`/gate run` 还会写一个 `gate-report.json`(与无损 JSON 相同的已定状态,位于 `gate-report.md` 旁边)。`doublecheck-gate` CLI 把该文件转成可供 GitHub Actions 使用的机器可读输出:
|
|
198
|
+
|
|
199
|
+
```sh
|
|
200
|
+
# JSON(PR 评论 / 状态载荷)
|
|
201
|
+
doublecheck-gate --format json --input gate-report.json
|
|
202
|
+
# SARIF 2.1.0(code-scanning 上传 / 状态检查)
|
|
203
|
+
doublecheck-gate --format sarif < gate-report.json
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
CLI 只序列化已定的 `GateState` —— 它从不重新运行四阶段门禁或证据折叠。其退出码映射裁决:`0` = 可交付,`1` = 返工,`2` = 用法/解析错误。
|
|
207
|
+
|
|
195
208
|
## 权限与数据
|
|
196
209
|
|
|
197
210
|
- **读取**:仅进程内读取会话日志(`tool/call` / `tool/result` / `tool/code-dispatch`、注入的 `user/message` 来源,以及外部的 `autoReview/*` 裁决记录);可选的计划模式服务状态。
|
package/lib/ci.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Headless gate-report CLI for CI (`doublecheck-gate`).
|
|
4
|
+
*
|
|
5
|
+
* Consumes a serialized {@link GateState} (the JSON the gate settles and
|
|
6
|
+
* writes next to `gate-report.md`) and emits a machine-readable report for a
|
|
7
|
+
* GH Actions PR comment or status check. It does NOT re-run the four-phase
|
|
8
|
+
* gate — it only serializes the already-settled state — so the gate runner
|
|
9
|
+
* and the evidence folds stay exactly as they are.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* doublecheck-gate --format json --input gate-report.json
|
|
13
|
+
* doublecheck-gate --format sarif < gate-report.json
|
|
14
|
+
*
|
|
15
|
+
* Exit code: 0 = deliverable, 1 = rework, 2 = usage/parse error.
|
|
16
|
+
*
|
|
17
|
+
* @module dsh-doublecheck/ci
|
|
18
|
+
*/
|
|
19
|
+
export {};
|
package/lib/ci.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Headless gate-report CLI for CI (`doublecheck-gate`).
|
|
4
|
+
*
|
|
5
|
+
* Consumes a serialized {@link GateState} (the JSON the gate settles and
|
|
6
|
+
* writes next to `gate-report.md`) and emits a machine-readable report for a
|
|
7
|
+
* GH Actions PR comment or status check. It does NOT re-run the four-phase
|
|
8
|
+
* gate — it only serializes the already-settled state — so the gate runner
|
|
9
|
+
* and the evidence folds stay exactly as they are.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* doublecheck-gate --format json --input gate-report.json
|
|
13
|
+
* doublecheck-gate --format sarif < gate-report.json
|
|
14
|
+
*
|
|
15
|
+
* Exit code: 0 = deliverable, 1 = rework, 2 = usage/parse error.
|
|
16
|
+
*
|
|
17
|
+
* @module dsh-doublecheck/ci
|
|
18
|
+
*/
|
|
19
|
+
import { readFileSync } from 'node:fs';
|
|
20
|
+
import { renderGateReportJson, renderGateReportSarif } from "./domain/gate.js";
|
|
21
|
+
/** Parse CLI arguments into `{ format, input }`. */
|
|
22
|
+
function parseArgs(argv) {
|
|
23
|
+
let format = 'json';
|
|
24
|
+
let input = null;
|
|
25
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
26
|
+
const arg = argv[index];
|
|
27
|
+
if (arg === '--format' || arg === '-f') {
|
|
28
|
+
const next = argv[index + 1];
|
|
29
|
+
if (next !== 'json' && next !== 'sarif')
|
|
30
|
+
throw new Error(`--format must be json or sarif, got ${JSON.stringify(next)}`);
|
|
31
|
+
format = next;
|
|
32
|
+
index += 1;
|
|
33
|
+
}
|
|
34
|
+
else if (arg === '--input' || arg === '-i') {
|
|
35
|
+
input = argv[index + 1] ?? null;
|
|
36
|
+
if (input === null)
|
|
37
|
+
throw new Error('--input requires a file path');
|
|
38
|
+
index += 1;
|
|
39
|
+
}
|
|
40
|
+
else if (arg === '--help' || arg === '-h') {
|
|
41
|
+
throw new Error('usage: doublecheck-gate [--format json|sarif] [--input <file>]');
|
|
42
|
+
}
|
|
43
|
+
else if (!arg.startsWith('-')) {
|
|
44
|
+
input = arg;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
throw new Error(`unknown argument ${JSON.stringify(arg)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { format, input };
|
|
51
|
+
}
|
|
52
|
+
/** Read the gate-state JSON from the input file or stdin (fd 0). */
|
|
53
|
+
function readState(input) {
|
|
54
|
+
const raw = input !== null ? readFileSync(input, 'utf8') : readFileSync(0, 'utf8');
|
|
55
|
+
return JSON.parse(raw);
|
|
56
|
+
}
|
|
57
|
+
/** Render and print the report, returning the process exit code. */
|
|
58
|
+
function main(argv) {
|
|
59
|
+
let format;
|
|
60
|
+
let input;
|
|
61
|
+
try {
|
|
62
|
+
;
|
|
63
|
+
({ format, input } = parseArgs(argv));
|
|
64
|
+
const state = readState(input);
|
|
65
|
+
process.stdout.write((format === 'sarif' ? renderGateReportSarif : renderGateReportJson)(state) + '\n');
|
|
66
|
+
return state.verdict === 'rework' ? 1 : 0;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
process.stderr.write(`doublecheck-gate: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
70
|
+
return 2;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
process.exitCode = main(process.argv.slice(2));
|
package/lib/domain/gate.d.ts
CHANGED
|
@@ -322,3 +322,50 @@ export declare function renderGateReportMarkdown(state: GateState, planSuggestio
|
|
|
322
322
|
export declare function renderPhaseMarkdown(result: GatePhaseResult): string[];
|
|
323
323
|
/** Human-readable phase headings (stable English audit ids). */
|
|
324
324
|
export declare function phaseLabel(phase: GatePhase): string;
|
|
325
|
+
/**
|
|
326
|
+
* The machine-readable CI report derived from a settled gate state. Lossless
|
|
327
|
+
* JSON over the same counts/ids/verdicts the markdown report carries — no
|
|
328
|
+
* session text or file contents — so a GH Actions step can consume it for a
|
|
329
|
+
* PR comment or status check. The four-phase runner and the evidence folds
|
|
330
|
+
* are unchanged; this is a pure serialization of their settled output.
|
|
331
|
+
*/
|
|
332
|
+
export interface CiReport {
|
|
333
|
+
readonly schemaVersion: 1;
|
|
334
|
+
readonly tool: 'dsh-doublecheck';
|
|
335
|
+
readonly verdict: GateVerdict;
|
|
336
|
+
/** Convenience boolean: true when the delivery may proceed. */
|
|
337
|
+
readonly deliverable: boolean;
|
|
338
|
+
readonly reviewEngine: GateReviewEngine;
|
|
339
|
+
readonly at: string;
|
|
340
|
+
/** Number of failing (red) checks across enabled phases. */
|
|
341
|
+
readonly redChecks: number;
|
|
342
|
+
readonly phases: Array<{
|
|
343
|
+
readonly phase: GatePhase;
|
|
344
|
+
readonly enabled: boolean;
|
|
345
|
+
readonly status: GateCheckStatus;
|
|
346
|
+
readonly checks: Array<{
|
|
347
|
+
readonly id: string;
|
|
348
|
+
readonly label: string;
|
|
349
|
+
readonly status: GateCheckStatus;
|
|
350
|
+
readonly summary: string;
|
|
351
|
+
readonly suggestion: string;
|
|
352
|
+
}>;
|
|
353
|
+
}>;
|
|
354
|
+
}
|
|
355
|
+
/** Build the JSON-safe CI report from a settled gate state. */
|
|
356
|
+
export declare function buildCiReport(state: GateState): CiReport;
|
|
357
|
+
/**
|
|
358
|
+
* Render the settled gate state as headless JSON for CI (`--ci` output).
|
|
359
|
+
* @param state - the settled gate state.
|
|
360
|
+
* @returns the pretty-printed JSON report.
|
|
361
|
+
*/
|
|
362
|
+
export declare function renderGateReportJson(state: GateState): string;
|
|
363
|
+
/**
|
|
364
|
+
* Render the settled gate state as a SARIF 2.1.0 document for CI
|
|
365
|
+
* (GitHub code-scanning / status checks). Each failing check is an `error`
|
|
366
|
+
* result and each warning is a `warning` result; passing/skipped/pending
|
|
367
|
+
* checks are declared as rules but produce no result.
|
|
368
|
+
* @param state - the settled gate state.
|
|
369
|
+
* @returns the pretty-printed SARIF document.
|
|
370
|
+
*/
|
|
371
|
+
export declare function renderGateReportSarif(state: GateState): string;
|
package/lib/domain/gate.js
CHANGED
|
@@ -750,3 +750,87 @@ export function phaseLabel(phase) {
|
|
|
750
750
|
case 'review': return 'Review conclusion';
|
|
751
751
|
}
|
|
752
752
|
}
|
|
753
|
+
/** Build the JSON-safe CI report from a settled gate state. */
|
|
754
|
+
export function buildCiReport(state) {
|
|
755
|
+
return {
|
|
756
|
+
schemaVersion: 1,
|
|
757
|
+
tool: 'dsh-doublecheck',
|
|
758
|
+
verdict: state.verdict,
|
|
759
|
+
deliverable: state.verdict === 'deliverable',
|
|
760
|
+
reviewEngine: state.reviewEngine,
|
|
761
|
+
at: state.at,
|
|
762
|
+
redChecks: countRedChecks(Object.values(state.phases)),
|
|
763
|
+
phases: GATE_PHASES.map(phase => {
|
|
764
|
+
const result = state.phases[phase];
|
|
765
|
+
return {
|
|
766
|
+
phase,
|
|
767
|
+
enabled: result?.enabled ?? false,
|
|
768
|
+
status: result?.status ?? 'pending',
|
|
769
|
+
checks: (result?.checks ?? []).map(check => ({
|
|
770
|
+
id: check.id,
|
|
771
|
+
label: check.label,
|
|
772
|
+
status: check.status,
|
|
773
|
+
summary: check.summary,
|
|
774
|
+
suggestion: check.suggestion,
|
|
775
|
+
})),
|
|
776
|
+
};
|
|
777
|
+
}),
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Render the settled gate state as headless JSON for CI (`--ci` output).
|
|
782
|
+
* @param state - the settled gate state.
|
|
783
|
+
* @returns the pretty-printed JSON report.
|
|
784
|
+
*/
|
|
785
|
+
export function renderGateReportJson(state) {
|
|
786
|
+
return JSON.stringify(buildCiReport(state), null, 2);
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Render the settled gate state as a SARIF 2.1.0 document for CI
|
|
790
|
+
* (GitHub code-scanning / status checks). Each failing check is an `error`
|
|
791
|
+
* result and each warning is a `warning` result; passing/skipped/pending
|
|
792
|
+
* checks are declared as rules but produce no result.
|
|
793
|
+
* @param state - the settled gate state.
|
|
794
|
+
* @returns the pretty-printed SARIF document.
|
|
795
|
+
*/
|
|
796
|
+
export function renderGateReportSarif(state) {
|
|
797
|
+
const rules = [];
|
|
798
|
+
const results = [];
|
|
799
|
+
for (const phase of GATE_PHASES) {
|
|
800
|
+
const result = state.phases[phase];
|
|
801
|
+
if (result === undefined || !result.enabled)
|
|
802
|
+
continue;
|
|
803
|
+
for (const check of result.checks) {
|
|
804
|
+
const ruleId = `doublecheck/${phase}/${check.id}`;
|
|
805
|
+
rules.push({ id: ruleId, shortDescription: { text: `${phaseLabel(phase)} — ${check.label}` } });
|
|
806
|
+
if (check.status === 'pass' || check.status === 'skip' || check.status === 'pending')
|
|
807
|
+
continue;
|
|
808
|
+
results.push({
|
|
809
|
+
ruleId,
|
|
810
|
+
level: check.status === 'fail' ? 'error' : 'warning',
|
|
811
|
+
message: { text: check.suggestion !== '' ? `${check.summary} — rework: ${check.suggestion}` : check.summary },
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
const sarif = {
|
|
816
|
+
version: '2.1.0',
|
|
817
|
+
$schema: 'https://json.schemastore.org/sarif-2.1.0.json',
|
|
818
|
+
runs: [{
|
|
819
|
+
tool: {
|
|
820
|
+
driver: {
|
|
821
|
+
name: 'dsh-doublecheck',
|
|
822
|
+
informationUri: 'https://github.com/PerryLink/dsh-doublecheck',
|
|
823
|
+
rules,
|
|
824
|
+
},
|
|
825
|
+
},
|
|
826
|
+
properties: {
|
|
827
|
+
verdict: state.verdict,
|
|
828
|
+
deliverable: state.verdict === 'deliverable',
|
|
829
|
+
reviewEngine: state.reviewEngine,
|
|
830
|
+
at: state.at,
|
|
831
|
+
},
|
|
832
|
+
results,
|
|
833
|
+
}],
|
|
834
|
+
};
|
|
835
|
+
return JSON.stringify(sarif, null, 2);
|
|
836
|
+
}
|
package/lib/guard/gate.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
27
27
|
import z from '@deepseek-ai/schemastery';
|
|
28
|
-
import { attachEvalChecks, countRedChecks, DEFAULT_COVERAGE_PATTERN, DEFAULT_EVAL_REPORTS_CONFIG, DEFAULT_GATE_QUESTIONS, deriveGateVerdict, evaluateConsistency, evaluateRequirements, evaluateReview, evaluateTests, foldAutoReviewEvidence, foldRequirementsEvidence, foldTestEvidence, GATE_FINDINGS_SCHEMA, parseEvalReport, renderGateReportMarkdown, renderPhaseMarkdown, skippedPhase, } from "../domain/gate.js";
|
|
28
|
+
import { attachEvalChecks, countRedChecks, DEFAULT_COVERAGE_PATTERN, DEFAULT_EVAL_REPORTS_CONFIG, DEFAULT_GATE_QUESTIONS, deriveGateVerdict, evaluateConsistency, evaluateRequirements, evaluateReview, evaluateTests, foldAutoReviewEvidence, foldRequirementsEvidence, foldTestEvidence, GATE_FINDINGS_SCHEMA, parseEvalReport, renderGateReportJson, renderGateReportMarkdown, renderPhaseMarkdown, skippedPhase, } from "../domain/gate.js";
|
|
29
29
|
import { sortFindings } from "./review.js";
|
|
30
30
|
import { PROSE } from "./prose.js";
|
|
31
31
|
/** The default gate configuration: every phase on, the six key questions required. */
|
|
@@ -396,19 +396,30 @@ async function writeGateFile(ctx, filePath, state, agent, signal) {
|
|
|
396
396
|
const fs = ctx.get('fs');
|
|
397
397
|
if (fs === undefined)
|
|
398
398
|
return;
|
|
399
|
-
let target;
|
|
400
399
|
try {
|
|
401
|
-
|
|
400
|
+
const markdownTarget = await fs.resolve(filePath, {
|
|
402
401
|
...agent.session.header.cwd !== undefined ? { cwd: agent.session.header.cwd } : {},
|
|
403
402
|
signal,
|
|
404
403
|
});
|
|
405
|
-
await fs.writeText(
|
|
404
|
+
await fs.writeText(markdownTarget, renderGateReportMarkdown(state, true), undefined, signal);
|
|
405
|
+
// The headless CI copy: the same settled state as JSON, for the
|
|
406
|
+
// `doublecheck-gate` CLI (PR comment / status checks). Additive output —
|
|
407
|
+
// the markdown report and the four-phase runner are unchanged.
|
|
408
|
+
const ciTarget = await fs.resolve(ciReportPath(filePath), {
|
|
409
|
+
...agent.session.header.cwd !== undefined ? { cwd: agent.session.header.cwd } : {},
|
|
410
|
+
signal,
|
|
411
|
+
});
|
|
412
|
+
await fs.writeText(ciTarget, renderGateReportJson(state), undefined, signal);
|
|
406
413
|
}
|
|
407
414
|
catch (error) {
|
|
408
415
|
signal.throwIfAborted();
|
|
409
416
|
ctx.logger.debug(`dsh-doublecheck: gate report file write skipped: ${String(error)}`);
|
|
410
417
|
}
|
|
411
418
|
}
|
|
419
|
+
/** Derive the JSON CI-report path from the markdown report path. */
|
|
420
|
+
function ciReportPath(filePath) {
|
|
421
|
+
return filePath.endsWith('.md') ? `${filePath.slice(0, -3)}.json` : `${filePath}.json`;
|
|
422
|
+
}
|
|
412
423
|
/**
|
|
413
424
|
* Read and fold the dsh-eval report through the filesystem seam. A missing
|
|
414
425
|
* seam, a missing file, malformed JSON, or a wrong document shape all settle
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-doublecheck",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Delivery quality gate for DeepSeek Harness: grill the requirements, test the implementation, prove the delivery, and gate the handoff with a deliverable/rework decision.",
|
|
5
5
|
"packageManager": "pnpm@11.7.0",
|
|
6
6
|
"repository": {
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"type": "module",
|
|
15
15
|
"main": "lib/index.js",
|
|
16
16
|
"types": "lib/index.d.ts",
|
|
17
|
+
"bin": {
|
|
18
|
+
"doublecheck-gate": "lib/ci.js"
|
|
19
|
+
},
|
|
17
20
|
"exports": {
|
|
18
21
|
".": {
|
|
19
22
|
"types": "./lib/index.d.ts",
|