@agentsean/content 1.0.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.
Files changed (50) hide show
  1. package/LICENSE +661 -0
  2. package/dist/brief.d.ts +15 -0
  3. package/dist/brief.d.ts.map +1 -0
  4. package/dist/brief.js +68 -0
  5. package/dist/brief.js.map +1 -0
  6. package/dist/decay.d.ts +7 -0
  7. package/dist/decay.d.ts.map +1 -0
  8. package/dist/decay.js +38 -0
  9. package/dist/decay.js.map +1 -0
  10. package/dist/disclosure.d.ts +8 -0
  11. package/dist/disclosure.d.ts.map +1 -0
  12. package/dist/disclosure.js +39 -0
  13. package/dist/disclosure.js.map +1 -0
  14. package/dist/engine.d.ts +11 -0
  15. package/dist/engine.d.ts.map +1 -0
  16. package/dist/engine.js +300 -0
  17. package/dist/engine.js.map +1 -0
  18. package/dist/evidence.d.ts +10 -0
  19. package/dist/evidence.d.ts.map +1 -0
  20. package/dist/evidence.js +11 -0
  21. package/dist/evidence.js.map +1 -0
  22. package/dist/extract.d.ts +9 -0
  23. package/dist/extract.d.ts.map +1 -0
  24. package/dist/extract.js +86 -0
  25. package/dist/extract.js.map +1 -0
  26. package/dist/gate.d.ts +16 -0
  27. package/dist/gate.d.ts.map +1 -0
  28. package/dist/gate.js +164 -0
  29. package/dist/gate.js.map +1 -0
  30. package/dist/generate.d.ts +15 -0
  31. package/dist/generate.d.ts.map +1 -0
  32. package/dist/generate.js +95 -0
  33. package/dist/generate.js.map +1 -0
  34. package/dist/index.d.ts +13 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +12 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/persist.d.ts +50 -0
  39. package/dist/persist.d.ts.map +1 -0
  40. package/dist/persist.js +130 -0
  41. package/dist/persist.js.map +1 -0
  42. package/dist/score.d.ts +4 -0
  43. package/dist/score.d.ts.map +1 -0
  44. package/dist/score.js +27 -0
  45. package/dist/score.js.map +1 -0
  46. package/dist/types.d.ts +133 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +7 -0
  49. package/dist/types.js.map +1 -0
  50. package/package.json +58 -0
@@ -0,0 +1,86 @@
1
+ const STOP = new Set("a an the and or of to for in on with without from by at as is are was were be been being this that these those it its you your we our they their not but if then than too very just into over after before about into up out so no yes can will".split(" "));
2
+ export function stripHtml(html) {
3
+ return html
4
+ .replace(/<script[\s\S]*?<\/script>/gi, " ")
5
+ .replace(/<style[\s\S]*?<\/style>/gi, " ")
6
+ .replace(/<[^>]+>/g, " ")
7
+ .replace(/&nbsp;/g, " ")
8
+ .replace(/&amp;/g, "&")
9
+ .replace(/&lt;/g, "<")
10
+ .replace(/&gt;/g, ">")
11
+ .replace(/\s+/g, " ")
12
+ .trim();
13
+ }
14
+ export function wordCount(text) {
15
+ const t = stripHtml(text);
16
+ if (!t)
17
+ return 0;
18
+ return t.split(/\s+/).filter(Boolean).length;
19
+ }
20
+ export function extractHeadings(text) {
21
+ const out = [];
22
+ for (const m of text.matchAll(/<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi)) {
23
+ const inner = stripHtml(m[2] ?? "");
24
+ if (inner)
25
+ out.push(inner);
26
+ }
27
+ for (const m of text.matchAll(/^(#{1,6})\s+(.+)$/gm)) {
28
+ const inner = (m[2] ?? "").trim();
29
+ if (inner)
30
+ out.push(inner);
31
+ }
32
+ return [...new Set(out)].slice(0, 20);
33
+ }
34
+ export function extractEntities(text, extra = []) {
35
+ const plain = stripHtml(text);
36
+ const counts = new Map();
37
+ for (const raw of plain.split(/[^A-Za-z0-9]+/)) {
38
+ const w = raw.trim();
39
+ if (w.length < 4)
40
+ continue;
41
+ const lower = w.toLowerCase();
42
+ if (STOP.has(lower))
43
+ continue;
44
+ counts.set(lower, (counts.get(lower) ?? 0) + 1);
45
+ }
46
+ const phrases = [...plain.matchAll(/\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+){0,3})\b/g)].map((m) => m[1] ?? "");
47
+ for (const p of phrases) {
48
+ if (p.split(" ").length < 2)
49
+ continue;
50
+ const lower = p.toLowerCase();
51
+ counts.set(lower, (counts.get(lower) ?? 0) + 2);
52
+ }
53
+ for (const e of extra) {
54
+ const lower = e.toLowerCase();
55
+ if (lower.length >= 3)
56
+ counts.set(lower, (counts.get(lower) ?? 0) + 3);
57
+ }
58
+ return [...counts.entries()]
59
+ .toSorted((a, b) => b[1] - a[1])
60
+ .map(([k]) => k)
61
+ .slice(0, 50);
62
+ }
63
+ export function extractQuestions(queries, headings) {
64
+ const q = new Set();
65
+ for (const row of queries) {
66
+ if (/\b(who|what|when|where|why|how|should|can)\b/i.test(row.query) ||
67
+ row.query.includes("?")) {
68
+ q.add(row.query.trim());
69
+ }
70
+ }
71
+ for (const h of headings) {
72
+ if (h.includes("?"))
73
+ q.add(h);
74
+ }
75
+ return [...q].slice(0, 12);
76
+ }
77
+ const NUMBER_RE = /(?:\$[\d,]+(?:\.\d+)?|\b\d{1,3}(?:,\d{3})+(?:\.\d+)?\b|\b\d+(?:\.\d+)?%|\b\d{2,}(?:\.\d+)?\b)/g;
78
+ export function numericClaims(text) {
79
+ const cleaned = text.replace(/<!--[\s\S]*?-->/g, " ");
80
+ const hits = cleaned.match(NUMBER_RE) ?? [];
81
+ return [...new Set(hits.map((h) => h.trim()))];
82
+ }
83
+ export function factsFromText(text, sourceUrl) {
84
+ return numericClaims(text).map((claim) => ({ claim, sourceUrl }));
85
+ }
86
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../src/extract.ts"],"names":[],"mappings":"AAEA,MAAM,IAAI,GAAG,IAAI,GAAG,CAClB,iPAAiP,CAAC,KAAK,CACrP,GAAG,CACJ,CACF,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,IAAI;SACR,OAAO,CAAC,6BAA6B,EAAE,GAAG,CAAC;SAC3C,OAAO,CAAC,2BAA2B,EAAE,GAAG,CAAC;SACzC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACjB,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,oCAAoC,CAAC,EAAE,CAAC;QACpE,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACpC,IAAI,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,QAAkB,EAAE;IAChE,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAC3B,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QAC9B,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,2CAA2C,CAAC,CAAC,CAAC,GAAG,CAClF,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAClB,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QACtC,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9B,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;SACzB,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SAC/B,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;SACf,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAqB,EAAE,QAAkB;IACxE,MAAM,CAAC,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5B,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IACE,+CAA+C,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAC/D,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EACvB,CAAC;YACD,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,SAAS,GACb,gGAAgG,CAAC;AAEnG,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAC5C,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,SAAiB;IAC3D,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;AACpE,CAAC"}
package/dist/gate.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import type { ContentBrief, ContentDraft, PublishGateResult, StyleProfile } from "./types.js";
2
+ export type GateContext = {
3
+ brief: ContentBrief;
4
+ draft: ContentDraft;
5
+ style: StyleProfile;
6
+ corpus: Array<{
7
+ url: string;
8
+ body: string;
9
+ }>;
10
+ ymylCategory: string | null;
11
+ newPagesToday: number;
12
+ kind: "refresh" | "create";
13
+ };
14
+ export declare function runPublishGate(ctx: GateContext): PublishGateResult;
15
+ export declare function coverageScore(brief: ContentBrief, body: string): number;
16
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EAEZ,iBAAiB,EACjB,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;CAC5B,CAAC;AAqNF,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,iBAAiB,CAclE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvE"}
package/dist/gate.js ADDED
@@ -0,0 +1,164 @@
1
+ import { BLAST, bannedHits } from "@agentsean/actions";
2
+ import { validateJsonLdBlocks } from "@agentsean/analyzers";
3
+ import { nearDuplicate, simhashHex } from "@agentsean/crawler";
4
+ import { contentScore } from "./score.js";
5
+ import { hasDisclosure } from "./disclosure.js";
6
+ import { extractHeadings, numericClaims, wordCount } from "./extract.js";
7
+ function check(id, code, ok, detail) {
8
+ return { id, code, ok, detail };
9
+ }
10
+ function sourceText(brief) {
11
+ return [
12
+ ...brief.facts.map((f) => f.claim),
13
+ ...brief.sources.map((s) => s.text),
14
+ ...brief.topics,
15
+ brief.title,
16
+ ].join("\n");
17
+ }
18
+ function factCheck(ctx) {
19
+ const allowed = sourceText(ctx.brief);
20
+ const claims = numericClaims(ctx.draft.body);
21
+ const missing = claims.filter((c) => !allowed.includes(c));
22
+ return check(1, "FACT_CHECK", missing.length === 0, missing.length
23
+ ? `untraced claims: ${missing.join(", ")}`
24
+ : `${claims.length} numeric claims traced to the brief`);
25
+ }
26
+ function nearDup(ctx) {
27
+ const hex = simhashHex(ctx.draft.body);
28
+ for (const page of ctx.corpus) {
29
+ if (page.url === ctx.brief.targetUrl)
30
+ continue;
31
+ if (nearDuplicate(hex, simhashHex(page.body), 3)) {
32
+ return check(2, "NEAR_DUPLICATE", false, `near-duplicate of ${page.url}`);
33
+ }
34
+ }
35
+ const self = ctx.corpus.find((p) => p.url === ctx.brief.targetUrl);
36
+ if (self && ctx.kind === "refresh") {
37
+ // Refreshing the same URL is allowed; identical copy is not a refresh.
38
+ if (nearDuplicate(hex, simhashHex(self.body), 1) &&
39
+ wordCount(ctx.draft.body) < ctx.brief.currentWordCount + 40) {
40
+ return check(2, "NEAR_DUPLICATE", false, "draft is effectively the existing page");
41
+ }
42
+ }
43
+ return check(2, "NEAR_DUPLICATE", true, "not a near-duplicate of the site corpus");
44
+ }
45
+ function fleschEase(text) {
46
+ const plain = text
47
+ .replace(/[#*_`>[\]()]/g, " ")
48
+ .replace(/\s+/g, " ")
49
+ .trim();
50
+ const sentences = plain.split(/[.!?]+/).filter((s) => s.trim().length > 0);
51
+ const words = plain.split(/\s+/).filter(Boolean);
52
+ const syllables = words.reduce((n, w) => n + Math.max(1, (w.match(/[aeiouy]+/gi) ?? []).length), 0);
53
+ const s = Math.max(1, sentences.length);
54
+ const w = Math.max(1, words.length);
55
+ return 206.835 - 1.015 * (w / s) - 84.6 * (syllables / w);
56
+ }
57
+ function readability(ctx) {
58
+ const words = wordCount(ctx.draft.body);
59
+ const headings = extractHeadings(ctx.draft.body);
60
+ const hasH1 = headings.length > 0 || /^#\s+/m.test(ctx.draft.body);
61
+ const h2 = (ctx.draft.body.match(/^##\s+/gm) ?? []).length +
62
+ (ctx.draft.body.match(/<h2[\s>]/gi) ?? []).length;
63
+ const ease = fleschEase(ctx.draft.body);
64
+ const minWords = Math.max(80, Math.floor(ctx.brief.currentWordCount * 0.8));
65
+ if (!hasH1)
66
+ return check(3, "READABILITY", false, "missing H1");
67
+ if (h2 < 2)
68
+ return check(3, "READABILITY", false, "need at least two H2s");
69
+ if (words < minWords)
70
+ return check(3, "READABILITY", false, `word count ${words} < ${minWords}`);
71
+ if (ease < 20)
72
+ return check(3, "READABILITY", false, `Flesch ease ${ease.toFixed(0)} is unreadable`);
73
+ return check(3, "READABILITY", true, `words=${words} h2=${h2} flesch=${ease.toFixed(0)}`);
74
+ }
75
+ function voice(ctx) {
76
+ const lower = ctx.draft.body.toLowerCase();
77
+ for (const phrase of ctx.style.bannedPhrases) {
78
+ if (phrase && lower.includes(phrase.toLowerCase())) {
79
+ return check(4, "BRAND_VOICE", false, `banned phrase: ${phrase}`);
80
+ }
81
+ }
82
+ for (const [preferred, synonym] of Object.entries(ctx.style.preferredTerms)) {
83
+ if (synonym &&
84
+ lower.includes(synonym.toLowerCase()) &&
85
+ !lower.includes(preferred.toLowerCase())) {
86
+ return check(4, "BRAND_VOICE", false, `use "${preferred}" instead of "${synonym}"`);
87
+ }
88
+ }
89
+ return check(4, "BRAND_VOICE", true, "voice profile clean");
90
+ }
91
+ function internalLinks(ctx) {
92
+ const hrefs = [...ctx.draft.body.matchAll(/\]\((https?:\/\/[^)\s]+)\)/g)].map((m) => m[1] ?? "");
93
+ const htmlHrefs = [...ctx.draft.body.matchAll(/href="(https?:\/\/[^"]+)"/g)].map((m) => m[1] ?? "");
94
+ const all = [...new Set([...hrefs, ...htmlHrefs])];
95
+ if (all.length < 1)
96
+ return check(5, "INTERNAL_LINKS", false, "draft has no internal links");
97
+ const allowed = new Set(ctx.brief.internalLinks.map((l) => l.url));
98
+ allowed.add(ctx.brief.targetUrl);
99
+ const bad = all.filter((u) => !allowed.has(u));
100
+ if (bad.length)
101
+ return check(5, "INTERNAL_LINKS", false, `unresolved hrefs: ${bad.join(", ")}`);
102
+ return check(5, "INTERNAL_LINKS", true, `${all.length} internal links resolve`);
103
+ }
104
+ function schemaCheck(ctx) {
105
+ if (!ctx.draft.jsonld) {
106
+ return check(6, "SCHEMA", true, "no JSON-LD in draft; not required on a refresh");
107
+ }
108
+ const issues = validateJsonLdBlocks([
109
+ {
110
+ raw: JSON.stringify(ctx.draft.jsonld),
111
+ parsed: ctx.draft.jsonld,
112
+ error: null,
113
+ inHead: true,
114
+ },
115
+ ]);
116
+ const blocking = issues.filter((i) => i.code !== "MISSING_RECOMMENDED_PROP");
117
+ if (blocking.length) {
118
+ return check(6, "SCHEMA", false, blocking.map((i) => i.message).join("; "));
119
+ }
120
+ return check(6, "SCHEMA", true, "JSON-LD valid against vendored schema.org");
121
+ }
122
+ function banned(ctx) {
123
+ const hits = bannedHits(ctx.draft.body);
124
+ if (hits.length)
125
+ return check(7, "BANNED_SUBSTRING", false, hits.join(","));
126
+ return check(7, "BANNED_SUBSTRING", true, "output-side scan clean");
127
+ }
128
+ function rateLimit(ctx) {
129
+ if (ctx.kind === "create" && ctx.newPagesToday >= BLAST.newPagesPerDay) {
130
+ return check(8, "RATE_LIMIT", false, `new-page cap is ${BLAST.newPagesPerDay}/day/site`);
131
+ }
132
+ return check(8, "RATE_LIMIT", true, `new pages today ${ctx.newPagesToday}/${BLAST.newPagesPerDay}`);
133
+ }
134
+ function vertical(ctx) {
135
+ const cat = (ctx.ymylCategory ?? "").toLowerCase();
136
+ const blocked = cat === "ymyl" || cat === "affiliate" || cat === "yours-money-your-life";
137
+ if (blocked) {
138
+ return check(9, "VERTICAL_BLOCK", false, `content generation is T4-blocked for ${cat} sites`);
139
+ }
140
+ return check(9, "VERTICAL_BLOCK", true, "vertical allows content");
141
+ }
142
+ function disclosure(ctx) {
143
+ const ok = hasDisclosure(ctx.draft.body, ctx.style);
144
+ return check(10, "AI_DISCLOSURE", ok, ok ? `disclosure=${ctx.style.disclosure}` : "EU AI Act Art. 50 mark missing");
145
+ }
146
+ export function runPublishGate(ctx) {
147
+ const checks = [
148
+ factCheck(ctx),
149
+ nearDup(ctx),
150
+ readability(ctx),
151
+ voice(ctx),
152
+ internalLinks(ctx),
153
+ schemaCheck(ctx),
154
+ banned(ctx),
155
+ rateLimit(ctx),
156
+ vertical(ctx),
157
+ disclosure(ctx),
158
+ ];
159
+ return { ok: checks.every((c) => c.ok), checks };
160
+ }
161
+ export function coverageScore(brief, body) {
162
+ return contentScore(body, brief.topics);
163
+ }
164
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type Action } from "@agentsean/actions";
2
+ import { type GenerateResult, type LlmConfig } from "@agentsean/llm";
3
+ import type { ContentBrief, ContentDraft, StyleProfile } from "./types.js";
4
+ export declare function briefPrompt(brief: ContentBrief): string;
5
+ export declare function draftFromBrief(brief: ContentBrief, cfg: LlmConfig, style: StyleProfile): Promise<{
6
+ draft: ContentDraft;
7
+ usage: GenerateResult;
8
+ }>;
9
+ export declare function actionFromDraft(opts: {
10
+ siteId: string;
11
+ brief: ContentBrief;
12
+ draft: ContentDraft;
13
+ findingIds: string[];
14
+ }): Action;
15
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAY3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAqBvD;AAyBD,wBAAsB,cAAc,CAClC,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAAC,CAoBzD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,YAAY,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,GAAG,MAAM,CA6BT"}
@@ -0,0 +1,95 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { KIND_TIER } from "@agentsean/actions";
3
+ import { generateText, taskClass, } from "@agentsean/llm";
4
+ import { applyDisclosure } from "./disclosure.js";
5
+ const SYSTEM = `You write SEO page copy for Agent Sean.
6
+ You emit a single JSON object and nothing else.
7
+ You never call tools, never request credentials, never invent URLs, never invent numeric facts.
8
+ Every number you use must appear in the brief.facts or brief.sources text.
9
+ Every href must be one of brief.internalLinks.url.
10
+ Prefer rewriting the existing page. Do not propose a new URL.
11
+ Schema: {"title": string, "body": string, "jsonld": object|null}
12
+ body is markdown with one H1, at least two H2s, and markdown links to internalLinks.
13
+ Keep body under 35000 characters.`;
14
+ export function briefPrompt(brief) {
15
+ return JSON.stringify({
16
+ kind: brief.kind,
17
+ targetUrl: brief.targetUrl,
18
+ title: brief.title,
19
+ intent: brief.intent,
20
+ topics: brief.topics.slice(0, 50),
21
+ headings: brief.headings,
22
+ questions: brief.questions,
23
+ internalLinks: brief.internalLinks,
24
+ facts: brief.facts,
25
+ sources: brief.sources.map((s) => ({ url: s.url, text: s.text.slice(0, 1500) })),
26
+ currentWordCount: brief.currentWordCount,
27
+ targetWordCount: brief.targetWordCount,
28
+ decay: brief.decay,
29
+ googleUpdateNote: brief.googleUpdateNote,
30
+ }, null, 2);
31
+ }
32
+ function parseDraftJson(text) {
33
+ const trimmed = text.trim();
34
+ const fence = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/);
35
+ const raw = fence?.[1]?.trim() ?? trimmed;
36
+ const parsed = JSON.parse(raw);
37
+ if (typeof parsed.title !== "string" || typeof parsed.body !== "string") {
38
+ throw new Error("LLM draft missing title/body");
39
+ }
40
+ const jsonld = parsed.jsonld && typeof parsed.jsonld === "object" && !Array.isArray(parsed.jsonld)
41
+ ? parsed.jsonld
42
+ : null;
43
+ return { title: parsed.title, body: parsed.body, jsonld };
44
+ }
45
+ export async function draftFromBrief(brief, cfg, style) {
46
+ const result = await generateText(cfg, {
47
+ class: taskClass("draft"),
48
+ system: SYSTEM,
49
+ prompt: briefPrompt(brief),
50
+ json: true,
51
+ });
52
+ const parsed = parseDraftJson(result.text);
53
+ const body = applyDisclosure(parsed.body, style);
54
+ return {
55
+ draft: {
56
+ title: parsed.title.slice(0, 70),
57
+ body: body.slice(0, 40_000),
58
+ jsonld: parsed.jsonld,
59
+ disclosure: style.disclosure,
60
+ model: result.model,
61
+ modelClass: result.class,
62
+ },
63
+ usage: result,
64
+ };
65
+ }
66
+ export function actionFromDraft(opts) {
67
+ const kind = opts.brief.kind === "create" ? "create_page" : "refresh_content";
68
+ const payload = kind === "create_page"
69
+ ? {
70
+ path: new URL(opts.brief.targetUrl).pathname || "/",
71
+ title: opts.draft.title,
72
+ body: opts.draft.body,
73
+ }
74
+ : { body: opts.draft.body };
75
+ return {
76
+ id: randomUUID(),
77
+ siteId: opts.siteId,
78
+ kind,
79
+ tier: KIND_TIER[kind],
80
+ target: { pageId: opts.brief.pageId, url: opts.brief.targetUrl },
81
+ payload,
82
+ rationale: [
83
+ opts.brief.kind === "refresh"
84
+ ? "Refresh an existing URL rather than mint a new one."
85
+ : "Create a page for a cluster with no existing URL.",
86
+ opts.brief.decay
87
+ ? `GSC clicks dropped from ${opts.brief.decay.previousClicks} to ${opts.brief.decay.currentClicks} (metric: clicks).`
88
+ : "Thin or under-covered page from the crawl catalogue.",
89
+ `Brief content score ${opts.brief.contentScore.toFixed(0)}/100.`,
90
+ ],
91
+ findingIds: opts.findingIds,
92
+ estimatedImpact: { metric: "clicks", estimate: 0, confidence: 0.2 },
93
+ };
94
+ }
95
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export { decayingPages } from "./decay.js";
2
+ export { contentScore, countMentions } from "./score.js";
3
+ export { stripHtml, wordCount, extractHeadings, extractEntities, extractQuestions, numericClaims, factsFromText, } from "./extract.js";
4
+ export { buildBrief } from "./brief.js";
5
+ export { runPublishGate, coverageScore, type GateContext } from "./gate.js";
6
+ export { draftFromBrief, actionFromDraft, briefPrompt } from "./generate.js";
7
+ export { runContentJob, pickCandidates } from "./engine.js";
8
+ export { loadStyleProfile, upsertStyleProfile, saveBrief, saveDraft, listContent, } from "./persist.js";
9
+ export { applyDisclosure, disclosureFor, hasDisclosure, HTML_COMMENT, } from "./disclosure.js";
10
+ export { evidenceForContentChange, EVIDENCE_MEANING, DEFAULT_EVIDENCE_TIER, } from "./evidence.js";
11
+ export type { ContentBrief, ContentDraft, ContentKind, ContentCandidate, PublishGateResult, GateCheck, StyleProfile, EvidenceTier, DecayingPage, RunContentOptions, RunContentResult, PageDaily, QueryDaily, } from "./types.js";
12
+ export { DEFAULT_STYLE } from "./types.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EACL,SAAS,EACT,SAAS,EACT,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,SAAS,EACT,SAAS,EACT,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ export { decayingPages } from "./decay.js";
2
+ export { contentScore, countMentions } from "./score.js";
3
+ export { stripHtml, wordCount, extractHeadings, extractEntities, extractQuestions, numericClaims, factsFromText, } from "./extract.js";
4
+ export { buildBrief } from "./brief.js";
5
+ export { runPublishGate, coverageScore } from "./gate.js";
6
+ export { draftFromBrief, actionFromDraft, briefPrompt } from "./generate.js";
7
+ export { runContentJob, pickCandidates } from "./engine.js";
8
+ export { loadStyleProfile, upsertStyleProfile, saveBrief, saveDraft, listContent, } from "./persist.js";
9
+ export { applyDisclosure, disclosureFor, hasDisclosure, HTML_COMMENT, } from "./disclosure.js";
10
+ export { evidenceForContentChange, EVIDENCE_MEANING, DEFAULT_EVIDENCE_TIER, } from "./evidence.js";
11
+ export { DEFAULT_STYLE } from "./types.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EACL,SAAS,EACT,SAAS,EACT,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAoB,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,SAAS,EACT,SAAS,EACT,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAgBvB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { type SqliteDatabase } from "@agentsean/db";
2
+ import { type ContentBrief, type PublishGateResult, type StyleProfile } from "./types.js";
3
+ export declare function loadStyleProfile(db: SqliteDatabase, siteId: string): StyleProfile;
4
+ export declare function upsertStyleProfile(db: SqliteDatabase, siteId: string, profile: StyleProfile): void;
5
+ export declare function saveBrief(db: SqliteDatabase, siteId: string, brief: ContentBrief): string;
6
+ export declare function saveDraft(db: SqliteDatabase, opts: {
7
+ briefId: string;
8
+ siteId: string;
9
+ pageId: string;
10
+ actionId: string | null;
11
+ title: string;
12
+ body: string;
13
+ model: string;
14
+ modelClass: string;
15
+ state: "draft" | "gated" | "published" | "rejected";
16
+ gate: PublishGateResult | null;
17
+ evidenceTier: string;
18
+ publishedAt?: string | null | undefined;
19
+ }): string;
20
+ export declare function listContent(db: SqliteDatabase, siteId?: string): {
21
+ briefs: {
22
+ id: string;
23
+ siteId: string;
24
+ pageId: string | null;
25
+ playbookId: string;
26
+ playbookVersion: string;
27
+ kind: string;
28
+ targetUrl: string;
29
+ briefJson: string;
30
+ score: number;
31
+ createdAt: string;
32
+ }[];
33
+ drafts: {
34
+ id: string;
35
+ briefId: string;
36
+ siteId: string;
37
+ pageId: string | null;
38
+ actionId: string | null;
39
+ title: string | null;
40
+ body: string | null;
41
+ model: string | null;
42
+ modelClass: string | null;
43
+ state: string;
44
+ gateJson: string | null;
45
+ evidenceTier: string;
46
+ createdAt: string;
47
+ publishedAt: string | null;
48
+ }[];
49
+ };
50
+ //# sourceMappingURL=persist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../src/persist.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAEpB,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAyBjF;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,GACpB,IAAI,CA4BN;AAED,wBAAgB,SAAS,CACvB,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,MAAM,CAiBR;AAED,wBAAgB,SAAS,CACvB,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE;IACJ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,CAAC;IACpD,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACzC,GACA,MAAM,CAqCR;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAY9D"}
@@ -0,0 +1,130 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { eq } from "drizzle-orm";
3
+ import { contentBriefs, contentDrafts, publishGateResults, styleProfiles, } from "@agentsean/db";
4
+ import { DEFAULT_STYLE, } from "./types.js";
5
+ export function loadStyleProfile(db, siteId) {
6
+ const row = db
7
+ .select()
8
+ .from(styleProfiles)
9
+ .where(eq(styleProfiles.siteId, siteId))
10
+ .get();
11
+ if (!row)
12
+ return { ...DEFAULT_STYLE };
13
+ try {
14
+ const parsed = JSON.parse(row.voiceJson);
15
+ const disclosure = row.disclosure === "none" ||
16
+ row.disclosure === "meta" ||
17
+ row.disclosure === "visible" ||
18
+ row.disclosure === "html_comment"
19
+ ? row.disclosure
20
+ : DEFAULT_STYLE.disclosure;
21
+ return {
22
+ bannedPhrases: parsed.bannedPhrases ?? [],
23
+ preferredTerms: parsed.preferredTerms ?? {},
24
+ maxSentenceWords: parsed.maxSentenceWords ?? DEFAULT_STYLE.maxSentenceWords,
25
+ disclosure,
26
+ };
27
+ }
28
+ catch {
29
+ return { ...DEFAULT_STYLE };
30
+ }
31
+ }
32
+ export function upsertStyleProfile(db, siteId, profile) {
33
+ const now = new Date().toISOString();
34
+ const existing = db
35
+ .select()
36
+ .from(styleProfiles)
37
+ .where(eq(styleProfiles.siteId, siteId))
38
+ .get();
39
+ const voiceJson = JSON.stringify({
40
+ bannedPhrases: profile.bannedPhrases,
41
+ preferredTerms: profile.preferredTerms,
42
+ maxSentenceWords: profile.maxSentenceWords,
43
+ });
44
+ if (existing) {
45
+ db.update(styleProfiles)
46
+ .set({ voiceJson, disclosure: profile.disclosure, updatedAt: now })
47
+ .where(eq(styleProfiles.siteId, siteId))
48
+ .run();
49
+ return;
50
+ }
51
+ db.insert(styleProfiles)
52
+ .values({
53
+ id: randomUUID(),
54
+ siteId,
55
+ voiceJson,
56
+ disclosure: profile.disclosure,
57
+ updatedAt: now,
58
+ })
59
+ .run();
60
+ }
61
+ export function saveBrief(db, siteId, brief) {
62
+ const id = randomUUID();
63
+ db.insert(contentBriefs)
64
+ .values({
65
+ id,
66
+ siteId,
67
+ pageId: brief.pageId,
68
+ playbookId: brief.playbookId,
69
+ playbookVersion: brief.playbookVersion,
70
+ kind: brief.kind,
71
+ targetUrl: brief.targetUrl,
72
+ briefJson: JSON.stringify(brief),
73
+ score: brief.contentScore,
74
+ createdAt: new Date().toISOString(),
75
+ })
76
+ .run();
77
+ return id;
78
+ }
79
+ export function saveDraft(db, opts) {
80
+ const id = randomUUID();
81
+ const now = new Date().toISOString();
82
+ db.insert(contentDrafts)
83
+ .values({
84
+ id,
85
+ briefId: opts.briefId,
86
+ siteId: opts.siteId,
87
+ pageId: opts.pageId,
88
+ actionId: opts.actionId,
89
+ title: opts.title,
90
+ body: opts.body,
91
+ model: opts.model,
92
+ modelClass: opts.modelClass,
93
+ state: opts.state,
94
+ gateJson: opts.gate ? JSON.stringify(opts.gate) : null,
95
+ evidenceTier: opts.evidenceTier,
96
+ createdAt: now,
97
+ publishedAt: opts.publishedAt ?? null,
98
+ })
99
+ .run();
100
+ if (opts.gate) {
101
+ for (const c of opts.gate.checks) {
102
+ db.insert(publishGateResults)
103
+ .values({
104
+ id: randomUUID(),
105
+ draftId: id,
106
+ checkId: c.id,
107
+ code: c.code,
108
+ ok: c.ok ? 1 : 0,
109
+ detail: c.detail,
110
+ createdAt: now,
111
+ })
112
+ .run();
113
+ }
114
+ }
115
+ return id;
116
+ }
117
+ export function listContent(db, siteId) {
118
+ const briefs = db
119
+ .select()
120
+ .from(contentBriefs)
121
+ .all()
122
+ .filter((b) => !siteId || b.siteId === siteId);
123
+ const drafts = db
124
+ .select()
125
+ .from(contentDrafts)
126
+ .all()
127
+ .filter((d) => !siteId || d.siteId === siteId);
128
+ return { briefs, drafts };
129
+ }
130
+ //# sourceMappingURL=persist.js.map