@wrenautomation/birdwatch 0.0.0-stage → 0.30.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 (141) hide show
  1. package/LICENSE.md +61 -0
  2. package/README.md +320 -2
  3. package/dist/app/cli.d.ts +4 -0
  4. package/dist/app/cli.js +149 -0
  5. package/dist/app/cli.js.map +1 -0
  6. package/dist/app/engine-cli.d.ts +44 -0
  7. package/dist/app/engine-cli.js +596 -0
  8. package/dist/app/engine-cli.js.map +1 -0
  9. package/dist/app/index.d.ts +6 -0
  10. package/dist/app/index.js +7 -0
  11. package/dist/app/index.js.map +1 -0
  12. package/dist/app/serve.d.ts +14 -0
  13. package/dist/app/serve.js +102 -0
  14. package/dist/app/serve.js.map +1 -0
  15. package/dist/document/body.d.ts +6 -0
  16. package/dist/document/body.js +18 -0
  17. package/dist/document/body.js.map +1 -0
  18. package/dist/document/check.d.ts +35 -0
  19. package/dist/document/check.js +68 -0
  20. package/dist/document/check.js.map +1 -0
  21. package/dist/document/extract.d.ts +81 -0
  22. package/dist/document/extract.js +226 -0
  23. package/dist/document/extract.js.map +1 -0
  24. package/dist/document/index.d.ts +11 -0
  25. package/dist/document/index.js +12 -0
  26. package/dist/document/index.js.map +1 -0
  27. package/dist/document/model.d.ts +10 -0
  28. package/dist/document/model.js +2 -0
  29. package/dist/document/model.js.map +1 -0
  30. package/dist/document/readers.d.ts +24 -0
  31. package/dist/document/readers.js +87 -0
  32. package/dist/document/readers.js.map +1 -0
  33. package/dist/document/types.d.ts +99 -0
  34. package/dist/document/types.js +93 -0
  35. package/dist/document/types.js.map +1 -0
  36. package/dist/engine/agent.d.ts +475 -0
  37. package/dist/engine/agent.js +990 -0
  38. package/dist/engine/agent.js.map +1 -0
  39. package/dist/engine/canonical.d.ts +4 -0
  40. package/dist/engine/canonical.js +55 -0
  41. package/dist/engine/canonical.js.map +1 -0
  42. package/dist/engine/context.d.ts +9 -0
  43. package/dist/engine/context.js +141 -0
  44. package/dist/engine/context.js.map +1 -0
  45. package/dist/engine/cost.d.ts +13 -0
  46. package/dist/engine/cost.js +31 -0
  47. package/dist/engine/cost.js.map +1 -0
  48. package/dist/engine/index.d.ts +16 -0
  49. package/dist/engine/index.js +17 -0
  50. package/dist/engine/index.js.map +1 -0
  51. package/dist/engine/judge.d.ts +158 -0
  52. package/dist/engine/judge.js +323 -0
  53. package/dist/engine/judge.js.map +1 -0
  54. package/dist/engine/people.d.ts +34 -0
  55. package/dist/engine/people.js +125 -0
  56. package/dist/engine/people.js.map +1 -0
  57. package/dist/engine/plan.d.ts +6 -0
  58. package/dist/engine/plan.js +7 -0
  59. package/dist/engine/plan.js.map +1 -0
  60. package/dist/engine/plans/index.d.ts +19 -0
  61. package/dist/engine/plans/index.js +104 -0
  62. package/dist/engine/plans/index.js.map +1 -0
  63. package/dist/engine/ports.d.ts +76 -0
  64. package/dist/engine/ports.js +28 -0
  65. package/dist/engine/ports.js.map +1 -0
  66. package/dist/engine/recall.d.ts +42 -0
  67. package/dist/engine/recall.js +71 -0
  68. package/dist/engine/recall.js.map +1 -0
  69. package/dist/engine/state.d.ts +96 -0
  70. package/dist/engine/state.js +162 -0
  71. package/dist/engine/state.js.map +1 -0
  72. package/dist/engine/steps.d.ts +98 -0
  73. package/dist/engine/steps.js +435 -0
  74. package/dist/engine/steps.js.map +1 -0
  75. package/dist/engine/tree.d.ts +76 -0
  76. package/dist/engine/tree.js +148 -0
  77. package/dist/engine/tree.js.map +1 -0
  78. package/dist/engine/types.d.ts +250 -0
  79. package/dist/engine/types.js +168 -0
  80. package/dist/engine/types.js.map +1 -0
  81. package/dist/engine/view.d.ts +138 -0
  82. package/dist/engine/view.js +188 -0
  83. package/dist/engine/view.js.map +1 -0
  84. package/dist/index.d.ts +15 -0
  85. package/dist/index.js +16 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/ledger/files.d.ts +39 -0
  88. package/dist/ledger/files.js +113 -0
  89. package/dist/ledger/files.js.map +1 -0
  90. package/dist/ledger/ids.d.ts +4 -0
  91. package/dist/ledger/ids.js +9 -0
  92. package/dist/ledger/ids.js.map +1 -0
  93. package/dist/ledger/index.d.ts +11 -0
  94. package/dist/ledger/index.js +12 -0
  95. package/dist/ledger/index.js.map +1 -0
  96. package/dist/ledger/ledger.d.ts +46 -0
  97. package/dist/ledger/ledger.js +105 -0
  98. package/dist/ledger/ledger.js.map +1 -0
  99. package/dist/ledger/memory.d.ts +19 -0
  100. package/dist/ledger/memory.js +19 -0
  101. package/dist/ledger/memory.js.map +1 -0
  102. package/dist/ledger/records.d.ts +1424 -0
  103. package/dist/ledger/records.js +292 -0
  104. package/dist/ledger/records.js.map +1 -0
  105. package/dist/sources/arxiv.d.ts +105 -0
  106. package/dist/sources/arxiv.js +321 -0
  107. package/dist/sources/arxiv.js.map +1 -0
  108. package/dist/sources/exa.d.ts +19 -0
  109. package/dist/sources/exa.js +59 -0
  110. package/dist/sources/exa.js.map +1 -0
  111. package/dist/sources/fetcher.d.ts +35 -0
  112. package/dist/sources/fetcher.js +67 -0
  113. package/dist/sources/fetcher.js.map +1 -0
  114. package/dist/sources/google.d.ts +16 -0
  115. package/dist/sources/google.js +64 -0
  116. package/dist/sources/google.js.map +1 -0
  117. package/dist/sources/index.d.ts +17 -0
  118. package/dist/sources/index.js +18 -0
  119. package/dist/sources/index.js.map +1 -0
  120. package/dist/sources/junk.d.ts +10 -0
  121. package/dist/sources/junk.js +16 -0
  122. package/dist/sources/junk.js.map +1 -0
  123. package/dist/sources/ladder.d.ts +47 -0
  124. package/dist/sources/ladder.js +158 -0
  125. package/dist/sources/ladder.js.map +1 -0
  126. package/dist/sources/ledger.d.ts +7 -0
  127. package/dist/sources/ledger.js +35 -0
  128. package/dist/sources/ledger.js.map +1 -0
  129. package/dist/sources/paste.d.ts +8 -0
  130. package/dist/sources/paste.js +22 -0
  131. package/dist/sources/paste.js.map +1 -0
  132. package/dist/sources/searxng.d.ts +11 -0
  133. package/dist/sources/searxng.js +38 -0
  134. package/dist/sources/searxng.js.map +1 -0
  135. package/dist/sources/sites.d.ts +53 -0
  136. package/dist/sources/sites.js +285 -0
  137. package/dist/sources/sites.js.map +1 -0
  138. package/dist/sources/ytdlp.d.ts +43 -0
  139. package/dist/sources/ytdlp.js +117 -0
  140. package/dist/sources/ytdlp.js.map +1 -0
  141. package/package.json +61 -3
@@ -0,0 +1,138 @@
1
+ import { type Brief } from "./agent.js";
2
+ import type { Deps } from "./ports.js";
3
+ import { type RunState } from "./state.js";
4
+ type Who = {
5
+ from: string;
6
+ by: string;
7
+ };
8
+ type Answers = Record<string, Record<string, number>>;
9
+ export interface RunQuery extends Who {
10
+ id: string;
11
+ round: number;
12
+ at: string;
13
+ terms: string;
14
+ why: string;
15
+ site?: string;
16
+ facet?: string;
17
+ tier?: number;
18
+ follow?: {
19
+ url: string;
20
+ as: string;
21
+ document?: string;
22
+ };
23
+ /** Hits it wrote, then known hits it found again. */
24
+ hits: string[];
25
+ again: string[];
26
+ }
27
+ export interface RunHit extends Who {
28
+ id: string;
29
+ round: number;
30
+ url: string;
31
+ title?: string;
32
+ channel?: string;
33
+ snippet?: string;
34
+ date?: string;
35
+ length?: number;
36
+ /** The sources that returned it. */
37
+ sources: string[];
38
+ /** Every query that returned it, the first one first. */
39
+ queries: string[];
40
+ call?: {
41
+ verdict: "keep" | "drop";
42
+ why?: string;
43
+ } & Who;
44
+ judge?: Answers;
45
+ document?: string;
46
+ }
47
+ export interface RunDocument extends Who {
48
+ id: string;
49
+ hit: string;
50
+ url: string;
51
+ title?: string;
52
+ channel?: string;
53
+ media: string;
54
+ date?: string;
55
+ length?: number;
56
+ chars: number;
57
+ class?: string;
58
+ judge?: Answers;
59
+ verdict?: {
60
+ quality: string;
61
+ gap?: string;
62
+ };
63
+ /** The person record that owns it. */
64
+ person?: string;
65
+ }
66
+ export interface RunFinding extends Who {
67
+ id: string;
68
+ round: number;
69
+ document: string;
70
+ text: string;
71
+ quote?: string;
72
+ date?: string;
73
+ kept: boolean;
74
+ fixes?: string;
75
+ class?: string;
76
+ judge?: Answers;
77
+ checks: ({
78
+ ok: boolean;
79
+ why: string;
80
+ at: string;
81
+ } & Who)[];
82
+ }
83
+ /** One step of the back and forth: a decision with its why, or a step's end with its note. */
84
+ export interface Moment extends Who {
85
+ id: string;
86
+ at: string;
87
+ round: number;
88
+ step?: string;
89
+ type: string;
90
+ text: string;
91
+ why?: string;
92
+ /** The record it is about. */
93
+ on?: string;
94
+ ok?: boolean;
95
+ }
96
+ export interface RunView {
97
+ v: 1;
98
+ run: string;
99
+ brief: Brief;
100
+ queries: RunQuery[];
101
+ hits: RunHit[];
102
+ documents: RunDocument[];
103
+ findings: RunFinding[];
104
+ timeline: Moment[];
105
+ /** Spend per source and op. */
106
+ spend: {
107
+ source: string;
108
+ op: string;
109
+ calls: number;
110
+ failed: number;
111
+ usd: number;
112
+ }[];
113
+ }
114
+ /** One line per run for a list. */
115
+ export interface RunRow {
116
+ run: string;
117
+ ask: string;
118
+ kind: string;
119
+ parent: string | null;
120
+ round: number;
121
+ /** Null once an edge said stop. */
122
+ next: {
123
+ round: number;
124
+ step: string;
125
+ } | null;
126
+ note: string | null;
127
+ started: string;
128
+ updated: string;
129
+ hits: number;
130
+ documents: number;
131
+ kept: number;
132
+ usd: number;
133
+ }
134
+ export declare function rowOf(state: RunState): RunRow;
135
+ export declare function viewOf(state: RunState, b: Brief): RunView;
136
+ /** A run's view from its ledger. */
137
+ export declare function runView(deps: Deps, run: string): Promise<RunView>;
138
+ export {};
@@ -0,0 +1,188 @@
1
+ import { brief } from "./agent.js";
2
+ import { ownersOf } from "./people.js";
3
+ import { fold, kept } from "./state.js";
4
+ const who = (r) => ({ from: r.from, by: r.by });
5
+ const some = (v, k) => (v === undefined ? {} : { [k]: v });
6
+ export function rowOf(state) {
7
+ const s = state.snapshot;
8
+ return {
9
+ run: state.run,
10
+ ask: s?.ask.text ?? "",
11
+ kind: s?.ask.kind ?? "",
12
+ parent: s?.parent?.run ?? null,
13
+ round: state.round,
14
+ next: state.next,
15
+ note: state.note,
16
+ started: state.records[0]?.at ?? "",
17
+ updated: state.records.at(-1)?.at ?? "",
18
+ hits: state.hits.length,
19
+ documents: state.documents.length,
20
+ kept: state.findings.filter((f) => kept(state, f)).length,
21
+ usd: state.spends.reduce((a, x) => a + (x.usd ?? 0), 0),
22
+ };
23
+ }
24
+ /** The record a moment shows, or null for bulk records (hits, pages, the judge, spends). */
25
+ function momentOf(r) {
26
+ const base = { id: r.id, at: r.at, round: r.round, ...some(r.step, "step"), ...who(r) };
27
+ switch (r.type) {
28
+ case "snapshot":
29
+ return { ...base, type: r.type, text: `plan: ${r.ask.text}`, why: r.sources.join(", ") };
30
+ case "query":
31
+ return {
32
+ ...base,
33
+ type: r.type,
34
+ text: r.follow ? `follow ${r.follow.as} of ${r.follow.url}` : r.terms,
35
+ why: r.why,
36
+ ...some(r.facet, "on"),
37
+ };
38
+ case "call":
39
+ return { ...base, type: r.type, text: r.verdict, on: r.on, ...some(r.why, "why") };
40
+ case "check":
41
+ return {
42
+ ...base,
43
+ type: r.type,
44
+ text: r.ok ? "backed" : "failed",
45
+ on: r.on,
46
+ why: r.why,
47
+ ok: r.ok,
48
+ };
49
+ case "edge":
50
+ return { ...base, type: r.type, text: r.next, why: r.why };
51
+ case "done":
52
+ return { ...base, type: r.type, text: r.step, ok: r.ok, ...some(r.note, "why") };
53
+ case "gap":
54
+ return { ...base, type: r.type, text: r.note, ...some(r.on, "on") };
55
+ case "steer":
56
+ return { ...base, type: r.type, text: r.text };
57
+ case "class":
58
+ return { ...base, type: r.type, text: r.class, on: r.on, why: r.why };
59
+ case "pattern":
60
+ return { ...base, type: r.type, text: r.text };
61
+ case "person":
62
+ return { ...base, type: r.type, text: r.name, why: r.why };
63
+ case "dead":
64
+ return { ...base, type: r.type, text: r.facet, why: r.why };
65
+ case "draft":
66
+ return { ...base, type: r.type, text: r.for };
67
+ // A finding written by hand; the extract's bulk ones show in its step's end.
68
+ case "finding":
69
+ return r.step ? null : { ...base, type: r.type, text: r.text, on: r.document };
70
+ default:
71
+ return null;
72
+ }
73
+ }
74
+ export function viewOf(state, b) {
75
+ const calls = new Map();
76
+ for (const c of state.calls)
77
+ calls.set(c.on, c);
78
+ const docOfHit = new Map(state.documents.map((d) => [d.hit, d.id]));
79
+ const owners = ownersOf(state);
80
+ const verdicts = new Map(state.verdicts.map((v) => [v.document, v]));
81
+ const hitQueries = new Map(state.hits.map((h) => [h.id, [...h.queries]]));
82
+ const again = new Map();
83
+ for (const f of state.founds) {
84
+ hitQueries.get(f.hit)?.push(f.query);
85
+ again.set(f.query, [...(again.get(f.query) ?? []), f.hit]);
86
+ }
87
+ const wrote = new Map();
88
+ for (const h of state.hits) {
89
+ const q = h.queries[0];
90
+ if (q)
91
+ wrote.set(q, [...(wrote.get(q) ?? []), h.id]);
92
+ }
93
+ const checks = new Map();
94
+ for (const c of state.checks)
95
+ checks.set(c.on, [...(checks.get(c.on) ?? []), { ok: c.ok, why: c.why, at: c.at, ...who(c) }]);
96
+ const callOf = (id) => {
97
+ const c = calls.get(id);
98
+ return c ? { call: { verdict: c.verdict, ...some(c.why, "why"), ...who(c) } } : {};
99
+ };
100
+ const spend = new Map();
101
+ for (const s of state.spends) {
102
+ const k = `${s.source}\u0000${s.op}`;
103
+ const row = spend.get(k) ?? { source: s.source, op: s.op, calls: 0, failed: 0, usd: 0 };
104
+ row.calls++;
105
+ if (!s.ok)
106
+ row.failed++;
107
+ row.usd += s.usd ?? 0;
108
+ spend.set(k, row);
109
+ }
110
+ return {
111
+ v: 1,
112
+ run: state.run,
113
+ brief: b,
114
+ queries: state.queries.map((q) => ({
115
+ id: q.id,
116
+ round: q.round,
117
+ at: q.at,
118
+ terms: q.terms,
119
+ why: q.why,
120
+ ...some(q.site, "site"),
121
+ ...some(q.facet, "facet"),
122
+ ...some(q.tier, "tier"),
123
+ ...some(q.follow, "follow"),
124
+ hits: wrote.get(q.id) ?? [],
125
+ again: again.get(q.id) ?? [],
126
+ ...who(q),
127
+ })),
128
+ hits: state.hits.map((h) => ({
129
+ id: h.id,
130
+ round: h.round,
131
+ url: h.url,
132
+ ...some(h.title, "title"),
133
+ ...some(h.channel, "channel"),
134
+ ...some(h.snippet, "snippet"),
135
+ ...some(h.date, "date"),
136
+ ...some(h.length, "length"),
137
+ sources: h.sources,
138
+ queries: hitQueries.get(h.id) ?? h.queries,
139
+ ...callOf(h.id),
140
+ ...some(state.judged.get(h.id), "judge"),
141
+ ...some(docOfHit.get(h.id), "document"),
142
+ ...who(h),
143
+ })),
144
+ documents: state.documents.map((d) => {
145
+ const v = verdicts.get(d.id);
146
+ return {
147
+ id: d.id,
148
+ hit: d.hit,
149
+ url: d.url,
150
+ ...some(d.title, "title"),
151
+ ...some(d.channel ?? state.hits.find((h) => h.id === d.hit)?.channel, "channel"),
152
+ media: d.media,
153
+ ...some(d.date, "date"),
154
+ ...some(d.length, "length"),
155
+ chars: d.text.length,
156
+ ...some(state.classOf.get(d.id), "class"),
157
+ ...some(state.judged.get(d.id), "judge"),
158
+ ...(v ? { verdict: { quality: v.quality, ...some(v.gap, "gap") } } : {}),
159
+ ...some(owners.get(d.id)?.id, "person"),
160
+ ...who(d),
161
+ };
162
+ }),
163
+ findings: state.findings.map((f) => ({
164
+ id: f.id,
165
+ round: f.round,
166
+ document: f.document,
167
+ text: f.text,
168
+ ...some(f.proof.quote ?? undefined, "quote"),
169
+ ...some(f.date, "date"),
170
+ kept: kept(state, f),
171
+ ...some(f.fixes, "fixes"),
172
+ ...some(state.classOf.get(f.id), "class"),
173
+ ...some(state.judged.get(f.id), "judge"),
174
+ checks: checks.get(f.id) ?? [],
175
+ ...who(f),
176
+ })),
177
+ timeline: state.records.flatMap((r) => momentOf(r) ?? []),
178
+ spend: [...spend.values()].sort((a, b) => b.usd - a.usd || b.calls - a.calls),
179
+ };
180
+ }
181
+ /** A run's view from its ledger. */
182
+ export async function runView(deps, run) {
183
+ const records = await deps.ledger.trace(run);
184
+ if (!records.length)
185
+ throw new Error(`run ${run}: no records`);
186
+ return viewOf(fold(run, records), await brief(deps, run));
187
+ }
188
+ //# sourceMappingURL=view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/engine/view.ts"],"names":[],"mappings":"AAMA,OAAO,EAAc,KAAK,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAiB,MAAM,YAAY,CAAC;AAkHvD,MAAM,GAAG,GAAG,CAAC,CAAe,EAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACnE,MAAM,IAAI,GAAG,CAAI,CAAgB,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAErF,MAAM,UAAU,KAAK,CAAC,KAAe;IACnC,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC;IACzB,OAAO;QACL,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE;QACtB,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE;QACvB,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,IAAI;QAC9B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE;QACnC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE;QACvC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM;QACvB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM;QACjC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM;QACzD,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;KACxD,CAAC;AACJ,CAAC;AAED,4FAA4F;AAC5F,SAAS,QAAQ,CAAC,CAAe;IAC/B,MAAM,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACxF,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,UAAU;YACb,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3F,KAAK,OAAO;YACV,OAAO;gBACL,GAAG,IAAI;gBACP,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK;gBACrE,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC;aACvB,CAAC;QACJ,KAAK,MAAM;YACT,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC;QACrF,KAAK,OAAO;YACV,OAAO;gBACL,GAAG,IAAI;gBACP,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;gBAChC,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,EAAE,EAAE,CAAC,CAAC,EAAE;aACT,CAAC;QACJ,KAAK,MAAM;YACT,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;QAC7D,KAAK,MAAM;YACT,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;QACnF,KAAK,KAAK;YACR,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;QACtE,KAAK,OAAO;YACV,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACjD,KAAK,OAAO;YACV,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;QACxE,KAAK,SAAS;YACZ,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACjD,KAAK,QAAQ;YACX,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;QAC7D,KAAK,MAAM;YACT,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;QAC9D,KAAK,OAAO;YACV,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;QAChD,6EAA6E;QAC7E,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;QACjF;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,KAAe,EAAE,CAAQ;IAC9C,MAAM,KAAK,GAAG,IAAI,GAAG,EAA2C,CAAC;IACjE,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK;QAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAC7B,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACrC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAgC,CAAC;IACvD,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM;QAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACjG,MAAM,MAAM,GAAG,CAAC,EAAU,EAAE,EAAE;QAC5B,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxB,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrF,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoC,CAAC;IAC1D,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;QACxF,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,GAAG,CAAC,MAAM,EAAE,CAAC;QACxB,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACtB,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpB,CAAC;IACD,OAAO;QACL,CAAC,EAAE,CAAC;QACJ,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,KAAK,EAAE,CAAC;QACR,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACjC,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC;YACvB,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC;YACzB,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC;YACvB,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC;YAC3B,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE;YAC3B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE;YAC5B,GAAG,GAAG,CAAC,CAAC,CAAC;SACV,CAAC,CAAC;QACH,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3B,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC;YACzB,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC;YAC7B,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC;YAC7B,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC;YACvB,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC;YAC3B,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO;YAC1C,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACf,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;YACxC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC;YACvC,GAAG,GAAG,CAAC,CAAC,CAAC;SACV,CAAC,CAAC;QACH,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACnC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC7B,OAAO;gBACL,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC;gBACzB,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC;gBAChF,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC;gBACvB,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC;gBAC3B,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM;gBACpB,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;gBACzC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;gBACxC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC;gBACvC,GAAG,GAAG,CAAC,CAAC,CAAC;aACV,CAAC;QACJ,CAAC,CAAC;QACF,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACnC,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,SAAS,EAAE,OAAO,CAAC;YAC5C,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC;YACvB,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YACpB,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC;YACzB,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;YACzC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;YACxC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE;YAC9B,GAAG,GAAG,CAAC,CAAC,CAAC;SACV,CAAC,CAAC;QACH,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzD,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;KAC9E,CAAC;AACJ,CAAC;AAED,oCAAoC;AACpC,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAU,EAAE,GAAW;IACnD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,GAAG,cAAc,CAAC,CAAC;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * birdwatch: research from the open web, driven by an agent one step per command, every record
3
+ * in a ledger. Five doors: `./engine` (the ask and plan files, the source port, registry, run
4
+ * state, the steps and the agent commands), `./sources` (SearXNG, Exa, Google, arXiv, yt-dlp, the
5
+ * site readers, the fetcher, the ladder, a paste, the ledger), `./ledger` (the records, a folder of
6
+ * JSON lines per run per writer, yield rows), `./document` (`Document`, `Finding`, `Proof`, readers
7
+ * by media, the claim extractor) and this root (the engine's CLI commands, `addEngineCommands`,
8
+ * for a host that mounts them on its own program). Reading the web and files is
9
+ * `@wrenautomation/read`'s; every model call goes through `@wrenautomation/models`. Design: wren's
10
+ * `designs/2026-10-26-research-engine.md`.
11
+ */
12
+ export * from "./app/index.js";
13
+ export * from "./engine/index.js";
14
+ export * from "./ledger/index.js";
15
+ export * from "./sources/index.js";
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * birdwatch: research from the open web, driven by an agent one step per command, every record
3
+ * in a ledger. Five doors: `./engine` (the ask and plan files, the source port, registry, run
4
+ * state, the steps and the agent commands), `./sources` (SearXNG, Exa, Google, arXiv, yt-dlp, the
5
+ * site readers, the fetcher, the ladder, a paste, the ledger), `./ledger` (the records, a folder of
6
+ * JSON lines per run per writer, yield rows), `./document` (`Document`, `Finding`, `Proof`, readers
7
+ * by media, the claim extractor) and this root (the engine's CLI commands, `addEngineCommands`,
8
+ * for a host that mounts them on its own program). Reading the web and files is
9
+ * `@wrenautomation/read`'s; every model call goes through `@wrenautomation/models`. Design: wren's
10
+ * `designs/2026-10-26-research-engine.md`.
11
+ */
12
+ export * from "./app/index.js";
13
+ export * from "./engine/index.js";
14
+ export * from "./ledger/index.js";
15
+ export * from "./sources/index.js";
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { type AskKind, PlanFile } from "../engine/types.js";
2
+ import { type Filter, type Ledger, type YieldFilter } from "./ledger.js";
3
+ import { LedgerRecord } from "./records.js";
4
+ /** A line the backend could not read: a partial last line from a killed writer, or a record it does not know. */
5
+ export interface Problem {
6
+ file: string;
7
+ line: number;
8
+ why: string;
9
+ }
10
+ export declare class FilesLedger implements Ledger {
11
+ readonly root: string;
12
+ readonly writer: string;
13
+ /** Lines skipped on read, since this ledger was made. Report them; never throw on them. */
14
+ readonly problems: Problem[];
15
+ /** `writer` names this session's file: a person's name, a session id. `by` on a record stays data. */
16
+ constructor(root: string, writer: string);
17
+ runDir(run: string): string;
18
+ file(run: string): string;
19
+ append(record: LedgerRecord): Promise<void>;
20
+ /** The runs on disk, by name. */
21
+ runs(): Promise<string[]>;
22
+ private readFile;
23
+ trace(run: string): Promise<LedgerRecord[]>;
24
+ scan(filter?: Filter): Promise<LedgerRecord[]>;
25
+ yield(filter?: YieldFilter): Promise<{
26
+ hits: number;
27
+ reads: number;
28
+ proposed: number;
29
+ kept: number;
30
+ by?: string | undefined;
31
+ source?: string | undefined;
32
+ channel?: string | undefined;
33
+ kind?: "video" | "channel" | "web" | "person" | "site" | undefined;
34
+ }[]>;
35
+ planPath(kind: AskKind): string;
36
+ /** The tuned plan file for a kind, or null when the ledger has none (the stock plan file applies). */
37
+ readPlan(kind: AskKind): Promise<PlanFile | null>;
38
+ writePlan(planFile: PlanFile): Promise<string>;
39
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The files backend: a folder in any repo. `runs/<run>/<writer>.jsonl`, one file per run per
3
+ * writer, so two sessions on one run never touch the same file and git merges clean. A trace is
4
+ * the union of a run's files in time order. Plan files sit beside the runs,
5
+ * `plans/<kind>.json`. DuckDB reads the JSONL as it is.
6
+ */
7
+ import { appendFile, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
8
+ import { join } from "node:path";
9
+ import { PlanFile } from "../engine/types.js";
10
+ import { matches, yieldRows } from "./ledger.js";
11
+ import { byTime, LedgerRecord } from "./records.js";
12
+ const safe = (name) => name.replace(/[^A-Za-z0-9._-]+/g, "-");
13
+ const exists = async (dir) => {
14
+ try {
15
+ return await readdir(dir);
16
+ }
17
+ catch (err) {
18
+ if (err.code === "ENOENT")
19
+ return [];
20
+ throw err;
21
+ }
22
+ };
23
+ export class FilesLedger {
24
+ root;
25
+ writer;
26
+ /** Lines skipped on read, since this ledger was made. Report them; never throw on them. */
27
+ problems = [];
28
+ /** `writer` names this session's file: a person's name, a session id. `by` on a record stays data. */
29
+ constructor(root, writer) {
30
+ this.root = root;
31
+ this.writer = writer;
32
+ }
33
+ runDir(run) {
34
+ return join(this.root, "runs", safe(run));
35
+ }
36
+ file(run) {
37
+ return join(this.runDir(run), `${safe(this.writer)}.jsonl`);
38
+ }
39
+ async append(record) {
40
+ await mkdir(this.runDir(record.run), { recursive: true });
41
+ await appendFile(this.file(record.run), `${JSON.stringify(record)}\n`, "utf8");
42
+ }
43
+ /** The runs on disk, by name. */
44
+ async runs() {
45
+ return (await exists(join(this.root, "runs"))).sort();
46
+ }
47
+ async readFile(path) {
48
+ const out = [];
49
+ const text = await readFile(path, "utf8");
50
+ const lines = text.split("\n");
51
+ const complete = text.endsWith("\n") ? lines.length - 1 : lines.length - 1;
52
+ lines.forEach((line, i) => {
53
+ if (!line.trim())
54
+ return;
55
+ if (i >= complete) {
56
+ this.problems.push({ file: path, line: i + 1, why: "partial last line" });
57
+ return;
58
+ }
59
+ let parsed;
60
+ try {
61
+ parsed = JSON.parse(line);
62
+ }
63
+ catch {
64
+ this.problems.push({ file: path, line: i + 1, why: "not JSON" });
65
+ return;
66
+ }
67
+ const r = LedgerRecord.safeParse(parsed);
68
+ if (r.success)
69
+ out.push(r.data);
70
+ else
71
+ this.problems.push({ file: path, line: i + 1, why: r.error.issues[0]?.message ?? "bad" });
72
+ });
73
+ return out;
74
+ }
75
+ async trace(run) {
76
+ const dir = this.runDir(run);
77
+ const files = (await exists(dir)).filter((f) => f.endsWith(".jsonl")).sort();
78
+ const parts = await Promise.all(files.map((f) => this.readFile(join(dir, f))));
79
+ return parts.flat().sort(byTime);
80
+ }
81
+ async scan(filter = {}) {
82
+ const runs = filter.run !== undefined ? [filter.run] : await this.runs();
83
+ const parts = await Promise.all(runs.map((r) => this.trace(r)));
84
+ return parts
85
+ .flat()
86
+ .filter((r) => matches(r, filter))
87
+ .sort(byTime);
88
+ }
89
+ async yield(filter = {}) {
90
+ return yieldRows(await this.scan(), filter);
91
+ }
92
+ planPath(kind) {
93
+ return join(this.root, "plans", `${kind}.json`);
94
+ }
95
+ /** The tuned plan file for a kind, or null when the ledger has none (the stock plan file applies). */
96
+ async readPlan(kind) {
97
+ try {
98
+ return PlanFile.parse(JSON.parse(await readFile(this.planPath(kind), "utf8")));
99
+ }
100
+ catch (err) {
101
+ if (err.code === "ENOENT")
102
+ return null;
103
+ throw err;
104
+ }
105
+ }
106
+ async writePlan(planFile) {
107
+ const path = this.planPath(planFile.kind);
108
+ await mkdir(join(this.root, "plans"), { recursive: true });
109
+ await writeFile(path, `${JSON.stringify(planFile, null, 2)}\n`, "utf8");
110
+ return path;
111
+ }
112
+ }
113
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/ledger/files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type Ids = () => string;
2
+ export declare const ulids: () => Ids;
3
+ /** `a-000001`, `a-000002`, ...: readable ids for tests. */
4
+ export declare const countingIds: (prefix?: string) => Ids;
@@ -0,0 +1,9 @@
1
+ /** Record ids: ULIDs, time-ordered and unique per writer. A test passes a counter instead. */
2
+ import { monotonicFactory } from "ulid";
3
+ export const ulids = () => monotonicFactory();
4
+ /** `a-000001`, `a-000002`, ...: readable ids for tests. */
5
+ export const countingIds = (prefix = "r") => {
6
+ let n = 0;
7
+ return () => `${prefix}-${String(++n).padStart(6, "0")}`;
8
+ };
9
+ //# sourceMappingURL=ids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/ledger/ids.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,MAAM,CAAC;AAIxC,MAAM,CAAC,MAAM,KAAK,GAAG,GAAQ,EAAE,CAAC,gBAAgB,EAAE,CAAC;AAEnD,2DAA2D;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAM,GAAG,GAAG,EAAO,EAAE;IAC/C,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,GAAG,EAAE,CAAC,GAAG,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC3D,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The ledger: the research engine's append-only store. The contract (`Ledger`: append, trace,
3
+ * scan, yield), the record shapes (one envelope, then the plan's and the document's fields), the files
4
+ * backend (JSONL per run per writer, plan files beside it) and a memory backend for tests.
5
+ * wren's Postgres answers the same four calls.
6
+ */
7
+ export * from "./files.js";
8
+ export * from "./ids.js";
9
+ export * from "./ledger.js";
10
+ export * from "./memory.js";
11
+ export * from "./records.js";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The ledger: the research engine's append-only store. The contract (`Ledger`: append, trace,
3
+ * scan, yield), the record shapes (one envelope, then the plan's and the document's fields), the files
4
+ * backend (JSONL per run per writer, plan files beside it) and a memory backend for tests.
5
+ * wren's Postgres answers the same four calls.
6
+ */
7
+ export * from "./files.js";
8
+ export * from "./ids.js";
9
+ export * from "./ledger.js";
10
+ export * from "./memory.js";
11
+ export * from "./records.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ledger/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The ledger contract: four calls every backend answers. `append` one record; `trace` one run's
3
+ * records in time order; `scan` records across runs by a filter; `yield` what sources, proposers,
4
+ * channels and ask kinds yielded, as the yield rows. The yield is a fold over records, shared here
5
+ * so the files backend and a database compute the same rows (a database may do it in SQL).
6
+ */
7
+ import type { AskKind, PlanFile, YieldRow } from "../engine/types.js";
8
+ import { type From, type LedgerRecord, type RecordOf, type RecordType, type Step } from "./records.js";
9
+ export interface Filter {
10
+ run?: string;
11
+ type?: RecordType | readonly RecordType[];
12
+ from?: From;
13
+ by?: string;
14
+ step?: Step;
15
+ round?: number;
16
+ /** ISO time: records at or after it. */
17
+ since?: string;
18
+ }
19
+ export interface YieldFilter {
20
+ source?: string;
21
+ by?: string;
22
+ channel?: string;
23
+ kind?: YieldRow["kind"];
24
+ }
25
+ export interface Ledger {
26
+ append(record: LedgerRecord): Promise<void>;
27
+ /** One run's records, by time then id. */
28
+ trace(run: string): Promise<LedgerRecord[]>;
29
+ /** Records across runs, by time then id. */
30
+ scan(filter?: Filter): Promise<LedgerRecord[]>;
31
+ yield(filter?: YieldFilter): Promise<YieldRow[]>;
32
+ /** The tuned plan file of a kind, when the ledger keeps plan files (the files backend does). */
33
+ readPlan?(kind: AskKind): Promise<PlanFile | null>;
34
+ writePlan?(planFile: PlanFile): Promise<string>;
35
+ }
36
+ export declare function matches(r: LedgerRecord, f: Filter): boolean;
37
+ export declare const ofType: <T extends RecordType>(records: readonly LedgerRecord[], type: T) => RecordOf<T>[];
38
+ /** The latest call on each record: keep or drop. Records must be in time order. */
39
+ export declare function latestCalls(records: readonly LedgerRecord[]): Map<string, "keep" | "drop">;
40
+ /**
41
+ * Rows per source, per proposer (`by` of the queries), per channel and per ask kind: hits seen,
42
+ * documents read, findings proposed, findings kept by the latest call. The chain is
43
+ * query → hit → document → finding, so a finding counts for every source that returned its hit.
44
+ * A finding is kept unless its latest call is a drop: the gate kept it; a review or a person drops.
45
+ */
46
+ export declare function yieldRows(records: readonly LedgerRecord[], filter?: YieldFilter): YieldRow[];