strom-research 1.13.0-beta.1 → 1.13.0-beta.2

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.
@@ -94,7 +94,7 @@
94
94
  "ui.menu.trees": "Jiný rodokmen · poslat nebo přijmout",
95
95
  "ui.menu.newtree": "Založit rodokmen · poslat nebo přijmout",
96
96
  "ui.menu.quit": "Konec",
97
- "ui.menu.bye": "Na shledanou. Příště stačí spustit: strom",
97
+ "ui.menu.bye": "Na shledanou. Příště stačí spustit: {strom}",
98
98
  "ui.run.how": "Kolik úkolů? (skončí dřív, když už nebude co dělat; 0 vrátí zpět)",
99
99
  "ui.run.start": "Agent teď pracuje sám. Zastaví ho klávesy Ctrl-C – nic se neztratí.",
100
100
  "ui.waiting.none": "Nic nečeká.",
@@ -118,14 +118,14 @@
118
118
  "ui.setup.git.ok": "✓ Git (historie výzkumu): {version}",
119
119
  "ui.setup.git.missing": "Chybí Git – strom v něm uchovává historii výzkumu, aby se nic neztratilo.",
120
120
  "ui.setup.git.wait": "Dokončit instalaci v okně, které se otevřelo, a pak Enter.",
121
- "ui.setup.git.manual": "Nainstalovat ho příkazem: {command} – a pak znovu spustit strom.",
121
+ "ui.setup.git.manual": "Nainstalovat ho příkazem: {command} – a pak znovu spustit {strom}.",
122
122
  "ui.setup.agent.ok": "✓ AI agent: {name}",
123
123
  "ui.setup.agent.none": "Nenašel jsem žádného AI agenta – strom ho potřebuje: výzkum se dělá s ním.",
124
124
  "ui.setup.agent.install": "Nainstalovat Claude Code hned (doporučeno; je potřeba předplatné Claude)",
125
125
  "ui.setup.agent.guide": "Ukázat, jací agenti jsou (otevře stránku v prohlížeči)",
126
126
  "ui.setup.agent.later": "Později",
127
127
  "ui.setup.agent.login": "Při prvním spuštění agenta přijde přihlášení – otevře se okno prohlížeče.",
128
- "ui.setup.agent.manual": "Nainstalovat AI agenta (jak: {url}) a pak znovu spustit strom.",
128
+ "ui.setup.agent.manual": "Nainstalovat AI agenta (jak: {url}) a pak znovu spustit {strom}.",
129
129
  "ui.setup.model": "Který model má výzkum dělat?",
130
130
  "ui.setup.model.opus": "Opus – nejlépe čte staré rukopisy (doporučeno)",
131
131
  "ui.setup.model.sonnet": "Sonnet – rychlejší; tištěné dokumenty a běžná práce",
@@ -307,7 +307,7 @@
307
307
  "ui.o.results.offer": "{file} – pro aplikaci Strom, tady zatím nenainstalovanou: nabídni uživateli instalaci z {url} (strom app install ji tam otevře)",
308
308
  "ui.o.results.plain": "{file} – pro jakýkoli program na rodokmeny",
309
309
  "ui.chat.handover": "Výzkum pokračuje ve vlastním rozhovoru: otevřelo se nové okno s agentem {agent} ve složce rodokmenu. Dál se pokračuje tam – tento rozhovor jde zavřít.",
310
- "ui.chat.handover.failed": "Nové okno se tady otevřít nepodařilo. Výzkum jde spustit ručně: v terminálu příkazem strom (nebo zástupcem Strom výzkum na ploše).",
310
+ "ui.chat.handover.failed": "Nové okno se tady otevřít nepodařilo. Výzkum jde spustit ručně: v terminálu příkazem {strom} (nebo zástupcem Strom výzkum na ploše).",
311
311
  "ui.chat.handover.end": "Dál se pokračuje tam – tento rozhovor jde zavřít.",
312
312
  "ui.why.handover": "výzkum patří do vlastního rozhovoru ve složce rodokmenu (jeho pravidla, bez ptaní u každého kroku): tohle ho otevře – řekni uživateli, ať pokračuje tam; tady pokračuj, jen když chce",
313
313
  "ui.app.research": "Otevírám výzkum {name} v aplikaci Strom ({where}): poprvé jako nový rodokmen, příště se tentýž rodokmen aktualizuje.",
@@ -453,7 +453,7 @@
453
453
  "ui.doc.backup": "záloha",
454
454
  "ui.backup.made": "Záloha před přechodem z {from} na {to}: {path} ({size}).",
455
455
  "ui.backup.last": "Poslední záloha (před přechodem z {from} na {to}, {date}): {path}",
456
- "ui.backup.readme": "Strom výzkum – záloha\n\nVytvořena {date}, před přechodem ze stromu {from} na {to}.\n\nUvnitř:\n- trees: všechny rodokmeny tohoto počítače, každý celou svou složkou i s historií (.git);\n- settings: nastavení stromu s klíči pečetí a přihlášeními, jak byly na tomto počítači.\n\nNení uvnitř: sdílené obrázky (složka shared/media). Každý je tam uložen podle svého obsahu a strom žádný nemaže; každá verze stromu čte tytéž. Vynecháno je i to, co strom vytvoří znovu sám (náhledy skenů, výřezy).\n\nVrácení rodokmenu: zkopírovat jeho složku z trees zpět tam, kde rodokmeny jsou (místo té, která tam je, nebo vedle ní pod jiným jménem), a spustit strom: strom ho zkontroluje (strom check).",
456
+ "ui.backup.readme": "Strom výzkum – záloha\n\nVytvořena {date}, před přechodem ze stromu {from} na {to}.\n\nUvnitř:\n- trees: všechny rodokmeny tohoto počítače, každý celou svou složkou i s historií (.git);\n- settings: nastavení stromu s klíči pečetí a přihlášeními, jak byly na tomto počítači.\n\nNení uvnitř: sdílené obrázky (složka shared/media). Každý je tam uložen podle svého obsahu a strom žádný nemaže; každá verze stromu čte tytéž. Vynecháno je i to, co strom vytvoří znovu sám (náhledy skenů, výřezy).\n\nVrácení rodokmenu: zkopírovat jeho složku z trees zpět tam, kde rodokmeny jsou (místo té, která tam je, nebo vedle ní pod jiným jménem), a spustit {strom}: strom ho zkontroluje ({strom} check).",
457
457
  "ui.trees.locked": "zamčeno: zapsal strom {by}",
458
458
  "ui.setup.stromapp": "Aplikace Strom (zdarma, v prohlížeči) ukáže výzkum jako rodokmen – u každého zápisu jeho obrázek vyříznutý ze skenu, příběhy předků – a když agent pracuje, sleduje výzkum živě. Používat ji?",
459
459
  "ui.setup.stromapp.install": "Ano – nainstalovat ji teď (otevře se v prohlížeči, strom řekne, kam kliknout)",
@@ -654,7 +654,7 @@
654
654
  "ui.help.archive.stats": "Archiv v kostce: osoby, jak jisté jsou údaje, předkové v každé generaci",
655
655
  "ui.help.archive.pack": "Zabalit archiv do jednoho souboru ZIP, aby v něm mohl pokračovat někdo jiný",
656
656
  "ui.help.archive.intake": "Přidat podklady od rodiny: dokumenty, fotky, rodokmen, co je známo",
657
- "ui.help.title": "strom <příkaz> – co člověk se stromem dělá (nebo jen strom: menu)",
657
+ "ui.help.title": "strom <příkaz> – co člověk se stromem dělá (nebo jen {strom}: menu)",
658
658
  "ui.help.more": "Nápověda k jednomu příkazu: strom help <příkaz> --human · všechny příkazy anglicky (co čte agent): strom help",
659
659
  "ui.help.more.archive": "Nápověda k jednomu příkazu: strom help <příkaz> --human",
660
660
  "ui.help.examples": "Příklady:",
@@ -755,6 +755,9 @@
755
755
  "ui.sync.name.new": "{n}. {who}: další jméno — {text}",
756
756
  "ui.sync.name.changed": "{n}. {who}: změněné jméno — {old} → {new}",
757
757
  "ui.sync.do.name.user": "platí úprava z aplikace: osoba se ukazuje pod novým jménem, jméno ze záznamu zůstane vedle něj",
758
+ "ui.sync.name.title": "{n}. {who}: {title} — {old} → {new}",
759
+ "ui.sync.do.title": "doplní se ke jménu s odkazem na strom z aplikace",
760
+ "ui.sync.do.title.user": "platí úprava z aplikace (verze výzkumu zůstane v historii)",
758
761
  "ui.sync.sex.changed": "{n}. {who}: pohlaví {text}",
759
762
  "ui.sync.note.new": "{n}. {who}: poznámka — „{text}“",
760
763
  "ui.sync.source.new": "{n}. pramen: „{text}“",
@@ -1004,8 +1007,8 @@
1004
1007
  "ui.link.off.done": "Odkazy z aplikace Strom už do výzkumu na tomto počítači nevedou.",
1005
1008
  "ui.link.off.failed": "Odkazy z aplikace Strom se z tohoto počítače nepodařilo odebrat.",
1006
1009
  "ui.link.which.one": "Tento výzkum je tu vícekrát. Který?",
1007
- "ui.link.noterminal.any": "strom nemohl otevřít okno terminálu. Spustit strom (výzkum {name}) a pokračovat z jeho nabídky.",
1008
- "ui.link.noterminal.new": "strom nemohl otevřít okno terminálu. Spustit strom a pak to zkusit z aplikace Strom znovu.",
1010
+ "ui.link.noterminal.any": "strom nemohl otevřít okno terminálu. Spustit {strom} (výzkum {name}) a pokračovat z jeho nabídky.",
1011
+ "ui.link.noterminal.new": "strom nemohl otevřít okno terminálu. Spustit {strom} a pak to zkusit z aplikace Strom znovu.",
1009
1012
  "ui.link.asks": "Aplikace Strom žádá: {what}\nVýzkum: {name}",
1010
1013
  "ui.link.go": "Pokračovat?",
1011
1014
  "ui.link.cost": "Agent pracuje na předplatné nebo kredit AI.",
@@ -1399,7 +1402,7 @@
1399
1402
  "ui.unpack.kept": " konektor {name} tu už byl – zůstává ten dosavadní",
1400
1403
  "ui.unpack.left": " prohledané stránky, které v něm nejsou: {n} – až budou potřeba, strom je stáhne z archivu",
1401
1404
  "ui.unpack.adopted": " převzato na tento počítač",
1402
- "ui.unpack.next": "Dál: strom (nabídka) nebo strom chat.",
1405
+ "ui.unpack.next": "Dál: {strom} (nabídka) nebo strom chat.",
1403
1406
  "ui.unpack.same": "tento výzkum už tu je: {root}",
1404
1407
  "ui.unpack.person": "výzkum rozbaluje jen člověk u počítače (přidává konektory)",
1405
1408
  "ui.pack.launch.extract": "Nejdřív rozbalit celý soubor ZIP – ve Windows pravým tlačítkem: Extrahovat vše – a spustit tohle znovu z rozbalené složky.",
@@ -1457,7 +1460,7 @@
1457
1460
  "ui.error.command.unknown": "neznámý příkaz „strom {cmd}“",
1458
1461
  "ui.error.command.unknown.hint": "strom help (všechny příkazy)",
1459
1462
  "ui.error.command.unknown.person": "neznámý příkaz „strom {cmd}“",
1460
- "ui.error.command.unknown.person.hint": "strom help --human – nebo jen strom: menu",
1463
+ "ui.error.command.unknown.person.hint": "strom help --human – nebo jen {strom}: menu",
1461
1464
  "ui.error.option.near": "neznámá volba {opt} u {cmd}",
1462
1465
  "ui.error.option.near.hint": "podobná volba: {near}",
1463
1466
  "ui.conflict.none": "žádné otevřené rozpory",
@@ -1465,6 +1468,8 @@
1465
1468
  "ui.conflict.sex": "pohlaví",
1466
1469
  "ui.conflict.sex.U": "neznámé",
1467
1470
  "ui.conflict.name": "jméno",
1471
+ "ui.conflict.titleBefore": "titul před jménem",
1472
+ "ui.conflict.titleAfter": "titul za jménem",
1468
1473
  "ui.conflict.parents": "rodiče",
1469
1474
  "ui.sync.family.union": "{n}. {who}: svazek – {union}",
1470
1475
  "ui.sync.do.family.union": "převezme se (žádný záznam ho nedokládá)",
@@ -94,7 +94,7 @@
94
94
  "ui.menu.trees": "Anderer Stammbaum · einen schicken oder empfangen",
95
95
  "ui.menu.newtree": "Stammbaum anlegen · einen schicken oder empfangen",
96
96
  "ui.menu.quit": "Beenden",
97
- "ui.menu.bye": "Auf Wiedersehen. Nächstes Mal genügt: strom",
97
+ "ui.menu.bye": "Auf Wiedersehen. Nächstes Mal genügt: {strom}",
98
98
  "ui.run.how": "Wie viele Aufgaben? (er hört früher auf, wenn es nichts mehr zu tun gibt; 0 geht zurück)",
99
99
  "ui.run.start": "Der Agent arbeitet jetzt allein. Strg-C hält ihn an – nichts geht verloren.",
100
100
  "ui.waiting.none": "Nichts wartet.",
@@ -118,14 +118,14 @@
118
118
  "ui.setup.git.ok": "✓ Git (Verlauf der Forschung): {version}",
119
119
  "ui.setup.git.missing": "Git fehlt – strom bewahrt darin den Verlauf der Forschung auf, damit nichts verloren geht.",
120
120
  "ui.setup.git.wait": "Die Installation im geöffneten Fenster abschließen, dann Enter drücken.",
121
- "ui.setup.git.manual": "Installation mit: {command} – dann strom erneut starten.",
121
+ "ui.setup.git.manual": "Installation mit: {command} – dann {strom} erneut starten.",
122
122
  "ui.setup.agent.ok": "✓ KI-Agent: {name}",
123
123
  "ui.setup.agent.none": "Kein KI-Agent gefunden – strom braucht einen: der Agent führt die Forschung im Gespräch.",
124
124
  "ui.setup.agent.install": "Claude Code jetzt installieren (empfohlen; nötig ist ein Claude-Abonnement)",
125
125
  "ui.setup.agent.guide": "Zeigen, welche Agenten es gibt (öffnet eine Seite im Browser)",
126
126
  "ui.setup.agent.later": "Später",
127
127
  "ui.setup.agent.login": "Beim ersten Start des Agenten ist eine Anmeldung nötig – ein Browserfenster öffnet sich.",
128
- "ui.setup.agent.manual": "Einen KI-Agenten installieren (wie: {url}), dann strom erneut starten.",
128
+ "ui.setup.agent.manual": "Einen KI-Agenten installieren (wie: {url}), dann {strom} erneut starten.",
129
129
  "ui.setup.model": "Welches Modell soll die Forschung machen?",
130
130
  "ui.setup.model.opus": "Opus – liest alte Handschriften am besten (empfohlen)",
131
131
  "ui.setup.model.sonnet": "Sonnet – schneller; gedruckte Dokumente und alltägliche Arbeit",
@@ -307,7 +307,7 @@
307
307
  "ui.o.results.offer": "{file} – für die Strom-App, hier noch nicht installiert: biete dem Benutzer die Installation von {url} an (strom app install öffnet sie dort)",
308
308
  "ui.o.results.plain": "{file} – für jedes Stammbaumprogramm",
309
309
  "ui.chat.handover": "Die Forschung geht in einem eigenen Gespräch weiter: Ein neues Fenster mit {agent} im Ordner des Stammbaums hat sich geöffnet. Dort geht es weiter – dieses Gespräch kann enden.",
310
- "ui.chat.handover.failed": "Ein neues Fenster ließ sich hier nicht öffnen. Die Forschung von Hand starten: strom im Terminal (oder die Verknüpfung Strom Ahnenforschung auf dem Desktop).",
310
+ "ui.chat.handover.failed": "Ein neues Fenster ließ sich hier nicht öffnen. Die Forschung von Hand starten: {strom} im Terminal (oder die Verknüpfung Strom Ahnenforschung auf dem Desktop).",
311
311
  "ui.chat.handover.end": "Dort geht es weiter – dieses Gespräch kann enden.",
312
312
  "ui.why.handover": "die Forschung gehört in ein eigenes Gespräch im Ordner des Stammbaums (seine Regeln, keine Nachfrage bei jedem Schritt): dies öffnet es – sag dem Benutzer, dort weiterzumachen; hier nur, wenn er will",
313
313
  "ui.app.research": "Die Forschung {name} wird in der Strom-App geöffnet ({where}): beim ersten Mal als neuer Stammbaum, danach wird derselbe Stammbaum aktualisiert.",
@@ -453,7 +453,7 @@
453
453
  "ui.doc.backup": "Sicherung",
454
454
  "ui.backup.made": "Sicherung vor dem Wechsel von {from} auf {to}: {path} ({size}).",
455
455
  "ui.backup.last": "Letzte Sicherung (vor dem Wechsel von {from} auf {to}, {date}): {path}",
456
- "ui.backup.readme": "Strom-Forschung – eine Sicherung\n\nErstellt {date}, vor dem Wechsel von strom {from} auf {to}.\n\nDarin:\n- trees: alle Stammbäume dieses Computers, jeder mit seinem ganzen Ordner samt Verlauf (.git);\n- settings: die Einstellungen von strom mit den Siegelschlüsseln und den Anmeldungen, wie sie auf diesem Computer waren.\n\nNicht darin: die gemeinsamen Bilder (der Ordner shared/media). Jedes liegt dort nach seinem Inhalt, und strom löscht keines; jede Version von strom liest dieselben. Ebenfalls weggelassen: was strom selbst wieder erstellt (Ansichten von Scans, Ausschnitte).\n\nEinen Stammbaum zurückholen: seinen Ordner aus trees dorthin zurückkopieren, wo die Stammbäume liegen (anstelle des vorhandenen oder daneben unter anderem Namen), dann strom starten: strom prüft ihn (strom check).",
456
+ "ui.backup.readme": "Strom-Forschung – eine Sicherung\n\nErstellt {date}, vor dem Wechsel von strom {from} auf {to}.\n\nDarin:\n- trees: alle Stammbäume dieses Computers, jeder mit seinem ganzen Ordner samt Verlauf (.git);\n- settings: die Einstellungen von strom mit den Siegelschlüsseln und den Anmeldungen, wie sie auf diesem Computer waren.\n\nNicht darin: die gemeinsamen Bilder (der Ordner shared/media). Jedes liegt dort nach seinem Inhalt, und strom löscht keines; jede Version von strom liest dieselben. Ebenfalls weggelassen: was strom selbst wieder erstellt (Ansichten von Scans, Ausschnitte).\n\nEinen Stammbaum zurückholen: seinen Ordner aus trees dorthin zurückkopieren, wo die Stammbäume liegen (anstelle des vorhandenen oder daneben unter anderem Namen), dann {strom} starten: strom prüft ihn ({strom} check).",
457
457
  "ui.trees.locked": "gesperrt: geschrieben von strom {by}",
458
458
  "ui.setup.stromapp": "Die Strom-App (kostenlos, im Browser) zeigt die Forschung als Stammbaum – jeden Eintrag mit seinem Bild aus dem Scan, die Geschichten der Vorfahren – und verfolgt sie live, während der Agent arbeitet. Soll sie verwendet werden?",
459
459
  "ui.setup.stromapp.install": "Ja – jetzt installieren (sie öffnet sich im Browser, strom zeigt, wo zu klicken ist)",
@@ -654,7 +654,7 @@
654
654
  "ui.help.archive.stats": "Das Archiv auf einen Blick: Personen, wie sicher die Angaben sind, Vorfahren je Generation",
655
655
  "ui.help.archive.pack": "Das Archiv in eine ZIP-Datei packen, damit jemand anderes weitermachen kann",
656
656
  "ui.help.archive.intake": "Material der Familie hinzufügen: Dokumente, Fotos, einen Stammbaum, eigenes Wissen",
657
- "ui.help.title": "strom <Befehl> – was ein Mensch mit strom tut (oder nur strom: das Menü)",
657
+ "ui.help.title": "strom <Befehl> – was ein Mensch mit strom tut (oder nur {strom}: das Menü)",
658
658
  "ui.help.more": "Hilfe zu einem Befehl: strom help <Befehl> --human · alle Befehle auf Englisch (was ein Agent liest): strom help",
659
659
  "ui.help.more.archive": "Hilfe zu einem Befehl: strom help <Befehl> --human",
660
660
  "ui.help.examples": "Beispiele:",
@@ -755,6 +755,9 @@
755
755
  "ui.sync.name.new": "{n}. {who}: ein weiterer Name — {text}",
756
756
  "ui.sync.name.changed": "{n}. {who}: Name geändert — {old} → {new}",
757
757
  "ui.sync.do.name.user": "Die eigene Änderung gilt: die Person erscheint unter dem neuen Namen, der Name aus dem Eintrag bleibt daneben",
758
+ "ui.sync.name.title": "{n}. {who}: {title} — {old} → {new}",
759
+ "ui.sync.do.title": "wird dem Namen hinzugefügt, mit Verweis auf den eigenen Stammbaum",
760
+ "ui.sync.do.title.user": "Die eigene Änderung gilt (die der Forschung bleibt in ihrer Geschichte)",
758
761
  "ui.sync.sex.changed": "{n}. {who}: Geschlecht {text}",
759
762
  "ui.sync.note.new": "{n}. {who}: eine Notiz — „{text}“",
760
763
  "ui.sync.source.new": "{n}. eine Quelle: „{text}“",
@@ -1004,8 +1007,8 @@
1004
1007
  "ui.link.off.done": "Links aus der Strom-App führen hier nicht mehr zur Forschung.",
1005
1008
  "ui.link.off.failed": "Die Links aus der Strom-App ließen sich von diesem Computer nicht entfernen.",
1006
1009
  "ui.link.which.one": "Diese Forschung ist hier mehrmals vorhanden. Welche?",
1007
- "ui.link.noterminal.any": "strom konnte kein Terminalfenster öffnen. strom starten (die Forschung {name}) und in seinem Menü weitermachen.",
1008
- "ui.link.noterminal.new": "strom konnte kein Terminalfenster öffnen. strom starten und es dann erneut aus der Strom-App versuchen.",
1010
+ "ui.link.noterminal.any": "strom konnte kein Terminalfenster öffnen. {strom} starten (die Forschung {name}) und in seinem Menü weitermachen.",
1011
+ "ui.link.noterminal.new": "strom konnte kein Terminalfenster öffnen. {strom} starten und es dann erneut aus der Strom-App versuchen.",
1009
1012
  "ui.link.asks": "Die Strom-App bittet um: {what}\nForschung: {name}",
1010
1013
  "ui.link.go": "Fortfahren?",
1011
1014
  "ui.link.cost": "Der Agent arbeitet auf das eigene Abonnement oder KI-Guthaben.",
@@ -1399,7 +1402,7 @@
1399
1402
  "ui.unpack.kept": " Konnektor {name} war schon da – der vorhandene bleibt",
1400
1403
  "ui.unpack.left": " {n} durchgesehene Seiten sind nicht darin: strom lädt sie aus dem Archiv, wenn sie gebraucht werden",
1401
1404
  "ui.unpack.adopted": " auf diesem Computer übernommen",
1402
- "ui.unpack.next": "Weiter: strom (das Menü) oder strom chat.",
1405
+ "ui.unpack.next": "Weiter: {strom} (das Menü) oder strom chat.",
1403
1406
  "ui.unpack.same": "diese Forschung ist schon da: {root}",
1404
1407
  "ui.unpack.person": "eine Forschung packt nur die Person am Computer aus (sie fügt Konnektoren hinzu)",
1405
1408
  "ui.pack.launch.extract": "Zuerst die ganze ZIP-Datei auspacken – unter Windows mit Rechtsklick: Alle extrahieren – und dies dann im ausgepackten Ordner neu starten.",
@@ -1457,7 +1460,7 @@
1457
1460
  "ui.error.command.unknown": "unbekannter Befehl „strom {cmd}“",
1458
1461
  "ui.error.command.unknown.hint": "strom help (alle Befehle)",
1459
1462
  "ui.error.command.unknown.person": "unbekannter Befehl „strom {cmd}“",
1460
- "ui.error.command.unknown.person.hint": "strom help --human – oder nur strom: das Menü",
1463
+ "ui.error.command.unknown.person.hint": "strom help --human – oder nur {strom}: das Menü",
1461
1464
  "ui.error.option.near": "unbekannte Option {opt} für {cmd}",
1462
1465
  "ui.error.option.near.hint": "ähnliche Option: {near}",
1463
1466
  "ui.conflict.none": "keine offenen Widersprüche",
@@ -1465,6 +1468,8 @@
1465
1468
  "ui.conflict.sex": "Geschlecht",
1466
1469
  "ui.conflict.sex.U": "unbekannt",
1467
1470
  "ui.conflict.name": "Name",
1471
+ "ui.conflict.titleBefore": "Titel vor dem Namen",
1472
+ "ui.conflict.titleAfter": "Titel nach dem Namen",
1468
1473
  "ui.conflict.parents": "Eltern",
1469
1474
  "ui.sync.family.union": "{n}. {who}: Verbindung – {union}",
1470
1475
  "ui.sync.do.family.union": "übernommen (kein Eintrag belegt es)",
@@ -25,7 +25,11 @@ without --dry-run. `#name` labels what a line creates, `@name` uses it later.
25
25
  and what the record adds to it: `event edit E… --age husband:27 --age wife:17
26
26
  --house 21 --with "witness:…" --with "officiant:…"` (filling in needs no reason).
27
27
  - The names a record gives go on the person: `name add` (a maiden name completes
28
- "Marie" to "Marie /Svobodová/"; a married name is `--kind married`).
28
+ "Marie" to "Marie /Svobodová/"; a married name is `--kind married`). A title
29
+ written with the name ("Ing.", "MUDr.", "ml.", "jun.") is the name's `--prefix`
30
+ or `--suffix` (`person add`, `name add`, `person edit`), never part of the
31
+ given name or the surname; a rank or office the record states is a fact
32
+ (`TITL`, `OCCU`).
29
33
  - A record that names someone's parents (a grandchild's baptism naming the
30
34
  grandparents) cites the family itself (`family add … --cite`, `cite F…`) and
31
35
  the new people's names (`person add … --cite`) — with `--information
@@ -53,14 +53,15 @@ export function shellArg(arg) {
53
53
  }
54
54
  /**
55
55
  * The commands a text names, as a second installation is started (strom-beta doctor, not strom doctor): `strom`
56
- * before one of strom's own commands (`words`) — never the word in a sentence ("Tento strom ho…"), never a path.
56
+ * before one of strom's own commands (`words`) — never the word in a sentence ("Tento strom ho…"), never a path or a
57
+ * file (strom doctor.txt); at the end of a sentence too (strom chat.).
57
58
  */
58
59
  export function asCommand(text, name, words) {
59
60
  if (!words.length)
60
61
  return text;
61
62
  const alt = [...new Set(words)].map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
62
63
  // (after an opening quote of any language too: „strom person xyz“, «strom …»)
63
- return text.replace(new RegExp(`(^|[\\s"'\`(\\[→:=„“«»‚‘])strom(?= (?:${alt})(?![\\p{L}\\p{M}\\p{N}_./\\\\-]))`, "gu"), `$1${name}`);
64
+ return text.replace(new RegExp(`(^|[\\s"'\`(\\[→:=„“«»‚‘])strom(?= (?:${alt})(?![\\p{L}\\p{M}\\p{N}_/\\\\-]|\\.[\\p{L}\\p{M}\\p{N}_]))`, "gu"), `$1${name}`);
64
65
  }
65
66
  /** asCommand over a JSON answer: the command lines in it (a value that is one: "strom …") and the hints. */
66
67
  export function asCommandJson(json, name, words) {
package/dist/cli/main.js CHANGED
@@ -26,7 +26,7 @@ import { clockLine, FINISH_LINE, finishAsked } from "../core/clock.js";
26
26
  import { currentSession } from "../core/session.js";
27
27
  import { checkArgs, GroupOnly, parseOptions, resolveCommand, firstWord, splitPassthrough } from "./execute.js";
28
28
  import { placeholders, UI, ui } from "./ui.js";
29
- import { catalog, localized } from "../core/phrases.js";
29
+ import { catalog, localized, sayCommandAs } from "../core/phrases.js";
30
30
  import "../commands/index.js";
31
31
  export { splitCommand } from "./execute.js";
32
32
  /**
@@ -130,6 +130,8 @@ export async function main(argv, io, env, cwd) {
130
130
  const own = ownCommand(env);
131
131
  if (own)
132
132
  io = asOwnCommand(io, own, json, argv);
133
+ // {strom} in a text: also in a window of the system or a file, which the output above does not pass
134
+ sayCommandAs(own ?? "strom");
133
135
  const debug = argv.includes("--debug");
134
136
  resetCache(undefined, "command");
135
137
  // the app's install line in its one variable (STROM_FROM): read as the five of an older line
@@ -20,7 +20,7 @@ import { appWindow } from "../core/appbrowser.js";
20
20
  import { moveTree } from "./move.js";
21
21
  import { changeLines } from "../core/changelog.js";
22
22
  import { startLive } from "../core/live.js";
23
- import { adoptAppUrl, appTreeNameFromInstall } from "../core/stromapp.js";
23
+ import { adoptAppUrl, appTreeNameFromInstall, defaultAppUrl } from "../core/stromapp.js";
24
24
  import { stromReadsTags } from "../gedcom/export.js";
25
25
  import { appMarkFromInstall } from "../core/links.js";
26
26
  import { settleFromApp } from "./wizard.js";
@@ -282,7 +282,10 @@ export async function newFromApp(ctx, runIn, token, openAt, forward, opts = {})
282
282
  // characters) — kept as the line's STROM_APP_URL is
283
283
  if (move?.mark.app && !ctx.env.STROM_APP_URL?.trim()) {
284
284
  ctx.settings.reload();
285
- ctx.settings.config.stromAppUrl = move.mark.app;
285
+ if (move.mark.app === defaultAppUrl(ctx.env))
286
+ delete ctx.settings.config.stromAppUrl;
287
+ else
288
+ ctx.settings.config.stromAppUrl = move.mark.app;
286
289
  ctx.settings.save();
287
290
  }
288
291
  let lang = ctx.uiLang();
package/dist/cli/ui.js CHANGED
@@ -62,7 +62,7 @@ export const UI = {
62
62
  "ui.menu.trees": "Another family tree · send or receive one",
63
63
  "ui.menu.newtree": "Create a family tree · send or receive one",
64
64
  "ui.menu.quit": "Quit",
65
- "ui.menu.bye": "Until next time. Start again with: strom",
65
+ "ui.menu.bye": "Until next time. Start again with: {strom}",
66
66
  "ui.run.how": "How many tasks? (it stops earlier when there is nothing to do; 0 goes back)",
67
67
  "ui.run.start": "The agent works on its own now. Ctrl-C stops it — nothing is lost.",
68
68
  "ui.waiting.none": "Nothing waits.",
@@ -86,14 +86,14 @@ export const UI = {
86
86
  "ui.setup.git.ok": "✓ Git (history of the research): {version}",
87
87
  "ui.setup.git.missing": "Git is missing — strom keeps the history of the research in it, so nothing gets lost.",
88
88
  "ui.setup.git.wait": "Finish the installation in the window that opened, then press Enter.",
89
- "ui.setup.git.manual": "Install it with: {command} — then start strom again.",
89
+ "ui.setup.git.manual": "Install it with: {command} — then start {strom} again.",
90
90
  "ui.setup.agent.ok": "✓ AI agent: {name}",
91
91
  "ui.setup.agent.none": "No AI agent found — strom needs one: the agent does the research.",
92
92
  "ui.setup.agent.install": "Install Claude Code now (recommended; it needs a Claude subscription)",
93
93
  "ui.setup.agent.guide": "Show me which agents there are (opens a page in the browser)",
94
94
  "ui.setup.agent.later": "Later",
95
95
  "ui.setup.agent.login": "The first time the agent starts, it asks for a login — a browser window opens.",
96
- "ui.setup.agent.manual": "Install an AI agent (how: {url}), then start strom again.",
96
+ "ui.setup.agent.manual": "Install an AI agent (how: {url}), then start {strom} again.",
97
97
  "ui.setup.model": "Which model should do the research?",
98
98
  "ui.setup.model.opus": "Opus — best at reading old handwriting (recommended)",
99
99
  "ui.setup.model.sonnet": "Sonnet — faster; printed documents and everyday work",
@@ -279,7 +279,7 @@ export const UI = {
279
279
  "ui.o.results.installed.live": "{file} — for the Strom app, installed here: strom app opens this research in it, and while you work the app follows it live (what you record shows there by itself) — offer it (strom says this once)",
280
280
  "ui.o.results.offer.live": "{file} — for the Strom app, not installed here yet: offer the user to watch the research grow in it live — installed from {url} (strom app install opens it there and says where to click), then strom app",
281
281
  "ui.chat.handover": "The research goes on in its own conversation: a new window opened with {agent} in the family tree's folder. Continue there — this conversation can end.",
282
- "ui.chat.handover.failed": "A new window could not be opened here. Start the research by hand: run strom in a terminal (or the Strom research shortcut on the desktop).",
282
+ "ui.chat.handover.failed": "A new window could not be opened here. Start the research by hand: run {strom} in a terminal (or the Strom research shortcut on the desktop).",
283
283
  "ui.chat.handover.recent": "A window with the research and {agent} opened a moment ago — continue there. This conversation can end.",
284
284
  "ui.chat.handover.end": "Continue there — this conversation can end.",
285
285
  "ui.why.handover": "the research belongs in its own conversation in the tree folder (its permissions, no asking at every step): this opens it — tell the user to continue there; go on here only if they want",
@@ -381,7 +381,7 @@ export const UI = {
381
381
  "ui.doc.backup": "backup",
382
382
  "ui.backup.made": "Backup before going from {from} to {to}: {path} ({size}).",
383
383
  "ui.backup.last": "The last backup (before going from {from} to {to}, {date}): {path}",
384
- "ui.backup.readme": "Strom research – a backup\n\nMade {date}, before going from strom {from} to {to}.\n\nInside:\n- trees: every family tree of this computer, each its whole folder with its history (.git);\n- settings: strom's settings with the seal keys and the logins, as they were on this computer.\n\nNot inside: the shared images (the folder shared/media). Each is kept there by its content and strom never deletes one; every version of strom reads the same ones. Left out too: what strom makes again by itself (views of scans, excerpts).\n\nTo bring a family tree back: copy its folder from trees back to where the family trees are (in place of the one there, or beside it under another name), then run strom: strom checks it (strom check).",
384
+ "ui.backup.readme": "Strom research – a backup\n\nMade {date}, before going from strom {from} to {to}.\n\nInside:\n- trees: every family tree of this computer, each its whole folder with its history (.git);\n- settings: strom's settings with the seal keys and the logins, as they were on this computer.\n\nNot inside: the shared images (the folder shared/media). Each is kept there by its content and strom never deletes one; every version of strom reads the same ones. Left out too: what strom makes again by itself (views of scans, excerpts).\n\nTo bring a family tree back: copy its folder from trees back to where the family trees are (in place of the one there, or beside it under another name), then run {strom}: strom checks it ({strom} check).",
385
385
  "ui.trees.locked": "locked: written by strom {by}",
386
386
  "ui.menu.browse": "Look through the family tree: overview, people, ancestors, what is new",
387
387
  "ui.browse.stats": "Overview of the research",
@@ -561,7 +561,7 @@ export const UI = {
561
561
  "ui.help.archive.stats": "The archive at a glance: people, how sure the facts are, ancestors in each generation",
562
562
  "ui.help.archive.pack": "Pack the archive into one ZIP file for someone to go on with it",
563
563
  "ui.help.archive.intake": "Add material from the family: documents, photos, a family tree, what the family knows",
564
- "ui.help.title": "strom <command> — what a person does with strom (or just strom: the menu)",
564
+ "ui.help.title": "strom <command> — what a person does with strom (or just {strom}: the menu)",
565
565
  "ui.help.more": "Help for one command: strom help <command> --human · every command in English (what an agent reads): strom help",
566
566
  "ui.help.more.archive": "Help for one command: strom help <command> --human",
567
567
  "ui.help.examples": "Examples:",
@@ -662,6 +662,9 @@ export const UI = {
662
662
  "ui.sync.name.new": "{n}. {who}: another name — {text}",
663
663
  "ui.sync.name.changed": "{n}. {who}: name changed — {old} → {new}",
664
664
  "ui.sync.do.name.user": "the edit wins: shown by the new name, the record's kept beside it",
665
+ "ui.sync.name.title": "{n}. {who}: {title} — {old} → {new}",
666
+ "ui.sync.do.title": "added to the name, citing the tree sent",
667
+ "ui.sync.do.title.user": "the edit wins (the research's in its history)",
665
668
  "ui.sync.sex.changed": "{n}. {who}: sex {text}",
666
669
  "ui.sync.note.new": "{n}. {who}: a note — “{text}”",
667
670
  "ui.sync.source.new": "{n}. a source: “{text}”",
@@ -920,8 +923,8 @@ export const UI = {
920
923
  "ui.link.off.done": "Links from the Strom app no longer lead to the research here.",
921
924
  "ui.link.off.failed": "The links from the Strom app could not be taken off this computer.",
922
925
  "ui.link.which.one": "This research is here more than once. Which one?",
923
- "ui.link.noterminal.any": "strom could not open a terminal window. Start strom (the research {name}) and go on from its menu.",
924
- "ui.link.noterminal.new": "strom could not open a terminal window. Start strom, then try again from the Strom app.",
926
+ "ui.link.noterminal.any": "strom could not open a terminal window. Start {strom} (the research {name}) and go on from its menu.",
927
+ "ui.link.noterminal.new": "strom could not open a terminal window. Start {strom}, then try again from the Strom app.",
925
928
  "ui.link.asks": "The Strom app asks for: {what}\nResearch: {name}",
926
929
  "ui.link.go": "Go on?",
927
930
  "ui.link.cost": "The agent works on the subscription or AI credit of its account.",
@@ -1236,7 +1239,7 @@ export const UI = {
1236
1239
  "ui.unpack.kept": " connector {name} was here already — the one here stays",
1237
1240
  "ui.unpack.left": " {n} pages searched through are not in it: strom fetches them from the archive when they are needed",
1238
1241
  "ui.unpack.adopted": " taken over on this computer",
1239
- "ui.unpack.next": "Go on: strom (the menu) or strom chat.",
1242
+ "ui.unpack.next": "Go on: {strom} (the menu) or strom chat.",
1240
1243
  "ui.unpack.same": "this research is here already: {root}",
1241
1244
  "ui.unpack.person": "only the person at the computer unpacks a research (it adds connectors)",
1242
1245
  "ui.pack.launch.extract": "First unpack the whole ZIP file - on Windows: right click, Extract All - then start this again from the unpacked folder.",
@@ -1302,7 +1305,7 @@ export const UI = {
1302
1305
  "ui.error.command.unknown": "unknown command \"strom {cmd}\"",
1303
1306
  "ui.error.command.unknown.hint": "strom help (all commands)",
1304
1307
  "ui.error.command.unknown.person": "unknown command \"strom {cmd}\"",
1305
- "ui.error.command.unknown.person.hint": "strom help --human — or just strom: the menu",
1308
+ "ui.error.command.unknown.person.hint": "strom help --human — or just {strom}: the menu",
1306
1309
  "ui.error.option.near": "unknown option {opt} for {cmd}",
1307
1310
  "ui.error.option.near.hint": "similar option: {near}",
1308
1311
  "ui.conflict.none": "no open conflicts",
@@ -1364,6 +1367,8 @@ export const UI = {
1364
1367
  "ui.conflict.sex": "sex",
1365
1368
  "ui.conflict.sex.U": "not known",
1366
1369
  "ui.conflict.name": "name",
1370
+ "ui.conflict.titleBefore": "title before the name",
1371
+ "ui.conflict.titleAfter": "title after the name",
1367
1372
  "ui.conflict.parents": "parents",
1368
1373
  "ui.arg.agent": "agent",
1369
1374
  "ui.arg.batch": "batch",
@@ -14,7 +14,7 @@ import { chooseWay, wayName } from "./ways.js";
14
14
  import { PROFILES } from "../agents/profiles.js";
15
15
  import { writeStored, PERMISSION_LEVELS } from "../core/config.js";
16
16
  import { globalTargets, installGlobal } from "../agents/global.js";
17
- import { appCopyOfInstall, appOpensLinks, noticeStromApp, researchUrl, stromAppState, stromAppUrl } from "../core/stromapp.js";
17
+ import { appCopyOfInstall, appOpensLinks, defaultAppUrl, noticeStromApp, researchUrl, STROM_APP_URL, stromAppState, stromAppUrl } from "../core/stromapp.js";
18
18
  import { openForUser } from "../core/open.js";
19
19
  import { createShortcut } from "../core/shortcut.js";
20
20
  import { appMarkFromInstall, linkFiles, linkHandlerState, linkOwner, registerLinks } from "../core/links.js";
@@ -259,11 +259,13 @@ export async function settleFromApp(ctx, lang, opts = {}) {
259
259
  s.reload();
260
260
  const cfg = s.config;
261
261
  cfg.stromApp = "yes";
262
+ // kept only where it is another than the copy this strom opens by itself (the beta channel: the app's beta)
262
263
  const copy = appCopyOfInstall(ctx.env);
263
- if (copy === null)
264
+ const url = copy === null ? STROM_APP_URL : copy;
265
+ if (url === defaultAppUrl(ctx.env))
264
266
  delete cfg.stromAppUrl;
265
- else if (copy)
266
- cfg.stromAppUrl = copy;
267
+ else if (url)
268
+ cfg.stromAppUrl = url;
267
269
  s.save();
268
270
  if (opts.shortcut)
269
271
  await offerShortcut(ctx, lang, (line) => ctx.io.stdout(line + "\n"));
@@ -343,7 +343,7 @@ register({
343
343
  if (take !== undefined && take !== "user" && take !== "research")
344
344
  throw new UsageError(`--take is user or research, not "${opts.take}"`, { code: "conflict.take", params: { take: String(opts.take) } });
345
345
  // a conflict of the user's edit in the Strom app: a fact's, a child's parents, a name's or a sex's
346
- const ofEdit = Boolean(c0.edit || c0.parents || ((c0.fact === "NAME" || c0.fact === "SEX") && c0.claims.some((c) => c.note === "the user's edit")));
346
+ const ofEdit = Boolean(c0.edit || c0.parents || (["NAME", "SEX", "NPFX", "NSFX"].includes(c0.fact ?? "") && c0.claims.some((c) => c.note === "the user's edit")));
347
347
  if (take && !ofEdit)
348
348
  throw new UsageError(`${id} is no conflict of an edit in the Strom app: write what you conclude with the commands that change facts, then resolve it with --resolution`, { hint: `strom conflict show ${id}`, code: "conflict.no-edit", params: { id } });
349
349
  // the conclusion naming one side's value exactly: that side taken (found on Mac: "tesař" resolved, the fact left
@@ -144,7 +144,7 @@ register({
144
144
  const tree = ctx.tree();
145
145
  const lang = ctx.uiLang();
146
146
  const c = personCard(tree, resolvePerson(tree, args[0]));
147
- const out = [whoText(c.person)];
147
+ const out = [whoText(c.titled ? { ...c.person, name: c.titled } : c.person)];
148
148
  if (c.otherNames.length)
149
149
  out.push(` ${ui(lang, "ui.card.also", { names: c.otherNames.join(", ") })}`);
150
150
  out.push(c.facts.length ? factRows(c.facts, lang, " ", ctx.archiveHere()) : ` ${ui(lang, "ui.card.nofacts")}`, "");
@@ -13,7 +13,7 @@ import { UsageError } from "../core/errors.js";
13
13
  import { excerptSettings, planExcerpts } from "../core/excerpt.js";
14
14
  import { runGit, tracked } from "../core/git.js";
15
15
  import { Settings } from "../core/config.js";
16
- import { appKnowsArchive, appKnowsNoCouple, appOpensLinks, appShowsCoupleEvents, appShowsEdges, appShowsSourceReads, appShowsFactStatus, appShowsStoryDrafts, appTurnsExcerpts } from "../core/stromapp.js";
16
+ import { appKnowsArchive, appKnowsNoCouple, appOpensLinks, appReadsTitles, appShowsCoupleEvents, appShowsEdges, appShowsSourceReads, appShowsFactStatus, appShowsStoryDrafts, appTurnsExcerpts } from "../core/stromapp.js";
17
17
  import { EXCERPT_QUALITIES, EXCERPT_SCOPES } from "../core/model.js";
18
18
  function findingRows(f) {
19
19
  return table(f.slice(0, 30).map((x) => [x.level === "error" ? "ERROR" : "warn", `line ${x.line}`, x.message]));
@@ -84,7 +84,8 @@ export function writeTreeGed(tree, opts) {
84
84
  const turnsExcerpts = opts.for === "strom" && appTurnsExcerpts(new Settings(tree.env, {}), opts.stromVersion);
85
85
  const noCouple = opts.for === "strom" && appKnowsNoCouple(new Settings(tree.env, {}), opts.stromVersion);
86
86
  const archive = opts.for === "strom" && appKnowsArchive(new Settings(tree.env, {}), opts.stromVersion);
87
- const result = exportGedcom(tree, { for: opts.for, stromVersion: opts.stromVersion, ...(persons ? { persons } : {}), ...(images ? { excerpts: images.of } : {}), ...(clips ? { clips } : {}), ...(research ? { research } : {}), ...(edges ? { edges } : {}), ...(storyDrafts ? { storyDrafts } : {}), ...(coupleResi ? { coupleResi } : {}), ...(sourceReads ? { sourceReads } : {}), ...(factStatus ? { factStatus } : {}), ...(archive ? { archive } : {}), ...(turnsExcerpts ? { turnsExcerpts } : {}), ...(noCouple ? { noCouple } : {}) });
87
+ const titles = opts.for === "strom" && appReadsTitles(new Settings(tree.env, {}), opts.stromVersion);
88
+ const result = exportGedcom(tree, { for: opts.for, stromVersion: opts.stromVersion, ...(persons ? { persons } : {}), ...(images ? { excerpts: images.of } : {}), ...(clips ? { clips } : {}), ...(research ? { research } : {}), ...(edges ? { edges } : {}), ...(storyDrafts ? { storyDrafts } : {}), ...(coupleResi ? { coupleResi } : {}), ...(sourceReads ? { sourceReads } : {}), ...(factStatus ? { factStatus } : {}), ...(archive ? { archive } : {}), ...(turnsExcerpts ? { turnsExcerpts } : {}), ...(noCouple ? { noCouple } : {}), ...(titles ? { titles } : {}) });
88
89
  const findings = validateGedcom(result.text, opts.for === "standard" ? { strict: true } : {});
89
90
  const file = opts.out ?? gedFile(tree, opts.for, opts.research);
90
91
  if (!hasGedErrors(findings) && !tree.dryRun) {
@@ -7,7 +7,7 @@ import { SINGLE_KINDS } from "../core/actions.js";
7
7
  import { UsageError } from "../core/errors.js";
8
8
  import { INFORMATION } from "../core/evidence.js";
9
9
  import { EVENT_KINDS, NAME_KINDS } from "../core/model.js";
10
- import { ancestorGenerations, displayName, familiesAsChild, familiesAsPartner, findPersons, formatName, label, lifespan, relationTo, resolvePerson, } from "../core/people.js";
10
+ import { ancestorGenerations, displayName, familiesAsChild, familiesAsPartner, findPersons, formatName, label, lifespan, primaryName, relationTo, resolvePerson, titledName, } from "../core/people.js";
11
11
  import { resolveResearch } from "./research.js";
12
12
  import { DEATH_AFTER_YEARS, unprovenPeople } from "../core/review.js";
13
13
  import { foldText } from "../core/text.js";
@@ -102,7 +102,7 @@ function citesOf(citations, w = ENGLISH) {
102
102
  }
103
103
  function nameLine(n, w = ENGLISH) {
104
104
  const cites = citesOf(n.citations, w);
105
- return `${formatName(n)}${n.kind ? ` (${w.word("name", n.kind)})` : ""}${cites ? ` ← ${cites}` : ""}`;
105
+ return `${titledName(n)}${n.kind ? ` (${w.word("name", n.kind)})` : ""}${cites ? ` ← ${cites}` : ""}`;
106
106
  }
107
107
  function eventLine(e, w = ENGLISH) {
108
108
  const cites = citesOf(e.citations, w);
@@ -125,6 +125,11 @@ function eventLine(e, w = ENGLISH) {
125
125
  .filter(Boolean)
126
126
  .join(" ");
127
127
  }
128
+ /** The titles of a name: GEDCOM's NPFX / NSFX, never part of the name itself (not searched or matched by them). */
129
+ const TITLE_OPTIONS = [
130
+ { name: "prefix", type: "string", value: "<title>", description: 'title before the name as the record gives it ("Ing.", "Dr.", "Graf")' },
131
+ { name: "suffix", type: "string", value: "<title>", description: 'title or epithet after the name ("ml.", "st.", "Ph.D.")' },
132
+ ];
128
133
  register({
129
134
  path: ["person", "add"],
130
135
  summary: "Add a person (facts without a record are leads)",
@@ -140,10 +145,12 @@ register({
140
145
  { name: "died", type: "string", value: "<date>", description: "death date (lead)" },
141
146
  { name: "died-place", type: "string", value: "<place>", description: "death place (lead)" },
142
147
  { name: "note", type: "string", value: "<text>", description: "short note" },
148
+ ...TITLE_OPTIONS,
143
149
  ...CITE_OPTIONS,
144
150
  ],
145
151
  examples: [
146
152
  'strom person add "Josef /Novák/" --sex M --born "ABT 1870" --note "Father of Jan, miller (family memory)"',
153
+ 'strom person add "Jan /Novák/" --sex M --prefix "Ing." --suffix "ml."',
147
154
  'strom person add "Jan /Novák/" --sex M --born "24 JUN 1885" --born-place "Kamenice nad Lipou" --cite S0001 --locator "fol. 12, č. 3"',
148
155
  'strom person add "Šimon /Ševčík/" --sex M --cite S0002 --locator "fol. 45, č. 12" --information secondary',
149
156
  ],
@@ -162,6 +169,8 @@ register({
162
169
  note: opts.note,
163
170
  citation: citationOf(opts),
164
171
  status: opts.status,
172
+ prefix: opts.prefix,
173
+ suffix: opts.suffix,
165
174
  });
166
175
  const similar = findPersons(tree, formatName(p.names[0])).filter((x) => x.id !== p.id);
167
176
  const warn = similar.length ? `note: similar name already in the tree: ${similar.slice(0, 3).map(label).join(" · ")}` : undefined;
@@ -234,7 +243,7 @@ register({
234
243
  const w = wordsFor(ctx, tree);
235
244
  const unknown = w.say("ui.show.unknown", "(unknown)");
236
245
  const out = [
237
- `${p.id} ${displayName(p)}${lifespan(p) ? ` (${lifespan(p)})` : ""} ${w.lang ? w.word("sex", p.sex) : `sex ${p.sex}`}`,
246
+ `${p.id} ${titledName(primaryName(p))}${lifespan(p) ? ` (${lifespan(p)})` : ""} ${w.lang ? w.word("sex", p.sex) : `sex ${p.sex}`}`,
238
247
  ...(p.names.length > 1 || p.names.some((n) => n.citations?.length) ? ["", w.say("ui.show.names", "names"), ...p.names.map((n) => ` ${nameLine(n, w)}`)] : []),
239
248
  "",
240
249
  w.say("ui.show.facts", "facts"),
@@ -277,7 +286,7 @@ register({
277
286
  },
278
287
  }, {
279
288
  path: ["person", "edit"],
280
- summary: "Correct a person: sex, the spelling of the name they are shown by",
289
+ summary: "Correct a person: sex, the spelling of the name they are shown by, its titles",
281
290
  group: "people",
282
291
  tree: true,
283
292
  writes: true,
@@ -286,11 +295,16 @@ register({
286
295
  options: [
287
296
  { name: "sex", type: "string", value: "M|F|U", description: "sex" },
288
297
  { name: "name", type: "string", value: "<name>", description: 'the corrected name, surname in slashes: "Jan /Novák/"' },
298
+ ...TITLE_OPTIONS.map((o) => ({ ...o, description: `${o.description}; "" takes it off` })),
299
+ ],
300
+ examples: [
301
+ "strom person edit P0004 --sex M",
302
+ 'strom person edit P0001 --name "Antonín /Víšek/" --reason "misread: the register has Víšek"',
303
+ 'strom person edit P0003 --prefix "MUDr."',
289
304
  ],
290
- examples: ["strom person edit P0004 --sex M", 'strom person edit P0001 --name "Antonín /Víšek/" --reason "misread: the register has Víšek"'],
291
305
  run(ctx, { args, opts }) {
292
306
  const tree = ctx.tree();
293
- const p = editPerson(tree, resolvePerson(tree, args[0]).id, { sex: opts.sex, name: opts.name }, opts.reason);
307
+ const p = editPerson(tree, resolvePerson(tree, args[0]).id, { sex: opts.sex, name: opts.name, prefix: opts.prefix, suffix: opts.suffix }, opts.reason);
294
308
  return { text: written(tree), data: { person: p } };
295
309
  },
296
310
  }, {
@@ -345,6 +359,7 @@ register({
345
359
  options: [
346
360
  { name: "kind", type: "string", value: "<kind>", description: `${NAME_KINDS.join(", ")} (default: plain)` },
347
361
  { name: "primary", type: "boolean", description: "show the person by this name" },
362
+ ...TITLE_OPTIONS,
348
363
  ...CITE_OPTIONS.filter((o) => o.name !== "status"),
349
364
  ],
350
365
  examples: [
@@ -354,7 +369,7 @@ register({
354
369
  run(ctx, { args, opts }) {
355
370
  const tree = ctx.tree();
356
371
  const p = resolvePerson(tree, args[0]);
357
- const r = addName(tree, p.id, { name: args[1], kind: opts.kind, citation: citationOf(opts), primary: Boolean(opts.primary) });
372
+ const r = addName(tree, p.id, { name: args[1], kind: opts.kind, citation: citationOf(opts), primary: Boolean(opts.primary), prefix: opts.prefix, suffix: opts.suffix });
358
373
  return { text: written(tree), data: { person: r.person, name: r.name } };
359
374
  },
360
375
  }, {
@@ -27,7 +27,7 @@ import { configDir, defaultHome, desktopDir, isolated, noLinks, ownCommand } fro
27
27
  import { backupBefore, backupSaid, lastBackupLine } from "../cli/backups.js";
28
28
  import { BACKUP_SAID_DAYS, lastBackup } from "../core/backup.js";
29
29
  import { planMove, sameFolder } from "../core/relocate.js";
30
- import { appOpensLinks, researchUrl, stromAppUrl, stromAppState } from "../core/stromapp.js";
30
+ import { appOpensLinks, defaultAppUrl, researchUrl, stromAppUrl, stromAppState } from "../core/stromapp.js";
31
31
  import { isInstalled } from "../agents/global.js";
32
32
  import { offerLinks, shortcutName } from "../cli/wizard.js";
33
33
  import { linkHandlerState, linkScheme } from "../core/links.js";
@@ -631,6 +631,8 @@ function effective(ctx, def) {
631
631
  return { value: DEFAULT_RUN_MINUTES, source: "default" };
632
632
  if (def.key === "connectors.consent")
633
633
  return { value: "off", source: "default" };
634
+ if (def.key === "strom.app.url")
635
+ return { value: defaultAppUrl(ctx.env), source: "default" };
634
636
  if (def.key === "browser.downloads")
635
637
  return { value: downloadsDir(ctx.env), source: "detected" };
636
638
  if (def.key === "agent.permissions")