strom-research 1.22.0 → 1.22.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/CHANGELOG.cs.md CHANGED
@@ -5,6 +5,15 @@
5
5
  Změny každé verze ve zkratce. Úplné poznámky a instalační řádky jsou na
6
6
  [GitHub Releases](https://github.com/ACiDekCZ/strom-research/releases) (anglicky).
7
7
 
8
+ ## 1.22.1
9
+
10
+ *29. 10. 2026 · patří k aplikaci Strom 3.17.0.*
11
+
12
+ - **Událost místa se u regionu nezapíše znovu.** Když se dějiny místa hledaly dřív než dějiny regionů, do kterých
13
+ patří, mohly dějiny regionu přidat tutéž událost ještě jednou (stejný druh, stejné roky). Region teď vynechá, co už
14
+ má některé z jeho míst; událost, která se týkala celého regionu, se zapíše dál. To, co agent k místu čte, říká
15
+ i to, které z jeho regionů se ještě neprošly.
16
+
8
17
  ## 1.22.0
9
18
 
10
19
  *29. 10. 2026 · patří k aplikaci Strom 3.17.0.*
package/CHANGELOG.de.md CHANGED
@@ -5,6 +5,16 @@
5
5
  Die Änderungen jeder Version in Kürze. Die vollständigen Hinweise und die Installationszeilen stehen bei
6
6
  [GitHub Releases](https://github.com/ACiDekCZ/strom-research/releases) (auf Englisch).
7
7
 
8
+ ## 1.22.1
9
+
10
+ *29.10.2026 · gehört zur Strom-App 3.17.0.*
11
+
12
+ - **Ein Ereignis eines Ortes wird bei seiner Region nicht noch einmal geschrieben.** Wurde die Geschichte eines Ortes
13
+ vor den Regionen gesucht, zu denen er gehört, konnte die Geschichte der Region dasselbe Ereignis noch einmal
14
+ hinzufügen (dieselbe Art, dieselben Jahre). Die Region lässt jetzt aus, was einer ihrer Orte schon hat; ein
15
+ Ereignis, das die ganze Region betraf, wird weiter geschrieben. Was der Agent zu einem Ort liest, sagt auch, welche
16
+ seiner Regionen noch nicht durchgesehen sind.
17
+
8
18
  ## 1.22.0
9
19
 
10
20
  *29.10.2026 · gehört zur Strom-App 3.17.0.*
package/CHANGELOG.md CHANGED
@@ -5,6 +5,15 @@ English · [Čeština](CHANGELOG.cs.md) · [Deutsch](CHANGELOG.de.md)
5
5
  The changes of each version in short. The full notes and the install lines are on
6
6
  [GitHub Releases](https://github.com/ACiDekCZ/strom-research/releases).
7
7
 
8
+ ## 1.22.1
9
+
10
+ *2026-10-29 · goes with the Strom app 3.17.0.*
11
+
12
+ - **An event of a place is not written again for its region.** When the history of a place was looked for before the
13
+ regions it lies in, the region's history could add the same event once more (the same kind, the same years). The
14
+ region now leaves out what one of its places has already; an event that touched the whole region is still written.
15
+ What the agent reads for a place also says which of its regions are not looked through yet.
16
+
8
17
  ## 1.22.0
9
18
 
10
19
  *2026-10-29 · goes with the Strom app 3.17.0.*
@@ -200,6 +200,9 @@ function placeSections(tree, id, shared, alone) {
200
200
  const events = c?.events ?? [];
201
201
  const live = events.filter((e) => !e.retracted);
202
202
  const theirs = regionEventsAt(tree, shared, p.id, at);
203
+ // its regions not looked through yet (K7.1a): what touched the whole region is theirs, written when they are
204
+ const maps = readPlaces(tree);
205
+ const waiting = [...new Set((at?.keys ?? []).flatMap((k) => maps[k]?.regions ?? []).map((g) => g.id))].filter((g) => !shared || !readCatalog(shared, g)?.done);
203
206
  const out = [];
204
207
  out.push({
205
208
  name: "history",
@@ -237,6 +240,9 @@ function placeSections(tree, id, shared, alone) {
237
240
  : [" none yet"]),
238
241
  theirs.length ? `The regions' events at this place in its years (${theirs.length}) — the Strom app shows them here already, never written for the place (refused):` : "No region's event at this place yet.",
239
242
  ...theirs.slice(0, EVENTS_SHOWN).map(({ event: e, region }) => ` ${e.id} ${years(e.from, e.to)} ${e.kind} (${region.region.id}) "${short(e.text[lang] ?? e.text.en ?? Object.values(e.text)[0] ?? "")}"`),
243
+ waiting.length
244
+ ? `Regions of this place not looked through yet (${waiting.join(", ")}): what touched the whole region (a war of the land, its epidemic, a reform of the state) is theirs, written when they are — here only what happened at the place or near enough to touch its people`
245
+ : "",
240
246
  c?.tried.length ? `Pages strom could not read (never tried again): ${c.tried.slice(-20).map((t) => `${t.url} (${short(t.why, 40)})`).join(" · ")}` : "",
241
247
  ].filter(Boolean).join("\n"),
242
248
  });
@@ -15,7 +15,7 @@ import { resolvePerson } from "../core/people.js";
15
15
  import { checkQuotes, cleanText, findPassages, mainQuote, pageParts, PageError, quotesShape, readPage, PART_CHARS } from "../core/pagecheck.js";
16
16
  import { currentSession } from "../core/session.js";
17
17
  import { addLocalEvent, addRegionEvent, askFirst, assignPlace, checkKind, checkTexts, checkYears, deleteEvent, ensureRegion, factPlaceKey, hideEvent, historyAnswer, historyStatus, forGaps, forHistory, gapsOfTask, gapText, historyOrder, historyHeld, historyTurn, mapPlace, raiseHistoryTasks, markDone, donePeriod, noteTried, readCatalog, redoRegion, refuseBeforePage, REGION_LANGS, regionIdOk, regionOfTask, requireHistoryOn, requireRegionId, retractEvent, skipHistory, EVENT_KINDS, yearsToSearch, whoSees, readPlaces, inRegion, regionName, placeRecordOf, } from "../core/pastevents.js";
18
- import { addPlaceEvent, askPlace, refusePlaceAsk, ensurePlaceCatalog, markPlaceDone, factsByRecord, notePlaceTried, placeEstimate, placeKeyOf, placeLabel, placeOfTask, readPlaceCatalog, refusePlaceBeforePage, requirePlace, setArea, yearsAt, } from "../core/placehistory.js";
18
+ import { addPlaceEvent, askPlace, refusePlaceAsk, ensurePlaceCatalog, markPlaceDone, factsByRecord, notePlaceTried, placeEstimate, placeKeyOf, placeLabel, placeOfTask, readPlaceCatalog, refusePlaceBeforePage, refusePlaceSame, requirePlace, setArea, yearsAt, } from "../core/placehistory.js";
19
19
  // strom history list
20
20
  import { moreLine, paginate } from "../cli/format.js";
21
21
  import { displayName } from "../core/people.js";
@@ -336,8 +336,11 @@ register({
336
336
  }
337
337
  if (place)
338
338
  refusePlaceBeforePage(tree, sh, place, { kind, from, to }, s, url);
339
- else
339
+ else {
340
340
  refuseBeforePage(sh, region, { kind, from, to }, s, url);
341
+ if (!s.sameAs && !s.distinct)
342
+ refusePlaceSame(tree, sh, region, { kind, from, to });
343
+ }
341
344
  let checked;
342
345
  try {
343
346
  checked = await checkQuotes(url, quotes, { from, to }, sh, ctx.env);
@@ -363,6 +366,9 @@ register({
363
366
  sha: checked.page.sha,
364
367
  };
365
368
  const event = { from, to, ...(date ? { date } : {}), kind, text, ...(why ? { why } : {}), ...(tip ? { tip } : {}), ...(opts.sensitive ? { sensitive: true } : {}), source };
369
+ // a place looked for before its region (K7.1a): its own events checked again once the page is read
370
+ if (!place && !s.sameAs && !s.distinct)
371
+ refusePlaceSame(tree, sh, region, { kind, from, to });
366
372
  const r = place ? addPlaceEvent(tree, sh, place, event, s) : addRegionEvent(sh, tree.config.id, { region: region, ...event }, s);
367
373
  const where = place ? `at ${placeLabel(place, "en")} (${place.id}) and its surroundings` : `in ${region}`;
368
374
  // who it shows at (their person in the Strom app, their story): for the agent to say to the person who asked
@@ -218,6 +218,39 @@ export function regionEventsAt(tree, shared, id, at = factsByRecord(tree).get(id
218
218
  }
219
219
  return [...out.values()].sort((a, b) => a.event.from - b.event.from || a.event.id.localeCompare(b.event.id));
220
220
  }
221
+ /**
222
+ * The own events of the tree's places that belong to a region in the years of an event (their facts' places mapped to
223
+ * it): the mirror of regionEventsAt, for a place looked for before its region (spec 020 K7.1a). Not taken back.
224
+ */
225
+ export function placeEventsIn(tree, shared, region, e) {
226
+ if (!shared)
227
+ return [];
228
+ const maps = readPlaces(tree);
229
+ const folded = new Map(Object.entries(maps).map(([k, v]) => [foldText(k), v]));
230
+ const out = [];
231
+ for (const [id, at] of factsByRecord(tree)) {
232
+ const inIt = at.keys.some((key) => ((maps[key] ?? folded.get(foldText(key)))?.regions ?? []).some((g) => g.id === region && inRegion(e, g)));
233
+ const p = inIt ? placeRecord(tree, id) : undefined;
234
+ if (!p)
235
+ continue;
236
+ for (const x of readPlaceCatalog(shared, placeKeyOf(tree, p))?.events ?? [])
237
+ if (!x.retracted)
238
+ out.push({ event: x, place: p });
239
+ }
240
+ return out.sort((a, b) => a.event.from - b.event.from || a.event.id.localeCompare(b.event.id));
241
+ }
242
+ /** An event of one of the region's places of the same kind and years: the region's history never writes it again. */
243
+ export function refusePlaceSame(tree, shared, region, e) {
244
+ const same = placeEventsIn(tree, shared, region, e).filter((x) => x.event.kind === e.kind && x.event.from <= e.to && e.from <= x.event.to);
245
+ if (!same.length)
246
+ return;
247
+ const ids = same.map((x) => `${x.event.id} (${x.place.id})`);
248
+ throw new UsageError(`an event of a place of ${region} of the same kind and years is there already: ${ids.join(", ")} — nothing written`, {
249
+ code: "history.same.place",
250
+ params: { ids: same.map((x) => x.event.id).join(", ") },
251
+ hint: `the place's event shows there already — leave it out; an event of the whole region (it touched its other places too): --distinct "<why it is another>"`,
252
+ });
253
+ }
221
254
  // ── the person's asks ──────────────────────────────────────────────────────
222
255
  export function readPlaceAsks(tree) {
223
256
  try {
package/dist/core/tree.js CHANGED
@@ -29,7 +29,7 @@ export const TREE_FILE = "strom.json";
29
29
  export const SEAL_FOREIGN = "seal.foreign";
30
30
  // between releases the candidate being made (a bridge run from the sources says what it is: the Strom app goes by it);
31
31
  // at a release the release's own (package.json)
32
- export const VERSION = "1.22.0";
32
+ export const VERSION = "1.22.1";
33
33
  const GITIGNORE = `# Strom Research — local state and large files are not versioned
34
34
  .strom/
35
35
  /media/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strom-research",
3
- "version": "1.22.0",
3
+ "version": "1.22.1",
4
4
  "description": "Genealogical research toolkit for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {