strom-research 1.13.0-beta.2 → 1.13.0-beta.5
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/assets/lang/cs.json +13 -3
- package/assets/lang/de.json +13 -3
- package/dist/agents/files.js +5 -2
- package/dist/agents/global.js +13 -8
- package/dist/cli/context.js +3 -2
- package/dist/cli/help.js +8 -7
- package/dist/cli/main.js +3 -3
- package/dist/cli/menu-links.js +4 -1
- package/dist/cli/menu.js +3 -3
- package/dist/cli/registry.js +20 -3
- package/dist/cli/ui.js +13 -3
- package/dist/cli/wizard.js +7 -3
- package/dist/commands/analysis.js +3 -0
- package/dist/commands/guide.js +5 -3
- package/dist/commands/meta.js +8 -7
- package/dist/commands/setup.js +31 -11
- package/dist/commands/start.js +38 -14
- package/dist/commands/sync.js +3 -1
- package/dist/core/actions.js +6 -1
- package/dist/core/appbrowser.js +2 -2
- package/dist/core/config.js +42 -15
- package/dist/core/dialog.js +12 -0
- package/dist/core/git.js +50 -18
- package/dist/core/import.js +62 -27
- package/dist/core/live.js +118 -20
- package/dist/core/people.js +70 -0
- package/dist/core/stromapp.js +119 -17
- package/dist/core/sync.js +87 -31
- package/dist/core/tree.js +6 -5
- package/dist/core/validate.js +14 -0
- package/dist/gedcom/export.js +21 -7
- package/package.json +1 -1
package/assets/lang/cs.json
CHANGED
|
@@ -275,6 +275,10 @@
|
|
|
275
275
|
"ui.doc.app.seen": "nalezena v počítači",
|
|
276
276
|
"ui.doc.app.no": "není chtěná",
|
|
277
277
|
"ui.doc.app.unknown": "nenalezena",
|
|
278
|
+
"ui.doc.appurl": "adresa aplikace Strom",
|
|
279
|
+
"ui.doc.appurl.config": "nastavení strom.app.url „{value}“ není adresa aplikace Strom – strom app nic neotevře, dokud se neopraví nebo neodebere",
|
|
280
|
+
"ui.doc.appurl.env": "proměnná STROM_APP_URL „{value}“ není adresa aplikace Strom – strom app nic neotevře, dokud se neopraví nebo neodebere",
|
|
281
|
+
"ui.doc.appurl.env.fix": "proměnnou STROM_APP_URL nastavit na adresu aplikace Strom ({web}, nebo její kopie na tomto počítači http://127.0.0.1:<port>/), nebo odebrat",
|
|
278
282
|
"ui.doc.tree.ok": "{name}: data v pořádku a zapečetěná",
|
|
279
283
|
"ui.doc.tree.bad": "{name}: problémů {n}",
|
|
280
284
|
"ui.doc.allok": "Všechno potřebné je na místě.",
|
|
@@ -654,7 +658,7 @@
|
|
|
654
658
|
"ui.help.archive.stats": "Archiv v kostce: osoby, jak jisté jsou údaje, předkové v každé generaci",
|
|
655
659
|
"ui.help.archive.pack": "Zabalit archiv do jednoho souboru ZIP, aby v něm mohl pokračovat někdo jiný",
|
|
656
660
|
"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)",
|
|
661
|
+
"ui.help.title": "{strom} <příkaz> – co člověk se stromem dělá (nebo jen {strom}: menu)",
|
|
658
662
|
"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
663
|
"ui.help.more.archive": "Nápověda k jednomu příkazu: strom help <příkaz> --human",
|
|
660
664
|
"ui.help.examples": "Příklady:",
|
|
@@ -846,11 +850,12 @@
|
|
|
846
850
|
"ui.live.app": " aplikace Strom ho sleduje na adrese: {url}",
|
|
847
851
|
"ui.live.stophow": " zastavit: strom live stop",
|
|
848
852
|
"ui.live.none": "most neběží – strom live start (nebo strom app --live)",
|
|
849
|
-
"ui.live.moved": " má novou adresu
|
|
853
|
+
"ui.live.moved": " má novou adresu: aplikace Strom ji najde, až v ní výzkum znovu otevře – strom app --live",
|
|
850
854
|
"ui.live.stopped": "most se zastavil",
|
|
851
855
|
"ui.live.killed": "most neskončil, když byl požádán: byl ukončen natvrdo",
|
|
852
856
|
"ui.live.noneran": "žádný most neběžel",
|
|
853
857
|
"ui.live.forgotten": "jeho adresa je zapomenutá: další most dostane novou",
|
|
858
|
+
"ui.live.newsecret": " další most dostane novou tajnou adresu: aplikace Strom ji dostane při dalším otevření výzkumu – strom app",
|
|
854
859
|
"ui.live.ended": "most skončil",
|
|
855
860
|
"ui.guide.archive": "Tento rodokmen je archiv: data přicházejí z aplikace Strom. Co v něm je: strom stats · strom person card <kdo> · strom pedigree <kdo> · strom recent. Výzkum zapíná jen uživatel: strom mode research (nebo menu).",
|
|
856
861
|
"ui.setup.links.archive": "Dovolit aplikaci Strom otevírat archiv na tomto počítači? (Jedním klikem pošle úpravy zpět nebo otevře výřez v plné kvalitě – vždy se tu nejdřív zeptá.)",
|
|
@@ -1496,6 +1501,10 @@
|
|
|
1496
1501
|
"ui.error.arg.missing": "chybí <{arg}>",
|
|
1497
1502
|
"ui.error.arg.missing.hint": "strom help {cmd}",
|
|
1498
1503
|
"ui.error.prefix": "chyba",
|
|
1504
|
+
"ui.error.config.app-url": "neplatné strom.app.url „{value}“: není to adresa aplikace Strom",
|
|
1505
|
+
"ui.error.config.app-url.hint": "aplikace Strom: {web}, nebo její kopie na tomto počítači http://127.0.0.1:<port>/",
|
|
1506
|
+
"ui.error.config.app-url.config.hint": "aplikace Strom: {web}, nebo její kopie na tomto počítači http://127.0.0.1:<port>/\nopravit: strom config set strom.app.url <adresa> – nebo odebrat: strom config unset strom.app.url",
|
|
1507
|
+
"ui.error.config.app-url.env.hint": "aplikace Strom: {web}, nebo její kopie na tomto počítači http://127.0.0.1:<port>/\nproměnnou STROM_APP_URL opravit, nebo odebrat",
|
|
1499
1508
|
"ui.error.backup.failed": "Zálohu před přechodem z {from} na {to} se nepodařilo vytvořit: {detail}. Nic se nepřepíná: tento strom neotevře žádný rodokmen k zápisu, dokud záloha nebude hotová.",
|
|
1500
1509
|
"ui.error.backup.failed.hint": "Uvolnit místo na disku ({where}) a spustit strom znovu – nebo se vrátit: strom update --channel {back}",
|
|
1501
1510
|
"ui.error.backup.failed.update": "Zálohu před přechodem z {from} na {to} se nepodařilo vytvořit: {detail}. Nic se nenainstalovalo.",
|
|
@@ -1587,6 +1596,7 @@
|
|
|
1587
1596
|
"ui.arg.tree-name": "název",
|
|
1588
1597
|
"ui.arg.url": "adresa",
|
|
1589
1598
|
"ui.arg.value": "hodnota",
|
|
1599
|
+
"ui.arg.address": "adresa",
|
|
1590
1600
|
"ui.arg.what": "co",
|
|
1591
1601
|
"ui.arg.where": "kde",
|
|
1592
1602
|
"ui.arg.who": "kdo",
|
|
@@ -1614,7 +1624,7 @@
|
|
|
1614
1624
|
"ui.error.event.needs-reason.hint": "např. --reason \"záznam S0012 uvádí 1811, ne 1813\"",
|
|
1615
1625
|
"ui.error.family.needs-reason": "změna toho, kdo do rodiny patří nebo jak, potřebuje --reason",
|
|
1616
1626
|
"ui.error.family.needs-reason.hint": "např. --reason \"křest uvádí Jana jako otčíma\"",
|
|
1617
|
-
"ui.error.person.needs-reason": "změna jména nebo známého pohlaví potřebuje --reason",
|
|
1627
|
+
"ui.error.person.needs-reason": "změna jména, jeho titulu nebo známého pohlaví potřebuje --reason",
|
|
1618
1628
|
"ui.error.person.needs-reason.hint": "např. --reason \"špatně přečteno: matrika má Novák, ne Nowak\"",
|
|
1619
1629
|
"ui.error.retract.needs-reason": "stažení potřebuje --reason",
|
|
1620
1630
|
"ui.error.retract.needs-reason.hint": "např. --reason \"špatně přečteno: zápis uvádí Annu, ne Antona\"",
|
package/assets/lang/de.json
CHANGED
|
@@ -275,6 +275,10 @@
|
|
|
275
275
|
"ui.doc.app.seen": "auf dem Computer gefunden",
|
|
276
276
|
"ui.doc.app.no": "nicht gewünscht",
|
|
277
277
|
"ui.doc.app.unknown": "nicht gefunden",
|
|
278
|
+
"ui.doc.appurl": "Adresse der Strom-App",
|
|
279
|
+
"ui.doc.appurl.config": "die Einstellung strom.app.url „{value}“ ist keine Adresse der Strom-App – strom app öffnet nichts, bis sie berichtigt oder entfernt ist",
|
|
280
|
+
"ui.doc.appurl.env": "die Variable STROM_APP_URL „{value}“ ist keine Adresse der Strom-App – strom app öffnet nichts, bis sie berichtigt oder entfernt ist",
|
|
281
|
+
"ui.doc.appurl.env.fix": "die Variable STROM_APP_URL auf eine Adresse der Strom-App setzen ({web}, oder eine Kopie auf diesem Computer http://127.0.0.1:<port>/) oder entfernen",
|
|
278
282
|
"ui.doc.tree.ok": "{name}: Daten in Ordnung und versiegelt",
|
|
279
283
|
"ui.doc.tree.bad": "{name}: Probleme: {n}",
|
|
280
284
|
"ui.doc.allok": "Alles Nötige ist vorhanden.",
|
|
@@ -654,7 +658,7 @@
|
|
|
654
658
|
"ui.help.archive.stats": "Das Archiv auf einen Blick: Personen, wie sicher die Angaben sind, Vorfahren je Generation",
|
|
655
659
|
"ui.help.archive.pack": "Das Archiv in eine ZIP-Datei packen, damit jemand anderes weitermachen kann",
|
|
656
660
|
"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ü)",
|
|
661
|
+
"ui.help.title": "{strom} <Befehl> – was ein Mensch mit strom tut (oder nur {strom}: das Menü)",
|
|
658
662
|
"ui.help.more": "Hilfe zu einem Befehl: strom help <Befehl> --human · alle Befehle auf Englisch (was ein Agent liest): strom help",
|
|
659
663
|
"ui.help.more.archive": "Hilfe zu einem Befehl: strom help <Befehl> --human",
|
|
660
664
|
"ui.help.examples": "Beispiele:",
|
|
@@ -846,11 +850,12 @@
|
|
|
846
850
|
"ui.live.app": " die Strom-App folgt ihr unter: {url}",
|
|
847
851
|
"ui.live.stophow": " anhalten: strom live stop",
|
|
848
852
|
"ui.live.none": "die Brücke läuft nicht – strom live start (oder strom app --live)",
|
|
849
|
-
"ui.live.moved": " sie hat eine neue Adresse
|
|
853
|
+
"ui.live.moved": " sie hat eine neue Adresse: die Strom-App findet sie, wenn die Forschung darin wieder geöffnet wird – strom app --live",
|
|
850
854
|
"ui.live.stopped": "die Brücke ist angehalten",
|
|
851
855
|
"ui.live.killed": "die Brücke endete nicht auf Bitte: sie wurde hart beendet",
|
|
852
856
|
"ui.live.noneran": "keine Brücke lief",
|
|
853
857
|
"ui.live.forgotten": "ihre Adresse ist vergessen: die nächste Brücke bekommt eine neue",
|
|
858
|
+
"ui.live.newsecret": " die nächste Brücke bekommt eine neue geheime Adresse: die Strom-App bekommt sie beim nächsten Öffnen der Forschung – strom app",
|
|
854
859
|
"ui.live.ended": "die Brücke ist beendet",
|
|
855
860
|
"ui.guide.archive": "Dieser Stammbaum ist ein Archiv: die Daten kommen aus der Strom-App. Was er enthält: strom stats · strom person card <wer> · strom pedigree <wer> · strom recent. Die Forschung schaltet nur der Benutzer ein: strom mode research (oder das Menü).",
|
|
856
861
|
"ui.setup.links.archive": "Der Strom-App erlauben, das Archiv auf diesem Computer zu öffnen? (Ein Klick schickt die Änderungen zurück oder öffnet einen Ausschnitt in voller Qualität – jeweils erst hier gefragt.)",
|
|
@@ -1496,6 +1501,10 @@
|
|
|
1496
1501
|
"ui.error.arg.missing": "<{arg}> fehlt",
|
|
1497
1502
|
"ui.error.arg.missing.hint": "strom help {cmd}",
|
|
1498
1503
|
"ui.error.prefix": "Fehler",
|
|
1504
|
+
"ui.error.config.app-url": "ungültige strom.app.url „{value}“: keine Adresse der Strom-App",
|
|
1505
|
+
"ui.error.config.app-url.hint": "die Strom-App: {web}, oder eine Kopie auf diesem Computer http://127.0.0.1:<port>/",
|
|
1506
|
+
"ui.error.config.app-url.config.hint": "die Strom-App: {web}, oder eine Kopie auf diesem Computer http://127.0.0.1:<port>/\nberichtigen: strom config set strom.app.url <Adresse> – oder entfernen: strom config unset strom.app.url",
|
|
1507
|
+
"ui.error.config.app-url.env.hint": "die Strom-App: {web}, oder eine Kopie auf diesem Computer http://127.0.0.1:<port>/\ndie Variable STROM_APP_URL berichtigen oder entfernen",
|
|
1499
1508
|
"ui.error.backup.failed": "Die Sicherung vor dem Wechsel von {from} auf {to} ließ sich nicht erstellen: {detail}. Es wird nichts umgestellt: dieses strom öffnet keinen Stammbaum zum Schreiben, bis die Sicherung erstellt ist.",
|
|
1500
1509
|
"ui.error.backup.failed.hint": "Platz auf dem Datenträger freimachen ({where}) und strom erneut starten – oder zurück: strom update --channel {back}",
|
|
1501
1510
|
"ui.error.backup.failed.update": "Die Sicherung vor dem Wechsel von {from} auf {to} ließ sich nicht erstellen: {detail}. Es wurde nichts installiert.",
|
|
@@ -1587,6 +1596,7 @@
|
|
|
1587
1596
|
"ui.arg.tree-name": "Name",
|
|
1588
1597
|
"ui.arg.url": "Adresse",
|
|
1589
1598
|
"ui.arg.value": "Wert",
|
|
1599
|
+
"ui.arg.address": "Adresse",
|
|
1590
1600
|
"ui.arg.what": "was",
|
|
1591
1601
|
"ui.arg.where": "wo",
|
|
1592
1602
|
"ui.arg.who": "wer",
|
|
@@ -1614,7 +1624,7 @@
|
|
|
1614
1624
|
"ui.error.event.needs-reason.hint": "z. B. --reason \"Eintrag S0012 nennt 1811, nicht 1813\"",
|
|
1615
1625
|
"ui.error.family.needs-reason": "wer zur Familie gehört oder wie, ändert sich nur mit --reason",
|
|
1616
1626
|
"ui.error.family.needs-reason.hint": "z. B. --reason \"die Taufe nennt Jan als Stiefvater\"",
|
|
1617
|
-
"ui.error.person.needs-reason": "ein Name oder ein bekanntes Geschlecht ändert sich nur mit --reason",
|
|
1627
|
+
"ui.error.person.needs-reason": "ein Name, sein Titel oder ein bekanntes Geschlecht ändert sich nur mit --reason",
|
|
1618
1628
|
"ui.error.person.needs-reason.hint": "z. B. --reason \"falsch gelesen: im Register steht Novák, nicht Nowak\"",
|
|
1619
1629
|
"ui.error.retract.needs-reason": "Zurückziehen braucht --reason",
|
|
1620
1630
|
"ui.error.retract.needs-reason.hint": "z. B. --reason \"falsch gelesen: der Eintrag nennt Anna, nicht Anton\"",
|
package/dist/agents/files.js
CHANGED
|
@@ -12,12 +12,15 @@ import { writeFileAtomic } from "../core/json.js";
|
|
|
12
12
|
import { PROFILES, SELF_READING } from "./profiles.js";
|
|
13
13
|
import { isArchive } from "../core/mode.js";
|
|
14
14
|
import { Settings } from "../core/config.js";
|
|
15
|
+
import { agentAppUrl, appSite } from "../core/stromapp.js";
|
|
15
16
|
import { configDir } from "../core/paths.js";
|
|
16
17
|
import { agentBrowser } from "../core/connector.js";
|
|
17
18
|
import { CHROME_ALLOW, CHROME_DENY, chromeDomain } from "../core/browser.js";
|
|
18
19
|
export const MARKER = "<!-- strom: generated above this line (strom agents sync); your own notes below are kept -->";
|
|
19
20
|
function agentsMd(tree) {
|
|
20
21
|
const lang = langName(tree.config.lang);
|
|
22
|
+
// the Strom app's address as strom app opens it now (the beta its beta, strom.app.url where it says another)
|
|
23
|
+
const app = agentAppUrl(tree.env);
|
|
21
24
|
return `# Family research: ${tree.config.name}
|
|
22
25
|
|
|
23
26
|
This folder is a family tree researched with **strom**, a command-line tool
|
|
@@ -99,12 +102,12 @@ they ask.
|
|
|
99
102
|
- **What waits for them** (\`strom\` shows it): tell them plainly what to do
|
|
100
103
|
and where, one thing at a time.
|
|
101
104
|
- **Results and the Strom app**: \`output/tree-strom.ged\` is the family tree
|
|
102
|
-
for the Strom app (
|
|
105
|
+
for the Strom app (${appSite(app)}) — strom's companion: a free family
|
|
103
106
|
tree app, no account, their data stay on their computer; it shows the tree,
|
|
104
107
|
the sources, a map, a family book. When they want to see the results, or
|
|
105
108
|
when \`strom\` says to offer it (it does once, not in every conversation),
|
|
106
109
|
suggest it gently, in a sentence or two: best installed as an app from the browser, from
|
|
107
|
-
|
|
110
|
+
${app} — \`strom app install\` opens it there and says
|
|
108
111
|
where to click; it works offline then; \`strom app\` opens it, with this
|
|
109
112
|
research when the app can take it — run by you, the app then follows the
|
|
110
113
|
research live, what you record shows there by itself (else in the app:
|
package/dist/agents/global.js
CHANGED
|
@@ -16,9 +16,11 @@ import path from "node:path";
|
|
|
16
16
|
import { isolated, userHome } from "../core/paths.js";
|
|
17
17
|
import { writeFileAtomic } from "../core/json.js";
|
|
18
18
|
import { installation } from "../core/self.js";
|
|
19
|
+
import { agentAppUrl, appSite } from "../core/stromapp.js";
|
|
19
20
|
const BEGIN = "<!-- strom: begin (strom agents install; removed by strom agents uninstall) -->";
|
|
20
21
|
const END = "<!-- strom: end -->";
|
|
21
|
-
|
|
22
|
+
/** What the agents are taught; app: the Strom app's address it names — the one `strom app` opens when it is written (agentAppUrl). */
|
|
23
|
+
export const globalText = (app) => `# strom — family history research
|
|
22
24
|
|
|
23
25
|
strom (the \`strom\` command) is installed on this computer: a tool for
|
|
24
26
|
researching a family's history with you as the researcher — people, parish
|
|
@@ -57,11 +59,11 @@ mentions strom, a family tree or the Strom app.
|
|
|
57
59
|
8. Scans come through strom. An archive the research needs has no
|
|
58
60
|
downloader (connector) yet: build one yourself, unasked
|
|
59
61
|
(\`strom connector new\`), and tell the user in a sentence.
|
|
60
|
-
9. The Strom app (
|
|
62
|
+
9. The Strom app (${appSite(app)}) is strom's companion: a free family
|
|
61
63
|
tree app, no account, the data stay on the user's computer. The research's
|
|
62
64
|
result (\`output/tree-strom.ged\`) opens in it. When the user wants to see
|
|
63
65
|
the tree (or \`strom\` says to offer it — once), suggest it gently — best installed as an app from the browser,
|
|
64
|
-
from
|
|
66
|
+
from ${app} (\`strom app install\` opens it there; it
|
|
65
67
|
then works offline); \`strom app\` opens it — with the research, followed
|
|
66
68
|
live while you work, when the app can take it. Without it, the user can ask
|
|
67
69
|
you about anyone in the tree: answer from \`strom person show\` and the like.
|
|
@@ -149,7 +151,9 @@ export function globalTargets(env) {
|
|
|
149
151
|
if (isolated(env))
|
|
150
152
|
return [];
|
|
151
153
|
const home = userHome(env);
|
|
152
|
-
|
|
154
|
+
// the app's address as strom app opens it now: a run of another channel (its first) writes the texts again
|
|
155
|
+
const app = agentAppUrl(env);
|
|
156
|
+
const targets = [
|
|
153
157
|
{ agent: "claude", file: path.join(env.CLAUDE_CONFIG_DIR ?? path.join(home, ".claude"), "skills", "strom", "SKILL.md"), kind: "own" },
|
|
154
158
|
{ agent: "claude", file: path.join(env.CLAUDE_CONFIG_DIR ?? path.join(home, ".claude"), "settings.json"), kind: "allow" },
|
|
155
159
|
{ agent: "codex", file: path.join(env.CODEX_HOME ?? path.join(home, ".codex"), "AGENTS.md"), kind: "block" },
|
|
@@ -161,13 +165,14 @@ export function globalTargets(env) {
|
|
|
161
165
|
{ agent: "grok", file: path.join(grokDir(env), "skills", "strom", "SKILL.md"), kind: "own" },
|
|
162
166
|
{ agent: "grok", file: path.join(grokDir(env), "config.toml"), kind: "allow" },
|
|
163
167
|
];
|
|
168
|
+
return targets.map((t) => ({ ...t, app }));
|
|
164
169
|
}
|
|
165
|
-
const
|
|
170
|
+
const skill = (app) => `---
|
|
166
171
|
name: strom
|
|
167
172
|
description: Family history and genealogy research with the strom command — ancestors, family trees, parish registers and archives, evidence, GEDCOM and the Strom app. Use when the user wants to research their family or mentions strom or the Strom app.
|
|
168
173
|
---
|
|
169
174
|
|
|
170
|
-
${
|
|
175
|
+
${globalText(app)}`;
|
|
171
176
|
function read(file) {
|
|
172
177
|
try {
|
|
173
178
|
return fs.readFileSync(file, "utf8");
|
|
@@ -282,10 +287,10 @@ export function installGlobal(t) {
|
|
|
282
287
|
next = JSON.stringify(s, null, 2) + "\n";
|
|
283
288
|
}
|
|
284
289
|
else if (t.kind === "own")
|
|
285
|
-
next = t.agent === "claude" || t.agent === "grok" ?
|
|
290
|
+
next = t.agent === "claude" || t.agent === "grok" ? skill(t.app) : globalText(t.app);
|
|
286
291
|
else {
|
|
287
292
|
const rest = cur ? withoutBlock(cur).replace(/\s+$/, "") : "";
|
|
288
|
-
next = `${rest ? `${rest}\n\n` : ""}${BEGIN}\n${
|
|
293
|
+
next = `${rest ? `${rest}\n\n` : ""}${BEGIN}\n${globalText(t.app)}${END}\n`;
|
|
289
294
|
}
|
|
290
295
|
if (cur === next)
|
|
291
296
|
return false;
|
package/dist/cli/context.js
CHANGED
|
@@ -16,7 +16,7 @@ import { readJsonIfExists } from "../core/json.js";
|
|
|
16
16
|
import { foldText } from "../core/text.js";
|
|
17
17
|
import { currentSession } from "../core/session.js";
|
|
18
18
|
import { isAgent } from "../core/which.js";
|
|
19
|
-
import { systemDialog, WAIT_SECONDS } from "../core/dialog.js";
|
|
19
|
+
import { canShowDialog, systemDialog, WAIT_SECONDS } from "../core/dialog.js";
|
|
20
20
|
import { UI, ui } from "./ui.js";
|
|
21
21
|
export class Context {
|
|
22
22
|
env;
|
|
@@ -179,7 +179,8 @@ export class Context {
|
|
|
179
179
|
const agent = isAgent(this.env);
|
|
180
180
|
if (this.interactive && !agent)
|
|
181
181
|
return "terminal";
|
|
182
|
-
|
|
182
|
+
// a window only where one can be shown (the test's own answer stands for one): else nothing said to wait in it
|
|
183
|
+
if (this.env.STROM_NONINTERACTIVE !== "1" && opts.window !== false && (this.io.dialog || canShowDialog(this.env))) {
|
|
183
184
|
const lang = this.uiLang();
|
|
184
185
|
const text = { title: ui(lang, "ui.dialog.title"), question: says ?? question, yes: ui(lang, "ui.dialog.yes"), no: ui(lang, "ui.dialog.no") };
|
|
185
186
|
// said first where it runs: a window can be behind others, and the command waits for it without a word
|
package/dist/cli/help.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Help text generated from the registry. Short by design: examples first,
|
|
2
2
|
// then arguments and options.
|
|
3
|
-
import { GROUPS, GLOBAL_OPTIONS, WRITE_OPTIONS, commands, match, subcommandsOf, usageLine } from "./registry.js";
|
|
3
|
+
import { GROUPS, GLOBAL_OPTIONS, WRITE_OPTIONS, commands, descriptionOf, match, subcommandsOf, usageLine } from "./registry.js";
|
|
4
4
|
import { table } from "./format.js";
|
|
5
5
|
import { suggest } from "./execute.js";
|
|
6
6
|
import { UI, ui } from "./ui.js";
|
|
@@ -43,13 +43,14 @@ function inArchive(def) {
|
|
|
43
43
|
return own;
|
|
44
44
|
return AI_WORDS.test(def.summary) ? undefined : def.summary;
|
|
45
45
|
}
|
|
46
|
-
export function commandHelp(def, archive
|
|
46
|
+
export function commandHelp(def, archive, appUrl) {
|
|
47
47
|
const summary = archive ? inArchive(def) : def.summary;
|
|
48
48
|
if (summary === undefined)
|
|
49
49
|
return `strom ${def.path.join(" ")}: not in an archive (research is switched on by the user: strom mode research)`;
|
|
50
50
|
const out = [usageLine(def), "", summary];
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
const description = descriptionOf(def, appUrl);
|
|
52
|
+
if (description && !(archive && AI_WORDS.test(description)))
|
|
53
|
+
out.push("", description);
|
|
53
54
|
const examples = (def.examples ?? []).filter((e) => !(archive && AI_WORDS.test(e)));
|
|
54
55
|
if (examples.length)
|
|
55
56
|
out.push("", "Examples:", ...examples.map((e) => ` ${e}`));
|
|
@@ -111,14 +112,14 @@ export function overview(archive = false) {
|
|
|
111
112
|
out.push("", "One command — usage, examples, options: strom help <command>", archive ? "Each command with what it does: strom commands <group>" : "Each command with what it does: strom commands [<group>] · with options and examples: strom commands <group> --json");
|
|
112
113
|
return out.join("\n");
|
|
113
114
|
}
|
|
114
|
-
export function helpFor(input, archive
|
|
115
|
+
export function helpFor(input, archive, appUrl) {
|
|
115
116
|
// "strom help 'research new'" — one quoted argument with several words.
|
|
116
117
|
const words = input.flatMap((w) => w.trim().split(/\s+/)).filter(Boolean);
|
|
117
118
|
if (words.length === 0)
|
|
118
119
|
return overview(archive);
|
|
119
120
|
const found = match(words);
|
|
120
121
|
if (found && found.used === words.length)
|
|
121
|
-
return commandHelp(found.def, archive);
|
|
122
|
+
return commandHelp(found.def, archive, appUrl);
|
|
122
123
|
if (subcommandsOf(words).length > 0)
|
|
123
124
|
return groupHelp(words, archive);
|
|
124
125
|
const all = commands().filter((c) => c.path.length > 0).map((c) => c.path.join(" "));
|
|
@@ -185,7 +186,7 @@ function pointer(words, as) {
|
|
|
185
186
|
export function helpAs(input, as) {
|
|
186
187
|
const words = input.flatMap((w) => w.trim().split(/\s+/)).filter(Boolean);
|
|
187
188
|
if (!as.human)
|
|
188
|
-
return helpFor(words, as.archive) + pointer(words, as);
|
|
189
|
+
return helpFor(words, as.archive, as.appUrl) + pointer(words, as);
|
|
189
190
|
if (words.length === 0)
|
|
190
191
|
return humanOverview(as);
|
|
191
192
|
const found = match(words);
|
package/dist/cli/main.js
CHANGED
|
@@ -16,7 +16,7 @@ import { fireHooks, HOOK_INTERFACE } from "../core/hooks.js";
|
|
|
16
16
|
import { prependPath } from "../runners/runner.js";
|
|
17
17
|
import { shimDir } from "../commands/session.js";
|
|
18
18
|
import { isAgent } from "../core/which.js";
|
|
19
|
-
import { noticeStromApp } from "../core/stromapp.js";
|
|
19
|
+
import { appUrlShown, noticeStromApp } from "../core/stromapp.js";
|
|
20
20
|
import { lastChannelOf, pendingTransition, updateChannel } from "../core/update.js";
|
|
21
21
|
import { backupBefore, backupSaid } from "./backups.js";
|
|
22
22
|
import { installation } from "../core/self.js";
|
|
@@ -157,7 +157,7 @@ export async function main(argv, io, env, cwd) {
|
|
|
157
157
|
catch (err) {
|
|
158
158
|
if (err instanceof GroupOnly) {
|
|
159
159
|
const c = Context.fromOptions({ env, cwd, io, json, values: {} });
|
|
160
|
-
io.stdout(groupHelpAs(err.group, { archive: c.archiveHere(), human: false, lang: c.uiLang(), pointer: io.tty && !isAgent(env) }) + "\n");
|
|
160
|
+
io.stdout(groupHelpAs(err.group, { archive: c.archiveHere(), human: false, lang: c.uiLang(), appUrl: appUrlShown(c.settings), pointer: io.tty && !isAgent(env) }) + "\n");
|
|
161
161
|
return EXIT.ok;
|
|
162
162
|
}
|
|
163
163
|
throw err;
|
|
@@ -170,7 +170,7 @@ export async function main(argv, io, env, cwd) {
|
|
|
170
170
|
// the agent's help, whoever asks (Milan, 2026-10-04: "výchozí je pro agenta"); a person at a terminal is told in a
|
|
171
171
|
// line of their language how to get theirs (strom help <command> --human)
|
|
172
172
|
const c = Context.fromOptions({ env, cwd, io, json, values: v });
|
|
173
|
-
io.stdout(helpAs(def.path, { archive: c.archiveHere(), human: false, lang: c.uiLang(), pointer: io.tty && !isAgent(env) }) + "\n");
|
|
173
|
+
io.stdout(helpAs(def.path, { archive: c.archiveHere(), human: false, lang: c.uiLang(), appUrl: appUrlShown(c.settings), pointer: io.tty && !isAgent(env) }) + "\n");
|
|
174
174
|
return EXIT.ok;
|
|
175
175
|
}
|
|
176
176
|
if (v.version) {
|
package/dist/cli/menu-links.js
CHANGED
|
@@ -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, defaultAppUrl } from "../core/stromapp.js";
|
|
23
|
+
import { adoptAppUrl, appTreeNameFromInstall, defaultAppUrl, stromAppUrl } 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";
|
|
@@ -288,6 +288,9 @@ export async function newFromApp(ctx, runIn, token, openAt, forward, opts = {})
|
|
|
288
288
|
ctx.settings.config.stromAppUrl = move.mark.app;
|
|
289
289
|
ctx.settings.save();
|
|
290
290
|
}
|
|
291
|
+
// a strom.app.url that is no address of the app: refused before anything is asked or made — the tree's way back
|
|
292
|
+
// would be an address built on it with the bridge's secret (B1-c)
|
|
293
|
+
stromAppUrl(ctx.settings);
|
|
291
294
|
let lang = ctx.uiLang();
|
|
292
295
|
let t = translator(lang);
|
|
293
296
|
out(ctx, t("ui.link.new.title"));
|
package/dist/cli/menu.js
CHANGED
|
@@ -24,7 +24,7 @@ import { lacksImages } from "../core/queue.js";
|
|
|
24
24
|
import { othersAtWork } from "../core/session.js";
|
|
25
25
|
import { DEFAULT_RUN_MINUTES } from "../core/config.js";
|
|
26
26
|
import { truncate } from "./format.js";
|
|
27
|
-
import { installedStromApp, noticeStromApp, stromAppState
|
|
27
|
+
import { appUrlSetting, installedStromApp, noticeStromApp, stromAppState } from "../core/stromapp.js";
|
|
28
28
|
import { appBrowsers } from "../core/chromium.js";
|
|
29
29
|
import { liveWorkers, runsAtWork } from "../core/workers.js";
|
|
30
30
|
import { askStromApp, settleInstall, shortcutName } from "./wizard.js";
|
|
@@ -344,7 +344,7 @@ export async function runMenu(ctx, run) {
|
|
|
344
344
|
const app = stromAppState(ctx.settings);
|
|
345
345
|
if (app !== "no") {
|
|
346
346
|
const atWork = liveWorkers(root).length > 0 || runsAtWork(root).length > 0;
|
|
347
|
-
const hasApp = app !== "unknown" || Boolean(installedStromApp(ctx.env, process.platform,
|
|
347
|
+
const hasApp = app !== "unknown" || Boolean(installedStromApp(ctx.env, process.platform, appUrlSetting(ctx.settings).url));
|
|
348
348
|
appItem = {
|
|
349
349
|
key: "7",
|
|
350
350
|
label: t(!hasApp ? "ui.menu.app.new" : atWork ? "ui.menu.app.watch" : "ui.menu.app"),
|
|
@@ -500,7 +500,7 @@ async function openStromApp(ctx, run, lang, said) {
|
|
|
500
500
|
await run(["app"]);
|
|
501
501
|
return;
|
|
502
502
|
}
|
|
503
|
-
if (!installedStromApp(ctx.env, process.platform,
|
|
503
|
+
if (!installedStromApp(ctx.env, process.platform, appUrlSetting(ctx.settings).url) && (await ctx.confirm(t("ui.app.notinstalled"), true))) {
|
|
504
504
|
await run(["app", "install"]);
|
|
505
505
|
return;
|
|
506
506
|
}
|
package/dist/cli/registry.js
CHANGED
|
@@ -73,11 +73,28 @@ export function usageLine(def) {
|
|
|
73
73
|
});
|
|
74
74
|
return ["strom", ...def.path, ...args, (def.options?.some((o) => !o.hidden) || def.writes) ? "[options]" : ""].filter(Boolean).join(" ");
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* A command's description as it is said here: {appUrl} the copy of the Strom app `strom app` opens (stromAppUrl — the
|
|
78
|
+
* beta for a strom of the beta channel, strom.app.url where it says another; found: help app named stromapp.info on the
|
|
79
|
+
* beta).
|
|
80
|
+
*/
|
|
81
|
+
export function descriptionOf(def, appUrl) {
|
|
82
|
+
const said = def.description?.replace(/\{appUrl\}/g, appUrl.url);
|
|
83
|
+
// an address of no Strom app in the setting: the help names the default and says so (B1-b)
|
|
84
|
+
return said && appUrl.invalid && def.description.includes("{appUrl}") ? `${said}\n${APP_URL_INVALID}` : said;
|
|
85
|
+
}
|
|
86
|
+
/** What a help says under the address of the Strom app when strom.app.url says no address of it (B1-b). */
|
|
87
|
+
export const APP_URL_INVALID = "Note: the setting strom.app.url (or STROM_APP_URL) is no address of the Strom app, so the address above is the default.\n" +
|
|
88
|
+
"Set it right (strom config set strom.app.url <address>) or remove it (strom config unset strom.app.url).";
|
|
89
|
+
/** What strom config where / config get say under a strom.app.url that is no address of the Strom app (B1-e). */
|
|
90
|
+
export const APP_URL_INVALID_SETTING = "Note: the setting strom.app.url (or STROM_APP_URL) is no address of the Strom app: strom app refuses it, and where only an address is named, the default is.\n" +
|
|
91
|
+
"Set it right (strom config set strom.app.url <address>) or remove it (strom config unset strom.app.url).";
|
|
76
92
|
/** Catalog entry for `strom commands --json`: only what is there (empty fields are left out). */
|
|
77
|
-
export function describe(def) {
|
|
93
|
+
export function describe(def, appUrl) {
|
|
78
94
|
const out = { command: def.path.join(" "), usage: usageLine(def), summary: def.summary, group: def.group };
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
const description = descriptionOf(def, appUrl);
|
|
96
|
+
if (description)
|
|
97
|
+
out.description = description;
|
|
81
98
|
if (def.writes)
|
|
82
99
|
out.writes = true;
|
|
83
100
|
if (def.tree)
|
package/dist/cli/ui.js
CHANGED
|
@@ -242,6 +242,10 @@ export const UI = {
|
|
|
242
242
|
"ui.doc.app.seen": "found on this computer",
|
|
243
243
|
"ui.doc.app.no": "not wanted",
|
|
244
244
|
"ui.doc.app.unknown": "not found",
|
|
245
|
+
"ui.doc.appurl": "address of the Strom app",
|
|
246
|
+
"ui.doc.appurl.config": "the setting strom.app.url \"{value}\" is no address of the Strom app — strom app opens nothing until it is set right or removed",
|
|
247
|
+
"ui.doc.appurl.env": "the variable STROM_APP_URL \"{value}\" is no address of the Strom app — strom app opens nothing until it is set right or removed",
|
|
248
|
+
"ui.doc.appurl.env.fix": "the variable STROM_APP_URL set to an address of the Strom app ({web}, or a copy on this computer http://127.0.0.1:<port>/), or removed",
|
|
245
249
|
"ui.doc.tree.ok": "{name}: data consistent and sealed",
|
|
246
250
|
"ui.doc.tree.bad": "{name}: {n} problem(s)",
|
|
247
251
|
"ui.doc.allok": "Everything needed is in place.",
|
|
@@ -561,7 +565,7 @@ export const UI = {
|
|
|
561
565
|
"ui.help.archive.stats": "The archive at a glance: people, how sure the facts are, ancestors in each generation",
|
|
562
566
|
"ui.help.archive.pack": "Pack the archive into one ZIP file for someone to go on with it",
|
|
563
567
|
"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)",
|
|
568
|
+
"ui.help.title": "{strom} <command> — what a person does with strom (or just {strom}: the menu)",
|
|
565
569
|
"ui.help.more": "Help for one command: strom help <command> --human · every command in English (what an agent reads): strom help",
|
|
566
570
|
"ui.help.more.archive": "Help for one command: strom help <command> --human",
|
|
567
571
|
"ui.help.examples": "Examples:",
|
|
@@ -762,11 +766,12 @@ export const UI = {
|
|
|
762
766
|
"ui.live.app": " the Strom app following it: {url}",
|
|
763
767
|
"ui.live.stophow": " stop: strom live stop",
|
|
764
768
|
"ui.live.none": "the bridge does not run — strom live start (or strom app --live)",
|
|
765
|
-
"ui.live.moved": " its address is new
|
|
769
|
+
"ui.live.moved": " its address is new: the Strom app finds it when the research is opened in it again — strom app --live",
|
|
766
770
|
"ui.live.stopped": "the bridge stopped",
|
|
767
771
|
"ui.live.killed": "the bridge did not end when asked: it was ended for good",
|
|
768
772
|
"ui.live.noneran": "no bridge ran",
|
|
769
773
|
"ui.live.forgotten": "its address is forgotten: the next bridge gets a new one",
|
|
774
|
+
"ui.live.newsecret": " the next bridge gets a new secret address: the Strom app gets it when the research is opened in it again — strom app",
|
|
770
775
|
"ui.live.ended": "the bridge ended",
|
|
771
776
|
"ui.guide.archive": "This family tree is an archive: the data come from the Strom app. What it holds: strom stats · strom person card <who> · strom pedigree <who> · strom recent. Research is switched on by the user alone: strom mode research (or the menu).",
|
|
772
777
|
"ui.setup.links.archive": "Let the Strom app open the archive on this computer? (One click sends the edits back or opens an excerpt in full quality — each asked here first.)",
|
|
@@ -1346,6 +1351,10 @@ export const UI = {
|
|
|
1346
1351
|
"ui.error.arg.missing": "<{arg}> is missing",
|
|
1347
1352
|
"ui.error.arg.missing.hint": "strom help {cmd}",
|
|
1348
1353
|
"ui.error.prefix": "error",
|
|
1354
|
+
"ui.error.config.app-url": "invalid strom.app.url \"{value}\": no address of the Strom app",
|
|
1355
|
+
"ui.error.config.app-url.hint": "the Strom app: {web}, or a copy on this computer http://127.0.0.1:<port>/",
|
|
1356
|
+
"ui.error.config.app-url.config.hint": "the Strom app: {web}, or a copy on this computer http://127.0.0.1:<port>/\nset it right: strom config set strom.app.url <address> — or remove it: strom config unset strom.app.url",
|
|
1357
|
+
"ui.error.config.app-url.env.hint": "the Strom app: {web}, or a copy on this computer http://127.0.0.1:<port>/\nthe variable STROM_APP_URL set right, or removed",
|
|
1349
1358
|
"ui.error.backup.failed": "The backup before going from {from} to {to} could not be made: {detail}. Nothing is switched: this strom opens no family tree for writing until the backup is made.",
|
|
1350
1359
|
"ui.error.backup.failed.hint": "Free room on the disk ({where}), then run strom again — or go back: strom update --channel {back}",
|
|
1351
1360
|
"ui.error.backup.failed.update": "The backup before going from {from} to {to} could not be made: {detail}. Nothing was installed.",
|
|
@@ -1421,6 +1430,7 @@ export const UI = {
|
|
|
1421
1430
|
"ui.arg.tree-name": "tree name",
|
|
1422
1431
|
"ui.arg.url": "url",
|
|
1423
1432
|
"ui.arg.value": "value",
|
|
1433
|
+
"ui.arg.address": "address",
|
|
1424
1434
|
"ui.arg.what": "what",
|
|
1425
1435
|
"ui.arg.where": "where",
|
|
1426
1436
|
"ui.arg.who": "who",
|
|
@@ -1449,7 +1459,7 @@ export const UI = {
|
|
|
1449
1459
|
"ui.error.event.needs-reason.hint": "e.g. --reason \"record S0012 gives 1811, not 1813\"",
|
|
1450
1460
|
"ui.error.family.needs-reason": "changing who belongs to a family, or how, needs --reason",
|
|
1451
1461
|
"ui.error.family.needs-reason.hint": "e.g. --reason \"the baptism names Jan as stepfather\"",
|
|
1452
|
-
"ui.error.person.needs-reason": "changing a name or a known sex needs --reason",
|
|
1462
|
+
"ui.error.person.needs-reason": "changing a name, its title or a known sex needs --reason",
|
|
1453
1463
|
"ui.error.person.needs-reason.hint": "e.g. --reason \"misread: the register has Novák, not Nowak\"",
|
|
1454
1464
|
"ui.error.retract.needs-reason": "retracting needs --reason",
|
|
1455
1465
|
"ui.error.retract.needs-reason.hint": "e.g. --reason \"misread: the entry names Anna, not Anton\"",
|
package/dist/cli/wizard.js
CHANGED
|
@@ -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, defaultAppUrl, noticeStromApp, researchUrl, STROM_APP_URL, stromAppState,
|
|
17
|
+
import { appCopyOfInstall, appOpensLinks, defaultAppUrl, noticeStromApp, researchUrl, STROM_APP_URL, stromAppState, appUrlSetting } 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";
|
|
@@ -355,8 +355,12 @@ export async function askStromApp(ctx, lang, back = ui(lang, "ui.browse.back"))
|
|
|
355
355
|
ctx.settings.config.stromApp = answer === "no" ? "no" : "yes";
|
|
356
356
|
ctx.settings.save();
|
|
357
357
|
if (answer === "install") {
|
|
358
|
-
|
|
359
|
-
|
|
358
|
+
// a strom.app.url that is no address of the app: nothing opened, said how it stands (strom doctor says how to put it right)
|
|
359
|
+
const said = appUrlSetting(ctx.settings);
|
|
360
|
+
if (said.invalid)
|
|
361
|
+
ctx.io.stdout(ui(lang, said.invalid.source === "env" ? "ui.doc.appurl.env" : "ui.doc.appurl.config", { value: said.invalid.value }) + "\n");
|
|
362
|
+
else
|
|
363
|
+
ctx.io.stdout(ui(lang, openForUser(said.url, ctx.env) ? "ui.app.install" : "ui.app.url", { url: said.url }) + "\n");
|
|
360
364
|
}
|
|
361
365
|
return answer;
|
|
362
366
|
}
|
|
@@ -577,6 +577,9 @@ function haystack(r) {
|
|
|
577
577
|
Object.values(v).forEach(add);
|
|
578
578
|
};
|
|
579
579
|
const { id: _i, type: _t, created: _c, updated: _u, ...rest } = r;
|
|
580
|
+
// a person's titles ("Ing.", "ml.") are never searched as their name — the Strom app finds nobody by them either
|
|
581
|
+
if (r.type === "person")
|
|
582
|
+
rest.names = r.names.map(({ prefix: _p, suffix: _s, ...n }) => n);
|
|
580
583
|
add(rest);
|
|
581
584
|
return parts.join(" \u0001 ");
|
|
582
585
|
}
|
package/dist/commands/guide.js
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
// sessions and costs tokens every time. Every command in it must exist
|
|
4
4
|
// (test/cli/examples.test.ts checks them against the registry).
|
|
5
5
|
import { langName } from "../core/lang.js";
|
|
6
|
-
|
|
6
|
+
import { appSite } from "../core/stromapp.js";
|
|
7
|
+
/** The guide; appUrl: the Strom app's address it names — the one `strom app` opens (appUrlShown). */
|
|
8
|
+
export function guideText(lang, appUrl) {
|
|
7
9
|
const language = lang
|
|
8
10
|
? `The research language of this tree is ${langName(lang)} (${lang}): talk to the user in ${langName(lang)} and write notes, tasks and stories in ${langName(lang)}. Keep transcripts of records in their original language.`
|
|
9
11
|
: "Talk to the user in their language. Set it as the research language: strom setup --lang <code> (cs, en, de, pl, …).";
|
|
@@ -181,11 +183,11 @@ output/tree-strom.ged (for the Strom app) — both from the same evidence, also
|
|
|
181
183
|
Changes are committed automatically; you never run git yourself.
|
|
182
184
|
|
|
183
185
|
THE STROM APP — where the user sees the result
|
|
184
|
-
The Strom app (
|
|
186
|
+
The Strom app (${appSite(appUrl)}) is strom's companion: a free family tree app, no account,
|
|
185
187
|
the family's data stay on their computer; it shows the tree, the sources, a map, a family book.
|
|
186
188
|
When the user wants to see the results, or when strom says to offer it (once, not in every
|
|
187
189
|
conversation), suggest it gently, in a sentence or two — best installed as an app from the browser, then it works offline:
|
|
188
|
-
|
|
190
|
+
${appUrl} the app itself: opened in the browser, installed from there (the
|
|
189
191
|
install icon at the end of the address bar; Safari: File → Add to Dock)
|
|
190
192
|
strom app install opens it there and says where to click
|
|
191
193
|
strom app opens it — with this research when the app can take it (strom says so), and
|
package/dist/commands/meta.js
CHANGED
|
@@ -5,7 +5,7 @@ import fs from "node:fs";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { newerVersion } from "../core/update.js";
|
|
7
7
|
import { mb, tidyPlan, TIDY_SAID } from "../core/tidy.js";
|
|
8
|
-
import { appOpensResearch,
|
|
8
|
+
import { appOpensResearch, appUrlSetting, appUrlShown, installedStromApp } from "../core/stromapp.js";
|
|
9
9
|
import { register, commands, describe, GROUPS } from "../cli/registry.js";
|
|
10
10
|
import { UsageError } from "../core/errors.js";
|
|
11
11
|
import { helpAs } from "../cli/help.js";
|
|
@@ -88,7 +88,7 @@ function orientation(ctx) {
|
|
|
88
88
|
// What a conversation tells the user once, not again after it starts afresh (a new conversation, /clear): the Strom app, the stories, asking here.
|
|
89
89
|
const told = ctx.settings.config.told ?? {};
|
|
90
90
|
if (fs.existsSync(file))
|
|
91
|
-
base.results = { file, app: !wanted ? "not-wanted" : installedStromApp(ctx.env, process.platform,
|
|
91
|
+
base.results = { file, app: !wanted ? "not-wanted" : installedStromApp(ctx.env, process.platform, appUrlSetting(ctx.settings).url) ? "installed" : "offer", ...(told.app ? { told: true } : {}) };
|
|
92
92
|
const vision = ctx.settings.models(ctx.settings.agent(tree.config).value, tree.config).vision;
|
|
93
93
|
if (vision) {
|
|
94
94
|
const other = readByOtherModels(tree, vision);
|
|
@@ -185,7 +185,7 @@ register({
|
|
|
185
185
|
? appOpensResearch(ctx.settings) && !o.results.told ? "ui.o.results.installed.live" : "ui.o.results.installed"
|
|
186
186
|
: o.results.app === "offer"
|
|
187
187
|
? o.results.told ? "ui.o.results.offered" : appOpensResearch(ctx.settings) ? "ui.o.results.offer.live" : "ui.o.results.offer"
|
|
188
|
-
: "ui.o.results.plain", { file: ctx.display(o.results.file), url:
|
|
188
|
+
: "ui.o.results.plain", { file: ctx.display(o.results.file), url: appUrlSetting(ctx.settings).url }))
|
|
189
189
|
: undefined, archive ? row(t("ui.o.mode"), t("ui.o.mode.archive")) : undefined, o.stories && !archive ? row(t("ui.o.stories"), t(`ui.o.stories.${o.stories}`)) : undefined, o.ask && !archive ? row(t("ui.o.ask"), t("ui.o.ask.tell")) : undefined, o.reread && !archive ? row(t("ui.o.reread"), t("ui.o.reread.offer", { n: o.reread.facts, models: o.reread.models.join(", "), model: o.reread.model })) : undefined, o.researches?.length
|
|
190
190
|
? t("ui.o.research") + "\n" + table(o.researches.map((r) => [` ${r.id}`, r.name, `[${r.state}]`, r.focus]))
|
|
191
191
|
: t("ui.o.research.none"), o.working?.length
|
|
@@ -209,7 +209,7 @@ register({
|
|
|
209
209
|
const said = ui(ctx.tree().lang, "ui.guide.archive");
|
|
210
210
|
return { text: said, data: { guide: said, lang, archive: true } };
|
|
211
211
|
}
|
|
212
|
-
const text = guideText(lang);
|
|
212
|
+
const text = guideText(lang, appUrlShown(ctx.settings).url);
|
|
213
213
|
return { text, data: { guide: text, lang } };
|
|
214
214
|
},
|
|
215
215
|
}, {
|
|
@@ -218,7 +218,7 @@ register({
|
|
|
218
218
|
group: "start",
|
|
219
219
|
args: [{ name: "filter", description: "only commands starting with these words, or of this group", variadic: true }],
|
|
220
220
|
examples: ["strom commands", "strom commands source --json", "strom commands analysis"],
|
|
221
|
-
run(
|
|
221
|
+
run(ctx, { args }) {
|
|
222
222
|
const words = args.flatMap((a) => a.split(/\s+/)).filter(Boolean);
|
|
223
223
|
const prefix = words.join(" ");
|
|
224
224
|
const defs = commands().filter((c) => c.path.length > 0 && (!prefix || c.group === prefix || c.path.join(" ") === prefix || c.path.join(" ").startsWith(`${prefix} `)));
|
|
@@ -231,7 +231,8 @@ register({
|
|
|
231
231
|
})
|
|
232
232
|
.filter(Boolean)
|
|
233
233
|
.join("\n\n");
|
|
234
|
-
|
|
234
|
+
const appUrl = appUrlShown(ctx.settings);
|
|
235
|
+
return { text, data: { version: VERSION, commands: defs.map((d) => describe(d, appUrl)), ...(appUrl.invalid ? { invalid: ["strom.app.url"] } : {}) } };
|
|
235
236
|
},
|
|
236
237
|
}, {
|
|
237
238
|
path: ["help"],
|
|
@@ -247,7 +248,7 @@ register({
|
|
|
247
248
|
// the agent's help, whoever asks — a person's only with --human (Milan, 2026-10-04); a person at a terminal is told
|
|
248
249
|
// how in a line of their language
|
|
249
250
|
const human = Boolean(input.opts.human) && !input.opts.agent;
|
|
250
|
-
const text = helpAs(input.args, { archive: ctx.archiveHere(), human, lang: ctx.uiLang(), pointer: !human && ctx.io.tty && !isAgent(ctx.env) });
|
|
251
|
+
const text = helpAs(input.args, { archive: ctx.archiveHere(), human, lang: ctx.uiLang(), appUrl: appUrlShown(ctx.settings), pointer: !human && ctx.io.tty && !isAgent(ctx.env) });
|
|
251
252
|
return { text, data: { help: text } };
|
|
252
253
|
},
|
|
253
254
|
});
|