strom-research 1.13.0 → 1.13.1-beta.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/brief/brief.js +2 -1
- package/dist/core/directions.js +19 -0
- package/dist/core/edge.js +5 -4
- package/dist/core/kin.js +7 -2
- package/dist/core/review.js +2 -1
- package/dist/core/tree.js +1 -1
- package/dist/gedcom/export.js +9 -2
- package/package.json +4 -1
package/dist/brief/brief.js
CHANGED
|
@@ -18,6 +18,7 @@ import { readyConnectors } from "../core/connector.js";
|
|
|
18
18
|
import { runs, shellArg } from "../cli/format.js";
|
|
19
19
|
import { foldText } from "../core/text.js";
|
|
20
20
|
import { subjectPeople } from "../core/records.js";
|
|
21
|
+
import { hypothesisPeople } from "../core/directions.js";
|
|
21
22
|
export { DEFAULT_BUDGET } from "../core/config.js";
|
|
22
23
|
import { DEFAULT_BUDGET } from "../core/config.js";
|
|
23
24
|
/** Rough token estimate: good enough for a soft budget. */
|
|
@@ -254,7 +255,7 @@ export function buildBrief(tree, opts) {
|
|
|
254
255
|
// the task's own conflicts and hypotheses come first, whatever their state
|
|
255
256
|
const own = (id) => subjects.has(id);
|
|
256
257
|
const conflicts = tree.list("conflict").filter((c) => own(c.id) || (c.state === "open" && c.subject.some((s) => ids.has(s))));
|
|
257
|
-
const hyps = tree.list("hypothesis").filter((h) => own(h.id) || (h.state === "open" && h.
|
|
258
|
+
const hyps = tree.list("hypothesis").filter((h) => own(h.id) || (h.state === "open" && hypothesisPeople(tree, h).some((s) => ids.has(s))));
|
|
258
259
|
const first = (list) => [...list.filter((x) => own(x.id)), ...list.filter((x) => !own(x.id))];
|
|
259
260
|
const mark = (id, state) => `${own(id) ? "→ " : " "}${id}${state === "open" ? "" : ` [${state}]`}`;
|
|
260
261
|
if (conflicts.length || hyps.length)
|
package/dist/core/directions.js
CHANGED
|
@@ -14,6 +14,25 @@ export function aboutPeople(tree, subject) {
|
|
|
14
14
|
const partners = subject.filter((id) => typeOfId(id) === "family").flatMap((id) => tree.get(id)?.partners ?? []);
|
|
15
15
|
return [...new Set([...subjectPeople(tree, subject), ...partners])];
|
|
16
16
|
}
|
|
17
|
+
/** Whether a text names a record by its ID (any script around it: never \b, which knows only ASCII letters). */
|
|
18
|
+
export function namesId(text, id) {
|
|
19
|
+
return new RegExp(`(?<![\\p{L}\\p{M}\\p{N}])${id}(?![\\p{L}\\p{M}\\p{N}])`, "u").test(text);
|
|
20
|
+
}
|
|
21
|
+
const PERSON_ID = /(?<![\p{L}\p{M}\p{N}])P\d{4,}(?![\p{L}\p{M}\p{N}])/gu;
|
|
22
|
+
/**
|
|
23
|
+
* The people a hypothesis is about: those of its subject, and the people of the tree its question and its variants'
|
|
24
|
+
* claims name by ID ("the son of P0012 and P0013") — a variant that names a family nothing links to the tree would
|
|
25
|
+
* join it, though the subject names only the person of the tree. What each variant cites for or against it is
|
|
26
|
+
* evidence, not who it is about.
|
|
27
|
+
*/
|
|
28
|
+
export function hypothesisPeople(tree, h) {
|
|
29
|
+
const named = [h.question, ...h.variants.map((v) => v.claim)].flatMap((text) => text.match(PERSON_ID) ?? []);
|
|
30
|
+
const people = named.filter((id) => {
|
|
31
|
+
const p = tree.get(id);
|
|
32
|
+
return p && !p.retracted;
|
|
33
|
+
});
|
|
34
|
+
return [...new Set([...aboutPeople(tree, h.subject), ...people])];
|
|
35
|
+
}
|
|
17
36
|
/** The direction a task belongs to: its own, else the narrowest one its people are in; none for a task about nobody. */
|
|
18
37
|
export function directionOf(tree, t, all) {
|
|
19
38
|
if (t.research)
|
package/dist/core/edge.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// tree ends (_STROM_EDGE, _STROM_ISLAND) and what `strom edge` says.
|
|
7
7
|
import { now } from "./tree.js";
|
|
8
8
|
import { Settings } from "./config.js";
|
|
9
|
-
import { aboutPeople, directionOf, scopes } from "./directions.js";
|
|
9
|
+
import { aboutPeople, directionOf, hypothesisPeople, namesId, scopes } from "./directions.js";
|
|
10
10
|
import { birthEstimate, birthRecordProven, birthWindow, frontier, FRONTIER_LEVELS, RECORD_KINDS, recordsetsCovering } from "./frontier.js";
|
|
11
11
|
import { kinship, offTree } from "./kin.js";
|
|
12
12
|
import { familiesAsChild, familiesAsPartner, parentsOf, primaryName } from "./people.js";
|
|
@@ -81,7 +81,7 @@ function islands(tree, kin, tasks, hypotheses) {
|
|
|
81
81
|
const island = {
|
|
82
82
|
people: [...people],
|
|
83
83
|
hypotheses: hypotheses
|
|
84
|
-
.map((h) => ({ h, about:
|
|
84
|
+
.map((h) => ({ h, about: hypothesisPeople(tree, h) }))
|
|
85
85
|
.filter(({ about }) => about.some((x) => people.has(x)) && about.some((x) => kin.has(x)))
|
|
86
86
|
.map(({ h, about }) => ({ id: h.id, joins: about.filter((x) => kin.has(x)) })),
|
|
87
87
|
held: tasks.filter((t) => LIVE.has(t.state) && off(t) && aboutPeople(tree, t.subject).some((x) => people.has(x))).length,
|
|
@@ -113,7 +113,7 @@ export function treeEdges(tree) {
|
|
|
113
113
|
frontiers.set(r.id, new Map(frontier(tree, r).map((i) => [i.person.id, i])));
|
|
114
114
|
return frontiers.get(r.id);
|
|
115
115
|
};
|
|
116
|
-
const hypAbout = hypotheses.map((h) => ({ h, about:
|
|
116
|
+
const hypAbout = hypotheses.map((h) => ({ h, about: hypothesisPeople(tree, h) }));
|
|
117
117
|
const edges = new Map();
|
|
118
118
|
for (const p of tree.list("person")) {
|
|
119
119
|
if (p.retracted)
|
|
@@ -256,7 +256,8 @@ export function treeEdges(tree) {
|
|
|
256
256
|
question: h.question,
|
|
257
257
|
joins,
|
|
258
258
|
...(isle ? { island: { people: isle.people.length, held: isle.held } } : {}),
|
|
259
|
-
|
|
259
|
+
// a task about it, or one whose words name it ("the baptism … (H0007 B)")
|
|
260
|
+
tests: tasks.filter((t) => LIVE.has(t.state) && (t.subject.includes(h.id) || namesId(t.what, h.id))).map((t) => t.id),
|
|
260
261
|
};
|
|
261
262
|
});
|
|
262
263
|
const edgeConflicts = conflicts
|
package/dist/core/kin.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// app opens on them), and how near anyone is to the people the research is
|
|
3
3
|
// for (which entries get their image in the Strom app first).
|
|
4
4
|
import { Settings } from "./config.js";
|
|
5
|
-
import { aboutPeople } from "./directions.js";
|
|
5
|
+
import { aboutPeople, hypothesisPeople } from "./directions.js";
|
|
6
6
|
import { ancestorGenerations, familiesAsChild, familiesAsPartner } from "./people.js";
|
|
7
7
|
function researches(tree) {
|
|
8
8
|
return tree
|
|
@@ -125,5 +125,10 @@ export function joiningHypotheses(tree, people) {
|
|
|
125
125
|
}
|
|
126
126
|
return tree
|
|
127
127
|
.list("hypothesis")
|
|
128
|
-
.filter((h) =>
|
|
128
|
+
.filter((h) => {
|
|
129
|
+
if (h.state !== "open")
|
|
130
|
+
return false;
|
|
131
|
+
const about = hypothesisPeople(tree, h);
|
|
132
|
+
return about.some((s) => family.has(s)) && about.some((s) => kin.has(s));
|
|
133
|
+
});
|
|
129
134
|
}
|
package/dist/core/review.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// Each kind is at most one task per person at a time, and what a task of that
|
|
8
8
|
// kind took up is never proposed again.
|
|
9
9
|
import { dateYears } from "./gdate.js";
|
|
10
|
+
import { hypothesisPeople } from "./directions.js";
|
|
10
11
|
import { birthEstimate, RECORD_KINDS, recordsetsCovering, researchPeople } from "./frontier.js";
|
|
11
12
|
import { birthEvent, displayName, familiesAsPartner, lifespan } from "./people.js";
|
|
12
13
|
import { phrase } from "./phrases.js";
|
|
@@ -209,7 +210,7 @@ function openConflicts(tree, p) {
|
|
|
209
210
|
const about = (subject) => subject.includes(p.id) || subject.some((s) => families.has(s));
|
|
210
211
|
return [
|
|
211
212
|
...tree.list("conflict").filter((c) => c.state === "open" && about(c.subject)),
|
|
212
|
-
...tree.list("hypothesis").filter((h) => h.state === "open" &&
|
|
213
|
+
...tree.list("hypothesis").filter((h) => h.state === "open" && hypothesisPeople(tree, h).includes(p.id)),
|
|
213
214
|
].map((x) => x.id);
|
|
214
215
|
}
|
|
215
216
|
/** The tasks strom proposes for the people of a person research (strom review). */
|
package/dist/core/tree.js
CHANGED
|
@@ -27,7 +27,7 @@ import { lastBackup } from "./backup.js";
|
|
|
27
27
|
export const TREE_FILE = "strom.json";
|
|
28
28
|
// between releases the candidate being made (a bridge run from the sources says what it is: the Strom app goes by it);
|
|
29
29
|
// at a release the release's own (package.json)
|
|
30
|
-
export const VERSION = "1.13.
|
|
30
|
+
export const VERSION = "1.13.1-beta.1";
|
|
31
31
|
const GITIGNORE = `# Strom Research — local state and large files are not versioned
|
|
32
32
|
.strom/
|
|
33
33
|
/media/
|
package/dist/gedcom/export.js
CHANGED
|
@@ -34,6 +34,7 @@ import { quay } from "../core/evidence.js";
|
|
|
34
34
|
import { VERSION } from "../core/tree.js";
|
|
35
35
|
import { dataUrl, turned } from "../core/excerpt.js";
|
|
36
36
|
import { mainPerson } from "../core/kin.js";
|
|
37
|
+
import { hypothesisPeople } from "../core/directions.js";
|
|
37
38
|
import * as git from "../core/git.js";
|
|
38
39
|
import { treeEdges } from "../core/edge.js";
|
|
39
40
|
import { readersOf } from "../core/review.js";
|
|
@@ -141,7 +142,13 @@ export function exportGedcom(tree, opts = {}) {
|
|
|
141
142
|
// What the research knows beyond the facts (the Strom profile, opts.research): read once.
|
|
142
143
|
const research = {
|
|
143
144
|
conflicts: opts.research ? tree.list("conflict") : [],
|
|
144
|
-
|
|
145
|
+
// with the people each is about: its subject's, and those its variants name (core/directions.ts hypothesisPeople)
|
|
146
|
+
hypotheses: opts.research
|
|
147
|
+
? tree
|
|
148
|
+
.list("hypothesis")
|
|
149
|
+
.filter((h) => h.state === "open")
|
|
150
|
+
.map((h) => ({ h, people: hypothesisPeople(tree, h) }))
|
|
151
|
+
: [],
|
|
145
152
|
// a search is of the people of the task it served
|
|
146
153
|
searched: opts.research
|
|
147
154
|
? tree
|
|
@@ -559,7 +566,7 @@ export function exportGedcom(tree, opts = {}) {
|
|
|
559
566
|
if (c.state === "resolved" && c.resolution)
|
|
560
567
|
w.text(2, "DECI", c.resolution);
|
|
561
568
|
}
|
|
562
|
-
for (const h of research.hypotheses.filter((x) =>
|
|
569
|
+
for (const { h } of research.hypotheses.filter((x) => x.people.includes(p.id))) {
|
|
563
570
|
w.line(1, "_STROM_HYPO", h.id);
|
|
564
571
|
w.text(2, "TITL", h.question);
|
|
565
572
|
w.text(2, "NOTE", h.variants.map((v) => `${v.label}: ${v.claim}`).join("\n"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strom-research",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.1-beta.1",
|
|
4
4
|
"description": "Genealogical research toolkit for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -45,5 +45,8 @@
|
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^22.20.4",
|
|
47
47
|
"typescript": "^7.0.2"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"tag": "beta"
|
|
48
51
|
}
|
|
49
52
|
}
|