strom-research 1.15.0-beta.5 → 1.15.0-beta.7
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 +50 -0
- package/CHANGELOG.de.md +55 -0
- package/CHANGELOG.md +50 -0
- package/assets/lang/cs.json +1 -0
- package/assets/lang/de.json +1 -0
- package/assets/method/core.md +4 -0
- package/assets/method/reading.md +9 -1
- package/assets/plugins/gates/README.md +13 -3
- package/assets/plugins/gates/claude-usage/gate.json +1 -1
- package/assets/plugins/gates/claude-usage/gate.ts +83 -21
- package/dist/agents/profiles.js +12 -1
- package/dist/brief/brief.js +20 -1
- package/dist/brief/sheet.js +4 -3
- package/dist/cli/commit.js +6 -3
- package/dist/cli/execute.js +41 -15
- package/dist/cli/format.js +11 -0
- package/dist/cli/help.js +9 -1
- package/dist/cli/main.js +7 -3
- package/dist/cli/registry.js +14 -1
- package/dist/cli/ui.js +1 -0
- package/dist/commands/analysis.js +25 -7
- package/dist/commands/batch.js +1 -1
- package/dist/commands/calibrate.js +1 -0
- package/dist/commands/connectors.js +660 -117
- package/dist/commands/guide.js +4 -2
- package/dist/commands/media.js +17 -4
- package/dist/commands/read.js +231 -41
- package/dist/commands/readings.js +99 -8
- package/dist/commands/session.js +1 -2
- package/dist/commands/sources.js +60 -6
- package/dist/commands/story.js +38 -2
- package/dist/core/actions.js +1 -1
- package/dist/core/age.js +114 -18
- package/dist/core/connector.js +14 -2
- package/dist/core/fetching.js +215 -0
- package/dist/core/git.js +10 -4
- package/dist/core/live.js +12 -3
- package/dist/core/media.js +21 -7
- package/dist/core/net.js +86 -0
- package/dist/core/reader.js +30 -15
- package/dist/core/readstats.js +21 -0
- package/dist/core/samebook.js +58 -0
- package/dist/core/terms.js +4 -0
- package/dist/core/tree.js +18 -1
- package/dist/core/views.js +3 -1
- package/dist/core/webgate.js +1 -1
- package/dist/core/whatsnew.js +79 -0
- package/package.json +5 -2
package/CHANGELOG.cs.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Co je nového ve Strom výzkumu
|
|
2
|
+
|
|
3
|
+
[English](CHANGELOG.md) · Čeština · [Deutsch](CHANGELOG.de.md)
|
|
4
|
+
|
|
5
|
+
Změny každé verze ve zkratce. Úplné poznámky a instalační řádky jsou na
|
|
6
|
+
[GitHub Releases](https://github.com/ACiDekCZ/strom-research/releases) (anglicky).
|
|
7
|
+
|
|
8
|
+
## 1.15.0
|
|
9
|
+
|
|
10
|
+
*Patří k aplikaci Strom 3.12.0.*
|
|
11
|
+
|
|
12
|
+
- **Archiv Stromu podle volby, i s AI agentem.** Průvodce nastavením se ptá, zda nové rodokmeny budou výzkumem
|
|
13
|
+
s agentem, nebo jen Archivem Stromu; v nastavení jde volbu změnit pro jeden rodokmen nebo pro nové.
|
|
14
|
+
- **Výzkum čeká na svého agenta.** Rodokmen, jehož AI agent na tomto počítači není, ukládá, co posílá aplikace Strom,
|
|
15
|
+
jako Archiv Stromu. Jakmile je agent nainstalovaný, výzkum pokračuje sám.
|
|
16
|
+
- **Jedna kniha archivu se stahuje jednou.** Kniha, která už ve výzkumu je, se pojmenuje místo nového zápisu
|
|
17
|
+
a stahování, takže archiv nikdy nedostane dvakrát žádost o tytéž snímky.
|
|
18
|
+
- **Rychlejší čtení.** Snímky čte současně pět čtenářů (nastavení `read.parallel`, 1 až 10) a dlouhé stahování
|
|
19
|
+
ukazuje, kolik už je hotovo („40/109 snímků“). Čtenáři začnou už během stahování knihy: snímky se registrují
|
|
20
|
+
po deseti a co nepřišlo, je řečeno přesně; Ctrl-C ponechá, co už přišlo. Archiv dostane stejné žádosti ve stejném
|
|
21
|
+
tempu. Kniha se může stahovat i na pozadí, zatímco agent pracuje dál (`strom fetch --background`), nikdy z archivu,
|
|
22
|
+
který dovoluje jen tempo člověka. Hledání jednoho zápisu může skončit u nálezu (`strom read --until-found`):
|
|
23
|
+
přečtené snímky jsou řečeny přesně a jen ty se počítají jako prohledané.
|
|
24
|
+
- **Rodokmeny z jiných programů.** Soubor GEDCOM uložený se značkou BOM nebo v UTF-16 (tak ho ukládají některé programy
|
|
25
|
+
ve Windows) se čte jako rodokmen; rodokmen jiného výzkumu se převezme jako cizí.
|
|
26
|
+
- **Čistě na jednom počítači.** Živé sledování končí čistě na každém systému, i ve Windows, a aplikace Strom se dozví,
|
|
27
|
+
že skončilo. Jiný strom na stejném počítači (z npm nebo sestavený ze zdrojů) nikdy nepřevezme odkazy aplikace Strom
|
|
28
|
+
ani kanál aktualizací.
|
|
29
|
+
- **Opravy ze skutečných výzkumů.** Denní příděl práce o samotě pustí nový týden hned, v posledních dvou hodinách
|
|
30
|
+
týdne využije, co zbývá, místo čekání přes obnovení, a říká, kdy se týden obnoví. Věk zapsaný zlomkem (½ roku, 1 1/2
|
|
31
|
+
léta, půl roku) se přečte a seznam snímků (`strom read --images 5-19,21-39`) se čte tak, jak je zadaný. Knihu
|
|
32
|
+
stahuje sezení, které ji čte, nikdy předem pro pozdější; `strom fetch --recordset` najde knihu sám; počty a příkazy
|
|
33
|
+
jsou řečeny tak, jak se píšou.
|
|
34
|
+
- **Co je nového.** Po `strom update` a u `strom --version` odkaz na tento přehled v jazyce výzkumu. Aplikace Strom
|
|
35
|
+
ukazuje body nové verze výzkumu ve svém okně „Co je nového“.
|
|
36
|
+
|
|
37
|
+
## 1.14.0
|
|
38
|
+
|
|
39
|
+
*11. 10. 2026 · patří k aplikaci Strom 3.11.0.*
|
|
40
|
+
|
|
41
|
+
- **Podmínky každého archivu.** strom dodržuje, jak daleko každý archiv dovoluje automatický přístup: povoleno,
|
|
42
|
+
omezeně, jen ručně, nebo vůbec. Kde podmínky nejsou jasné, rozhodne jednou člověk. Odmítnutí archiv na den odloží.
|
|
43
|
+
- **Co čeká, po místech.** Věci pro člověka jsou seřazené podle druhu a seskupené podle toho, kde se vyřizují: jeden
|
|
44
|
+
archiv, jeden úřad, rodina, jeden web. Dopis nebo dotaz jde označit jako odeslaný.
|
|
45
|
+
- **Čtení starého písma.** Snímky ve velikosti, jakou každý pohled potřebuje, čtenář snímků na modelu, který si člověk
|
|
46
|
+
zvolil, a čtení vyladěné na vlastních doložených záznamech výzkumu.
|
|
47
|
+
- **S aplikací Strom 3.11.0.** Rozpor mezi úpravou v aplikaci a záznamem se rozhoduje v aplikaci; hypotézy ukazují, co
|
|
48
|
+
by která varianta spojila.
|
|
49
|
+
- **Menší podklady pro agenta, které vědí víc**, a míra uvažování je volbou člověka (`model.effort`).
|
|
50
|
+
- **`strom grep`** prohledává podklady, poznámky a výstupy výzkumu, i bez ohledu na diakritiku.
|
package/CHANGELOG.de.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Was ist neu in Strom Ahnenforschung
|
|
2
|
+
|
|
3
|
+
[English](CHANGELOG.md) · [Čeština](CHANGELOG.cs.md) · Deutsch
|
|
4
|
+
|
|
5
|
+
Die Änderungen jeder Version in Kürze. Die vollständigen Hinweise und die Installationszeilen stehen bei
|
|
6
|
+
[GitHub Releases](https://github.com/ACiDekCZ/strom-research/releases) (auf Englisch).
|
|
7
|
+
|
|
8
|
+
## 1.15.0
|
|
9
|
+
|
|
10
|
+
*Gehört zur Strom-App 3.12.0.*
|
|
11
|
+
|
|
12
|
+
- **Ein Strom-Archiv nach Wahl, auch mit einem KI-Agenten.** Die Einrichtung fragt, ob neue Stammbäume Forschungen mit
|
|
13
|
+
dem Agenten sind oder nur ein Strom-Archiv; in den Einstellungen lässt sich das für einen Stammbaum oder für die
|
|
14
|
+
neuen ändern.
|
|
15
|
+
- **Eine Forschung wartet auf ihren Agenten.** Ein Stammbaum, dessen KI-Agent nicht auf diesem Computer ist, speichert,
|
|
16
|
+
was die Strom-App sendet, wie ein Strom-Archiv. Sobald der Agent installiert ist, geht die Forschung von selbst weiter.
|
|
17
|
+
- **Ein Buch eines Archivs, einmal geladen.** Ein Buch, das schon in der Forschung ist, wird genannt, statt neu
|
|
18
|
+
eingetragen und wieder geladen zu werden – ein Archiv wird nie zweimal um dieselben Bilder gebeten.
|
|
19
|
+
- **Schneller lesen.** Fünf Leser lesen die Scans gleichzeitig (die Einstellung `read.parallel`, 1 bis 10), und ein
|
|
20
|
+
langer Download zeigt, wie weit er ist („40/109 Bilder“). Die Leser beginnen schon, während ein Buch lädt: seine
|
|
21
|
+
Bilder werden zu zehnt registriert, und was nicht kam, wird genau gesagt; Strg+C behält, was schon kam. Ein Archiv
|
|
22
|
+
bekommt dieselben Anfragen im selben Tempo wie bisher. Ein Buch kann auch im Hintergrund laden, während der Agent
|
|
23
|
+
weiterarbeitet (`strom fetch --background`), nie aus einem Archiv, das nur das Tempo eines Menschen erlaubt. Die
|
|
24
|
+
Suche nach einem Eintrag kann beim Fund enden (`strom read --until-found`): die gelesenen Bilder werden genau gesagt,
|
|
25
|
+
und nur sie gelten als durchsucht.
|
|
26
|
+
- **Stammbäume aus anderen Programmen.** Eine GEDCOM-Datei mit Byte-Order-Mark oder in UTF-16 (so speichern sie manche
|
|
27
|
+
Windows-Programme) wird als Stammbaum gelesen; der Stammbaum einer anderen Forschung wird als fremder übernommen.
|
|
28
|
+
- **Sauber auf einem Computer.** Die Live-Ansicht endet sauber auf jedem System, auch unter Windows, und die Strom-App
|
|
29
|
+
erfährt, dass sie endete. Ein anderer strom auf demselben Computer (aus npm oder aus den Quellen gebaut) übernimmt nie
|
|
30
|
+
die Links der Strom-App oder den Update-Kanal.
|
|
31
|
+
- **Korrekturen aus echten Forschungen.** Die tägliche Ration des Alleinarbeitens lässt eine neue Woche sofort
|
|
32
|
+
beginnen, nutzt in den letzten zwei Stunden der Woche, was übrig ist, statt über die Erneuerung hinaus zu warten,
|
|
33
|
+
und sagt, wann sich die Woche erneuert. Ein Alter als Bruch (½ Jahr, 1 1/2 Jahre, ein halbes Jahr) wird gelesen, und
|
|
34
|
+
eine Liste von Bildern (`strom read --images 5-19,21-39`) wird so gelesen, wie sie angegeben ist. Ein Buch lädt die
|
|
35
|
+
Sitzung, die es liest, nie im Voraus für eine spätere; `strom fetch --recordset` findet das Buch selbst; Zahlen und
|
|
36
|
+
Befehle werden so genannt, wie sie geschrieben werden.
|
|
37
|
+
- **Was ist neu.** Nach `strom update` und bei `strom --version` ein Link zu dieser Übersicht in der Sprache der
|
|
38
|
+
Forschung. Die Strom-App zeigt die Punkte einer neuen Forschungsversion in ihrem Fenster „Was ist neu“.
|
|
39
|
+
|
|
40
|
+
## 1.14.0
|
|
41
|
+
|
|
42
|
+
*11.10.2026 · gehört zur Strom-App 3.11.0.*
|
|
43
|
+
|
|
44
|
+
- **Die Bedingungen jedes Archivs.** strom hält sich daran, wie weit jedes Archiv automatischen Zugriff erlaubt:
|
|
45
|
+
erlaubt, eingeschränkt, nur von Hand oder gar nicht. Wo die Bedingungen unklar sind, entscheidet einmal der Mensch.
|
|
46
|
+
Eine Ablehnung pausiert ein Archiv für einen Tag.
|
|
47
|
+
- **Was wartet, nach Orten.** Die Dinge für den Menschen sind nach Art sortiert und danach gruppiert, wo sie erledigt
|
|
48
|
+
werden: ein Archiv, ein Amt, die Familie, eine Website. Ein Brief oder eine Frage lässt sich als verschickt markieren.
|
|
49
|
+
- **Alte Handschrift lesen.** Scans in der Größe, die jede Ansicht braucht, ein Leser der Scans auf dem Modell, das der
|
|
50
|
+
Mensch gewählt hat, und das Lesen abgestimmt auf die eigenen belegten Einträge der Forschung.
|
|
51
|
+
- **Mit der Strom-App 3.11.0.** Ein Widerspruch zwischen einer Änderung in der App und einem Eintrag wird in der App
|
|
52
|
+
entschieden; Hypothesen zeigen, was jede Variante verbinden würde.
|
|
53
|
+
- **Kleinere Unterlagen für den Agenten, die mehr wissen**, und der Denkaufwand ist die Wahl des Menschen
|
|
54
|
+
(`model.effort`).
|
|
55
|
+
- **`strom grep`** durchsucht die Unterlagen, Notizen und Ausgaben der Forschung, auch über Akzente hinweg.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# What's new in Strom Research
|
|
2
|
+
|
|
3
|
+
English · [Čeština](CHANGELOG.cs.md) · [Deutsch](CHANGELOG.de.md)
|
|
4
|
+
|
|
5
|
+
The changes of each version in short. The full notes and the install lines are on
|
|
6
|
+
[GitHub Releases](https://github.com/ACiDekCZ/strom-research/releases).
|
|
7
|
+
|
|
8
|
+
## 1.15.0
|
|
9
|
+
|
|
10
|
+
*Goes with the Strom app 3.12.0.*
|
|
11
|
+
|
|
12
|
+
- **A Strom archive by choice, with an AI agent too.** The setup asks whether new family trees are researches with the
|
|
13
|
+
agent or only a Strom archive; the settings change it for one family tree or for the new ones.
|
|
14
|
+
- **A research waiting for its agent.** A family tree whose AI agent is not on this computer keeps what the Strom app
|
|
15
|
+
sends, as a Strom archive does. Once the agent is installed, the research goes on by itself.
|
|
16
|
+
- **One book of an archive, fetched once.** A book already in the research is named instead of being registered and
|
|
17
|
+
fetched again, so an archive is never asked twice for the same images.
|
|
18
|
+
- **Faster reading.** Five readers read the scans at the same time (the setting `read.parallel`, 1 to 10), and a long
|
|
19
|
+
download says how far it is ("40/109 images"). The readers begin while a book is still downloading: its images are
|
|
20
|
+
registered ten at a time, and what did not come is said exactly; Ctrl-C keeps what came. An archive gets the same
|
|
21
|
+
requests at the same pace. A book can also be fetched in the background while the agent works on (`strom fetch
|
|
22
|
+
--background`), never from an archive that allows only a person's pace. A search for one entry can stop at the find
|
|
23
|
+
(`strom read --until-found`): the images read are said exactly, and only they count as searched.
|
|
24
|
+
- **Family trees from other programs.** A GEDCOM file saved with a byte order mark or in UTF-16 (as some Windows
|
|
25
|
+
programs save it) is read as a family tree; a family tree of another research is taken in as a foreign one.
|
|
26
|
+
- **Cleaner on one computer.** The live view ends cleanly on every system, Windows too, and the Strom app learns that
|
|
27
|
+
it ended. Another strom on the same computer (from npm, or built from the sources) never takes over the links of the
|
|
28
|
+
Strom app or the update channel.
|
|
29
|
+
- **Fixes from real researches.** The daily ration of working alone lets a new week begin at once, uses what is left
|
|
30
|
+
in the week's last two hours instead of waiting past the reset, and says when the week resets. Ages written as
|
|
31
|
+
fractions (½ roku, 1 1/2 years, ein halbes Jahr) are read, and a list of images (`strom read --images 5-19,21-39`)
|
|
32
|
+
is read as given. A book is fetched by the session that reads it, never ahead for a later one;
|
|
33
|
+
`strom fetch --recordset` finds the book itself; counts and commands are said as typed.
|
|
34
|
+
- **What's new.** After `strom update` and with `strom --version`, a link to this list in the research language. The
|
|
35
|
+
Strom app shows the points of a new research version in its own “What's new” window.
|
|
36
|
+
|
|
37
|
+
## 1.14.0
|
|
38
|
+
|
|
39
|
+
*2026-10-11 · goes with the Strom app 3.11.0.*
|
|
40
|
+
|
|
41
|
+
- **Each archive's terms.** strom keeps to how far each archive allows automated access: allowed, restricted, by hand
|
|
42
|
+
only, or not at all. Where the terms are unclear, the person decides once. A refusal pauses an archive for a day.
|
|
43
|
+
- **What waits, in places.** Things for the person are sorted by kind and grouped by where they are done: one archive,
|
|
44
|
+
one office, the family, one site. A letter or a question can be marked as sent.
|
|
45
|
+
- **Reading old handwriting.** Scans at the size each view needs, a reader of scans on the person's model, and the
|
|
46
|
+
reading tuned on the research's own proven records.
|
|
47
|
+
- **With the Strom app 3.11.0.** A conflict between an edit in the app and a record is decided in the app; hypotheses
|
|
48
|
+
show what each variant would connect.
|
|
49
|
+
- **A smaller brief that knows more**, and the reasoning effort is the person's choice (`model.effort`).
|
|
50
|
+
- **`strom grep`** searches the research's inputs, notes and output, through accents too.
|
package/assets/lang/cs.json
CHANGED
|
@@ -250,6 +250,7 @@
|
|
|
250
250
|
"ui.tune.book.weak": "zápory na slabých skenech {n} z {of}",
|
|
251
251
|
"ui.tune.book.requests": "požadavky {n}",
|
|
252
252
|
"ui.tune.book.unread": "staženo a nepřečteno {n} z {of}",
|
|
253
|
+
"ui.tune.book.background": "na pozadí: nepřečteno {n} z {of}",
|
|
253
254
|
"ui.tune.hosts": "Archivy:",
|
|
254
255
|
"ui.tune.host": " {host}: sezení {sessions} · požadavky {requests} ({perSession} na sezení, {perImage} na snímek) · čekání {wait} min · limit vyčerpán {later}×",
|
|
255
256
|
"ui.tune.web": "Webové nástroje agenta:",
|
package/assets/lang/de.json
CHANGED
|
@@ -250,6 +250,7 @@
|
|
|
250
250
|
"ui.tune.book.weak": "Negativbefunde auf schwachen Scans {n} von {of}",
|
|
251
251
|
"ui.tune.book.requests": "Anfragen {n}",
|
|
252
252
|
"ui.tune.book.unread": "geladen und nie gelesen {n} von {of}",
|
|
253
|
+
"ui.tune.book.background": "im Hintergrund: nie gelesen {n} von {of}",
|
|
253
254
|
"ui.tune.hosts": "Archive:",
|
|
254
255
|
"ui.tune.host": " {host}: Sitzungen {sessions} · Anfragen {requests} ({perSession} pro Sitzung, {perImage} pro Bild) · gewartet {wait} min · Limit erschöpft {later}×",
|
|
255
256
|
"ui.tune.web": "Eigene Webwerkzeuge des Agenten:",
|
package/assets/method/core.md
CHANGED
|
@@ -102,6 +102,10 @@ conclusion so the next researcher can follow it.
|
|
|
102
102
|
number by one or two images, never a batch of ten; an entry: its image ±1
|
|
103
103
|
(it may run over a page). An archive that allows automation: batches as
|
|
104
104
|
usual (about ±5 around the target, an index in batches) — fewer turns.
|
|
105
|
+
`strom read` may follow a fetch at work: sooner, never more images.
|
|
106
|
+
Images you will read later in the session: `--background` fetches them
|
|
107
|
+
while you work on, `strom read` reads them as they come. Nothing for a
|
|
108
|
+
later session: the session that reads a book fetches it.
|
|
105
109
|
<!-- end -->
|
|
106
110
|
- **What strom or the tree denies stays denied.** Never offer the user to
|
|
107
111
|
change your permissions or settings, strom's or the tree's, to get round it:
|
package/assets/method/reading.md
CHANGED
|
@@ -51,7 +51,8 @@ never open again a view cleared from your context — your notes hold it.
|
|
|
51
51
|
- **Browsing a book or a range is a reader's job**: `strom read B0001
|
|
52
52
|
--images 40-69 --question "…"` (small script: `--half both`) — readers in
|
|
53
53
|
batches of ten, each with the full question, their reports in
|
|
54
|
-
notes/readings/.
|
|
54
|
+
notes/readings/. For every agent, also one with subagents of its own: a
|
|
55
|
+
third of their cost, every reading kept. It ends with what they found, compact: the found and
|
|
55
56
|
unclear entries whole, what was illegible where nothing was found (a
|
|
56
57
|
possible match often hides there — look at it), the gaps in the book.
|
|
57
58
|
Later: `strom readings` (`--match <surname>`, `--list`; one image's block:
|
|
@@ -65,6 +66,13 @@ never open again a view cleared from your context — your notes hold it.
|
|
|
65
66
|
and headings only, one surname's entries, one entry whole — and transcribes
|
|
66
67
|
nothing else. Record each report as it comes back, before the next readers.
|
|
67
68
|
Only the entries that will be cited need your own eyes, at full resolution.
|
|
69
|
+
<!-- for link verify enrich -->
|
|
70
|
+
- **`--until-found` only for ONE particular entry** (one person's baptism,
|
|
71
|
+
marriage or burial whose details you know): no more readers begin once one
|
|
72
|
+
reports it. Never for every entry of a place or surname, nor where a
|
|
73
|
+
namesake may follow. Record only the images it names as read, `--result
|
|
74
|
+
partial`; if the find is not the one, read the rest.
|
|
75
|
+
<!-- end -->
|
|
68
76
|
- **Report image by image, as you go**: the image and page, what was found (or
|
|
69
77
|
nothing), what was illegible and where, the hand, how sure each name is.
|
|
70
78
|
- **Cite the image, and where the entry is on it**: `strom source add …
|
|
@@ -110,9 +110,19 @@ usage is at least the number you give it behind the week gone:
|
|
|
110
110
|
strom config set run.gate "claude-usage 10" gone − used ≥ 10
|
|
111
111
|
|
|
112
112
|
Without a number: 0 — no faster than the week goes; 14: about a day in hand.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
|
|
114
|
+
Early in the week the number grows with it: at least half the week gone, the
|
|
115
|
+
full number from twice it on (at 15: from 30 % gone). Right after the reset a
|
|
116
|
+
session starts at once, and the first day uses at most half of its share.
|
|
117
|
+
In the week's last 2 hours what is left would go with the reset: a session
|
|
118
|
+
starts when the room left (to 100 %, or to the cap) holds one — counted high,
|
|
119
|
+
10 points.
|
|
120
|
+
|
|
121
|
+
Not enough in hand: it waits until the first of — the week has caught up, the
|
|
122
|
+
week's last 2 hours (with room for a session), the reset itself (a new week
|
|
123
|
+
starts at once); never past the reset. Every answer says when the week resets
|
|
124
|
+
("weekly reset in 1.7 h"). A used-up session: until it resets. Another agent
|
|
125
|
+
than Claude Code: it lets the work go on.
|
|
116
126
|
|
|
117
127
|
**A cap** — your own hard stop for the week:
|
|
118
128
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"interface": 1,
|
|
3
3
|
"title": "Claude usage",
|
|
4
|
-
"description": "Keeps working alone to the daily ration of your Claude subscription: a session starts only while the week's usage is at least n points behind the share of the week gone (a day ≈ 14.3): strom config set run.gate \"claude-usage 10\" (without a number: 0). A cap: \"claude-usage 10 --cap 95\" — at 95 % of the week no session starts, in any run, and no \"start anyway\" goes past it.",
|
|
4
|
+
"description": "Keeps working alone to the daily ration of your Claude subscription: a session starts only while the week's usage is at least n points behind the share of the week gone (a day ≈ 14.3; early in the week half the share gone, so a new week starts at once; in its last 2 hours what is left goes when it holds a session): strom config set run.gate \"claude-usage 10\" (without a number: 0). A cap: \"claude-usage 10 --cap 95\" — at 95 % of the week no session starts, in any run, and no \"start anyway\" goes past it.",
|
|
5
5
|
"command": [
|
|
6
6
|
"node",
|
|
7
7
|
"gate.ts"
|
|
@@ -8,8 +8,19 @@
|
|
|
8
8
|
// (a day is about 14.3 %) against the week's usage. With the number you give
|
|
9
9
|
// it (strom config set run.gate "claude-usage 10") a session starts only while
|
|
10
10
|
// usage is at least that many points behind the week gone: gone − used ≥ 10.
|
|
11
|
-
// Without a number: 0 — no faster than the week goes.
|
|
12
|
-
//
|
|
11
|
+
// Without a number: 0 — no faster than the week goes.
|
|
12
|
+
//
|
|
13
|
+
// Early in the week the number grows with it: at least min(n, gone / 2) — right
|
|
14
|
+
// after the reset (0 % gone, 0 % used) a session may start, and until 2·n % of
|
|
15
|
+
// the week is gone usage may reach half of it; from there on the full number.
|
|
16
|
+
// So the first day never spends the week (at most half its share), and a new
|
|
17
|
+
// week is not idle for n % of it (a day and more at 15) for nothing.
|
|
18
|
+
// Late in the week what is left goes with the reset: in its last END_WINDOW a
|
|
19
|
+
// session starts when what is left (to 100 %, or to the cap) holds one session
|
|
20
|
+
// (SESSION_POINTS).
|
|
21
|
+
// Else it waits until the first of: the week has caught up, its last
|
|
22
|
+
// END_WINDOW (with room for a session), its reset (a new week starts at once) —
|
|
23
|
+
// never past the reset. A full session: until it resets.
|
|
13
24
|
//
|
|
14
25
|
// A cap (strom config set run.gate "claude-usage 15 --cap 95"): at 95 % of the
|
|
15
26
|
// week used no session starts — the user's own hard stop, asked before every
|
|
@@ -28,15 +39,32 @@ const FRESH_MS = 15 * 60_000;
|
|
|
28
39
|
/** Under a cap, a session at work is asked to finish at this much of the week. */
|
|
29
40
|
const FINISH_AT = 0.99;
|
|
30
41
|
const WEEK = 7 * DAY;
|
|
42
|
+
/**
|
|
43
|
+
* The last stretch of the week in which what is left is spent rather than kept: about one session of `strom run`
|
|
44
|
+
* (60 minutes by default) with its wrap-up and the gate's next asking. What is not used by the reset is gone with
|
|
45
|
+
* it; what a person keeps in hand for their own work is missed for this long at most.
|
|
46
|
+
*/
|
|
47
|
+
const END_WINDOW = 2 * 3_600_000;
|
|
48
|
+
/** What one session may take of the week, counted high (points of the week's %): the room it needs before the reset. */
|
|
49
|
+
const SESSION_POINTS = 10;
|
|
50
|
+
/** After the reset the gate asks again this much later, so the new week is what Claude Code says. */
|
|
51
|
+
const AFTER_RESET = 60_000;
|
|
31
52
|
const lang = (process.env.STROM_LANG ?? "en").slice(0, 2);
|
|
32
53
|
|
|
33
54
|
const T: Record<string, Record<string, string>> = {
|
|
34
55
|
en: {
|
|
35
56
|
other: "the agent is not Claude Code — nothing to check",
|
|
36
57
|
api: "Claude Code runs on an API key, not a subscription — no plan limits",
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
58
|
+
head: "week {used} % used, {gone} % gone, {behind} in hand (at least {min} needed{early})",
|
|
59
|
+
early: " — half the week gone, early in the week",
|
|
60
|
+
resetIn: "; weekly reset in {reset}",
|
|
61
|
+
catch: " — until the week catches up; weekly reset in {reset}",
|
|
62
|
+
last: " — until the last {window} before the weekly reset in {reset}",
|
|
63
|
+
reset: " — until the weekly reset in {reset}",
|
|
64
|
+
end: "week {used} % used, weekly reset in {reset} — the {room} % left is enough for a session",
|
|
65
|
+
session: "the session is used up — until it resets; weekly reset in {reset}",
|
|
66
|
+
hours: "{n} h",
|
|
67
|
+
days: "{n} days",
|
|
40
68
|
bad: "the number must be 0 to 99, not \"{arg}\"",
|
|
41
69
|
badcap: "the cap must be 1 to 100 (\"--cap 95\"), not \"{arg}\"",
|
|
42
70
|
cap: "week {used} % used — the cap of {cap} % reached; it resets {resets}",
|
|
@@ -47,9 +75,16 @@ const T: Record<string, Record<string, string>> = {
|
|
|
47
75
|
cs: {
|
|
48
76
|
other: "agent není Claude Code — není co hlídat",
|
|
49
77
|
api: "Claude Code běží na API klíči, ne na předplatném — žádné limity plánu",
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
78
|
+
head: "týden: využito {used} %, uplynulo {gone} %, náskok {behind} (potřeba aspoň {min}{early})",
|
|
79
|
+
early: " – na začátku týdne polovina uplynulého",
|
|
80
|
+
resetIn: "; týden se obnoví za {reset}",
|
|
81
|
+
catch: " — dokud čas nedožene; týden se obnoví za {reset}",
|
|
82
|
+
last: " — do posledních {window} před obnovením týdne za {reset}",
|
|
83
|
+
reset: " — do obnovení týdne za {reset}",
|
|
84
|
+
end: "týden: využito {used} %, obnoví se za {reset} — zbylých {room} % stačí na sezení",
|
|
85
|
+
session: "sezení je vyčerpané — do jeho obnovení; týden se obnoví za {reset}",
|
|
86
|
+
hours: "{n} h",
|
|
87
|
+
days: "{n} dne",
|
|
53
88
|
bad: "číslo musí být 0 až 99, ne \"{arg}\"",
|
|
54
89
|
badcap: "strop musí být 1 až 100 (\"--cap 95\"), ne \"{arg}\"",
|
|
55
90
|
cap: "týden: využito {used} % – strop {cap} % dosažen; obnoví se {resets}",
|
|
@@ -60,9 +95,16 @@ const T: Record<string, Record<string, string>> = {
|
|
|
60
95
|
de: {
|
|
61
96
|
other: "der Agent ist nicht Claude Code — nichts zu prüfen",
|
|
62
97
|
api: "Claude Code läuft mit einem API-Schlüssel, nicht im Abo — keine Planlimits",
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
98
|
+
head: "Woche: {used} % genutzt, {gone} % vergangen, Vorsprung {behind} (mindestens {min} nötig{early})",
|
|
99
|
+
early: " – am Wochenanfang die Hälfte des Vergangenen",
|
|
100
|
+
resetIn: "; Wochen-Reset in {reset}",
|
|
101
|
+
catch: " — bis die Zeit aufholt; Wochen-Reset in {reset}",
|
|
102
|
+
last: " — bis zu den letzten {window} vor dem Wochen-Reset in {reset}",
|
|
103
|
+
reset: " — bis zum Wochen-Reset in {reset}",
|
|
104
|
+
end: "Woche: {used} % genutzt, Wochen-Reset in {reset} — die übrigen {room} % reichen für eine Sitzung",
|
|
105
|
+
session: "die Sitzung ist aufgebraucht — bis sie zurückgesetzt wird; Wochen-Reset in {reset}",
|
|
106
|
+
hours: "{n} h",
|
|
107
|
+
days: "{n} Tagen",
|
|
66
108
|
bad: "die Zahl muss 0 bis 99 sein, nicht \"{arg}\"",
|
|
67
109
|
badcap: "die Obergrenze muss 1 bis 100 sein (\"--cap 95\"), nicht \"{arg}\"",
|
|
68
110
|
cap: "Woche: {used} % genutzt – Obergrenze {cap} % erreicht; zurückgesetzt {resets}",
|
|
@@ -135,19 +177,39 @@ if (cap !== undefined && week.used >= cap)
|
|
|
135
177
|
answer(2, say("cap", { used: Math.floor(week.used), cap, resets: week.resets.toLocaleString(lang, { weekday: "short", day: "numeric", month: "numeric", hour: "2-digit", minute: "2-digit" }) }), undefined, true);
|
|
136
178
|
|
|
137
179
|
const now = Date.now();
|
|
138
|
-
const
|
|
180
|
+
const resets = week.resets.getTime();
|
|
181
|
+
const start = resets - WEEK;
|
|
139
182
|
const gone = Math.max(0, Math.min(100, ((now - start) / WEEK) * 100));
|
|
140
183
|
const behind = gone - week.used;
|
|
141
|
-
//
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
184
|
+
// the number needed in hand: half the week gone early in the week, the full number from 2·n % gone on
|
|
185
|
+
const need = Math.min(min, gone / 2);
|
|
186
|
+
const early = need < min ? say("early") : "";
|
|
187
|
+
const reset = inTime(resets - now);
|
|
188
|
+
// shown rounded down: never "15 in hand (at least 15 needed)" for 14.6 — and gone − used stays what it says; the
|
|
189
|
+
// need early in the week is a fraction: rounded down when it goes, up when it waits, so the two never seem to disagree
|
|
190
|
+
const v = { used: Math.floor(week.used), gone: Math.floor(gone), behind: Math.floor(behind), early, reset };
|
|
191
|
+
if (session && session.used >= 100) answer(1, say("session", { reset }), session.resets ? new Date(session.resets.getTime() + AFTER_RESET) : undefined);
|
|
192
|
+
if (behind >= need) answer(0, say("head", { ...v, min: Math.floor(need) }) + say("resetIn", { reset }));
|
|
193
|
+
// what is left before the reset: (to the cap, else to 100 %) enough for a session — in the week's last stretch it goes
|
|
194
|
+
const room = (cap ?? 100) - week.used;
|
|
195
|
+
const fits = room >= SESSION_POINTS;
|
|
196
|
+
if (fits && resets - now <= END_WINDOW) answer(0, say("end", { used: v.used, reset, room: Math.floor(room) }));
|
|
197
|
+
// else it waits for the first of: the week caught up (gone − used ≥ the need: used < n → gone = 2·used, else
|
|
198
|
+
// used + n), the week's last stretch (with room for a session), the reset — a new week at 0 % goes at once, so
|
|
199
|
+
// never past it
|
|
200
|
+
const caught = start + ((week.used < min ? 2 * week.used : week.used + min) / 100) * WEEK;
|
|
201
|
+
const last = fits ? resets - END_WINDOW : Infinity;
|
|
202
|
+
const after = resets + AFTER_RESET;
|
|
203
|
+
const at = Math.min(caught, last, after);
|
|
204
|
+
const tail = at === caught ? say("catch", { reset }) : at === last ? say("last", { reset, window: say("hours", { n: END_WINDOW / 3_600_000 }) }) : say("reset", { reset });
|
|
205
|
+
answer(1, say("head", { ...v, min: Math.ceil(need) }) + tail, new Date(Math.max(at, now + 5 * 60_000)));
|
|
206
|
+
|
|
207
|
+
/** A stretch of time as a person reads it: hours to two days, then days — one decimal, in the research language. */
|
|
208
|
+
function inTime(ms: number): string {
|
|
209
|
+
const h = Math.max(0, ms) / 3_600_000;
|
|
210
|
+
const n = (x: number) => x.toLocaleString(lang, { minimumFractionDigits: 1, maximumFractionDigits: 1 });
|
|
211
|
+
return h < 48 ? say("hours", { n: n(h) }) : say("days", { n: n(h / 24) });
|
|
149
212
|
}
|
|
150
|
-
answer(0, say("go", v));
|
|
151
213
|
|
|
152
214
|
/**
|
|
153
215
|
* The limits Claude Code said in this run (strom passes them: [{kind, used 0–1, resetsAt, at}]), when the week's is
|
package/dist/agents/profiles.js
CHANGED
|
@@ -30,6 +30,9 @@ function delegationRules(n) {
|
|
|
30
30
|
return `- Browsing a book, an index or a range of images ("is our surname on this page?")
|
|
31
31
|
goes to \`strom read\` (by halves: \`--half both\`); a delegate reads only crops
|
|
32
32
|
of the entries found. Anything self-contained that returns little is delegated.
|
|
33
|
+
\`strom read\` and not subagents of your own for a range: about a third of
|
|
34
|
+
their cost on the same images, every reading kept (\`strom readings\`), the
|
|
35
|
+
places its readers found unclear held against a negative.
|
|
33
36
|
- A delegate other than strom-scan-reader (text, print, a search) gets no brief:
|
|
34
37
|
begin its prompt with this, word for word — "${DELEGATE_SHEET}"
|
|
35
38
|
- About ${first} scans (images B…:n) per delegate, four views each (halves and
|
|
@@ -56,6 +59,13 @@ function delegationRules(n) {
|
|
|
56
59
|
export function selfReading(n = DEFAULT_READING_NUMBERS) {
|
|
57
60
|
return `## Reading scans (Codex, Antigravity, OpenCode, Grok)
|
|
58
61
|
|
|
62
|
+
Browsing a book, an index or a range of images goes to \`strom read\`
|
|
63
|
+
(\`strom read B0001 --images 40-69 --question "…"\`), also for an agent with
|
|
64
|
+
sub-agents of its own: cheaper than reading the range in your context or by
|
|
65
|
+
a sub-agent, every reading kept (\`strom readings\`), the places its readers
|
|
66
|
+
found unclear held against a negative. Where strom says no reader can start
|
|
67
|
+
here, and for the entries found:
|
|
68
|
+
|
|
59
69
|
Read the images yourself, with your strongest model — never hand old
|
|
60
70
|
handwriting to a faster or cheaper model, subagent or pass. Read them
|
|
61
71
|
in batches of about ${inWords(n.batch)}: open a batch (one call gives its views —
|
|
@@ -103,7 +113,8 @@ comes back to you. Choose the model by the kind of work:
|
|
|
103
113
|
|
|
104
114
|
| work | model |
|
|
105
115
|
|---|---|
|
|
106
|
-
| handwriting:
|
|
116
|
+
| browsing handwriting: a book, an index, a range of images | \`strom read\` (its readers on the model for handwriting) — not a subagent of yours |
|
|
117
|
+
| handwriting read closely: the entries found, a page of a land book | \`strom-scan-reader\`, ${m.vision ? `on \`${m.vision}\`` : "on your own model"} — never cheaper |
|
|
107
118
|
| print and type: documents of the 20th century, catalogues, web pages, big text files (the lines \`strom grep\` found) | \`${m.text ?? "sonnet"}\` |
|
|
108
119
|
| mechanical: downloads, renaming, counting | \`${m.cheap ?? "haiku"}\` |
|
|
109
120
|
| a text in inputs/ or notes/ | nobody — \`strom grep\`, one call |
|
package/dist/brief/brief.js
CHANGED
|
@@ -21,7 +21,7 @@ import { byHandOnly, listConnectors, missingConsents, readyConnectors, routeOf }
|
|
|
21
21
|
import { clock, hostAllowed, hostState, REFUSED_FOREVER } from "../core/net.js";
|
|
22
22
|
import { archiveLevel } from "../core/terms.js";
|
|
23
23
|
import { onHost, permissionQuestions, setHosts } from "../core/archivewait.js";
|
|
24
|
-
import { runs, shellArg } from "../cli/format.js";
|
|
24
|
+
import { runs, runsArg, shellArg } from "../cli/format.js";
|
|
25
25
|
import { commandSheet } from "./sheet.js";
|
|
26
26
|
import { foldText } from "../core/text.js";
|
|
27
27
|
import { subjectPeople } from "../core/records.js";
|
|
@@ -39,6 +39,7 @@ import { ENRICH_PAGES, STORY_SOURCES_ORIGIN } from "../core/stories.js";
|
|
|
39
39
|
import { sandboxOf, WITHOUT_READERS } from "../core/sandbox.js";
|
|
40
40
|
import { WEB_SOFT } from "../core/metrics.js";
|
|
41
41
|
import { indexBriefLines } from "../core/indexfirst.js";
|
|
42
|
+
import { activeFetches, endedFetches } from "../core/fetching.js";
|
|
42
43
|
/** The hosts of a connector, as its manifest names them (a wildcard without its star). */
|
|
43
44
|
function connectorHosts(shared, name) {
|
|
44
45
|
try {
|
|
@@ -627,6 +628,15 @@ function imagesLines(tree, b, route, shape, finder, noSharper = false, waiting)
|
|
|
627
628
|
: ""),
|
|
628
629
|
].filter(Boolean);
|
|
629
630
|
}
|
|
631
|
+
/** The fetches at work for the research (each book: how far), and those in the background that ended lately with images left. */
|
|
632
|
+
function fetchingLines(root) {
|
|
633
|
+
const active = activeFetches(root);
|
|
634
|
+
const out = active.map((m) => `- ${m.recordset}: ${m.registered}/${m.images.length} images registered (${m.background ? `in the background${m.task ? `, for ${m.task}` : ""}` : "in the foreground"}) — strom read ${m.recordset} --images ${runsArg(m.images)} reads them as they come; not fetched again`);
|
|
635
|
+
for (const e of endedFetches(root))
|
|
636
|
+
if (e.missed.length && !active.some((m) => m.recordset === e.recordset))
|
|
637
|
+
out.push(`- ${e.recordset}: a fetch in the background ended with images ${runs(e.missed)} not fetched${e.stopped ? ` (stopped: ${e.stopped})` : ""} — strom fetch ${e.connector} ${shellArg(e.book)} --images ${runsArg(e.missed)} --recordset ${e.recordset} if they are needed`);
|
|
638
|
+
return out;
|
|
639
|
+
}
|
|
630
640
|
/** What the user put in the shared inbox, waiting to be registered — by folder (one download each). */
|
|
631
641
|
function inboxLines(shared) {
|
|
632
642
|
if (!shared)
|
|
@@ -1197,6 +1207,15 @@ export function buildBrief(tree, opts) {
|
|
|
1197
1207
|
' strom media add --inbox "<folder>" --recordset B… · a document (certificate, letter): strom intake <file>',
|
|
1198
1208
|
].join("\n"),
|
|
1199
1209
|
});
|
|
1210
|
+
// 7c. images being fetched for the research now (strom fetch --background of an earlier session, or another strom),
|
|
1211
|
+
// and what fetches in the background left unfetched lately: read as they come, never fetched twice
|
|
1212
|
+
const fetching = fetchingLines(tree.root);
|
|
1213
|
+
if (fetching.length)
|
|
1214
|
+
sections.push({
|
|
1215
|
+
name: "fetching",
|
|
1216
|
+
pointer: "strom fetch --status",
|
|
1217
|
+
text: ["## Images being fetched now (strom fetch --status)", ...fetching].join("\n"),
|
|
1218
|
+
});
|
|
1200
1219
|
// 8. method for this kind of task
|
|
1201
1220
|
// (budgeted first, with the record sets and the commands: when the brief is long, the lists are cut before how to work)
|
|
1202
1221
|
// only the parts the level uses — of getting images, those of how this task's record sets get them (none named:
|
package/dist/brief/sheet.js
CHANGED
|
@@ -27,10 +27,11 @@ const LEVELS = {
|
|
|
27
27
|
const RARE = {
|
|
28
28
|
"search add": ["by"],
|
|
29
29
|
"task add": ["research", "anyway"],
|
|
30
|
-
"media view": ["scale", "max", "grey", "png", "image"],
|
|
30
|
+
"media view": ["scale", "max", "grey", "png", "image", "whole"],
|
|
31
31
|
read: ["context", "batch", "model", "minutes", "max"],
|
|
32
|
-
// a book the research has already: the refusal says --again where it applies
|
|
33
|
-
|
|
32
|
+
// a book the research has already: the refusal says --again where it applies; --status and --stop: the method and the brief name them;
|
|
33
|
+
// --task: strom takes the task the agent works on where it is plain, and says --task where it took one
|
|
34
|
+
fetch: ["take", "result", "again", "status", "stop", "task"],
|
|
34
35
|
"source add": ["translation", "media"],
|
|
35
36
|
"source edit": ["translation", "media"],
|
|
36
37
|
"recordset add": ["images", "again"],
|
package/dist/cli/commit.js
CHANGED
|
@@ -13,7 +13,9 @@ export function commitMessage(summaries, command) {
|
|
|
13
13
|
/** Commit the changes of this command. Returns what blocked the commit, if anything did. */
|
|
14
14
|
export function autoCommit(ctx, def) {
|
|
15
15
|
const tree = ctx.current();
|
|
16
|
-
|
|
16
|
+
// what an earlier commit of the same command holds already (strom fetch commits each batch of images) is not again
|
|
17
|
+
const ops = tree?.uncommitted() ?? [];
|
|
18
|
+
if (!tree || tree.dryRun || ops.length === 0)
|
|
17
19
|
return undefined;
|
|
18
20
|
// Incremental gate: records were validated when written; here only what
|
|
19
21
|
// changed since the last commit is checked, so the cost stays flat.
|
|
@@ -30,11 +32,11 @@ export function autoCommit(ctx, def) {
|
|
|
30
32
|
problems: errors.map((f) => ({ ...(f.id ? { id: f.id } : {}), ...(f.file ? { file: f.file } : {}), message: f.message })),
|
|
31
33
|
};
|
|
32
34
|
}
|
|
33
|
-
const message = commitMessage(
|
|
35
|
+
const message = commitMessage(ops.map((o) => o.summary), `strom ${def.path.join(" ")}`);
|
|
34
36
|
// Only the files this command wrote, plus the free-form folders the agent
|
|
35
37
|
// may edit — `git add` then never has to scan the whole data/ tree.
|
|
36
38
|
const written = new Set(["data/_counters.json"]);
|
|
37
|
-
for (const op of
|
|
39
|
+
for (const op of ops)
|
|
38
40
|
for (const f of op.files)
|
|
39
41
|
written.add(f.path);
|
|
40
42
|
for (const f of tree.opsFilesTouched())
|
|
@@ -43,6 +45,7 @@ export function autoCommit(ctx, def) {
|
|
|
43
45
|
// commit of something else (found on Windows: strom mode committed a file of the user's) — nor by the switch itself
|
|
44
46
|
const free = isArchive(tree) || def.path[0] === "mode" ? ["inputs", "output"] : ["notes", "tools", "inputs", "output"];
|
|
45
47
|
tree.withTreeLock(() => tree.commit(message, [...written, ...free]));
|
|
48
|
+
tree.markCommitted();
|
|
46
49
|
tree.settle();
|
|
47
50
|
return undefined;
|
|
48
51
|
}
|