strom-research 1.28.0-beta.1 → 1.28.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.cs.md +14 -1
- package/CHANGELOG.de.md +16 -1
- package/CHANGELOG.md +16 -1
- package/CHANGELOG.pl.md +16 -1
- package/assets/lang/cs.json +6 -4
- package/assets/lang/de.json +6 -4
- package/assets/lang/pl.json +6 -4
- package/dist/cli/menu.js +5 -4
- package/dist/cli/ui.js +6 -4
- package/dist/commands/session.js +15 -8
- package/dist/core/live.js +57 -18
- package/dist/core/tree.js +1 -1
- package/dist/core/workplace.js +69 -0
- package/dist/runners/claude.js +14 -4
- package/package.json +1 -1
package/CHANGELOG.cs.md
CHANGED
|
@@ -7,7 +7,7 @@ Změny každé verze ve zkratce. Úplné poznámky a instalační řádky jsou n
|
|
|
7
7
|
|
|
8
8
|
## 1.28.0
|
|
9
9
|
|
|
10
|
-
*Připravuje se: bety do 1.28.0-beta.
|
|
10
|
+
*Připravuje se: bety do 1.28.0-beta.3. Oddíl bude úplný s vydáním.*
|
|
11
11
|
|
|
12
12
|
- **Jak Strom funguje je přímo ve stromu: `strom doc`.** Dokumentace aplikace a výzkumu v češtině, angličtině, němčině
|
|
13
13
|
a polštině je součástí stromu a čte se i bez internetu: `strom doc` vypíše kapitoly, `strom doc R10.1` jedno pravidlo
|
|
@@ -26,9 +26,22 @@ Změny každé verze ve zkratce. Úplné poznámky a instalační řádky jsou n
|
|
|
26
26
|
- **Překlad vedle přepisu.** Záznam v jiném jazyce nebo písmu, než je jazyk výzkumu – latina, kurent, polština,
|
|
27
27
|
azbuka –, dostane vedle doslovného přepisu i překlad do jazyka výzkumu.
|
|
28
28
|
|
|
29
|
+
- **Kde agent pracuje, pro mapu aplikace Strom.** Během práce agenta strom aplikaci říká, ke kterému místu patří kniha,
|
|
30
|
+
kterou agent zkoumá – farnost nebo obec jejích zápisů, nikdy archiv –, aby ho aplikace při sledování práce mohla
|
|
31
|
+
ukázat na mapě. Když to výzkum neví, nic neříká a aplikace zůstane u míst osoby. Práce na rodině uvede pár – manžela,
|
|
32
|
+
jinak manželku – i rodinu samotnou, aby se aplikace mohla zaměřit na pár.
|
|
33
|
+
|
|
29
34
|
- **DigiArchiv SOA v Třeboni:** podmínky, jak je archiv potvrdil – ručně jen vybrané snímky, nikdy celá kniha, žádné
|
|
30
35
|
nástroje ke stahování – a jak citovat trvalý odkaz na snímek.
|
|
31
36
|
|
|
37
|
+
- **Seznam před během ukazuje, co běh vezme.** V položce Nechat agenta pracovat samotného jsou mezi úkoly v pořadí, v jakém je agent
|
|
38
|
+
vezme, i úkoly dějin míst, když na ně přijde řada – místa údajů k zařazení jdou napřed –, označené jako dějiny.
|
|
39
|
+
|
|
40
|
+
- **Podmínka běhu na jednom řádku.** Co podmínka (`run.gate`) odpověděla, jak se ptá – před každým sezením, nebo při
|
|
41
|
+
ručním spuštění jednou – a její strop se před prvním sezením řeknou na jednom řádku, ne na třech. Agent, který čte
|
|
42
|
+
webové stránky přes vlastního pomocníka, se už nehlásí jako bez nástroje na čtení webu; nástroj, který opravdu
|
|
43
|
+
chybí, se řekne v jazyce výzkumu.
|
|
44
|
+
|
|
32
45
|
## 1.27.0
|
|
33
46
|
|
|
34
47
|
*5. 11. 2026 · patří k aplikaci Strom 3.23.0.*
|
package/CHANGELOG.de.md
CHANGED
|
@@ -7,7 +7,7 @@ Die Änderungen jeder Version in Kürze. Die vollständigen Hinweise und die Ins
|
|
|
7
7
|
|
|
8
8
|
## 1.28.0
|
|
9
9
|
|
|
10
|
-
*In Vorbereitung: die Betas bis 1.28.0-beta.
|
|
10
|
+
*In Vorbereitung: die Betas bis 1.28.0-beta.3. Der Abschnitt ist mit dem Release vollständig.*
|
|
11
11
|
|
|
12
12
|
- **Wie Strom funktioniert gehört zu strom: `strom doc`.** Die Dokumentation der App und der Forschung auf Tschechisch,
|
|
13
13
|
Englisch, Deutsch und Polnisch ist Teil von strom und liest sich auch ohne Internet: `strom doc` listet die Kapitel,
|
|
@@ -29,10 +29,25 @@ Die Änderungen jeder Version in Kürze. Die vollständigen Hinweise und die Ins
|
|
|
29
29
|
Latein, Kurrent, Polnisch, Kyrillisch – bekommt neben der wörtlichen Abschrift eine Übersetzung in die Sprache der
|
|
30
30
|
Forschung.
|
|
31
31
|
|
|
32
|
+
- **Wo der Agent arbeitet, für die Karte der Strom-App.** Während ein Agent arbeitet, sagt strom der App, zu welchem
|
|
33
|
+
Ort das Buch gehört, das er untersucht – die Pfarrei oder das Dorf seiner Einträge, nie das Archiv –, damit die App
|
|
34
|
+
ihn beim Verfolgen der Arbeit auf der Karte zeigen kann. Weiß die Forschung es nicht, sagt sie nichts, und die App
|
|
35
|
+
bleibt bei den Orten der Person. Arbeit an einer Familie nennt das Paar – den Ehemann, sonst die Ehefrau – und die
|
|
36
|
+
Familie selbst, damit die App sich dem Paar zuwenden kann.
|
|
37
|
+
|
|
32
38
|
- **DigiArchiv des Staatlichen Gebietsarchivs Třeboň:** seine Bedingungen, wie das Archiv sie bestätigt hat – von Hand
|
|
33
39
|
nur ausgewählte Bilder, nie ein ganzes Buch, keine Download-Werkzeuge – und wie der dauerhafte Link eines Bildes
|
|
34
40
|
zitiert wird.
|
|
35
41
|
|
|
42
|
+
- **Die Liste vor einem Lauf zeigt, was der Lauf nimmt.** Unter „Den Agenten allein arbeiten lassen“ stehen unter den
|
|
43
|
+
Aufgaben in der Reihenfolge, in der der Agent sie nimmt, nun auch die Aufgaben der Geschichte der Orte, wenn sie an der
|
|
44
|
+
Reihe sind – die Orte der Angaben zuerst –, als Geschichte gekennzeichnet.
|
|
45
|
+
|
|
46
|
+
- **Die Bedingung eines Laufs in einer Zeile.** Was die Bedingung (`run.gate`) geantwortet hat, wie sie gefragt wird
|
|
47
|
+
– vor jeder Sitzung oder bei von Hand gestarteten Aufgaben einmal – und ihre Obergrenze stehen vor der ersten Sitzung
|
|
48
|
+
in einer Zeile, nicht in dreien. Ein Agent, der Webseiten über seinen eigenen Helfer liest, wird nicht mehr
|
|
49
|
+
als ohne Werkzeug zum Lesen des Webs gemeldet; ein Werkzeug, das wirklich fehlt, wird in der Sprache der Forschung gesagt.
|
|
50
|
+
|
|
36
51
|
## 1.27.0
|
|
37
52
|
|
|
38
53
|
*5.11.2026 · gehört zur Strom-App 3.23.0.*
|
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,7 @@ The changes of each version in short. The full notes and the install lines are o
|
|
|
7
7
|
|
|
8
8
|
## 1.28.0
|
|
9
9
|
|
|
10
|
-
*In preparation: the betas up to 1.28.0-beta.
|
|
10
|
+
*In preparation: the betas up to 1.28.0-beta.3. The section is complete with the release.*
|
|
11
11
|
|
|
12
12
|
- **How Strom works comes with strom: `strom doc`.** The documentation of the app and the research, in Czech, English,
|
|
13
13
|
German and Polish, is part of strom and reads offline: `strom doc` lists its chapters, `strom doc R10.1` shows one rule
|
|
@@ -27,9 +27,24 @@ The changes of each version in short. The full notes and the install lines are o
|
|
|
27
27
|
- **A translation beside the transcript.** A record in another language or script than the research's – Latin, German
|
|
28
28
|
Kurrent, Polish, Cyrillic – gets a translation into the research's language beside its word-for-word transcript.
|
|
29
29
|
|
|
30
|
+
- **Where the agent works, for the map of the Strom app.** While an agent works, strom tells the app which place the
|
|
31
|
+
book it examines belongs to – the parish or village of its records, never the archive – so the app can show it on the
|
|
32
|
+
map when following the work. When the research does not know it, it says nothing, and the app keeps to the person's
|
|
33
|
+
own places. Work on a family names the couple – the husband, else the wife – and the family itself, so the app can
|
|
34
|
+
turn to the pair.
|
|
35
|
+
|
|
30
36
|
- **DigiArchiv of the regional archive in Třeboň:** its terms as the archive confirmed them – selected images saved by
|
|
31
37
|
hand only, never a whole book, no download tools – and how to cite an image's permanent link.
|
|
32
38
|
|
|
39
|
+
- **The list before a run shows what the run takes.** Under Let the agent work on its own, the tasks listed in the order
|
|
40
|
+
the agent takes them now include the tasks of the history of the places in their turn – the places of the facts to
|
|
41
|
+
map come first – marked as history.
|
|
42
|
+
|
|
43
|
+
- **The condition of a run in one line.** What the condition (`run.gate`) answered, how it is asked – before each
|
|
44
|
+
session, once for tasks started by hand – and its cap are said in one line before the first session, not in three.
|
|
45
|
+
An agent that reads web pages through its own helper is no longer reported as missing its web fetch; a tool
|
|
46
|
+
really missing is said in the research's language.
|
|
47
|
+
|
|
33
48
|
## 1.27.0
|
|
34
49
|
|
|
35
50
|
*2026-11-05 · goes with the Strom app 3.23.0.*
|
package/CHANGELOG.pl.md
CHANGED
|
@@ -7,7 +7,7 @@ Zmiany każdej wersji w skrócie. Pełne informacje o wydaniach i polecenia inst
|
|
|
7
7
|
|
|
8
8
|
## 1.28.0
|
|
9
9
|
|
|
10
|
-
*W przygotowaniu: bety do 1.28.0-beta.
|
|
10
|
+
*W przygotowaniu: bety do 1.28.0-beta.3. Sekcja będzie kompletna z wydaniem.*
|
|
11
11
|
|
|
12
12
|
- **Jak działa Strom – w samym stromie: `strom doc`.** Dokumentacja aplikacji i badań po czesku, angielsku, niemiecku i
|
|
13
13
|
polsku jest częścią stromu i czyta się ją także bez internetu: `strom doc` wypisuje rozdziały, `strom doc R10.1` jedną
|
|
@@ -28,9 +28,24 @@ Zmiany każdej wersji w skrócie. Pełne informacje o wydaniach i polecenia inst
|
|
|
28
28
|
- **Tłumaczenie obok transkrypcji.** Wpis w innym języku lub piśmie niż język badań – łacina, kurrenta, niemiecki,
|
|
29
29
|
cyrylica – otrzymuje obok dosłownej transkrypcji tłumaczenie na język badań.
|
|
30
30
|
|
|
31
|
+
- **Gdzie pracuje agent – dla mapy aplikacji Strom.** Podczas pracy agenta strom podaje aplikacji, do którego miejsca
|
|
32
|
+
należy księga, którą agent bada – parafia lub wieś jej wpisów, nigdy archiwum – aby aplikacja mogła je pokazać na
|
|
33
|
+
mapie podczas śledzenia pracy. Gdy badania tego nie wiedzą, nic nie podają, a aplikacja pozostaje przy miejscach
|
|
34
|
+
osoby. Praca nad rodziną podaje parę – męża, a jeśli go brak, żonę – oraz samą rodzinę, aby aplikacja mogła skupić
|
|
35
|
+
się na parze.
|
|
36
|
+
|
|
31
37
|
- **DigiArchiv Archiwum Państwowego w Třeboniu:** jego warunki, tak jak potwierdziło je archiwum – ręcznie tylko wybrane
|
|
32
38
|
skany, nigdy cała księga, żadnych narzędzi do pobierania – i jak cytować stały link do skanu.
|
|
33
39
|
|
|
40
|
+
- **Lista przed uruchomieniem pokazuje, co weźmie agent.** W pozycji „Pozwól agentowi pracować samodzielnie“ wśród
|
|
41
|
+
zadań w kolejności, w jakiej bierze je agent, są teraz także zadania historii miejsc, gdy przychodzi ich kolej –
|
|
42
|
+
miejsca danych najpierw –, oznaczone jako historia.
|
|
43
|
+
|
|
44
|
+
- **Warunek przebiegu w jednym wierszu.** Co odpowiedział warunek (`run.gate`), jak jest pytany – przed każdą sesją
|
|
45
|
+
albo raz przy zadaniach uruchomionych ręcznie – i jego pułap są podane przed pierwszą sesją w jednym wierszu, nie w
|
|
46
|
+
trzech. Agent, który czyta strony internetowe przez własnego pomocnika, nie jest już zgłaszany jako
|
|
47
|
+
pozbawiony narzędzia do czytania stron; narzędzie, którego naprawdę brak, jest podawane w języku badań.
|
|
48
|
+
|
|
34
49
|
## 1.27.0
|
|
35
50
|
|
|
36
51
|
*5.11.2026 · współpracuje z aplikacją Strom 3.23.0.*
|
package/assets/lang/cs.json
CHANGED
|
@@ -614,6 +614,7 @@
|
|
|
614
614
|
"ui.run.denied": " · oprávnění odmítla {n}×: {what}",
|
|
615
615
|
"ui.run.refused": " · strom odmítl {n}× (limit {per, plural, one {# webového požadavku} other {# webových požadavků}} na jeden server v sezení nebo limit serveru): {what}",
|
|
616
616
|
"ui.run.recover": " · spojení agenta selhalo ({why}) — jeho sezení pokračuje za {s} s ({n}/{max})",
|
|
617
|
+
"ui.run.missingtools": " · Claude Code nenačetl {tools} – sezení se bez toho nemusí obejít; s nastavením agent.addons on běží se vším jako dřív",
|
|
617
618
|
"ui.run.exitOnly": " · {session}: agent sezení uzavřel a pak skončil s kódem {code} — bráno jako hotové, běh pokračuje",
|
|
618
619
|
"session.user": "zastaveno uživatelem",
|
|
619
620
|
"session.run": "běh se zastavil dřív, než sezení skončilo (přerušení, nebo vypnutý počítač)",
|
|
@@ -2009,6 +2010,7 @@
|
|
|
2009
2010
|
"ui.run.skip.held": " · {task} vynechán: pracuje na něm jiný agent",
|
|
2010
2011
|
"ui.run.next": "Na řadě jsou tyto úkoly, v pořadí, v jakém je agent vezme:",
|
|
2011
2012
|
"ui.run.story": " (vyprávění)",
|
|
2013
|
+
"ui.run.ofhistory": " (dějiny)",
|
|
2012
2014
|
"ui.run.what": "Co má agent udělat?",
|
|
2013
2015
|
"ui.run.queue": "Pracovat v pořadí fronty – počet úkolů se zadá",
|
|
2014
2016
|
"ui.run.pick": "Jen vybrané úkoly ze seznamu",
|
|
@@ -2022,21 +2024,21 @@
|
|
|
2022
2024
|
"ui.menu.working.more": "Samostatně teď pracují agenti: {n}.",
|
|
2023
2025
|
"ui.run.beside": "⚠ Agent už tu pracuje sám (běhy: {n}). Další vedle něj si vezme jiné úkoly – náklady se sčítají.",
|
|
2024
2026
|
"ui.run.beside.sure": "Spustit další vedle něj?",
|
|
2025
|
-
"ui.run.gate": "· podmínka: {name} — ptá se před každým sezením; běh může nechat čekat",
|
|
2026
2027
|
"ui.run.gate.wait": "⏸ čekání do {at} — {reason} (Ctrl-C běh ukončí)",
|
|
2027
2028
|
"ui.run.asleep.wait": "⏸ čekání do {at} – zbylé úkoly potřebují {host}, který teď neodpovídá (Ctrl-C běh ukončí)",
|
|
2028
2029
|
"ui.run.asleep.why": "{host} teď neodpovídá",
|
|
2029
2030
|
"ui.run.stop.gate": "podmínka „{name}“ řekla dost — {reason}",
|
|
2030
2031
|
"ui.run.stop.gate.error": "podmínka „{name}“ neodpověděla, jak má — {reason} (strom gate test)",
|
|
2031
|
-
"ui.run.gate.once": "· podmínka: {name} — ruční spuštění: při nesplněné podmínce jedna otázka, zda přesto začít",
|
|
2032
2032
|
"ui.run.gate.anyway": "Podmínka „{name}“ by teď nespouštěla — {reason}. Spustit přesto?",
|
|
2033
2033
|
"ui.run.gate.anyway.here": "Spustit přesto?",
|
|
2034
2034
|
"ui.run.gate.later": "zatím ne",
|
|
2035
2035
|
"ui.run.gate.no": "ne",
|
|
2036
2036
|
"ui.run.gate.noanswer": "neodpověděla, jak má (strom gate test)",
|
|
2037
2037
|
"ui.run.stop.gate.declined": "nespuštěno — podmínka „{name}“: {reason}",
|
|
2038
|
-
"ui.run.gate.
|
|
2039
|
-
"ui.run.gate.
|
|
2038
|
+
"ui.run.gate.said": "· podmínka {name}{how}: {word}{reason} (kód {status}; .strom/gate.log)",
|
|
2039
|
+
"ui.run.gate.how.each": " (ptá se před každým sezením)",
|
|
2040
|
+
"ui.run.gate.how.once": " (ruční spuštění: ptá se jednou)",
|
|
2041
|
+
"ui.run.gate.how.cap": " (strop: hlídá se před každým sezením, žádné „přesto začít“ ho nepřekročí)",
|
|
2040
2042
|
"ui.run.stop.gate.cap": "strop podmínky „{name}“ – {reason} (pevná hranice z run.gate; „přesto začít“ ji nepřekročí)",
|
|
2041
2043
|
"ui.run.cap.finish": "⏳ {session}: limit agenta na {used} % ({kind}) – sezení dostalo žádost zapsat, co našlo, a skončit; za stropem další sezení nezačne",
|
|
2042
2044
|
"ui.run.limit.five_hour": "pětihodinové okno",
|
package/assets/lang/de.json
CHANGED
|
@@ -614,6 +614,7 @@
|
|
|
614
614
|
"ui.run.denied": " · Berechtigungen verweigert {n}×: {what}",
|
|
615
615
|
"ui.run.refused": " · strom hat {n}× abgelehnt (die Grenze von {per, plural, one {# Webanfrage} other {# Webanfragen}} an einen Server in einer Sitzung oder die des Servers): {what}",
|
|
616
616
|
"ui.run.recover": " · die Verbindung des Agenten ist abgebrochen ({why}) — seine Sitzung geht in {s} s weiter ({n}/{max})",
|
|
617
|
+
"ui.run.missingtools": " · Claude Code hat {tools} nicht geladen – die Sitzung kommt ohne vielleicht nicht aus; mit der Einstellung agent.addons on läuft sie wie früher mit allem",
|
|
617
618
|
"ui.run.exitOnly": " · {session}: der Agent hat die Sitzung abgeschlossen und danach mit Code {code} geendet — als erledigt gewertet, der Lauf geht weiter",
|
|
618
619
|
"session.user": "vom Benutzer angehalten",
|
|
619
620
|
"session.run": "der Lauf brach ab, bevor die Sitzung endete (unterbrochen, oder der Computer wurde ausgeschaltet)",
|
|
@@ -2009,6 +2010,7 @@
|
|
|
2009
2010
|
"ui.run.skip.held": " · {task} ausgelassen: ein anderer Agent arbeitet daran",
|
|
2010
2011
|
"ui.run.next": "Als Nächstes in der Warteschlange, in der Reihenfolge, in der der Agent sie nimmt:",
|
|
2011
2012
|
"ui.run.story": " (eine Geschichte)",
|
|
2013
|
+
"ui.run.ofhistory": " (Geschichte)",
|
|
2012
2014
|
"ui.run.what": "Was soll der Agent tun?",
|
|
2013
2015
|
"ui.run.queue": "Die Warteschlange in dieser Reihenfolge abarbeiten – wie viele, steht zur Wahl",
|
|
2014
2016
|
"ui.run.pick": "Nur die aus der Liste gewählten Aufgaben",
|
|
@@ -2022,21 +2024,21 @@
|
|
|
2022
2024
|
"ui.menu.working.more": "Gerade arbeiten Agenten selbstständig: {n}.",
|
|
2023
2025
|
"ui.run.beside": "⚠ Hier arbeitet schon ein Agent selbstständig (Läufe: {n}). Ein weiterer daneben nimmt andere Aufgaben – die Kosten addieren sich.",
|
|
2024
2026
|
"ui.run.beside.sure": "Einen weiteren daneben starten?",
|
|
2025
|
-
"ui.run.gate": "· Bedingung: {name} — vor jeder Sitzung gefragt; sie kann den Lauf warten lassen",
|
|
2026
2027
|
"ui.run.gate.wait": "⏸ Warten bis {at} — {reason} (Strg-C beendet den Lauf)",
|
|
2027
2028
|
"ui.run.asleep.wait": "⏸ Warten bis {at} — die übrigen Aufgaben brauchen {host}, der gerade nicht antwortet (Strg-C beendet den Lauf)",
|
|
2028
2029
|
"ui.run.asleep.why": "{host} antwortet gerade nicht",
|
|
2029
2030
|
"ui.run.stop.gate": "die Bedingung „{name}“ sagte Halt — {reason}",
|
|
2030
2031
|
"ui.run.stop.gate.error": "die Bedingung „{name}“ gab keine gültige Antwort — {reason} (strom gate test)",
|
|
2031
|
-
"ui.run.gate.once": "· Bedingung: {name} — von Hand gestartet: ist die Bedingung nicht erfüllt, eine Frage, ob trotzdem begonnen wird",
|
|
2032
2032
|
"ui.run.gate.anyway": "Die Bedingung „{name}“ würde jetzt nicht starten — {reason}. Trotzdem starten?",
|
|
2033
2033
|
"ui.run.gate.anyway.here": "Trotzdem starten?",
|
|
2034
2034
|
"ui.run.gate.later": "noch nicht",
|
|
2035
2035
|
"ui.run.gate.no": "nein",
|
|
2036
2036
|
"ui.run.gate.noanswer": "keine gültige Antwort (strom gate test)",
|
|
2037
2037
|
"ui.run.stop.gate.declined": "nicht gestartet — die Bedingung „{name}“: {reason}",
|
|
2038
|
-
"ui.run.gate.
|
|
2039
|
-
"ui.run.gate.
|
|
2038
|
+
"ui.run.gate.said": "· Bedingung {name}{how}: {word}{reason} (Code {status}; .strom/gate.log)",
|
|
2039
|
+
"ui.run.gate.how.each": " (vor jeder Sitzung gefragt)",
|
|
2040
|
+
"ui.run.gate.how.once": " (von Hand gestartet: einmal gefragt)",
|
|
2041
|
+
"ui.run.gate.how.cap": " (Obergrenze: vor jeder Sitzung geprüft, kein „trotzdem starten“ geht darüber hinaus)",
|
|
2040
2042
|
"ui.run.stop.gate.cap": "die Obergrenze der Bedingung „{name}“ – {reason} (eine feste Grenze aus run.gate; kein „trotzdem starten“ geht darüber hinaus)",
|
|
2041
2043
|
"ui.run.cap.finish": "⏳ {session}: das Limit des Agenten bei {used} % ({kind}) – die Sitzung ist gebeten aufzuschreiben, was gefunden wurde, und zu schließen; über der Obergrenze beginnt keine nächste Sitzung",
|
|
2042
2044
|
"ui.run.limit.five_hour": "Fünf-Stunden-Fenster",
|
package/assets/lang/pl.json
CHANGED
|
@@ -614,6 +614,7 @@
|
|
|
614
614
|
"ui.run.denied": " · uprawnienia odmówiły {n}×: {what}",
|
|
615
615
|
"ui.run.refused": " · strom odmówił {n}× (limit {per, plural, one {# zapytania internetowego} few {# zapytań internetowych} many {# zapytań internetowych} other {# zapytań internetowych}} do jednego serwera w sesji albo limit serwera): {what}",
|
|
616
616
|
"ui.run.recover": " · połączenie agenta zostało przerwane ({why}) — jego sesja będzie kontynuowana za {s} s ({n}/{max})",
|
|
617
|
+
"ui.run.missingtools": " · Claude Code nie wczytał {tools} – sesja może się bez tego nie obejść; z ustawieniem agent.addons on działa ze wszystkim, jak dawniej",
|
|
617
618
|
"ui.run.exitOnly": " · {session}: agent zamknął sesję, a potem zakończył się kodem {code} — uznane za ukończone, przebieg trwa dalej",
|
|
618
619
|
"session.user": "zatrzymano przez użytkownika",
|
|
619
620
|
"session.run": "przebieg zatrzymał się, zanim sesja się zakończyła (przerwanie albo wyłączony komputer)",
|
|
@@ -2009,6 +2010,7 @@
|
|
|
2009
2010
|
"ui.run.skip.held": " · {task} pominięte: pracuje nad nim inny agent",
|
|
2010
2011
|
"ui.run.next": "Teraz kolej na te zadania, w kolejności, w jakiej weźmie je agent:",
|
|
2011
2012
|
"ui.run.story": " (opowieść)",
|
|
2013
|
+
"ui.run.ofhistory": " (historia)",
|
|
2012
2014
|
"ui.run.what": "Co ma zrobić agent?",
|
|
2013
2015
|
"ui.run.queue": "Praca według kolejki – liczba zadań do podania",
|
|
2014
2016
|
"ui.run.pick": "Tylko wybrane zadania z listy",
|
|
@@ -2022,21 +2024,21 @@
|
|
|
2022
2024
|
"ui.menu.working.more": "Agenci pracujący teraz samodzielnie: {n}.",
|
|
2023
2025
|
"ui.run.beside": "⚠ Agent już tu pracuje samodzielnie (przebiegi: {n}). Kolejny obok niego weźmie inne zadania – koszty się sumują.",
|
|
2024
2026
|
"ui.run.beside.sure": "Uruchomić kolejnego obok niego?",
|
|
2025
|
-
"ui.run.gate": "· warunek: {name} – pytany przed każdą sesją; może kazać przebiegowi czekać",
|
|
2026
2027
|
"ui.run.gate.wait": "⏸ oczekiwanie do {at} – {reason} (Ctrl-C kończy przebieg)",
|
|
2027
2028
|
"ui.run.asleep.wait": "⏸ oczekiwanie do {at} – pozostałe zadania potrzebują {host}, który teraz nie odpowiada (Ctrl-C kończy przebieg)",
|
|
2028
2029
|
"ui.run.asleep.why": "{host} teraz nie odpowiada",
|
|
2029
2030
|
"ui.run.stop.gate": "warunek „{name}” powiedział dość – {reason}",
|
|
2030
2031
|
"ui.run.stop.gate.error": "warunek „{name}” nie odpowiedział, jak powinien – {reason} (strom gate test)",
|
|
2031
|
-
"ui.run.gate.once": "· warunek: {name} – uruchomienie ręczne: gdy warunek nie jest spełniony, jedno pytanie, czy mimo to zacząć",
|
|
2032
2032
|
"ui.run.gate.anyway": "Warunek „{name}” teraz by nie uruchomił – {reason}. Uruchomić mimo to?",
|
|
2033
2033
|
"ui.run.gate.anyway.here": "Uruchomić mimo to?",
|
|
2034
2034
|
"ui.run.gate.later": "jeszcze nie",
|
|
2035
2035
|
"ui.run.gate.no": "nie",
|
|
2036
2036
|
"ui.run.gate.noanswer": "nie odpowiedział, jak powinien (strom gate test)",
|
|
2037
2037
|
"ui.run.stop.gate.declined": "nie uruchomiono – warunek „{name}”: {reason}",
|
|
2038
|
-
"ui.run.gate.
|
|
2039
|
-
"ui.run.gate.
|
|
2038
|
+
"ui.run.gate.said": "· warunek {name}{how}: {word}{reason} (kod {status}; .strom/gate.log)",
|
|
2039
|
+
"ui.run.gate.how.each": " (pytany przed każdą sesją)",
|
|
2040
|
+
"ui.run.gate.how.once": " (uruchomienie ręczne: pytany raz)",
|
|
2041
|
+
"ui.run.gate.how.cap": " (pułap: sprawdzany przed każdą sesją, żadne „mimo to zacząć” go nie przekroczy)",
|
|
2040
2042
|
"ui.run.stop.gate.cap": "pułap warunku „{name}” – {reason} (sztywna granica z run.gate; „mimo to zacząć” jej nie przekroczy)",
|
|
2041
2043
|
"ui.run.cap.finish": "⏳ {session}: limit agenta na {used} % ({kind}) – sesja dostała prośbę o zapisanie, co znalazła, i zakończenie; po przekroczeniu pułapu kolejna sesja nie ruszy",
|
|
2042
2044
|
"ui.run.limit.five_hour": "okno pięciogodzinne",
|
package/dist/cli/menu.js
CHANGED
|
@@ -27,7 +27,7 @@ import { taskQueue } from "../commands/tasks.js";
|
|
|
27
27
|
import { humanTask } from "../commands/browse.js";
|
|
28
28
|
import { loadGate } from "../core/gate.js";
|
|
29
29
|
import { lacksImages } from "../core/queue.js";
|
|
30
|
-
import { historyOn } from "../core/pastevents.js";
|
|
30
|
+
import { forHistory, historyOn } from "../core/pastevents.js";
|
|
31
31
|
import { othersAtWork } from "../core/session.js";
|
|
32
32
|
import { DEFAULT_RUN_MINUTES } from "../core/config.js";
|
|
33
33
|
import { truncate } from "./format.js";
|
|
@@ -318,10 +318,11 @@ export async function runMenu(ctx, run) {
|
|
|
318
318
|
await pause(lang);
|
|
319
319
|
return;
|
|
320
320
|
}
|
|
321
|
-
// What comes next, as
|
|
321
|
+
// What comes next, as strom run takes it (commands/session.ts): a story now and then, the tasks of history by
|
|
322
|
+
// their pace (the places to map before the research), without what others hold.
|
|
322
323
|
const fresh = Tree.open(root, ctx.env);
|
|
323
324
|
const held = othersAtWork(fresh, fresh.env).tasks;
|
|
324
|
-
const queue = taskQueue(fresh, { strategy: ctx.settings.strategy(fresh.config), storyTurn: true }).filter((x) => !held.has(x.id));
|
|
325
|
+
const queue = taskQueue(fresh, { strategy: ctx.settings.strategy(fresh.config), storyTurn: true, history: true }).filter((x) => !held.has(x.id));
|
|
325
326
|
const shown = queue.slice(0, RUN_LIST);
|
|
326
327
|
// The tasks of history alone, in their order whatever its pace (strom run --history): only while it is on.
|
|
327
328
|
const history = historyOn(fresh, ctx.settings) ? taskQueue(fresh, { strategy: ctx.settings.strategy(fresh.config), history: "only" }).filter((x) => !held.has(x.id)) : [];
|
|
@@ -336,7 +337,7 @@ export async function runMenu(ctx, run) {
|
|
|
336
337
|
if (shown.length) {
|
|
337
338
|
out(t("ui.run.next"));
|
|
338
339
|
for (const [k, x] of shown.entries())
|
|
339
|
-
out(` ${String(k + 1).padStart(2)}. ${truncate(humanTask(fresh, x.what, lang), 100)}${forStory(x) ? t("ui.run.story") : ""}${lacksImages(fresh, x) ? t("ui.plan.images") : ""}`);
|
|
340
|
+
out(` ${String(k + 1).padStart(2)}. ${truncate(humanTask(fresh, x.what, lang), 100)}${forStory(x) ? t("ui.run.story") : forHistory(x) ? t("ui.run.ofhistory") : ""}${lacksImages(fresh, x) ? t("ui.plan.images") : ""}`);
|
|
340
341
|
if (queue.length > shown.length)
|
|
341
342
|
out(` ${t("ui.plan.more", { n: queue.length - shown.length })}`);
|
|
342
343
|
}
|
package/dist/cli/ui.js
CHANGED
|
@@ -591,6 +591,7 @@ export const UI = {
|
|
|
591
591
|
"ui.run.denied": " · permissions refused {n}×: {what}",
|
|
592
592
|
"ui.run.refused": " · strom refused {n}× (its limit of {per, plural, one {# web request} other {# web requests}} to one server in a session, or the server's own): {what}",
|
|
593
593
|
"ui.run.recover": " · the agent's connection failed ({why}) — its session goes on in {s} s ({n}/{max})",
|
|
594
|
+
"ui.run.missingtools": " · Claude Code did not load {tools} — the session may not manage without; with the setting agent.addons on it runs with everything, as before",
|
|
594
595
|
"ui.run.exitOnly": " · {session}: the agent closed the session, then ended with exit code {code} — taken as done, the run goes on",
|
|
595
596
|
"ui.tree.created": "✓ The family tree \"{name}\" is ready: {dir}",
|
|
596
597
|
"ui.chat.trust": "The first time, Claude Code asks whether this folder is trusted. It is the family tree's folder, made by strom — confirm with \"Yes, proceed\".",
|
|
@@ -1991,6 +1992,7 @@ export const UI = {
|
|
|
1991
1992
|
"ui.run.skip.held": " · {task} left out: another agent is working on it",
|
|
1992
1993
|
"ui.run.next": "Next in the queue, in the order the agent takes them:",
|
|
1993
1994
|
"ui.run.story": " (a story)",
|
|
1995
|
+
"ui.run.ofhistory": " (history)",
|
|
1994
1996
|
"ui.run.what": "What should the agent do?",
|
|
1995
1997
|
"ui.run.queue": "Work through the queue in this order – as many as chosen",
|
|
1996
1998
|
"ui.run.pick": "Only the tasks picked from the list",
|
|
@@ -2005,21 +2007,21 @@ export const UI = {
|
|
|
2005
2007
|
"ui.run.beside": "⚠ An agent is already working on its own here (runs: {n}). Another one beside it takes other tasks — the costs add up.",
|
|
2006
2008
|
"ui.run.beside.sure": "Start another one beside it?",
|
|
2007
2009
|
"ui.run.others": "⚠ Another run works in this family tree already (since {since}): this one takes other tasks — the costs add up.",
|
|
2008
|
-
"ui.run.gate": "· condition: {name} — asked before each session; it may make the run wait",
|
|
2009
2010
|
"ui.run.gate.wait": "⏸ waiting until {at} — {reason} (Ctrl-C ends the run)",
|
|
2010
2011
|
"ui.run.asleep.wait": "⏸ waiting until {at} — the tasks left need {host}, which is not answering now (Ctrl-C ends the run)",
|
|
2011
2012
|
"ui.run.asleep.why": "{host} is not answering now",
|
|
2012
2013
|
"ui.run.stop.gate": "the condition “{name}” said stop — {reason}",
|
|
2013
2014
|
"ui.run.stop.gate.error": "the condition “{name}” gave no proper answer — {reason} (strom gate test)",
|
|
2014
|
-
"ui.run.gate.once": "· condition: {name} — a run started by hand: when the condition is not met, one question whether to start anyway",
|
|
2015
2015
|
"ui.run.gate.anyway": "The condition “{name}” would not start now — {reason}. Start anyway?",
|
|
2016
2016
|
"ui.run.gate.anyway.here": "Start anyway?",
|
|
2017
2017
|
"ui.run.gate.later": "not yet",
|
|
2018
2018
|
"ui.run.gate.no": "no",
|
|
2019
2019
|
"ui.run.gate.noanswer": "no proper answer (strom gate test)",
|
|
2020
2020
|
"ui.run.stop.gate.declined": "not started — the condition “{name}”: {reason}",
|
|
2021
|
-
"ui.run.gate.
|
|
2022
|
-
"ui.run.gate.
|
|
2021
|
+
"ui.run.gate.said": "· condition {name}{how}: {word}{reason} (exit {status}; .strom/gate.log)",
|
|
2022
|
+
"ui.run.gate.how.each": " (asked before each session)",
|
|
2023
|
+
"ui.run.gate.how.once": " (a run started by hand: asked once)",
|
|
2024
|
+
"ui.run.gate.how.cap": " (a cap: checked before each session, no “start anyway” goes past it)",
|
|
2023
2025
|
"ui.run.stop.gate.cap": "the cap of the condition “{name}” — {reason} (a hard stop set in run.gate; no “start anyway” goes past it)",
|
|
2024
2026
|
"ui.run.cap.finish": "⏳ {session}: the agent's limit at {used} % ({kind}) — the session is asked to write down what it found and close; past the cap no next session starts",
|
|
2025
2027
|
"ui.run.limit.five_hour": "five-hour window",
|
package/dist/commands/session.js
CHANGED
|
@@ -896,8 +896,9 @@ register(updatedDuringRun({
|
|
|
896
896
|
// --task) are their choice: the gate is asked once, and when it would not start, the user decides.
|
|
897
897
|
const gateHolds = Boolean(opts.loop || until);
|
|
898
898
|
let gateAnswered = false;
|
|
899
|
-
|
|
900
|
-
|
|
899
|
+
// how the gate is asked (before each session, once, its cap) is said in its first answer's line, never a line of its own
|
|
900
|
+
let gateTold = false;
|
|
901
|
+
let capTold = false;
|
|
901
902
|
// Claude Code of a folder said outright (CLAUDE_CONFIG_DIR, agent.claudeConfigDir) not logged in there: no session
|
|
902
903
|
// would work — said before the first one, with how to log in (found 2026-11-03)
|
|
903
904
|
const loggedOut = runnerId === "claude" && claudeConfigSet(runEnv) !== undefined && claudeLoggedIn(runEnv, runner.command) === false;
|
|
@@ -1002,10 +1003,14 @@ register(updatedDuringRun({
|
|
|
1002
1003
|
const name = gate.manifest.title ?? gate.name;
|
|
1003
1004
|
// what it answered, in one line (a wait the run keeps to says it in its own line below)
|
|
1004
1005
|
const waits = gateHolds && said.verdict === "wait" && !said.hard && !(until && Date.now() + said.waitMs > until);
|
|
1005
|
-
if (!waits)
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
out(
|
|
1006
|
+
if (!waits) {
|
|
1007
|
+
// one line: what it answered, and the first time how it is asked (a cap: when it is first said)
|
|
1008
|
+
const how = said.watch && !capTold ? "cap" : !gateTold ? (gateHolds ? "each" : "once") : undefined;
|
|
1009
|
+
out(gateSaid(lang, name, said, how));
|
|
1010
|
+
gateTold = true;
|
|
1011
|
+
if (said.watch)
|
|
1012
|
+
capTold = true;
|
|
1013
|
+
}
|
|
1009
1014
|
watch = said.watch;
|
|
1010
1015
|
if (said.hard && said.verdict !== "go") {
|
|
1011
1016
|
noted("stop");
|
|
@@ -1163,6 +1168,8 @@ register(updatedDuringRun({
|
|
|
1163
1168
|
onProgress: (l) => out(` · ${l}`),
|
|
1164
1169
|
// its connection failed on the way (a passing network error): its session resumed after a wait
|
|
1165
1170
|
onRecover: (r) => out(ui(lang, "ui.run.recover", { why: r.why, s: Math.round(r.waitMs / 1000), n: r.n, max: r.max })),
|
|
1171
|
+
// a tool it asked for and the agent did not load: said in the research language
|
|
1172
|
+
onMissingTools: (tools) => out(ui(lang, "ui.run.missingtools", { tools: tools.join(", ") })),
|
|
1166
1173
|
// its use as it says it, per request where it can: the measure of the reading of scans (core/metrics.ts)
|
|
1167
1174
|
...usageOpt(tree, session.id, {
|
|
1168
1175
|
agent: runnerId,
|
|
@@ -1413,11 +1420,11 @@ async function runGate(ctx, opts) {
|
|
|
1413
1420
|
}
|
|
1414
1421
|
/** Why the gate would not start, for the user: its own words, else what it answered. */
|
|
1415
1422
|
/** What the gate answered, in one line of the run's output (the research language): its word, why, its exit status. */
|
|
1416
|
-
function gateSaid(lang, name, said) {
|
|
1423
|
+
function gateSaid(lang, name, said, how) {
|
|
1417
1424
|
const word = said.verdict === "wait"
|
|
1418
1425
|
? ui(lang, "ui.gate.test.wait", { at: new Date(Date.now() + said.waitMs).toLocaleString(lang, { weekday: "short", hour: "2-digit", minute: "2-digit" }) })
|
|
1419
1426
|
: ui(lang, said.verdict === "go" ? "ui.gate.test.go" : said.verdict === "stop" ? "ui.gate.test.stop" : "ui.run.gate.noanswer");
|
|
1420
|
-
return ui(lang, "ui.run.gate.said", { name, word, reason: said.reason ? ` — ${said.reason}` : "", status: said.status === undefined || said.status === null ? "–" : String(said.status) });
|
|
1427
|
+
return ui(lang, "ui.run.gate.said", { name, how: how ? ui(lang, `ui.run.gate.how.${how}`) : "", word, reason: said.reason ? ` — ${said.reason}` : "", status: said.status === undefined || said.status === null ? "–" : String(said.status) });
|
|
1421
1428
|
}
|
|
1422
1429
|
function gateReason(said, lang) {
|
|
1423
1430
|
return said.reason ?? ui(lang, said.verdict === "error" ? "ui.run.gate.noanswer" : said.verdict === "wait" ? "ui.run.gate.later" : "ui.run.gate.no");
|
package/dist/core/live.js
CHANGED
|
@@ -12,7 +12,11 @@
|
|
|
12
12
|
// Made once for a state of the research on a thread of its own (core/livestatus.ts) and
|
|
13
13
|
// answered from it while the state lasts. ?parts=1 (feature status.parts): without the parts
|
|
14
14
|
// that weigh (waiting; queue, queueMore, queueCounts; offLine; researches), with parts {name:
|
|
15
|
-
// rev} instead — the same rev, the same part.
|
|
15
|
+
// rev} instead — the same rev, the same part. Each of working (who is at work; the event
|
|
16
|
+
// working too): the place record (L…) of the book the agent examines, when the research knows
|
|
17
|
+
// it (place, core/workplace.ts; none: not known) — feature working.place; work on a family
|
|
18
|
+
// (a couple's story): the family (family F…) and its husband, else wife, as the person —
|
|
19
|
+
// feature working.family.
|
|
16
20
|
// GET <token>/status/<part> one of those parts: {part, rev, head, …its fields as /status carries them}; 404
|
|
17
21
|
// status.part for another name.
|
|
18
22
|
// A queue item off the lines of a research with several (core/offline.ts) says offLine:
|
|
@@ -299,6 +303,7 @@
|
|
|
299
303
|
// new secret. Nothing is replaced on a timer.
|
|
300
304
|
import { browserState, treeBrowserArchives } from "./browserhelp.js";
|
|
301
305
|
import { opsLogsOf } from "./opslog.js";
|
|
306
|
+
import { placeOfWork } from "./workplace.js";
|
|
302
307
|
import { notDownloaded } from "./integrity.js";
|
|
303
308
|
import fs from "node:fs";
|
|
304
309
|
import os from "node:os";
|
|
@@ -1122,7 +1127,7 @@ function idsOf(applied, known) {
|
|
|
1122
1127
|
return Object.keys(ids.persons).length || Object.keys(ids.sources).length ? { ids } : {};
|
|
1123
1128
|
}
|
|
1124
1129
|
/** What the bridge does that an app may ask about (each added once, never taken away). */
|
|
1125
|
-
export const BRIDGE_FEATURES = ["sync.again", "sync.undoneSince", "sync.takenBack", "sync.conflictEdit", "sync.since", "sync.ids", "family.noCouple", "family.alone", "adopt.transfer", "adopt.empty", "material.list", "person.titles", "media.codes", "hypothesis.links", "status.recent", "spend.readers", "hypothesis.intree", "archive.permission", "task.check", "waiting.groups", "waiting.sent", "waiting.note", "batch.kept", "live.end", "whats.new", "terminal.choice", "person.marriedSurname", "phone", "read.now", "read.sync", "excerpt.get", "log.sources", "material.assign", "material.thumb", "seal.foreign", "tree.state", "disk.full", "tree.notDownloaded", "sync.removed", "tree.kind", "experiments", "experiments.off", "experiments.link", "experiments.split", "history.events", "history.hide", "experiments.pace", "history.first", "history.regions", "history.hide.all", "history.skip", "history.map", "history.delete", "history.delete.restore", "stories.history", "history.place", "surnames.suggest", "surnames.read", "lineage.read", "duplicates.judge", "quality.dismiss", "quality.read", "person.primary", "fixes.list", "fixes.towns", "history.back", "places.identify", "places.answer", "places.undo", "tasks.offLine", "status.busy", "history.kinds", "history.align", "places.nameKinds", "directions.edit", "directions.order", "directions.found", "directions.people", "offLine.branches", "queue.own", "story.sources", "queue.page", "status.parts", "waiting.answer", "browser.state"];
|
|
1130
|
+
export const BRIDGE_FEATURES = ["sync.again", "sync.undoneSince", "sync.takenBack", "sync.conflictEdit", "sync.since", "sync.ids", "family.noCouple", "family.alone", "adopt.transfer", "adopt.empty", "material.list", "person.titles", "media.codes", "hypothesis.links", "status.recent", "spend.readers", "hypothesis.intree", "archive.permission", "task.check", "waiting.groups", "waiting.sent", "waiting.note", "batch.kept", "live.end", "whats.new", "terminal.choice", "person.marriedSurname", "phone", "read.now", "read.sync", "excerpt.get", "log.sources", "material.assign", "material.thumb", "seal.foreign", "tree.state", "disk.full", "tree.notDownloaded", "sync.removed", "tree.kind", "experiments", "experiments.off", "experiments.link", "experiments.split", "history.events", "history.hide", "experiments.pace", "history.first", "history.regions", "history.hide.all", "history.skip", "history.map", "history.delete", "history.delete.restore", "stories.history", "history.place", "surnames.suggest", "surnames.read", "lineage.read", "duplicates.judge", "quality.dismiss", "quality.read", "person.primary", "fixes.list", "fixes.towns", "history.back", "places.identify", "places.answer", "places.undo", "tasks.offLine", "status.busy", "history.kinds", "history.align", "places.nameKinds", "directions.edit", "directions.order", "directions.found", "directions.people", "offLine.branches", "queue.own", "story.sources", "queue.page", "status.parts", "waiting.answer", "browser.state", "working.place", "working.family"];
|
|
1126
1131
|
/** /status busy: how many sessions and runs work now. */
|
|
1127
1132
|
function busyOf(tree) {
|
|
1128
1133
|
const b = busyIn(tree);
|
|
@@ -1337,33 +1342,62 @@ export function whoAtWork(label, lang) {
|
|
|
1337
1342
|
}
|
|
1338
1343
|
/**
|
|
1339
1344
|
* The person an agent works on, for the app to follow it in the tree: the first person its task is about (a marriage
|
|
1340
|
-
* names both, the one it asks about first), else the last one its session wrote about.
|
|
1345
|
+
* names both, the one it asks about first), else the last one its session wrote about. Work on a family (a couple's
|
|
1346
|
+
* story, its marriage — subject F…, or a record of it written last): its first partner as the person, the husband, else
|
|
1347
|
+
* the wife (an app reading only `person` follows the couple so), and the family itself (feature working.family).
|
|
1341
1348
|
*/
|
|
1342
|
-
function workedOn(
|
|
1343
|
-
const
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1349
|
+
function workedOn(tree, ops, task) {
|
|
1350
|
+
const of = (id) => {
|
|
1351
|
+
if (/^P\d{1,7}$/.test(id))
|
|
1352
|
+
return tree.get(id) !== undefined ? { person: id } : undefined;
|
|
1353
|
+
if (!/^F\d{1,7}$/.test(id))
|
|
1354
|
+
return undefined;
|
|
1355
|
+
const fam = tree.get(id);
|
|
1356
|
+
if (!fam)
|
|
1357
|
+
return undefined;
|
|
1358
|
+
const partners = fam.partners.filter((p) => tree.get(p) !== undefined);
|
|
1359
|
+
const husband = partners.find((p) => tree.get(p)?.sex === "M") ?? partners.find((p) => p === fam.husb) ?? partners[0];
|
|
1360
|
+
return { ...(husband ? { person: husband } : {}), family: id };
|
|
1361
|
+
};
|
|
1362
|
+
for (const id of task?.subject ?? []) {
|
|
1363
|
+
const found = of(id);
|
|
1364
|
+
if (found)
|
|
1365
|
+
return found;
|
|
1366
|
+
}
|
|
1367
|
+
// a record written: its last person, else its family
|
|
1368
|
+
for (let i = ops.length - 1; i >= 0; i--) {
|
|
1369
|
+
const targets = ops[i].targets ?? [];
|
|
1370
|
+
const person = targets.findLast((id) => /^P\d{1,7}$/.test(id) && tree.get(id) !== undefined);
|
|
1371
|
+
if (person)
|
|
1372
|
+
return { person };
|
|
1373
|
+
for (const id of [...targets].reverse()) {
|
|
1374
|
+
const found = of(id);
|
|
1375
|
+
if (found)
|
|
1376
|
+
return found;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
return {};
|
|
1380
|
+
}
|
|
1381
|
+
/** What a session wrote, in its order (a line being written, or a log not readable: left out). */
|
|
1382
|
+
function sessionOps(root, s) {
|
|
1347
1383
|
let lines = [];
|
|
1348
1384
|
try {
|
|
1349
1385
|
lines = opsLogsOf(path.join(root, "data"), s.id).flatMap((file) => fs.readFileSync(file, "utf8").split("\n"));
|
|
1350
1386
|
}
|
|
1351
1387
|
catch {
|
|
1352
|
-
return
|
|
1388
|
+
return [];
|
|
1353
1389
|
}
|
|
1354
|
-
|
|
1355
|
-
|
|
1390
|
+
const ops = [];
|
|
1391
|
+
for (const line of lines) {
|
|
1356
1392
|
try {
|
|
1357
|
-
|
|
1393
|
+
if (line.trim())
|
|
1394
|
+
ops.push(JSON.parse(line));
|
|
1358
1395
|
}
|
|
1359
1396
|
catch {
|
|
1360
|
-
|
|
1397
|
+
// a line being written
|
|
1361
1398
|
}
|
|
1362
|
-
const person = (op.targets ?? []).findLast(known);
|
|
1363
|
-
if (person)
|
|
1364
|
-
return { person };
|
|
1365
1399
|
}
|
|
1366
|
-
return
|
|
1400
|
+
return ops;
|
|
1367
1401
|
}
|
|
1368
1402
|
/** Who is at work now, on which task (an agent strom started, and its open session). */
|
|
1369
1403
|
function working(root, tree, all) {
|
|
@@ -1378,11 +1412,16 @@ function working(root, tree, all) {
|
|
|
1378
1412
|
who: whoAtWork(w.label, tree.lang),
|
|
1379
1413
|
since: w.since,
|
|
1380
1414
|
...(w.paused ? { paused: w.paused } : {}),
|
|
1381
|
-
...(s ? { session: s.id, ...(s.task ? { task: task ? taskTitle(tree, task) : s.task } : {}), ...
|
|
1415
|
+
...(s ? { session: s.id, ...(s.task ? { task: task ? taskTitle(tree, task) : s.task } : {}), ...worked(tree, sessionOps(root, s), task) } : {}),
|
|
1382
1416
|
...(research ? { research } : {}),
|
|
1383
1417
|
};
|
|
1384
1418
|
});
|
|
1385
1419
|
}
|
|
1420
|
+
/** The person and the place (L…, core/workplace.ts) an agent works on, from what its session wrote and its task. */
|
|
1421
|
+
function worked(tree, ops, task) {
|
|
1422
|
+
const place = placeOfWork(tree, ops, task);
|
|
1423
|
+
return { ...workedOn(tree, ops, task), ...(place ? { place } : {}) };
|
|
1424
|
+
}
|
|
1386
1425
|
/** The direction a session worked on: its own, else its task's. */
|
|
1387
1426
|
function sessionResearch(tree, s, all) {
|
|
1388
1427
|
if (s.research)
|
package/dist/core/tree.js
CHANGED
|
@@ -31,7 +31,7 @@ export const TREE_FILE = "strom.json";
|
|
|
31
31
|
export const SEAL_FOREIGN = "seal.foreign";
|
|
32
32
|
// between releases the candidate being made (a bridge run from the sources says what it is: the Strom app goes by it);
|
|
33
33
|
// at a release the release's own (package.json)
|
|
34
|
-
export const VERSION = "1.28.0-beta.
|
|
34
|
+
export const VERSION = "1.28.0-beta.3";
|
|
35
35
|
const GITIGNORE = `# Strom Research — local state and large files are not versioned
|
|
36
36
|
.strom/
|
|
37
37
|
/media/
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Where an agent works now, for the Strom app's map while it follows the work (the bridge's working[].place, feature
|
|
2
|
+
// working.place): the place record (L…) of the book the agent examines — the parish or the village of its records,
|
|
3
|
+
// never an archive. Only what the agent wrote through strom tells it, nothing guessed: the newest record of its work the
|
|
4
|
+
// session wrote (an image fetched, a source, a search, a book) decides alone — its book's place, none when its book is
|
|
5
|
+
// unsure (a search in several books of several places, a source of no book: the web); before any, the books its task
|
|
6
|
+
// names. What it writes of people from a record (a fact, a citation) keeps the place of that record.
|
|
7
|
+
// A book is a place's when the place lists it among its records (strom place jurisdiction --recordset), else when one
|
|
8
|
+
// place record alone bears the name of the first place the book covers. Unsure (no such place, several of one name,
|
|
9
|
+
// the task's books in several places): none — the app shows the person's places then.
|
|
10
|
+
import { foldText } from "./text.js";
|
|
11
|
+
/** The place record (L…) of the book the agent examines now, when the research knows it. */
|
|
12
|
+
export function placeOfWork(tree, ops, task) {
|
|
13
|
+
// the newest record of its work the session wrote decides alone: its book's place, or none — never an older book's
|
|
14
|
+
for (let i = ops.length - 1; i >= 0; i--) {
|
|
15
|
+
const main = ops[i].targets?.[0];
|
|
16
|
+
if (main && /^[BMSQ]\d+$/.test(main))
|
|
17
|
+
return placeOfRecord(tree, main);
|
|
18
|
+
}
|
|
19
|
+
// nothing written yet: the books its task names, when they are all of one place
|
|
20
|
+
return placeOfBooks(tree, (task?.where ?? []).map((w) => w.trim()));
|
|
21
|
+
}
|
|
22
|
+
/** The place of the books named, when they are all of one known place. */
|
|
23
|
+
function placeOfBooks(tree, ids) {
|
|
24
|
+
const books = ids.map((id) => tree.get(id)).filter((b) => b?.type === "recordset" && !b.retracted);
|
|
25
|
+
const places = new Set(books.map((b) => placeOfBook(tree, b)));
|
|
26
|
+
return places.size === 1 ? [...places][0] : undefined;
|
|
27
|
+
}
|
|
28
|
+
/** The place of a record of work: of its book, of the books of a search when all of one place; none when unsure. */
|
|
29
|
+
function placeOfRecord(tree, id) {
|
|
30
|
+
if (/^Q\d+$/.test(id)) {
|
|
31
|
+
const q = tree.get(id);
|
|
32
|
+
return q && !q.retracted ? placeOfBooks(tree, q.recordsets) : undefined;
|
|
33
|
+
}
|
|
34
|
+
const book = bookOf(tree, id);
|
|
35
|
+
return book ? placeOfBook(tree, book) : undefined;
|
|
36
|
+
}
|
|
37
|
+
/** The book a record is of: a book itself, an image of it, a source from it. */
|
|
38
|
+
function bookOf(tree, id) {
|
|
39
|
+
const book = (b) => {
|
|
40
|
+
const r = b ? tree.get(b) : undefined;
|
|
41
|
+
return r?.type === "recordset" && !r.retracted ? r : undefined;
|
|
42
|
+
};
|
|
43
|
+
if (/^B\d+$/.test(id))
|
|
44
|
+
return book(id);
|
|
45
|
+
if (/^M\d+$/.test(id)) {
|
|
46
|
+
const m = tree.get(id);
|
|
47
|
+
return m && !m.retracted ? book(m.recordset) : undefined;
|
|
48
|
+
}
|
|
49
|
+
if (/^S\d+$/.test(id)) {
|
|
50
|
+
const s = tree.get(id);
|
|
51
|
+
if (!s || s.retracted)
|
|
52
|
+
return undefined;
|
|
53
|
+
return book(s.recordset) ?? book((s.media ?? []).map((m) => tree.get(m)?.recordset).find(Boolean));
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
/** The place record of a book: the one listing it among its records, else the one alone of the name of its first place. */
|
|
58
|
+
function placeOfBook(tree, book) {
|
|
59
|
+
const places = tree.list("place").filter((p) => !p.retracted);
|
|
60
|
+
const listing = places.filter((p) => p.jurisdictions.some((j) => (j.recordsets ?? []).includes(book.id)));
|
|
61
|
+
if (listing.length === 1)
|
|
62
|
+
return listing[0].id;
|
|
63
|
+
const first = book.places[0]?.trim();
|
|
64
|
+
if (!first)
|
|
65
|
+
return undefined;
|
|
66
|
+
const name = foldText(first);
|
|
67
|
+
const named = (listing.length ? listing : places).filter((p) => p.names.some((n) => foldText(n.name) === name));
|
|
68
|
+
return named.length === 1 ? named[0].id : undefined;
|
|
69
|
+
}
|
package/dist/runners/claude.js
CHANGED
|
@@ -56,10 +56,17 @@ export function cleanTools(reader, platform = process.platform) {
|
|
|
56
56
|
/**
|
|
57
57
|
* The tools a clean session asked for that Claude Code did not load (its init event's list): a newer Claude Code may
|
|
58
58
|
* have renamed one. The subagent tool is listed as Task; PowerShell only where it is on, Bash's place on Windows.
|
|
59
|
+
* WebFetch: a newer Claude Code (2.1.318, checked 2026-11-05) leaves it out of the session's own tools and reads a page
|
|
60
|
+
* through its web-fetch agent (init `agents`), whose WebFetch goes through the same permissions and hooks — no loss.
|
|
59
61
|
*/
|
|
60
|
-
export function missingTools(asked, loaded) {
|
|
62
|
+
export function missingTools(asked, loaded, agents = []) {
|
|
61
63
|
const has = new Set(loaded);
|
|
62
|
-
|
|
64
|
+
const subagents = has.has("Agent") || has.has("Task");
|
|
65
|
+
return asked.filter((t) => t !== "PowerShell" &&
|
|
66
|
+
!has.has(t) &&
|
|
67
|
+
!(t === "Agent" && has.has("Task")) &&
|
|
68
|
+
!(t === "Bash" && has.has("PowerShell")) &&
|
|
69
|
+
!(t === "WebFetch" && subagents && agents.includes("web-fetch")));
|
|
63
70
|
}
|
|
64
71
|
const LIMIT_KINDS = ["five_hour", "seven_day"];
|
|
65
72
|
/**
|
|
@@ -298,10 +305,13 @@ function attempt(opts, args, input, timeoutMs, sid) {
|
|
|
298
305
|
}
|
|
299
306
|
// a tool strom asked for and Claude Code did not load (renamed in a newer version?): said, the session goes on
|
|
300
307
|
if (msg.type === "system" && msg.subtype === "init" && opts.clean && !opts.interactive && Array.isArray(msg.tools)) {
|
|
301
|
-
const missing = missingTools(cleanTools(opts.reader), msg.tools.map(String));
|
|
308
|
+
const missing = missingTools(cleanTools(opts.reader), msg.tools.map(String), Array.isArray(msg.agents) ? msg.agents.map(String) : []);
|
|
302
309
|
if (missing.length) {
|
|
303
310
|
const said = `Claude Code did not load ${missing.join(", ")} — the session may not manage without; strom config set agent.addons on runs it with everything, as before`;
|
|
304
|
-
opts.
|
|
311
|
+
if (opts.onMissingTools)
|
|
312
|
+
opts.onMissingTools(missing);
|
|
313
|
+
else
|
|
314
|
+
opts.onProgress?.(said);
|
|
305
315
|
log.note(`\n[strom] ${said}\n`);
|
|
306
316
|
}
|
|
307
317
|
}
|