dsh-research-report 0.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/CHANGELOG.md +18 -0
- package/LICENSE +201 -0
- package/README.es.md +155 -0
- package/README.hi.md +155 -0
- package/README.md +155 -0
- package/README.pt.md +155 -0
- package/README.zh.md +155 -0
- package/THIRD_PARTY_NOTICES.md +21 -0
- package/cordis.patch.yml +24 -0
- package/lib/index.js +2143 -0
- package/lib/types/assemble.d.ts +123 -0
- package/lib/types/assemble.d.ts.map +1 -0
- package/lib/types/assemble.js +239 -0
- package/lib/types/assemble.js.map +1 -0
- package/lib/types/config.d.ts +48 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/config.js +60 -0
- package/lib/types/config.js.map +1 -0
- package/lib/types/gather.d.ts +119 -0
- package/lib/types/gather.d.ts.map +1 -0
- package/lib/types/gather.js +165 -0
- package/lib/types/gather.js.map +1 -0
- package/lib/types/index.d.ts +51 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +71 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/ledger.d.ts +159 -0
- package/lib/types/ledger.d.ts.map +1 -0
- package/lib/types/ledger.js +276 -0
- package/lib/types/ledger.js.map +1 -0
- package/lib/types/provider-local.d.ts +137 -0
- package/lib/types/provider-local.d.ts.map +1 -0
- package/lib/types/provider-local.js +418 -0
- package/lib/types/provider-local.js.map +1 -0
- package/lib/types/service.d.ts +302 -0
- package/lib/types/service.d.ts.map +1 -0
- package/lib/types/service.js +31 -0
- package/lib/types/service.js.map +1 -0
- package/lib/types/tools/evidence-add.d.ts +36 -0
- package/lib/types/tools/evidence-add.d.ts.map +1 -0
- package/lib/types/tools/evidence-add.js +107 -0
- package/lib/types/tools/evidence-add.js.map +1 -0
- package/lib/types/tools/ledger-query.d.ts +42 -0
- package/lib/types/tools/ledger-query.d.ts.map +1 -0
- package/lib/types/tools/ledger-query.js +154 -0
- package/lib/types/tools/ledger-query.js.map +1 -0
- package/lib/types/tools/research-report.d.ts +67 -0
- package/lib/types/tools/research-report.d.ts.map +1 -0
- package/lib/types/tools/research-report.js +345 -0
- package/lib/types/tools/research-report.js.map +1 -0
- package/lib/types/verify.d.ts +128 -0
- package/lib/types/verify.d.ts.map +1 -0
- package/lib/types/verify.js +208 -0
- package/lib/types/verify.js.map +1 -0
- package/lib/types/version.d.ts +7 -0
- package/lib/types/version.d.ts.map +1 -0
- package/lib/types/version.js +7 -0
- package/lib/types/version.js.map +1 -0
- package/package.json +147 -0
- package/src/assemble.ts +302 -0
- package/src/config.ts +97 -0
- package/src/gather.ts +239 -0
- package/src/index.ts +139 -0
- package/src/ledger.ts +344 -0
- package/src/provider-local.ts +489 -0
- package/src/service.ts +322 -0
- package/src/tools/evidence-add.ts +132 -0
- package/src/tools/ledger-query.ts +191 -0
- package/src/tools/research-report.ts +424 -0
- package/src/verify.ts +285 -0
- package/src/version.ts +7 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Report assembly and sealing — pure functions. The provider owns the ledger
|
|
3
|
+
* and the filesystem; this module owns request validation, the `report.md`
|
|
4
|
+
* rendering, the `manifest.json` construction, and the seal hash.
|
|
5
|
+
*
|
|
6
|
+
* Sealing: `report.md` is rendered deterministically from the validated
|
|
7
|
+
* request plus the verdicts; `manifest.json` carries the report hash, every
|
|
8
|
+
* evidence hash, and the verdicts; the seal hash is the SHA-256 of the exact
|
|
9
|
+
* manifest bytes. Recomputing the hashes from the sealed directory always
|
|
10
|
+
* reproduces the seal.
|
|
11
|
+
*
|
|
12
|
+
* @module dsh-research-report/assemble
|
|
13
|
+
*/
|
|
14
|
+
import type { EvidenceRecord } from './service.js';
|
|
15
|
+
import type { AssembleReportRequest, ClaimVerdict } from './service.js';
|
|
16
|
+
/** The manifest schema tag written into every manifest.json. */
|
|
17
|
+
export declare const MANIFEST_SCHEMA = "dsh-research-report/v1";
|
|
18
|
+
/** Body marker appended after a paragraph per UNVERIFIED claim it cites. */
|
|
19
|
+
export declare const UNVERIFIED_MARK = "[\u672A\u6838\u5B9E]";
|
|
20
|
+
/** Body marker appended after a paragraph per CONTRADICTED claim it cites. */
|
|
21
|
+
export declare const CONTRADICTED_MARK = "[\u4E0E\u8BC1\u636E\u77DB\u76FE]";
|
|
22
|
+
/** A loud assemble-time request validation failure. */
|
|
23
|
+
export declare class RequestValidationError extends Error {
|
|
24
|
+
constructor(message: string);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Slug one topic for the report directory name: unicode letters and digits
|
|
28
|
+
* are kept, everything else folds to `-`; empty slugs fall back to `report`.
|
|
29
|
+
* @param topic - the report topic.
|
|
30
|
+
* @returns a filesystem-safe slug of at most 48 characters.
|
|
31
|
+
*/
|
|
32
|
+
export declare function slugify(topic: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Format one timestamp as the version directory id `YYYYMMDD-HHmmss` (UTC).
|
|
35
|
+
* @param at - the time to format.
|
|
36
|
+
* @returns the directory id.
|
|
37
|
+
*/
|
|
38
|
+
export declare function versionIdOf(at: Date): string;
|
|
39
|
+
/**
|
|
40
|
+
* The config fingerprint recorded in every report: a short hash of the
|
|
41
|
+
* resolved runtime knobs, so two reports sealed under different policies are
|
|
42
|
+
* distinguishable at a glance.
|
|
43
|
+
* @param knobs - the policy values that shape assembly output.
|
|
44
|
+
* @returns 16 hex characters of the knobs' SHA-256.
|
|
45
|
+
*/
|
|
46
|
+
export declare function configFingerprint(knobs: {
|
|
47
|
+
maxEvidenceBytes: number;
|
|
48
|
+
maxEvidencePerReport: number;
|
|
49
|
+
}): string;
|
|
50
|
+
/**
|
|
51
|
+
* Validate one assemble request; every violation throws (a loud rejection —
|
|
52
|
+
* the caller must fix the request, nothing is silently skipped).
|
|
53
|
+
* @param request - the frozen assemble request.
|
|
54
|
+
* @param limits - the resolved caps.
|
|
55
|
+
*/
|
|
56
|
+
export declare function validateAssembleRequest(request: AssembleReportRequest, limits: {
|
|
57
|
+
maxEvidenceBytes: number;
|
|
58
|
+
maxEvidencePerReport: number;
|
|
59
|
+
}): void;
|
|
60
|
+
/** Everything the renderers need: the validated request plus the outcomes. */
|
|
61
|
+
export interface ReportPlan {
|
|
62
|
+
/** The validated request. */
|
|
63
|
+
request: AssembleReportRequest;
|
|
64
|
+
/** Per-claim verdicts (claim registration order). */
|
|
65
|
+
verdicts: ClaimVerdict[];
|
|
66
|
+
/** The durable evidence records (hash + provenance). */
|
|
67
|
+
evidence: EvidenceRecord[];
|
|
68
|
+
/** ISO-8601 generation time. */
|
|
69
|
+
generatedAt: string;
|
|
70
|
+
/** The config fingerprint. */
|
|
71
|
+
fingerprint: string;
|
|
72
|
+
/** The generator version. */
|
|
73
|
+
pluginVersion: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Render `report.md`. Unverified/contradicted claims keep a visible body
|
|
77
|
+
* marker after every paragraph that cites them — nothing is silently passed.
|
|
78
|
+
* @param plan - the validated request plus verdicts and evidence records.
|
|
79
|
+
* @returns the report markdown.
|
|
80
|
+
*/
|
|
81
|
+
export declare function renderReportMarkdown(plan: ReportPlan): string;
|
|
82
|
+
/** The durable manifest document (`manifest.json`). */
|
|
83
|
+
export interface ReportManifest {
|
|
84
|
+
schema: typeof MANIFEST_SCHEMA;
|
|
85
|
+
title: string;
|
|
86
|
+
topic: string;
|
|
87
|
+
generatedAt: string;
|
|
88
|
+
generator: string;
|
|
89
|
+
reportFile: string;
|
|
90
|
+
reportSha256: string;
|
|
91
|
+
configFingerprint: string;
|
|
92
|
+
evidence: Array<{
|
|
93
|
+
id: string;
|
|
94
|
+
sha256: string;
|
|
95
|
+
origin: string;
|
|
96
|
+
title: string;
|
|
97
|
+
capturedAt: string;
|
|
98
|
+
bytes: number;
|
|
99
|
+
}>;
|
|
100
|
+
claims: Array<{
|
|
101
|
+
id: string;
|
|
102
|
+
text: string;
|
|
103
|
+
evidenceIds: string[];
|
|
104
|
+
}>;
|
|
105
|
+
verdicts: ClaimVerdict[];
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Build the manifest document for one sealed report. Key order is fixed by
|
|
109
|
+
* construction so the serialized bytes (and therefore the seal hash) are
|
|
110
|
+
* deterministic for the same inputs.
|
|
111
|
+
* @param plan - the validated request plus verdicts and evidence records.
|
|
112
|
+
* @param reportSha256 - the SHA-256 of the rendered report.md bytes.
|
|
113
|
+
* @returns the manifest document.
|
|
114
|
+
*/
|
|
115
|
+
export declare function buildManifest(plan: ReportPlan, reportSha256: string): ReportManifest;
|
|
116
|
+
/**
|
|
117
|
+
* Serialize one manifest to its exact durable bytes. The seal hash is the
|
|
118
|
+
* SHA-256 of this text.
|
|
119
|
+
* @param manifest - the manifest document.
|
|
120
|
+
* @returns the canonical manifest.json content.
|
|
121
|
+
*/
|
|
122
|
+
export declare function serializeManifest(manifest: ReportManifest): string;
|
|
123
|
+
//# sourceMappingURL=assemble.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/assemble.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEvE,gEAAgE;AAChE,eAAO,MAAM,eAAe,2BAA2B,CAAA;AAEvD,4EAA4E;AAC5E,eAAO,MAAM,eAAe,yBAAU,CAAA;AAEtC,8EAA8E;AAC9E,eAAO,MAAM,iBAAiB,qCAAY,CAAA;AAE1C,uDAAuD;AACvD,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ7C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,IAAI,GAAG,MAAM,CAM5C;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,oBAAoB,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAM3G;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,oBAAoB,EAAE,MAAM,CAAA;CAAE,GACjE,IAAI,CAiDN;AAED,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,OAAO,EAAE,qBAAqB,CAAA;IAC9B,qDAAqD;IACrD,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB,wDAAwD;IACxD,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,6BAA6B;IAC7B,aAAa,EAAE,MAAM,CAAA;CACtB;AAgBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CA+D7D;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,eAAe,CAAA;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,iBAAiB,EAAE,MAAM,CAAA;IACzB,QAAQ,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;QAClB,KAAK,EAAE,MAAM,CAAA;KACd,CAAC,CAAA;IACF,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;IAClE,QAAQ,EAAE,YAAY,EAAE,CAAA;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,GAAG,cAAc,CAqBpF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAElE"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Report assembly and sealing — pure functions. The provider owns the ledger
|
|
3
|
+
* and the filesystem; this module owns request validation, the `report.md`
|
|
4
|
+
* rendering, the `manifest.json` construction, and the seal hash.
|
|
5
|
+
*
|
|
6
|
+
* Sealing: `report.md` is rendered deterministically from the validated
|
|
7
|
+
* request plus the verdicts; `manifest.json` carries the report hash, every
|
|
8
|
+
* evidence hash, and the verdicts; the seal hash is the SHA-256 of the exact
|
|
9
|
+
* manifest bytes. Recomputing the hashes from the sealed directory always
|
|
10
|
+
* reproduces the seal.
|
|
11
|
+
*
|
|
12
|
+
* @module dsh-research-report/assemble
|
|
13
|
+
*/
|
|
14
|
+
import { sha256Of } from "./ledger.js";
|
|
15
|
+
/** The manifest schema tag written into every manifest.json. */
|
|
16
|
+
export const MANIFEST_SCHEMA = 'dsh-research-report/v1';
|
|
17
|
+
/** Body marker appended after a paragraph per UNVERIFIED claim it cites. */
|
|
18
|
+
export const UNVERIFIED_MARK = '[未核实]';
|
|
19
|
+
/** Body marker appended after a paragraph per CONTRADICTED claim it cites. */
|
|
20
|
+
export const CONTRADICTED_MARK = '[与证据矛盾]';
|
|
21
|
+
/** A loud assemble-time request validation failure. */
|
|
22
|
+
export class RequestValidationError extends Error {
|
|
23
|
+
constructor(message) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = 'RequestValidationError';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Slug one topic for the report directory name: unicode letters and digits
|
|
30
|
+
* are kept, everything else folds to `-`; empty slugs fall back to `report`.
|
|
31
|
+
* @param topic - the report topic.
|
|
32
|
+
* @returns a filesystem-safe slug of at most 48 characters.
|
|
33
|
+
*/
|
|
34
|
+
export function slugify(topic) {
|
|
35
|
+
const slug = topic
|
|
36
|
+
.trim()
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.replace(/[^\p{L}\p{N}]+/gu, '-')
|
|
39
|
+
.replace(/^-+|-+$/gu, '')
|
|
40
|
+
.slice(0, 48);
|
|
41
|
+
return slug === '' ? 'report' : slug;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Format one timestamp as the version directory id `YYYYMMDD-HHmmss` (UTC).
|
|
45
|
+
* @param at - the time to format.
|
|
46
|
+
* @returns the directory id.
|
|
47
|
+
*/
|
|
48
|
+
export function versionIdOf(at) {
|
|
49
|
+
const pad = (value) => String(value).padStart(2, '0');
|
|
50
|
+
return [
|
|
51
|
+
`${at.getUTCFullYear()}${pad(at.getUTCMonth() + 1)}${pad(at.getUTCDate())}`,
|
|
52
|
+
`${pad(at.getUTCHours())}${pad(at.getUTCMinutes())}${pad(at.getUTCSeconds())}`,
|
|
53
|
+
].join('-');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The config fingerprint recorded in every report: a short hash of the
|
|
57
|
+
* resolved runtime knobs, so two reports sealed under different policies are
|
|
58
|
+
* distinguishable at a glance.
|
|
59
|
+
* @param knobs - the policy values that shape assembly output.
|
|
60
|
+
* @returns 16 hex characters of the knobs' SHA-256.
|
|
61
|
+
*/
|
|
62
|
+
export function configFingerprint(knobs) {
|
|
63
|
+
const stable = JSON.stringify({
|
|
64
|
+
maxEvidenceBytes: knobs.maxEvidenceBytes,
|
|
65
|
+
maxEvidencePerReport: knobs.maxEvidencePerReport,
|
|
66
|
+
});
|
|
67
|
+
return sha256Of(stable).slice(0, 16);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Validate one assemble request; every violation throws (a loud rejection —
|
|
71
|
+
* the caller must fix the request, nothing is silently skipped).
|
|
72
|
+
* @param request - the frozen assemble request.
|
|
73
|
+
* @param limits - the resolved caps.
|
|
74
|
+
*/
|
|
75
|
+
export function validateAssembleRequest(request, limits) {
|
|
76
|
+
if (request.title.trim() === '')
|
|
77
|
+
throw new RequestValidationError('title must be non-empty');
|
|
78
|
+
if (request.topic.trim() === '')
|
|
79
|
+
throw new RequestValidationError('topic must be non-empty');
|
|
80
|
+
if (request.sections.length === 0)
|
|
81
|
+
throw new RequestValidationError('sections must contain at least one section');
|
|
82
|
+
for (const [index, section] of request.sections.entries()) {
|
|
83
|
+
if (section.heading.trim() === '')
|
|
84
|
+
throw new RequestValidationError(`sections[${index}].heading must be non-empty`);
|
|
85
|
+
}
|
|
86
|
+
if (request.evidence.length > limits.maxEvidencePerReport) {
|
|
87
|
+
throw new RequestValidationError(`evidence has ${request.evidence.length} items, above the configured maxEvidencePerReport ${limits.maxEvidencePerReport}`);
|
|
88
|
+
}
|
|
89
|
+
const evidenceIds = new Set();
|
|
90
|
+
for (const item of request.evidence) {
|
|
91
|
+
if (item.id.trim() === '')
|
|
92
|
+
throw new RequestValidationError('evidence id must be non-empty');
|
|
93
|
+
if (evidenceIds.has(item.id))
|
|
94
|
+
throw new RequestValidationError(`duplicate evidence id "${item.id}"`);
|
|
95
|
+
evidenceIds.add(item.id);
|
|
96
|
+
const bytes = Buffer.byteLength(item.content, 'utf8');
|
|
97
|
+
if (bytes > limits.maxEvidenceBytes) {
|
|
98
|
+
throw new RequestValidationError(`evidence "${item.id}" is ${bytes} bytes, above the configured maxEvidenceBytes ${limits.maxEvidenceBytes}`);
|
|
99
|
+
}
|
|
100
|
+
if (Number.isNaN(Date.parse(item.capturedAt))) {
|
|
101
|
+
throw new RequestValidationError(`evidence "${item.id}" has an unparseable capturedAt ${JSON.stringify(item.capturedAt)}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const claimIds = new Set();
|
|
105
|
+
for (const claim of request.claims) {
|
|
106
|
+
if (claim.id.trim() === '')
|
|
107
|
+
throw new RequestValidationError('claim id must be non-empty');
|
|
108
|
+
if (claimIds.has(claim.id))
|
|
109
|
+
throw new RequestValidationError(`duplicate claim id "${claim.id}"`);
|
|
110
|
+
claimIds.add(claim.id);
|
|
111
|
+
for (const evidenceId of claim.evidenceIds) {
|
|
112
|
+
if (!evidenceIds.has(evidenceId)) {
|
|
113
|
+
throw new RequestValidationError(`claim "${claim.id}" binds unknown evidence id "${evidenceId}"`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
for (const [sectionIndex, section] of request.sections.entries()) {
|
|
118
|
+
for (const [paragraphIndex, paragraph] of section.paragraphs.entries()) {
|
|
119
|
+
for (const claimId of paragraph.claimIds ?? []) {
|
|
120
|
+
if (!claimIds.has(claimId)) {
|
|
121
|
+
throw new RequestValidationError(`sections[${sectionIndex}].paragraphs[${paragraphIndex}] cites unregistered claim id "${claimId}"`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** The status mark used in the appendix table. */
|
|
128
|
+
function statusMark(status) {
|
|
129
|
+
switch (status) {
|
|
130
|
+
case 'verified': return '✅ verified';
|
|
131
|
+
case 'unverified': return '⚠️ unverified';
|
|
132
|
+
case 'contradicted': return '❌ contradicted';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** Escape a table cell. */
|
|
136
|
+
function cell(text) {
|
|
137
|
+
return text.replace(/\|/gu, '\\|').replace(/\r?\n/gu, ' ');
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Render `report.md`. Unverified/contradicted claims keep a visible body
|
|
141
|
+
* marker after every paragraph that cites them — nothing is silently passed.
|
|
142
|
+
* @param plan - the validated request plus verdicts and evidence records.
|
|
143
|
+
* @returns the report markdown.
|
|
144
|
+
*/
|
|
145
|
+
export function renderReportMarkdown(plan) {
|
|
146
|
+
const verdictByClaim = new Map(plan.verdicts.map(verdict => [verdict.claimId, verdict]));
|
|
147
|
+
const counts = { verified: 0, unverified: 0, contradicted: 0 };
|
|
148
|
+
for (const verdict of plan.verdicts)
|
|
149
|
+
counts[verdict.status] += 1;
|
|
150
|
+
const lines = [
|
|
151
|
+
`# ${plan.request.title}`,
|
|
152
|
+
'',
|
|
153
|
+
`- Topic: ${plan.request.topic}`,
|
|
154
|
+
`- Generated: ${plan.generatedAt} (UTC)`,
|
|
155
|
+
`- Claims: ${counts.verified} verified / ${counts.unverified} unverified / ${counts.contradicted} contradicted`,
|
|
156
|
+
`- Generator: dsh-research-report ${plan.pluginVersion}`,
|
|
157
|
+
'',
|
|
158
|
+
];
|
|
159
|
+
for (const section of plan.request.sections) {
|
|
160
|
+
lines.push(`## ${section.heading}`, '');
|
|
161
|
+
for (const paragraph of section.paragraphs) {
|
|
162
|
+
const marks = [];
|
|
163
|
+
for (const claimId of paragraph.claimIds ?? []) {
|
|
164
|
+
const verdict = verdictByClaim.get(claimId);
|
|
165
|
+
if (verdict?.status === 'unverified')
|
|
166
|
+
marks.push(UNVERIFIED_MARK);
|
|
167
|
+
if (verdict?.status === 'contradicted')
|
|
168
|
+
marks.push(CONTRADICTED_MARK);
|
|
169
|
+
}
|
|
170
|
+
lines.push(marks.length === 0 ? paragraph.text : `${paragraph.text} ${marks.join(' ')}`, '');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
lines.push('## Appendix A: Claim verification', '');
|
|
174
|
+
if (plan.verdicts.length === 0) {
|
|
175
|
+
lines.push('No claims were registered.', '');
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
lines.push('| Claim | Verdict | Evidence | Note |', '|---|---|---|---|');
|
|
179
|
+
const claimById = new Map(plan.request.claims.map(claim => [claim.id, claim]));
|
|
180
|
+
for (const verdict of plan.verdicts) {
|
|
181
|
+
const claim = claimById.get(verdict.claimId);
|
|
182
|
+
lines.push(`| ${cell(verdict.claimId)} | ${statusMark(verdict.status)} | ${cell((claim?.evidenceIds ?? []).join(', '))} | ${cell(verdict.note ?? '')} |`);
|
|
183
|
+
}
|
|
184
|
+
lines.push('');
|
|
185
|
+
}
|
|
186
|
+
lines.push('## Appendix B: Evidence list', '');
|
|
187
|
+
if (plan.evidence.length === 0) {
|
|
188
|
+
lines.push('No evidence was bound.', '');
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
lines.push('| Id | Title | Origin | SHA-256 | Captured |', '|---|---|---|---|---|');
|
|
192
|
+
for (const record of plan.evidence) {
|
|
193
|
+
lines.push(`| ${cell(record.id)} | ${cell(record.title)} | ${cell(record.origin)} | \`${record.hash}\` | ${record.capturedAt} |`);
|
|
194
|
+
}
|
|
195
|
+
lines.push('');
|
|
196
|
+
}
|
|
197
|
+
lines.push('## Appendix C: Seal', '', `- Manifest: \`manifest.json\` (schema ${MANIFEST_SCHEMA})`, `- Config fingerprint: \`${plan.fingerprint}\``, `- Generated: ${plan.generatedAt} (UTC)`, '');
|
|
198
|
+
return `${lines.join('\n').trimEnd()}\n`;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Build the manifest document for one sealed report. Key order is fixed by
|
|
202
|
+
* construction so the serialized bytes (and therefore the seal hash) are
|
|
203
|
+
* deterministic for the same inputs.
|
|
204
|
+
* @param plan - the validated request plus verdicts and evidence records.
|
|
205
|
+
* @param reportSha256 - the SHA-256 of the rendered report.md bytes.
|
|
206
|
+
* @returns the manifest document.
|
|
207
|
+
*/
|
|
208
|
+
export function buildManifest(plan, reportSha256) {
|
|
209
|
+
return {
|
|
210
|
+
schema: MANIFEST_SCHEMA,
|
|
211
|
+
title: plan.request.title,
|
|
212
|
+
topic: plan.request.topic,
|
|
213
|
+
generatedAt: plan.generatedAt,
|
|
214
|
+
generator: `dsh-research-report ${plan.pluginVersion}`,
|
|
215
|
+
reportFile: 'report.md',
|
|
216
|
+
reportSha256,
|
|
217
|
+
configFingerprint: plan.fingerprint,
|
|
218
|
+
evidence: plan.evidence.map(record => ({
|
|
219
|
+
id: record.id,
|
|
220
|
+
sha256: record.hash,
|
|
221
|
+
origin: record.origin,
|
|
222
|
+
title: record.title,
|
|
223
|
+
capturedAt: record.capturedAt,
|
|
224
|
+
bytes: record.bytes,
|
|
225
|
+
})),
|
|
226
|
+
claims: plan.request.claims.map(claim => ({ id: claim.id, text: claim.text, evidenceIds: claim.evidenceIds })),
|
|
227
|
+
verdicts: plan.verdicts,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Serialize one manifest to its exact durable bytes. The seal hash is the
|
|
232
|
+
* SHA-256 of this text.
|
|
233
|
+
* @param manifest - the manifest document.
|
|
234
|
+
* @returns the canonical manifest.json content.
|
|
235
|
+
*/
|
|
236
|
+
export function serializeManifest(manifest) {
|
|
237
|
+
return `${JSON.stringify(manifest, null, 2)}\n`;
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=assemble.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/assemble.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config schema and resolution for `dsh-research-report`. Every tunable is a
|
|
3
|
+
* validated {@link Config} field changeable from cordis.yml; the resolution
|
|
4
|
+
* step validates bounds so misconfiguration fails loud at mount.
|
|
5
|
+
* @module dsh-research-report/config
|
|
6
|
+
*/
|
|
7
|
+
import z from '@deepseek-ai/schemastery';
|
|
8
|
+
/** Raw plugin config — every field optional; {@link resolveConfig} supplies the defaults. */
|
|
9
|
+
export interface Config {
|
|
10
|
+
/** Master switch. `false` mounts nothing (no service, no tools, no prompt section). */
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Evidence-ledger directory (content-addressed objects + JSONL journals),
|
|
14
|
+
* resolved against the harness working directory when relative.
|
|
15
|
+
*/
|
|
16
|
+
ledgerRoot?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Sealed-report root; each assemble writes
|
|
19
|
+
* `<reportRoot>/<slug(topic)>/<YYYYMMDD-HHmmss>/{report.md,manifest.json}`.
|
|
20
|
+
* Resolved against the harness working directory when relative.
|
|
21
|
+
*/
|
|
22
|
+
reportRoot?: string;
|
|
23
|
+
/** Hard cap on one evidence snapshot's UTF-8 byte size. */
|
|
24
|
+
maxEvidenceBytes?: number;
|
|
25
|
+
/** Hard cap on how many evidence items one report may bind. */
|
|
26
|
+
maxEvidencePerReport?: number;
|
|
27
|
+
/** Deadline (ms) for one `ctx.web` fetch during evidence capture. */
|
|
28
|
+
fetchTimeoutMs?: number;
|
|
29
|
+
}
|
|
30
|
+
/** Fully resolved config handed to the runtime; roots are absolute paths. */
|
|
31
|
+
export interface ResolvedConfig {
|
|
32
|
+
readonly enabled: boolean;
|
|
33
|
+
readonly ledgerRoot: string;
|
|
34
|
+
readonly reportRoot: string;
|
|
35
|
+
readonly maxEvidenceBytes: number;
|
|
36
|
+
readonly maxEvidencePerReport: number;
|
|
37
|
+
readonly fetchTimeoutMs: number;
|
|
38
|
+
}
|
|
39
|
+
/** Schemastery schema: the loader validates and fills defaults before `apply`. */
|
|
40
|
+
export declare const Config: z<Config>;
|
|
41
|
+
/**
|
|
42
|
+
* Validate raw values and fill explicit defaults. Invalid bounds throw here —
|
|
43
|
+
* misconfiguration fails loud at mount even without the Schemastery loader.
|
|
44
|
+
* @param config - raw (possibly partial) plugin config.
|
|
45
|
+
* @returns the fully resolved config.
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveConfig(config?: Config): ResolvedConfig;
|
|
48
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,6FAA6F;AAC7F,MAAM,WAAW,MAAM;IACrB,uFAAuF;IACvF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,+DAA+D;IAC/D,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAA;IACrC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAChC;AAED,kFAAkF;AAClF,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAO3B,CAAA;AAwBF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,GAAE,MAAW,GAAG,cAAc,CAejE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config schema and resolution for `dsh-research-report`. Every tunable is a
|
|
3
|
+
* validated {@link Config} field changeable from cordis.yml; the resolution
|
|
4
|
+
* step validates bounds so misconfiguration fails loud at mount.
|
|
5
|
+
* @module dsh-research-report/config
|
|
6
|
+
*/
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import z from '@deepseek-ai/schemastery';
|
|
9
|
+
/** Schemastery schema: the loader validates and fills defaults before `apply`. */
|
|
10
|
+
export const Config = z.object({
|
|
11
|
+
enabled: z.boolean().default(true),
|
|
12
|
+
ledgerRoot: z.string().default('.research-ledger'),
|
|
13
|
+
reportRoot: z.string().default('research-reports'),
|
|
14
|
+
maxEvidenceBytes: z.number().default(2 * 1024 * 1024),
|
|
15
|
+
maxEvidencePerReport: z.number().default(200),
|
|
16
|
+
fetchTimeoutMs: z.number().default(20_000),
|
|
17
|
+
});
|
|
18
|
+
/** Throw unless `value` is a positive safe integer. */
|
|
19
|
+
function assertPositiveInt(name, value) {
|
|
20
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
21
|
+
throw new TypeError(`${name} must be a positive safe integer, got ${String(value)}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve one configured root to an absolute path. Relative roots anchor at
|
|
26
|
+
* the harness working directory (the workspace the deployment runs in), which
|
|
27
|
+
* keeps the ledger and the sealed reports inside the workspace by default.
|
|
28
|
+
* @param value - the configured root.
|
|
29
|
+
* @param name - the config key, for error messages.
|
|
30
|
+
* @returns the absolute root path.
|
|
31
|
+
*/
|
|
32
|
+
function resolveRoot(value, name) {
|
|
33
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
34
|
+
throw new TypeError(`${name} must be a non-empty path`);
|
|
35
|
+
}
|
|
36
|
+
return path.resolve(value);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Validate raw values and fill explicit defaults. Invalid bounds throw here —
|
|
40
|
+
* misconfiguration fails loud at mount even without the Schemastery loader.
|
|
41
|
+
* @param config - raw (possibly partial) plugin config.
|
|
42
|
+
* @returns the fully resolved config.
|
|
43
|
+
*/
|
|
44
|
+
export function resolveConfig(config = {}) {
|
|
45
|
+
const maxEvidenceBytes = config.maxEvidenceBytes ?? 2 * 1024 * 1024;
|
|
46
|
+
assertPositiveInt('maxEvidenceBytes', maxEvidenceBytes);
|
|
47
|
+
const maxEvidencePerReport = config.maxEvidencePerReport ?? 200;
|
|
48
|
+
assertPositiveInt('maxEvidencePerReport', maxEvidencePerReport);
|
|
49
|
+
const fetchTimeoutMs = config.fetchTimeoutMs ?? 20_000;
|
|
50
|
+
assertPositiveInt('fetchTimeoutMs', fetchTimeoutMs);
|
|
51
|
+
return {
|
|
52
|
+
enabled: config.enabled ?? true,
|
|
53
|
+
ledgerRoot: resolveRoot(config.ledgerRoot ?? '.research-ledger', 'ledgerRoot'),
|
|
54
|
+
reportRoot: resolveRoot(config.reportRoot ?? 'research-reports', 'reportRoot'),
|
|
55
|
+
maxEvidenceBytes,
|
|
56
|
+
maxEvidencePerReport,
|
|
57
|
+
fetchTimeoutMs,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAmCxC,kFAAkF;AAClF,MAAM,CAAC,MAAM,MAAM,GAAc,CAAC,CAAC,MAAM,CAAC;IACxC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC;IAClD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC;IAClD,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IACrD,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;IAC7C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;CAC3C,CAAC,CAAA;AAEF,uDAAuD;AACvD,SAAS,iBAAiB,CAAC,IAAY,EAAE,KAAa;IACpD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,yCAAyC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IACtF,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,WAAW,CAAC,KAAa,EAAE,IAAY;IAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrD,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,2BAA2B,CAAC,CAAA;IACzD,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC5B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB,EAAE;IAC/C,MAAM,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAA;IACnE,iBAAiB,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAA;IACvD,MAAM,oBAAoB,GAAG,MAAM,CAAC,oBAAoB,IAAI,GAAG,CAAA;IAC/D,iBAAiB,CAAC,sBAAsB,EAAE,oBAAoB,CAAC,CAAA;IAC/D,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,MAAM,CAAA;IACtD,iBAAiB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAA;IACnD,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI;QAC/B,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,UAAU,IAAI,kBAAkB,EAAE,YAAY,CAAC;QAC9E,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,UAAU,IAAI,kBAAkB,EAAE,YAAY,CAAC;QAC9E,gBAAgB;QAChB,oBAAoB;QACpB,cAAc;KACf,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evidence capture: URL snapshots via the `ctx.web` seam, workspace file
|
|
3
|
+
* snapshots via `node:fs` — never a direct `fetch` (provider selection and the
|
|
4
|
+
* WebError taxonomy stay with the seam), never a path outside the workspace.
|
|
5
|
+
* @module dsh-research-report/gather
|
|
6
|
+
*/
|
|
7
|
+
import type { WebRuntime } from '@deepseek-ai/dsh-web';
|
|
8
|
+
/** Capture failure codes surfaced to the tools layer. */
|
|
9
|
+
export type CaptureErrorCode = 'WEB_UNAVAILABLE' | 'FETCH_FAILED' | 'FETCH_STATUS' | 'FETCH_TIMEOUT' | 'ORIGIN_UNREADABLE' | 'ORIGIN_OUTSIDE_WORKSPACE';
|
|
10
|
+
/** A loud capture failure with a machine-routable code (also in the message). */
|
|
11
|
+
export declare class CaptureError extends Error {
|
|
12
|
+
/** The machine-routable failure code. */
|
|
13
|
+
readonly code: CaptureErrorCode;
|
|
14
|
+
constructor(code: CaptureErrorCode, message: string);
|
|
15
|
+
}
|
|
16
|
+
/** Whether the origin is an HTTP(S) URL (vs a workspace path). */
|
|
17
|
+
export declare function isUrlOrigin(origin: string): boolean;
|
|
18
|
+
/** Everything the capture paths need. */
|
|
19
|
+
export interface CaptureDeps {
|
|
20
|
+
/** The web seam, when the composition mounts it. */
|
|
21
|
+
web: WebRuntime | undefined;
|
|
22
|
+
/** Fetch deadline (ms). */
|
|
23
|
+
fetchTimeoutMs: number;
|
|
24
|
+
/** Absolute workspace root; local reads never escape it. */
|
|
25
|
+
workspaceRoot: string;
|
|
26
|
+
}
|
|
27
|
+
/** One captured snapshot. */
|
|
28
|
+
export interface CapturedSnapshot {
|
|
29
|
+
/** The verbatim snapshot bytes as UTF-8 text. */
|
|
30
|
+
content: string;
|
|
31
|
+
/** The effective origin (final URL after redirects, or the workspace-relative path). */
|
|
32
|
+
origin: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a workspace-relative origin to an absolute path inside the
|
|
36
|
+
* workspace. Both sides are resolved before comparison (Windows backslash
|
|
37
|
+
* trap) and the prefix check is segment-aware.
|
|
38
|
+
* @param workspaceRoot - absolute workspace root.
|
|
39
|
+
* @param origin - the workspace-relative (or absolute) origin.
|
|
40
|
+
* @returns the absolute in-workspace path.
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveWorkspacePath(workspaceRoot: string, origin: string): string;
|
|
43
|
+
/** Relativize an absolute in-workspace path for display/durable records. */
|
|
44
|
+
export declare function toWorkspaceRelative(workspaceRoot: string, absolute: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Capture one URL snapshot through the web seam.
|
|
47
|
+
* @param deps - web seam, deadline, workspace root.
|
|
48
|
+
* @param url - the URL to fetch.
|
|
49
|
+
* @param signal - caller cancellation.
|
|
50
|
+
* @returns the snapshot (throws {@link CaptureError} on every failure).
|
|
51
|
+
*/
|
|
52
|
+
export declare function captureFromWeb(deps: CaptureDeps, url: string, signal?: AbortSignal): Promise<CapturedSnapshot>;
|
|
53
|
+
/**
|
|
54
|
+
* Capture one workspace file snapshot.
|
|
55
|
+
* @param deps - workspace root (the web fields are unused here).
|
|
56
|
+
* @param origin - the workspace-relative path.
|
|
57
|
+
* @returns the snapshot (throws {@link CaptureError} when unreadable).
|
|
58
|
+
*/
|
|
59
|
+
export declare function captureFromFile(deps: CaptureDeps, origin: string): Promise<CapturedSnapshot>;
|
|
60
|
+
/**
|
|
61
|
+
* Capture one snapshot from any supported origin.
|
|
62
|
+
* @param deps - web seam, deadline, workspace root.
|
|
63
|
+
* @param origin - URL or workspace path.
|
|
64
|
+
* @param signal - caller cancellation.
|
|
65
|
+
* @returns the snapshot.
|
|
66
|
+
*/
|
|
67
|
+
export declare function captureSnapshot(deps: CaptureDeps, origin: string, signal?: AbortSignal): Promise<CapturedSnapshot>;
|
|
68
|
+
/** Search depth → how many sources are fetched for snapshot capture. */
|
|
69
|
+
export declare const GATHER_DEPTH_RESULTS: {
|
|
70
|
+
readonly quick: 3;
|
|
71
|
+
readonly standard: 5;
|
|
72
|
+
readonly deep: 8;
|
|
73
|
+
};
|
|
74
|
+
/** The gather depth knob. */
|
|
75
|
+
export type GatherDepth = keyof typeof GATHER_DEPTH_RESULTS;
|
|
76
|
+
/** One gathered source and whether its snapshot landed in the ledger. */
|
|
77
|
+
export interface GatherCandidate {
|
|
78
|
+
/** The source URL. */
|
|
79
|
+
url: string;
|
|
80
|
+
/** Provider title, when given. */
|
|
81
|
+
title?: string;
|
|
82
|
+
/** Provider snippet, when given. */
|
|
83
|
+
snippet?: string;
|
|
84
|
+
/** `captured` entries carry the ledger evidence id. */
|
|
85
|
+
status: 'captured' | 'uncaptured';
|
|
86
|
+
/** Ledger evidence id (captured only). */
|
|
87
|
+
evidenceId?: string;
|
|
88
|
+
/** Why the snapshot could not be captured (uncaptured only). */
|
|
89
|
+
reason?: string;
|
|
90
|
+
}
|
|
91
|
+
/** The gather outcome: candidates plus an explicit gap list for the model. */
|
|
92
|
+
export interface GatherOutcome {
|
|
93
|
+
/** The searched topic. */
|
|
94
|
+
topic: string;
|
|
95
|
+
/** Every source the search returned, with capture status. */
|
|
96
|
+
candidates: GatherCandidate[];
|
|
97
|
+
/** Explicit gaps the model should close before assembling. */
|
|
98
|
+
gaps: string[];
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Run one search over the topic and capture snapshots for the top sources.
|
|
102
|
+
* Captured snapshots are registered through `register`; uncaptured sources
|
|
103
|
+
* land in the gap list with their reason — gathering never fabricates
|
|
104
|
+
* evidence and never auto-assembles.
|
|
105
|
+
* @param deps - web seam, deadline, workspace root.
|
|
106
|
+
* @param topic - the research topic.
|
|
107
|
+
* @param depth - quick | standard | deep.
|
|
108
|
+
* @param signal - caller cancellation.
|
|
109
|
+
* @param register - ledger registration callback for captured snapshots.
|
|
110
|
+
* @returns candidates plus gaps.
|
|
111
|
+
*/
|
|
112
|
+
export declare function gatherCandidates(deps: CaptureDeps, topic: string, depth: GatherDepth, signal: AbortSignal | undefined, register: (input: {
|
|
113
|
+
title: string;
|
|
114
|
+
origin: string;
|
|
115
|
+
content: string;
|
|
116
|
+
}) => Promise<{
|
|
117
|
+
id: string;
|
|
118
|
+
}>): Promise<GatherOutcome>;
|
|
119
|
+
//# sourceMappingURL=gather.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gather.d.ts","sourceRoot":"","sources":["../../src/gather.ts"],"names":[],"mappings":"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"}
|