mewkit 1.11.2 → 1.12.1
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/commands/index-command.d.ts.map +1 -1
- package/dist/commands/index-command.js +2 -1
- package/dist/commands/index-command.js.map +1 -1
- package/dist/core/derived-index.d.ts +12 -3
- package/dist/core/derived-index.d.ts.map +1 -1
- package/dist/core/derived-index.js +42 -13
- package/dist/core/derived-index.js.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/wiki/application/ports.d.ts +111 -0
- package/dist/wiki/application/ports.d.ts.map +1 -0
- package/dist/wiki/application/ports.js +33 -0
- package/dist/wiki/application/ports.js.map +1 -0
- package/dist/wiki/application/queries.d.ts +5 -0
- package/dist/wiki/application/queries.d.ts.map +1 -0
- package/dist/wiki/application/queries.js +10 -0
- package/dist/wiki/application/queries.js.map +1 -0
- package/dist/wiki/application/research.d.ts +16 -0
- package/dist/wiki/application/research.d.ts.map +1 -0
- package/dist/wiki/application/research.js +48 -0
- package/dist/wiki/application/research.js.map +1 -0
- package/dist/wiki/application/service.d.ts +27 -0
- package/dist/wiki/application/service.d.ts.map +1 -0
- package/dist/wiki/application/service.js +153 -0
- package/dist/wiki/application/service.js.map +1 -0
- package/dist/wiki/domain/index.d.ts +5 -0
- package/dist/wiki/domain/index.d.ts.map +1 -0
- package/dist/wiki/domain/index.js +6 -0
- package/dist/wiki/domain/index.js.map +1 -0
- package/dist/wiki/domain/invariants.d.ts +28 -0
- package/dist/wiki/domain/invariants.d.ts.map +1 -0
- package/dist/wiki/domain/invariants.js +84 -0
- package/dist/wiki/domain/invariants.js.map +1 -0
- package/dist/wiki/domain/salience.d.ts +11 -0
- package/dist/wiki/domain/salience.d.ts.map +1 -0
- package/dist/wiki/domain/salience.js +40 -0
- package/dist/wiki/domain/salience.js.map +1 -0
- package/dist/wiki/domain/types.d.ts +151 -0
- package/dist/wiki/domain/types.d.ts.map +1 -0
- package/dist/wiki/domain/types.js +27 -0
- package/dist/wiki/domain/types.js.map +1 -0
- package/dist/wiki/domain/write-decision.d.ts +25 -0
- package/dist/wiki/domain/write-decision.d.ts.map +1 -0
- package/dist/wiki/domain/write-decision.js +71 -0
- package/dist/wiki/domain/write-decision.js.map +1 -0
- package/dist/wiki/infrastructure/fetcher-adapter.d.ts +45 -0
- package/dist/wiki/infrastructure/fetcher-adapter.d.ts.map +1 -0
- package/dist/wiki/infrastructure/fetcher-adapter.js +99 -0
- package/dist/wiki/infrastructure/fetcher-adapter.js.map +1 -0
- package/dist/wiki/infrastructure/inventory-adapter.d.ts +13 -0
- package/dist/wiki/infrastructure/inventory-adapter.d.ts.map +1 -0
- package/dist/wiki/infrastructure/inventory-adapter.js +46 -0
- package/dist/wiki/infrastructure/inventory-adapter.js.map +1 -0
- package/dist/wiki/infrastructure/markdown-repository.d.ts +23 -0
- package/dist/wiki/infrastructure/markdown-repository.d.ts.map +1 -0
- package/dist/wiki/infrastructure/markdown-repository.js +168 -0
- package/dist/wiki/infrastructure/markdown-repository.js.map +1 -0
- package/dist/wiki/infrastructure/scan-patterns.d.ts +20 -0
- package/dist/wiki/infrastructure/scan-patterns.d.ts.map +1 -0
- package/dist/wiki/infrastructure/scan-patterns.js +106 -0
- package/dist/wiki/infrastructure/scan-patterns.js.map +1 -0
- package/dist/wiki/infrastructure/scanner-adapter.d.ts +10 -0
- package/dist/wiki/infrastructure/scanner-adapter.d.ts.map +1 -0
- package/dist/wiki/infrastructure/scanner-adapter.js +147 -0
- package/dist/wiki/infrastructure/scanner-adapter.js.map +1 -0
- package/dist/wiki/infrastructure/sqlite-index.d.ts +9 -0
- package/dist/wiki/infrastructure/sqlite-index.d.ts.map +1 -0
- package/dist/wiki/infrastructure/sqlite-index.js +43 -0
- package/dist/wiki/infrastructure/sqlite-index.js.map +1 -0
- package/dist/wiki/infrastructure/trace-adapter.d.ts +7 -0
- package/dist/wiki/infrastructure/trace-adapter.d.ts.map +1 -0
- package/dist/wiki/infrastructure/trace-adapter.js +42 -0
- package/dist/wiki/infrastructure/trace-adapter.js.map +1 -0
- package/dist/wiki/infrastructure/wiki-ingest.d.ts +14 -0
- package/dist/wiki/infrastructure/wiki-ingest.d.ts.map +1 -0
- package/dist/wiki/infrastructure/wiki-ingest.js +138 -0
- package/dist/wiki/infrastructure/wiki-ingest.js.map +1 -0
- package/dist/wiki/infrastructure/wiki-query.d.ts +15 -0
- package/dist/wiki/infrastructure/wiki-query.d.ts.map +1 -0
- package/dist/wiki/infrastructure/wiki-query.js +58 -0
- package/dist/wiki/infrastructure/wiki-query.js.map +1 -0
- package/dist/wiki/infrastructure/wiki-schema.d.ts +3 -0
- package/dist/wiki/infrastructure/wiki-schema.d.ts.map +1 -0
- package/dist/wiki/infrastructure/wiki-schema.js +43 -0
- package/dist/wiki/infrastructure/wiki-schema.js.map +1 -0
- package/dist/wiki/interface/cli.d.ts +7 -0
- package/dist/wiki/interface/cli.d.ts.map +1 -0
- package/dist/wiki/interface/cli.js +160 -0
- package/dist/wiki/interface/cli.js.map +1 -0
- package/dist/wiki/render.d.ts +3 -0
- package/dist/wiki/render.d.ts.map +1 -0
- package/dist/wiki/render.js +58 -0
- package/dist/wiki/render.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Write-decision logic. Maps a salience score + scan verdict + dup
|
|
2
|
+
// check onto a write decision. By construction this NEVER decides to write a
|
|
3
|
+
// canonical page — the strongest outcome is a candidate. Canonical pages come
|
|
4
|
+
// only from the human approve path in the application layer.
|
|
5
|
+
import { isClean } from "./types.js";
|
|
6
|
+
/** Salience thresholds, kept in one place for tuning. */
|
|
7
|
+
export const SALIENCE_THRESHOLDS = {
|
|
8
|
+
/** Total ≥ this proposes a candidate for human approval. */
|
|
9
|
+
proposeCandidate: 8,
|
|
10
|
+
/** Total ≥ this, with a strong verified signal, may auto-append to
|
|
11
|
+
* candidates.jsonl (still never a canonical page). */
|
|
12
|
+
appendCandidate: 10,
|
|
13
|
+
};
|
|
14
|
+
/** Minimum scan passes for a "clean" verdict to be trusted. A clean
|
|
15
|
+
* verdict with fewer passes is treated as
|
|
16
|
+
* incompletely scanned and quarantined — `isClean` reports findings only, it
|
|
17
|
+
* does NOT imply the content was scanned enough to write. */
|
|
18
|
+
export const MIN_SCAN_PASSES = 2;
|
|
19
|
+
/** A "strong verified signal" (accepted fix + passing tests +
|
|
20
|
+
* human-authored note) is encoded as the verified_outcome component at its max.
|
|
21
|
+
* Callers set verified_outcome to 3 only when that bundle holds. */
|
|
22
|
+
function hasStrongVerifiedSignal(score) {
|
|
23
|
+
return score.components.verified_outcome >= 3;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Decide what to do with a proposed write. Precedence:
|
|
27
|
+
* 1. Any injection/secret finding → quarantine (security wins over salience).
|
|
28
|
+
* 2. A clean verdict with too few scan passes → quarantine (incompletely scanned).
|
|
29
|
+
* 3. High duplication → link to the existing page, never a new one.
|
|
30
|
+
* 4. Total ≥ 10 with a strong verified signal → append to candidates.jsonl.
|
|
31
|
+
* 5. Total ≥ 8 and scan clean → propose a candidate for approval.
|
|
32
|
+
* 6. Otherwise → discard.
|
|
33
|
+
*/
|
|
34
|
+
export function decideWrite(score, verdict, dup) {
|
|
35
|
+
if (!isClean(verdict)) {
|
|
36
|
+
return {
|
|
37
|
+
kind: "quarantine",
|
|
38
|
+
reason: `scan found ${verdict.status}; quarantined`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (verdict.passes < MIN_SCAN_PASSES) {
|
|
42
|
+
return {
|
|
43
|
+
kind: "quarantine",
|
|
44
|
+
reason: `scan incomplete (${verdict.passes} < ${MIN_SCAN_PASSES} passes); quarantined pending full scan`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (dup.isHighDuplicate && dup.existingPageId) {
|
|
48
|
+
return {
|
|
49
|
+
kind: "link-existing",
|
|
50
|
+
existingPageId: dup.existingPageId,
|
|
51
|
+
reason: "high duplication; linked to existing page",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (score.total >= SALIENCE_THRESHOLDS.appendCandidate && hasStrongVerifiedSignal(score)) {
|
|
55
|
+
return {
|
|
56
|
+
kind: "append-candidate",
|
|
57
|
+
reason: `salience ${score.total} ≥ ${SALIENCE_THRESHOLDS.appendCandidate} with verified signal`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (score.total >= SALIENCE_THRESHOLDS.proposeCandidate) {
|
|
61
|
+
return {
|
|
62
|
+
kind: "propose-candidate",
|
|
63
|
+
reason: `salience ${score.total} ≥ ${SALIENCE_THRESHOLDS.proposeCandidate}`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
kind: "discard",
|
|
68
|
+
reason: `salience ${score.total} below threshold ${SALIENCE_THRESHOLDS.proposeCandidate}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=write-decision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-decision.js","sourceRoot":"","sources":["../../../src/wiki/domain/write-decision.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,6EAA6E;AAC7E,8EAA8E;AAC9E,6DAA6D;AAQ7D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,yDAAyD;AACzD,MAAM,CAAC,MAAM,mBAAmB,GAAG;IAClC,4DAA4D;IAC5D,gBAAgB,EAAE,CAAC;IACnB;0DACsD;IACtD,eAAe,EAAE,EAAE;CACV,CAAC;AAEX;;;6DAG6D;AAC7D,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AAEjC;;oEAEoE;AACpE,SAAS,uBAAuB,CAAC,KAAoB;IACpD,OAAO,KAAK,CAAC,UAAU,CAAC,gBAAgB,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAC1B,KAAoB,EACpB,OAAyB,EACzB,GAAa;IAEb,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACvB,OAAO;YACN,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,cAAc,OAAO,CAAC,MAAM,eAAe;SACnD,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QACtC,OAAO;YACN,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,oBAAoB,OAAO,CAAC,MAAM,MAAM,eAAe,yCAAyC;SACxG,CAAC;IACH,CAAC;IAED,IAAI,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;QAC/C,OAAO;YACN,IAAI,EAAE,eAAe;YACrB,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,MAAM,EAAE,2CAA2C;SACnD,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,IAAI,mBAAmB,CAAC,eAAe,IAAI,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1F,OAAO;YACN,IAAI,EAAE,kBAAkB;YACxB,MAAM,EAAE,YAAY,KAAK,CAAC,KAAK,MAAM,mBAAmB,CAAC,eAAe,uBAAuB;SAC/F,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,IAAI,mBAAmB,CAAC,gBAAgB,EAAE,CAAC;QACzD,OAAO;YACN,IAAI,EAAE,mBAAmB;YACzB,MAAM,EAAE,YAAY,KAAK,CAAC,KAAK,MAAM,mBAAmB,CAAC,gBAAgB,EAAE;SAC3E,CAAC;IACH,CAAC;IAED,OAAO;QACN,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,YAAY,KAAK,CAAC,KAAK,oBAAoB,mBAAmB,CAAC,gBAAgB,EAAE;KACzF,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { WikiSeed } from "../domain/index.js";
|
|
2
|
+
import type { Fetcher, FetchedDoc } from "../application/ports.js";
|
|
3
|
+
interface FetchResponse {
|
|
4
|
+
status: number;
|
|
5
|
+
ok: boolean;
|
|
6
|
+
headers: {
|
|
7
|
+
get(name: string): string | null;
|
|
8
|
+
};
|
|
9
|
+
body: {
|
|
10
|
+
getReader(): {
|
|
11
|
+
read(): Promise<{
|
|
12
|
+
done: boolean;
|
|
13
|
+
value?: Uint8Array;
|
|
14
|
+
}>;
|
|
15
|
+
cancel(): Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
} | null;
|
|
18
|
+
text(): Promise<string>;
|
|
19
|
+
}
|
|
20
|
+
export type FetchImpl = (url: string, init: {
|
|
21
|
+
redirect: "manual";
|
|
22
|
+
signal: unknown;
|
|
23
|
+
headers: Record<string, string>;
|
|
24
|
+
}) => Promise<FetchResponse>;
|
|
25
|
+
export interface FetcherOptions {
|
|
26
|
+
fetchImpl?: FetchImpl;
|
|
27
|
+
maxBytes?: number;
|
|
28
|
+
maxHops?: number;
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
}
|
|
31
|
+
export declare class FetcherAdapter implements Fetcher {
|
|
32
|
+
private readonly fetchImpl;
|
|
33
|
+
private readonly maxBytes;
|
|
34
|
+
private readonly maxHops;
|
|
35
|
+
private readonly timeoutMs;
|
|
36
|
+
constructor(opts?: FetcherOptions);
|
|
37
|
+
/** Map a seed to a fetch URL. Web seeds carry a URL; arXiv/GitHub map to their public APIs. */
|
|
38
|
+
buildUrl(seed: WikiSeed): string;
|
|
39
|
+
fetch(seed: WikiSeed): Promise<FetchedDoc>;
|
|
40
|
+
/** url-guard at EVERY hop; manual redirects; size cap; timeout. */
|
|
41
|
+
private safeGet;
|
|
42
|
+
private readCapped;
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=fetcher-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetcher-adapter.d.ts","sourceRoot":"","sources":["../../../src/wiki/infrastructure/fetcher-adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAUnE,UAAU,aAAa;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE;QAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC9C,IAAI,EAAE;QAAE,SAAS,IAAI;YAAE,IAAI,IAAI,OAAO,CAAC;gBAAE,IAAI,EAAE,OAAO,CAAC;gBAAC,KAAK,CAAC,EAAE,UAAU,CAAA;aAAE,CAAC,CAAC;YAAC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;SAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAClH,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACxB;AACD,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;AAEhJ,MAAM,WAAW,cAAc;IAC9B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAMD,qBAAa,cAAe,YAAW,OAAO;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,IAAI,GAAE,cAAmB;IAQrC,+FAA+F;IAC/F,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM;IAa1B,KAAK,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAahD,mEAAmE;YACrD,OAAO;YA2BP,UAAU;CAqBxB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { isSafeSourceUrl, MAX_CONTENT_BYTES } from "./scanner-adapter.js";
|
|
3
|
+
function sha16(s) {
|
|
4
|
+
return createHash("sha256").update(s).digest("hex").slice(0, 16);
|
|
5
|
+
}
|
|
6
|
+
export class FetcherAdapter {
|
|
7
|
+
fetchImpl;
|
|
8
|
+
maxBytes;
|
|
9
|
+
maxHops;
|
|
10
|
+
timeoutMs;
|
|
11
|
+
constructor(opts = {}) {
|
|
12
|
+
// Builtin fetch is structurally compatible with FetchResponse (undici). Cast at the boundary.
|
|
13
|
+
this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
14
|
+
this.maxBytes = opts.maxBytes ?? MAX_CONTENT_BYTES;
|
|
15
|
+
this.maxHops = opts.maxHops ?? 3;
|
|
16
|
+
this.timeoutMs = opts.timeoutMs ?? 15000;
|
|
17
|
+
}
|
|
18
|
+
/** Map a seed to a fetch URL. Web seeds carry a URL; arXiv/GitHub map to their public APIs. */
|
|
19
|
+
buildUrl(seed) {
|
|
20
|
+
switch (seed.kind) {
|
|
21
|
+
case "web":
|
|
22
|
+
return seed.query;
|
|
23
|
+
case "arxiv":
|
|
24
|
+
return "http://export.arxiv.org/api/query?search_query=all:" + encodeURIComponent(seed.query) + "&max_results=1";
|
|
25
|
+
case "github":
|
|
26
|
+
return "https://api.github.com/search/repositories?q=" + encodeURIComponent(seed.query) + "&per_page=1";
|
|
27
|
+
default:
|
|
28
|
+
throw new Error("seed kind is not fetchable: " + seed.kind);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async fetch(seed) {
|
|
32
|
+
const url = this.buildUrl(seed);
|
|
33
|
+
const content = await this.safeGet(url);
|
|
34
|
+
const source = {
|
|
35
|
+
id: "src-" + sha16(url),
|
|
36
|
+
kind: seed.kind,
|
|
37
|
+
url,
|
|
38
|
+
fetchedAt: new Date().toISOString(),
|
|
39
|
+
contentHash: sha16(content),
|
|
40
|
+
};
|
|
41
|
+
return { content, sourceUrl: url, source };
|
|
42
|
+
}
|
|
43
|
+
/** url-guard at EVERY hop; manual redirects; size cap; timeout. */
|
|
44
|
+
async safeGet(startUrl) {
|
|
45
|
+
let url = startUrl;
|
|
46
|
+
for (let hop = 0; hop <= this.maxHops; hop++) {
|
|
47
|
+
if (!isSafeSourceUrl(url))
|
|
48
|
+
throw new Error("blocked unsafe URL: " + url);
|
|
49
|
+
const ctrl = new AbortController();
|
|
50
|
+
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
51
|
+
let res;
|
|
52
|
+
try {
|
|
53
|
+
res = await this.fetchImpl(url, { redirect: "manual", signal: ctrl.signal, headers: { "user-agent": "mewkit-wiki-research" } });
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
}
|
|
58
|
+
if (res.status >= 300 && res.status < 400) {
|
|
59
|
+
const loc = res.headers.get("location");
|
|
60
|
+
if (!loc)
|
|
61
|
+
throw new Error("redirect without Location header");
|
|
62
|
+
url = new URL(loc, url).toString(); // resolve relative; re-validated at loop top
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (!res.ok)
|
|
66
|
+
throw new Error("fetch failed: HTTP " + res.status);
|
|
67
|
+
const cl = Number(res.headers.get("content-length") ?? "0");
|
|
68
|
+
// Finite-guard: a non-numeric header coerces to NaN; the streaming cap is the real backstop.
|
|
69
|
+
if (Number.isFinite(cl) && cl > this.maxBytes)
|
|
70
|
+
throw new Error("size cap exceeded (content-length)");
|
|
71
|
+
return await this.readCapped(res);
|
|
72
|
+
}
|
|
73
|
+
throw new Error("too many redirects (> " + this.maxHops + ")");
|
|
74
|
+
}
|
|
75
|
+
async readCapped(res) {
|
|
76
|
+
// Fail closed on a body-less response — res.text() would read unbounded into memory with
|
|
77
|
+
// no streaming cap. A normal GET 200 always exposes a readable body.
|
|
78
|
+
if (!res.body)
|
|
79
|
+
throw new Error("response has no readable body");
|
|
80
|
+
const reader = res.body.getReader();
|
|
81
|
+
const chunks = [];
|
|
82
|
+
let total = 0;
|
|
83
|
+
for (;;) {
|
|
84
|
+
const { done, value } = await reader.read();
|
|
85
|
+
if (done)
|
|
86
|
+
break;
|
|
87
|
+
if (value) {
|
|
88
|
+
total += value.length;
|
|
89
|
+
if (total > this.maxBytes) {
|
|
90
|
+
await reader.cancel();
|
|
91
|
+
throw new Error("size cap exceeded during stream");
|
|
92
|
+
}
|
|
93
|
+
chunks.push(value);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=fetcher-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetcher-adapter.js","sourceRoot":"","sources":["../../../src/wiki/infrastructure/fetcher-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { InventoryRegistrar } from "../application/ports.js";
|
|
2
|
+
/** The wiki serves the existing "project-memory" responsibility (see core/substrate.ts TAXONOMY). */
|
|
3
|
+
export declare const WIKI_RESPONSIBILITY = "project-memory";
|
|
4
|
+
export declare class InventoryAdapter implements InventoryRegistrar {
|
|
5
|
+
private readonly claudeDir;
|
|
6
|
+
constructor(claudeDir: string);
|
|
7
|
+
private file;
|
|
8
|
+
register(artifactPath: string, meta?: {
|
|
9
|
+
criticality?: string;
|
|
10
|
+
status?: string;
|
|
11
|
+
}): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=inventory-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inventory-adapter.d.ts","sourceRoot":"","sources":["../../../src/wiki/infrastructure/inventory-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAOlE,qGAAqG;AACrG,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAOpD,qBAAa,gBAAiB,YAAW,kBAAkB;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM;IAE9C,OAAO,CAAC,IAAI;IAIZ,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,IAAI;CA0B1F"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
// Registers wiki harness artifacts into .claude/harness-inventory.json under an existing
|
|
4
|
+
// taxonomy value. The wiki IS long-term project memory, so it reuses "project-memory" — no
|
|
5
|
+
// new taxonomy enum value is needed (decided, not assumed). Idempotent: re-registering the
|
|
6
|
+
// same path is a no-op, so `mewkit inventory --substrate` shows no drift on repeat runs.
|
|
7
|
+
/** The wiki serves the existing "project-memory" responsibility (see core/substrate.ts TAXONOMY). */
|
|
8
|
+
export const WIKI_RESPONSIBILITY = "project-memory";
|
|
9
|
+
export class InventoryAdapter {
|
|
10
|
+
claudeDir;
|
|
11
|
+
constructor(claudeDir) {
|
|
12
|
+
this.claudeDir = claudeDir;
|
|
13
|
+
}
|
|
14
|
+
file() {
|
|
15
|
+
return path.join(this.claudeDir, "harness-inventory.json");
|
|
16
|
+
}
|
|
17
|
+
register(artifactPath, meta = {}) {
|
|
18
|
+
const file = this.file();
|
|
19
|
+
if (!fs.existsSync(file))
|
|
20
|
+
return; // no registry in this tree — nothing to tag
|
|
21
|
+
let parsed;
|
|
22
|
+
try {
|
|
23
|
+
parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return; // tolerant: a malformed registry is not this adapter's to repair
|
|
27
|
+
}
|
|
28
|
+
if (!parsed.artifacts || typeof parsed.artifacts !== "object")
|
|
29
|
+
return;
|
|
30
|
+
const desired = {
|
|
31
|
+
owner: "lifecycle",
|
|
32
|
+
criticality: meta.criticality ?? "medium",
|
|
33
|
+
status: meta.status ?? "active",
|
|
34
|
+
runtime: "portable",
|
|
35
|
+
responsibility: WIKI_RESPONSIBILITY,
|
|
36
|
+
};
|
|
37
|
+
const existing = parsed.artifacts[artifactPath];
|
|
38
|
+
if (existing && JSON.stringify(existing) === JSON.stringify(desired))
|
|
39
|
+
return; // idempotent
|
|
40
|
+
parsed.artifacts[artifactPath] = desired;
|
|
41
|
+
const tmp = file + ".tmp-" + process.pid;
|
|
42
|
+
fs.writeFileSync(tmp, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
43
|
+
fs.renameSync(tmp, file);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=inventory-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inventory-adapter.js","sourceRoot":"","sources":["../../../src/wiki/infrastructure/inventory-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,yFAAyF;AACzF,2FAA2F;AAC3F,2FAA2F;AAC3F,yFAAyF;AAEzF,qGAAqG;AACrG,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAOpD,MAAM,OAAO,gBAAgB;IACC;IAA7B,YAA6B,SAAiB;QAAjB,cAAS,GAAT,SAAS,CAAQ;IAAG,CAAC;IAE1C,IAAI;QACX,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;IAC5D,CAAC;IAED,QAAQ,CAAC,YAAoB,EAAE,OAAkD,EAAE;QAClF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,4CAA4C;QAC9E,IAAI,MAAqB,CAAC;QAC1B,IAAI,CAAC;YACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAkB,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,CAAC,iEAAiE;QAC1E,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;YAAE,OAAO;QAEtE,MAAM,OAAO,GAAG;YACf,KAAK,EAAE,WAAW;YAClB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,QAAQ;YACzC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,QAAQ;YAC/B,OAAO,EAAE,UAAU;YACnB,cAAc,EAAE,mBAAmB;SACnC,CAAC;QACF,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAChD,IAAI,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAAE,OAAO,CAAC,aAAa;QAE3F,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC;QACzC,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;QACvE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;CACD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { InjectionVerdict, WikiCandidate, WikiIntervention, WikiPage, WikiSeed, WikiSlug, WikiSource } from "../domain/index.js";
|
|
2
|
+
import type { ApprovedWrite, WikiRepository } from "../application/ports.js";
|
|
3
|
+
export declare class MarkdownWikiRepository implements WikiRepository {
|
|
4
|
+
private readonly projectRoot;
|
|
5
|
+
constructor(projectRoot: string);
|
|
6
|
+
private wikiDir;
|
|
7
|
+
/** Resolve a repo-relative sub-path inside a slug dir, rejecting traversal. */
|
|
8
|
+
private resolveInSlug;
|
|
9
|
+
createWiki(slug: WikiSlug, title: string): void;
|
|
10
|
+
writePage(token: ApprovedWrite): void;
|
|
11
|
+
readPage(slug: WikiSlug, file: string): WikiPage | null;
|
|
12
|
+
listPages(slug: WikiSlug): string[];
|
|
13
|
+
private appendJsonl;
|
|
14
|
+
private readJsonl;
|
|
15
|
+
appendCandidate(candidate: WikiCandidate): void;
|
|
16
|
+
appendIntervention(slug: WikiSlug, intervention: WikiIntervention): void;
|
|
17
|
+
appendSeed(slug: WikiSlug, seed: WikiSeed): void;
|
|
18
|
+
appendSource(slug: WikiSlug, source: WikiSource): void;
|
|
19
|
+
listCandidates(slug: WikiSlug): WikiCandidate[];
|
|
20
|
+
getCandidate(slug: WikiSlug, id: string): WikiCandidate | null;
|
|
21
|
+
quarantine(slug: WikiSlug, content: string, verdict: InjectionVerdict): string;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=markdown-repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-repository.d.ts","sourceRoot":"","sources":["../../../src/wiki/infrastructure/markdown-repository.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACX,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAwC7E,qBAAa,sBAAuB,YAAW,cAAc;IAChD,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAAX,WAAW,EAAE,MAAM;IAEhD,OAAO,CAAC,OAAO;IAIf,+EAA+E;IAC/E,OAAO,CAAC,aAAa;IAUrB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK/C,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAqBrC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAwBvD,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE;IAMnC,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,SAAS;IAgBjB,eAAe,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI;IAI/C,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,GAAG,IAAI;IAIxE,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IAIhD,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAItD,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,aAAa,EAAE;IAM/C,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAI9D,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM;CAQ9E"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import yaml from "js-yaml";
|
|
5
|
+
import { assertCanonicalComplete, assertNoTraversal, makeWikiPageId, makeWikiSlug } from "../domain/index.js";
|
|
6
|
+
// Canonical Markdown repository for tasks/wikis/<slug>/. All writes are atomic (temp-file +
|
|
7
|
+
// rename) via a LOCAL helper — there is no shared IO wrapper and no-direct-io does not cover
|
|
8
|
+
// src/wiki/, so the safety property is type-enforced: writePage accepts ONLY an ApprovedWrite
|
|
9
|
+
// token. Quarantined content lands in a read-blocked .quarantined file.
|
|
10
|
+
function atomicWriteText(filePath, text) {
|
|
11
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
12
|
+
const tmp = filePath + ".tmp-" + process.pid;
|
|
13
|
+
fs.writeFileSync(tmp, text, "utf-8");
|
|
14
|
+
fs.renameSync(tmp, filePath);
|
|
15
|
+
}
|
|
16
|
+
/** Minimal runtime shape check for a candidate record from JSONL. The required string fields
|
|
17
|
+
* + a salience object are what the approve path and index ingest rely on; malformed records
|
|
18
|
+
* (incl. anything an untrusted producer might emit) are dropped. */
|
|
19
|
+
function isCandidateRecord(r) {
|
|
20
|
+
if (!r || typeof r !== "object")
|
|
21
|
+
return false;
|
|
22
|
+
const o = r;
|
|
23
|
+
return (typeof o["id"] === "string" &&
|
|
24
|
+
typeof o["slug"] === "string" &&
|
|
25
|
+
typeof o["title"] === "string" &&
|
|
26
|
+
typeof o["content"] === "string" &&
|
|
27
|
+
typeof o["state"] === "string" &&
|
|
28
|
+
typeof o["salience"] === "object" &&
|
|
29
|
+
o["salience"] !== null);
|
|
30
|
+
}
|
|
31
|
+
function parseFrontmatter(raw) {
|
|
32
|
+
if (!raw.startsWith("---"))
|
|
33
|
+
return { meta: {}, body: raw };
|
|
34
|
+
const end = raw.indexOf("\n---", 3);
|
|
35
|
+
if (end === -1)
|
|
36
|
+
return { meta: {}, body: raw };
|
|
37
|
+
const loaded = yaml.load(raw.slice(3, end).trim());
|
|
38
|
+
const meta = loaded && typeof loaded === "object" ? loaded : {};
|
|
39
|
+
return { meta, body: raw.slice(end + 4).replace(/^\r?\n/, "") };
|
|
40
|
+
}
|
|
41
|
+
export class MarkdownWikiRepository {
|
|
42
|
+
projectRoot;
|
|
43
|
+
constructor(projectRoot) {
|
|
44
|
+
this.projectRoot = projectRoot;
|
|
45
|
+
}
|
|
46
|
+
wikiDir(slug) {
|
|
47
|
+
return path.join(this.projectRoot, "tasks", "wikis", slug);
|
|
48
|
+
}
|
|
49
|
+
/** Resolve a repo-relative sub-path inside a slug dir, rejecting traversal. */
|
|
50
|
+
resolveInSlug(slug, relative) {
|
|
51
|
+
assertNoTraversal(relative);
|
|
52
|
+
const base = this.wikiDir(slug);
|
|
53
|
+
const target = path.resolve(base, relative);
|
|
54
|
+
if (target !== base && !target.startsWith(base + path.sep)) {
|
|
55
|
+
throw new Error("path escapes the wiki directory: " + JSON.stringify(relative));
|
|
56
|
+
}
|
|
57
|
+
return target;
|
|
58
|
+
}
|
|
59
|
+
createWiki(slug, title) {
|
|
60
|
+
const meta = { slug, title, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() };
|
|
61
|
+
atomicWriteText(path.join(this.wikiDir(slug), "wiki.json"), JSON.stringify(meta, null, 2) + "\n");
|
|
62
|
+
}
|
|
63
|
+
writePage(token) {
|
|
64
|
+
const page = token.page;
|
|
65
|
+
assertCanonicalComplete(page); // re-assert invariants at the write boundary
|
|
66
|
+
const target = this.resolveInSlug(page.slug, page.path);
|
|
67
|
+
// `origin` stays top-level so the ingest reads it; full provenance is persisted too.
|
|
68
|
+
const meta = {
|
|
69
|
+
id: page.id,
|
|
70
|
+
slug: page.slug,
|
|
71
|
+
title: page.title,
|
|
72
|
+
state: page.state,
|
|
73
|
+
origin: page.provenance.origin,
|
|
74
|
+
createdAt: page.createdAt,
|
|
75
|
+
updatedAt: page.updatedAt,
|
|
76
|
+
links: page.links,
|
|
77
|
+
sourceIds: page.provenance.sourceIds,
|
|
78
|
+
};
|
|
79
|
+
if (page.provenance.approvedBy)
|
|
80
|
+
meta["approvedBy"] = page.provenance.approvedBy;
|
|
81
|
+
if (page.provenance.candidateId)
|
|
82
|
+
meta["candidateId"] = page.provenance.candidateId;
|
|
83
|
+
atomicWriteText(target, "---\n" + yaml.dump(meta) + "---\n" + page.content + "\n");
|
|
84
|
+
}
|
|
85
|
+
readPage(slug, file) {
|
|
86
|
+
const target = this.resolveInSlug(slug, path.join("pages", file));
|
|
87
|
+
if (!fs.existsSync(target))
|
|
88
|
+
return null;
|
|
89
|
+
const { meta, body } = parseFrontmatter(fs.readFileSync(target, "utf-8"));
|
|
90
|
+
const origin = meta["origin"] === "agent" || meta["origin"] === "system" ? meta["origin"] : "human";
|
|
91
|
+
return {
|
|
92
|
+
id: makeWikiPageId(typeof meta["id"] === "string" ? meta["id"] : slug + "/" + file),
|
|
93
|
+
slug: makeWikiSlug(typeof meta["slug"] === "string" ? meta["slug"] : slug),
|
|
94
|
+
title: typeof meta["title"] === "string" ? meta["title"] : file.replace(/\.md$/, ""),
|
|
95
|
+
path: path.join("pages", file),
|
|
96
|
+
content: body,
|
|
97
|
+
state: typeof meta["state"] === "string" ? meta["state"] : "committed",
|
|
98
|
+
createdAt: typeof meta["createdAt"] === "string" ? meta["createdAt"] : "",
|
|
99
|
+
updatedAt: typeof meta["updatedAt"] === "string" ? meta["updatedAt"] : "",
|
|
100
|
+
provenance: {
|
|
101
|
+
origin,
|
|
102
|
+
sourceIds: Array.isArray(meta["sourceIds"]) ? meta["sourceIds"] : [],
|
|
103
|
+
approvedBy: typeof meta["approvedBy"] === "string" ? meta["approvedBy"] : undefined,
|
|
104
|
+
candidateId: typeof meta["candidateId"] === "string" ? meta["candidateId"] : undefined,
|
|
105
|
+
},
|
|
106
|
+
links: [],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
listPages(slug) {
|
|
110
|
+
const dir = path.join(this.wikiDir(slug), "pages");
|
|
111
|
+
if (!fs.existsSync(dir))
|
|
112
|
+
return [];
|
|
113
|
+
return fs.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
114
|
+
}
|
|
115
|
+
appendJsonl(slug, file, record) {
|
|
116
|
+
const target = this.resolveInSlug(slug, file);
|
|
117
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
118
|
+
fs.appendFileSync(target, JSON.stringify(record) + "\n", "utf-8");
|
|
119
|
+
}
|
|
120
|
+
readJsonl(slug, file) {
|
|
121
|
+
const target = this.resolveInSlug(slug, file);
|
|
122
|
+
if (!fs.existsSync(target))
|
|
123
|
+
return [];
|
|
124
|
+
const out = [];
|
|
125
|
+
for (const line of fs.readFileSync(target, "utf-8").split("\n")) {
|
|
126
|
+
if (!line.trim())
|
|
127
|
+
continue;
|
|
128
|
+
try {
|
|
129
|
+
const parsed = JSON.parse(line);
|
|
130
|
+
if (parsed && typeof parsed === "object")
|
|
131
|
+
out.push(parsed);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// tolerant — skip a malformed line
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
appendCandidate(candidate) {
|
|
140
|
+
this.appendJsonl(candidate.slug, "candidates.jsonl", candidate);
|
|
141
|
+
}
|
|
142
|
+
appendIntervention(slug, intervention) {
|
|
143
|
+
this.appendJsonl(slug, "interventions.jsonl", intervention);
|
|
144
|
+
}
|
|
145
|
+
appendSeed(slug, seed) {
|
|
146
|
+
this.appendJsonl(slug, "seeds.jsonl", seed);
|
|
147
|
+
}
|
|
148
|
+
appendSource(slug, source) {
|
|
149
|
+
this.appendJsonl(slug, "sources.jsonl", source);
|
|
150
|
+
}
|
|
151
|
+
listCandidates(slug) {
|
|
152
|
+
// Runtime shape guard at the store boundary — candidates.jsonl gains an untrusted
|
|
153
|
+
// producer (fetched→candidate), so malformed records are skipped, not cast blind.
|
|
154
|
+
return this.readJsonl(slug, "candidates.jsonl").filter(isCandidateRecord);
|
|
155
|
+
}
|
|
156
|
+
getCandidate(slug, id) {
|
|
157
|
+
return this.listCandidates(slug).find((c) => c.id === id) ?? null;
|
|
158
|
+
}
|
|
159
|
+
quarantine(slug, content, verdict) {
|
|
160
|
+
const hash = createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
161
|
+
const target = this.resolveInSlug(slug, path.join("quarantine", hash + ".quarantined"));
|
|
162
|
+
const header = "QUARANTINED — DATA, do not execute. verdict=" + verdict.status + " findings=" + JSON.stringify(verdict.findings) + "\n";
|
|
163
|
+
atomicWriteText(target, header + content);
|
|
164
|
+
fs.chmodSync(target, 0o400); // owner read-only — re-injection-resistant at rest
|
|
165
|
+
return target;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=markdown-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-repository.js","sourceRoot":"","sources":["../../../src/wiki/infrastructure/markdown-repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Injection patterns. First 8 are verbatim from validate-content.cjs; the rest are the
|
|
2
|
+
* web-to-markdown Layer 5 local additions (tool-call hijack, memory poisoning, role-play). */
|
|
3
|
+
export declare const INJECTION_PATTERNS: readonly RegExp[];
|
|
4
|
+
export interface ContentValidation {
|
|
5
|
+
valid: boolean;
|
|
6
|
+
pattern?: string;
|
|
7
|
+
match?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Mirror of validate-content.cjs: {valid:true} on pass (no pattern/match);
|
|
10
|
+
* {valid:false, pattern, match} on the first hit. */
|
|
11
|
+
export declare function validateContent(text: string): ContentValidation;
|
|
12
|
+
/** Secret patterns, ported verbatim from secret-scrub.cjs. Conservative: false positives
|
|
13
|
+
* accepted, missed secrets are not. Each entry is [matcher, replacement]. */
|
|
14
|
+
export declare const SECRET_PATTERNS: readonly (readonly [RegExp, string])[];
|
|
15
|
+
/** Mirror of secret-scrub.cjs scrubSecrets. */
|
|
16
|
+
export declare function scrubSecrets(input: string): string;
|
|
17
|
+
/** Strip zero-width chars and apply NFKC (catches homoglyph/zero-width obfuscation),
|
|
18
|
+
* per web-to-markdown Layer 5 pass 1. */
|
|
19
|
+
export declare function normalizeForScan(text: string): string;
|
|
20
|
+
//# sourceMappingURL=scan-patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-patterns.d.ts","sourceRoot":"","sources":["../../../src/wiki/infrastructure/scan-patterns.ts"],"names":[],"mappings":"AASA;8FAC8F;AAC9F,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EA8C/C,CAAC;AAEF,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;qDACqD;AACrD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAO/D;AAED;6EAC6E;AAC7E,eAAO,MAAM,eAAe,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAmBjE,CAAC;AAEF,+CAA+C;AAC/C,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED;yCACyC;AACzC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD"}
|