strom-research 1.26.0-beta.8 → 1.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.cs.md +13 -1
- package/CHANGELOG.de.md +16 -1
- package/CHANGELOG.md +14 -1
- package/CHANGELOG.pl.md +14 -1
- package/assets/lang/cs.json +8 -0
- package/assets/lang/de.json +8 -0
- package/assets/lang/pl.json +8 -0
- package/dist/cli/commit.js +4 -0
- package/dist/cli/ui.js +8 -0
- package/dist/commands/checks.js +29 -5
- package/dist/core/git.js +45 -5
- package/dist/core/integrity.js +56 -5
- package/dist/core/tree.js +3 -2
- package/package.json +1 -4
package/CHANGELOG.cs.md
CHANGED
|
@@ -5,9 +5,21 @@
|
|
|
5
5
|
Změny každé verze ve zkratce. Úplné poznámky a instalační řádky jsou na
|
|
6
6
|
[GitHub Releases](https://github.com/ACiDekCZ/strom-research/releases) (anglicky).
|
|
7
7
|
|
|
8
|
+
## 1.26.1
|
|
9
|
+
|
|
10
|
+
*4. 11. 2026 · patří k aplikaci Strom 3.22.0.*
|
|
11
|
+
|
|
12
|
+
- **Přerušený zápis už výzkum natrvalo nezablokuje.** Příkaz zastavený mezi `git add` a commitem (ukončený agentem, nebo
|
|
13
|
+
na Windows s indexem gitu drženým jiným programem) mohl nechat své soubory v indexu gitu: každý další zápis pak končil
|
|
14
|
+
„data výzkumu se změnila mimo strom“, ačkoli `strom verify` ani `strom repair` nic nenašly. Nové soubory, které takový
|
|
15
|
+
zápis nechá v indexu (ve složce už nejsou a v historii nikdy nebyly), nejsou ničí změna – další zápis je sám vrátí a
|
|
16
|
+
pokračuje. `strom repair` vrátí vždy celý index k zapečetěnému stavu, i se změnou záznamu, která v něm zůstala. Zámek,
|
|
17
|
+
který nechal git ukončený uprostřed práce (`.git/index.lock`, starší než 10 minut), `strom repair` odstraní a zápis,
|
|
18
|
+
který na něm skončí, to řekne. Záznam opravdu smazaný nebo upravený mimo strom se hlásí jako dřív.
|
|
19
|
+
|
|
8
20
|
## 1.26.0
|
|
9
21
|
|
|
10
|
-
*
|
|
22
|
+
*4. 11. 2026 · patří k aplikaci Strom 3.22.0.*
|
|
11
23
|
|
|
12
24
|
- **Linie výzkumu z aplikace Strom: založit, upravit, pozastavit, seřadit.** Linii jde v aplikaci založit nebo upravit
|
|
13
25
|
(osoba, směr, otázka, meze), pozastavit, ukončit nebo znovu spustit; pořadí linií je pořadí práce a stránka telefonu
|
package/CHANGELOG.de.md
CHANGED
|
@@ -5,9 +5,24 @@
|
|
|
5
5
|
Die Änderungen jeder Version in Kürze. Die vollständigen Hinweise und die Installationszeilen stehen bei
|
|
6
6
|
[GitHub Releases](https://github.com/ACiDekCZ/strom-research/releases) (auf Englisch).
|
|
7
7
|
|
|
8
|
+
## 1.26.1
|
|
9
|
+
|
|
10
|
+
*4.11.2026 · gehört zur Strom-App 3.22.0.*
|
|
11
|
+
|
|
12
|
+
- **Ein unterbrochenes Schreiben sperrt die Forschung nicht mehr auf Dauer.** Ein Befehl, der zwischen `git add` und dem
|
|
13
|
+
Commit endete (vom Agenten beendet oder unter Windows mit einem Index von git, den ein anderes Programm hielt), konnte
|
|
14
|
+
seine Dateien im Index von git lassen: jedes weitere Schreiben endete mit „die Daten der Forschung wurden außerhalb
|
|
15
|
+
von strom geändert“, obwohl `strom verify` und `strom repair` nichts fanden. Die neuen Dateien, die ein solches
|
|
16
|
+
Schreiben im Index lässt (nicht mehr im Ordner, nie in der Geschichte), sind niemandes Änderung – das nächste
|
|
17
|
+
Schreiben nimmt sie von selbst heraus und macht weiter. `strom repair` setzt immer den ganzen Index auf den
|
|
18
|
+
versiegelten Stand zurück, auch mit einer dort gebliebenen Änderung eines Eintrags. Eine Sperre, die ein mitten in der
|
|
19
|
+
Arbeit beendetes git hinterließ (`.git/index.lock`, älter als 10 Minuten), entfernt `strom repair`, und ein Schreiben,
|
|
20
|
+
das daran scheitert, sagt es. Ein wirklich außerhalb von strom gelöschter oder geänderter Eintrag wird wie bisher
|
|
21
|
+
gemeldet.
|
|
22
|
+
|
|
8
23
|
## 1.26.0
|
|
9
24
|
|
|
10
|
-
*
|
|
25
|
+
*4.11.2026 · gehört zur Strom-App 3.22.0.*
|
|
11
26
|
|
|
12
27
|
- **Die Linien der Forschung aus der Strom-App: anlegen, ändern, pausieren, ordnen.** Eine Linie lässt sich in der App
|
|
13
28
|
anlegen oder ändern (Person, Richtung, Frage, Grenzen), pausieren, beenden oder wieder aufnehmen; die Reihenfolge der
|
package/CHANGELOG.md
CHANGED
|
@@ -5,9 +5,22 @@ English · [Čeština](CHANGELOG.cs.md) · [Deutsch](CHANGELOG.de.md) · [Polski
|
|
|
5
5
|
The changes of each version in short. The full notes and the install lines are on
|
|
6
6
|
[GitHub Releases](https://github.com/ACiDekCZ/strom-research/releases).
|
|
7
7
|
|
|
8
|
+
## 1.26.1
|
|
9
|
+
|
|
10
|
+
*2026-11-04 · goes with the Strom app 3.22.0.*
|
|
11
|
+
|
|
12
|
+
- **A write cut short no longer blocks the research for good.** A command stopped between strom's `git add` and its
|
|
13
|
+
commit (ended by the agent, or git's index held by another program on Windows) could leave its files in git's index:
|
|
14
|
+
every write after it ended with "data was changed outside strom", while `strom verify` and `strom repair` found
|
|
15
|
+
nothing. The new files such a write leaves in the index — gone from the folder, never in the history — are no change
|
|
16
|
+
of anybody's: the next write takes them out by itself and goes on. `strom repair` always puts the whole index back to
|
|
17
|
+
the sealed state, a record's change left there too. A lock a git ended mid-way left (`.git/index.lock`, older than 10
|
|
18
|
+
minutes) is taken away by `strom repair`, and a write refused by it says so. A record truly deleted or edited outside
|
|
19
|
+
strom is said as ever.
|
|
20
|
+
|
|
8
21
|
## 1.26.0
|
|
9
22
|
|
|
10
|
-
*
|
|
23
|
+
*2026-11-04 · goes with the Strom app 3.22.0.*
|
|
11
24
|
|
|
12
25
|
- **The lines of the research from the Strom app: created, changed, paused, put in order.** A line is created or changed
|
|
13
26
|
in the app (its person, direction, question, limits), paused, ended or taken up again; the order of the lines is the
|
package/CHANGELOG.pl.md
CHANGED
|
@@ -5,9 +5,22 @@
|
|
|
5
5
|
Zmiany każdej wersji w skrócie. Pełne informacje o wydaniach i polecenia instalacji są na
|
|
6
6
|
[GitHub Releases](https://github.com/ACiDekCZ/strom-research/releases) (po angielsku).
|
|
7
7
|
|
|
8
|
+
## 1.26.1
|
|
9
|
+
|
|
10
|
+
*4.11.2026 · współpracuje z aplikacją Strom 3.22.0.*
|
|
11
|
+
|
|
12
|
+
- **Przerwany zapis już nie blokuje badania na stałe.** Polecenie zatrzymane między `git add` a commitem (zakończone
|
|
13
|
+
przez agenta albo w Windows z indeksem gita trzymanym przez inny program) mogło zostawić swoje pliki w indeksie gita:
|
|
14
|
+
każdy kolejny zapis kończył się komunikatem „dane badania zmieniły się poza strom”, choć `strom verify` ani `strom
|
|
15
|
+
repair` nic nie znalazły. Nowe pliki, które taki zapis zostawia w indeksie (nie ma ich już w folderze, w historii
|
|
16
|
+
nigdy nie były), nie są niczyją zmianą – następny zapis sam je wycofa i działa dalej. `strom repair` zawsze przywraca
|
|
17
|
+
cały indeks do zapieczętowanego stanu, także ze zmianą rekordu, która w nim została. Blokadę zostawioną przez git
|
|
18
|
+
przerwany w trakcie pracy (`.git/index.lock`, starszą niż 10 minut) `strom repair` usuwa, a zapis, który na niej się
|
|
19
|
+
kończy, mówi o tym. Rekord naprawdę usunięty lub zmieniony poza strom jest zgłaszany jak dotąd.
|
|
20
|
+
|
|
8
21
|
## 1.26.0
|
|
9
22
|
|
|
10
|
-
*
|
|
23
|
+
*4.11.2026 · współpracuje z aplikacją Strom 3.22.0.*
|
|
11
24
|
|
|
12
25
|
- **Linie badania z aplikacji Strom: założyć, zmienić, wstrzymać, uporządkować.** Linię można w aplikacji założyć lub
|
|
13
26
|
zmienić (osoba, kierunek, pytanie, granice), wstrzymać, zakończyć lub wznowić; kolejność linii to kolejność pracy, a
|
package/assets/lang/cs.json
CHANGED
|
@@ -1884,6 +1884,12 @@
|
|
|
1884
1884
|
"ui.check.streetplaces": "{n, plural, one {# údaj má} few {# údaje mají} other {# údajů má}} v místě ulici nebo číslo domu",
|
|
1885
1885
|
"ui.error.tree.not-downloaded": "z iCloudu ještě nestaženo: {n, plural, one {# soubor} few {# soubory} other {# souborů}} výzkumu (první: {first}) – nic se nezapsalo",
|
|
1886
1886
|
"ui.error.tree.not-downloaded.hint": "otevřít složku výzkumu ve Finderu a soubory stáhnout (nebo složku z iCloud Drive vyjmout), pak spustit znovu – ne strom repair",
|
|
1887
|
+
"ui.error.tree.index-leftovers": "v indexu gitu zůstalo, co nechal přerušený zápis ({n, plural, one {# soubor} few {# soubory} other {# souborů}}, první: {first}), a git to nedokázal vrátit – nic se nezapsalo",
|
|
1888
|
+
"ui.error.tree.index-leftovers.hint": "strom repair (vrátí index gitu k poslednímu zapečetěnému stavu; pak spustit příkaz znovu)",
|
|
1889
|
+
"ui.error.git.index-locked": "index gitu je zamčený (.git/index.lock) – ve výzkumu pracuje jiný git, nebo zámek nechal git ukončený uprostřed práce",
|
|
1890
|
+
"ui.error.git.index-locked.hint": "strom repair (odstraní zámek, který žádný git nedrží déle než 10 minut; pak spustit příkaz znovu)",
|
|
1891
|
+
"ui.error.repair.index": "git nedokázal vrátit svůj index k zapečetěnému stavu",
|
|
1892
|
+
"ui.error.repair.index.hint": "zavřít programy, které mohou držet složku výzkumu (synchronizace, kontrola antiviru, jiný git), pak znovu strom repair",
|
|
1887
1893
|
"ui.error.tree.changed-outside": "data výzkumu se změnila mimo strom ({n, plural, one {# problém} few {# problémy} other {# problémů}}): nic se nezapsalo",
|
|
1888
1894
|
"ui.error.tree.changed-outside.hint": "strom verify (podrobnosti)\nstrom repair (vrátí poslední zapečetěný stav)",
|
|
1889
1895
|
"ui.error.tree.changed-outside.keys.hint": "strom verify (podrobnosti)\nstrom repair, pak strom seal adopt (vrátí jen to, co se udělalo mimo strom – práce obou klíčů tohoto počítače zůstane)",
|
|
@@ -3444,6 +3450,8 @@
|
|
|
3444
3450
|
"ui.repair.removed": "odebráno {file}",
|
|
3445
3451
|
"ui.repair.from": "zapečetěný stav: {commit} · kopie nahrazených souborů: .strom/quarantine/",
|
|
3446
3452
|
"ui.repair.still": "{n, plural, one {zbývá # problém} few {zbývají # problémy} other {zbývá # problémů}} → strom verify",
|
|
3453
|
+
"ui.repair.lock": "odstraněno .git/index.lock – zámek gitu ukončeného uprostřed práce",
|
|
3454
|
+
"ui.repair.index": "index gitu vrácen k zapečetěnému stavu: {n, plural, one {# soubor} few {# soubory} other {# souborů}} po přerušeném zápisu (ve složce se nic nezměnilo)",
|
|
3447
3455
|
"ui.error.seal.repair-in-terminal": "výzkum „{name}“ obsahuje práci zapečetěnou klíčem stromu z terminálu, který strom spuštěný z aplikace nevidí: nic se neopravilo",
|
|
3448
3456
|
"ui.error.seal.repair-in-terminal.hint": "ve vlastním terminálu: strom repair, pak strom seal adopt – ten vidí oba klíče a vrátí jen to, co se udělalo mimo strom",
|
|
3449
3457
|
"ui.error.back.busy": "na výzkumu se právě pracuje: návrat až po skončení práce",
|
package/assets/lang/de.json
CHANGED
|
@@ -1884,6 +1884,12 @@
|
|
|
1884
1884
|
"ui.check.streetplaces": "{n, plural, one {# Angabe hat} other {# Angaben haben}} eine Straße oder eine Nummer im Ort",
|
|
1885
1885
|
"ui.error.tree.not-downloaded": "noch nicht aus iCloud geladen: {n, plural, one {# Datei} other {# Dateien}} der Forschung (die erste: {first}) – nichts wurde geschrieben",
|
|
1886
1886
|
"ui.error.tree.not-downloaded.hint": "den Ordner der Forschung im Finder öffnen und die Dateien laden (oder den Ordner aus iCloud Drive herausnehmen), dann erneut ausführen – nicht strom repair",
|
|
1887
|
+
"ui.error.tree.index-leftovers": "im Index von git ist geblieben, was ein unterbrochenes Schreiben hinterlassen hat ({n, plural, one {# Datei} other {# Dateien}}, die erste: {first}), und git konnte es nicht herausnehmen – nichts wurde geschrieben",
|
|
1888
|
+
"ui.error.tree.index-leftovers.hint": "strom repair (setzt den Index von git auf den letzten versiegelten Stand zurück; dann den Befehl erneut ausführen)",
|
|
1889
|
+
"ui.error.git.index-locked": "der Index von git ist gesperrt (.git/index.lock) – ein anderes git arbeitet in der Forschung, oder ein mitten in der Arbeit beendetes git hat seine Sperre hinterlassen",
|
|
1890
|
+
"ui.error.git.index-locked.hint": "strom repair (entfernt eine Sperre, die seit 10 Minuten kein git mehr hält; dann den Befehl erneut ausführen)",
|
|
1891
|
+
"ui.error.repair.index": "git konnte seinen Index nicht auf den versiegelten Stand zurücksetzen",
|
|
1892
|
+
"ui.error.repair.index.hint": "Programme schließen, die den Ordner der Forschung halten könnten (Synchronisierung, Virenscan, ein anderes git), dann erneut strom repair",
|
|
1887
1893
|
"ui.error.tree.changed-outside": "die Daten der Forschung wurden außerhalb von strom geändert ({n, plural, one {# Problem} other {# Probleme}}): nichts wurde geschrieben",
|
|
1888
1894
|
"ui.error.tree.changed-outside.hint": "strom verify (Einzelheiten)\nstrom repair (stellt den letzten versiegelten Stand wieder her)",
|
|
1889
1895
|
"ui.error.tree.changed-outside.keys.hint": "strom verify (Einzelheiten)\nstrom repair, dann strom seal adopt (macht nur rückgängig, was außerhalb von strom geschah – die Arbeit beider Schlüssel dieses Computers bleibt)",
|
|
@@ -3444,6 +3450,8 @@
|
|
|
3444
3450
|
"ui.repair.removed": "entfernt {file}",
|
|
3445
3451
|
"ui.repair.from": "versiegelter Stand: {commit} · Kopien ersetzter Dateien: .strom/quarantine/",
|
|
3446
3452
|
"ui.repair.still": "noch {n, plural, one {# Problem} other {# Probleme}} → strom verify",
|
|
3453
|
+
"ui.repair.lock": "entfernt .git/index.lock – die Sperre eines mitten in der Arbeit beendeten git",
|
|
3454
|
+
"ui.repair.index": "Index von git auf den versiegelten Stand zurückgesetzt: {n, plural, one {# Datei} other {# Dateien}} nach einem unterbrochenen Schreiben (im Ordner hat sich nichts geändert)",
|
|
3447
3455
|
"ui.error.seal.repair-in-terminal": "die Forschung „{name}“ enthält Arbeit, versiegelt mit dem Schlüssel des strom aus dem Terminal, den ein aus einer App gestartetes strom nicht sieht: nichts wurde repariert",
|
|
3448
3456
|
"ui.error.seal.repair-in-terminal.hint": "in einem eigenen Terminal: strom repair, dann strom seal adopt – es sieht beide Schlüssel und macht nur rückgängig, was außerhalb von strom geschah",
|
|
3449
3457
|
"ui.error.back.busy": "an dieser Forschung wird gerade gearbeitet: eine Rückkehr erst, wenn die Arbeit beendet ist",
|
package/assets/lang/pl.json
CHANGED
|
@@ -1884,6 +1884,12 @@
|
|
|
1884
1884
|
"ui.check.streetplaces": "{n, plural, one {# fakt ma} few {# fakty mają} many {# faktów ma} other {# faktów ma}} w miejscu ulicę lub numer domu",
|
|
1885
1885
|
"ui.error.tree.not-downloaded": "jeszcze nie pobrano z iCloud: {n, plural, one {# plik} few {# pliki} many {# plików} other {# plików}} badania (pierwszy: {first}) – nic nie zapisano",
|
|
1886
1886
|
"ui.error.tree.not-downloaded.hint": "otworzyć folder badania w Finderze i pobrać pliki (albo wyjąć folder z iCloud Drive), potem uruchomić ponownie – nie strom repair",
|
|
1887
|
+
"ui.error.tree.index-leftovers": "w indeksie gita zostało to, co zostawił przerwany zapis ({n, plural, one {# plik} few {# pliki} many {# plików} other {# plików}}, pierwszy: {first}), a git nie zdołał tego wycofać – nic nie zapisano",
|
|
1888
|
+
"ui.error.tree.index-leftovers.hint": "strom repair (przywraca indeks gita do ostatniego zapieczętowanego stanu; potem uruchomić polecenie ponownie)",
|
|
1889
|
+
"ui.error.git.index-locked": "indeks gita jest zablokowany (.git/index.lock) – w badaniu pracuje inny git albo blokadę zostawił git przerwany w trakcie pracy",
|
|
1890
|
+
"ui.error.git.index-locked.hint": "strom repair (usuwa blokadę, której żaden git nie trzyma dłużej niż 10 minut; potem uruchomić polecenie ponownie)",
|
|
1891
|
+
"ui.error.repair.index": "git nie zdołał przywrócić swojego indeksu do zapieczętowanego stanu",
|
|
1892
|
+
"ui.error.repair.index.hint": "zamknąć programy, które mogą trzymać folder badania (synchronizacja, skanowanie antywirusowe, inny git), potem ponownie strom repair",
|
|
1887
1893
|
"ui.error.tree.changed-outside": "dane badania zmieniły się poza strom ({n, plural, one {# problem} few {# problemy} many {# problemów} other {# problemów}}): nic nie zapisano",
|
|
1888
1894
|
"ui.error.tree.changed-outside.hint": "strom verify (szczegóły)\nstrom repair (przywraca ostatni zapieczętowany stan)",
|
|
1889
1895
|
"ui.error.tree.changed-outside.keys.hint": "strom verify (szczegóły)\nstrom repair, potem strom seal adopt (cofa tylko to, co zrobiono poza strom – praca obu kluczy tego komputera zostaje)",
|
|
@@ -3444,6 +3450,8 @@
|
|
|
3444
3450
|
"ui.repair.removed": "usunięto {file}",
|
|
3445
3451
|
"ui.repair.from": "stan zapieczętowany: {commit} · kopie zastąpionych plików: .strom/quarantine/",
|
|
3446
3452
|
"ui.repair.still": "{n, plural, one {zostaje # problem} few {zostają # problemy} many {zostaje # problemów} other {zostaje # problemów}} → strom verify",
|
|
3453
|
+
"ui.repair.lock": "usunięto .git/index.lock – blokada gita przerwanego w trakcie pracy",
|
|
3454
|
+
"ui.repair.index": "indeks gita przywrócony do zapieczętowanego stanu: {n, plural, one {# plik} few {# pliki} many {# plików} other {# plików}} po przerwanym zapisie (w folderze nic się nie zmieniło)",
|
|
3447
3455
|
"ui.error.seal.repair-in-terminal": "badanie „{name}” zawiera pracę zapieczętowaną kluczem strom z terminala, którego strom uruchomiony z aplikacji nie widzi: nic nie naprawiono",
|
|
3448
3456
|
"ui.error.seal.repair-in-terminal.hint": "we własnym terminalu: strom repair, potem strom seal adopt – ten widzi oba klucze i cofa tylko to, co zrobiono poza strom",
|
|
3449
3457
|
"ui.error.back.busy": "nad badaniem właśnie trwa praca: powrót dopiero po jej zakończeniu",
|
package/dist/cli/commit.js
CHANGED
|
@@ -47,6 +47,10 @@ export function autoCommit(ctx, def) {
|
|
|
47
47
|
written.add(f.path);
|
|
48
48
|
for (const f of tree.opsFilesTouched())
|
|
49
49
|
written.add(f);
|
|
50
|
+
// what an interrupted write left in git's index (core/integrity.ts leftoverOf): its paths with the commit's own, so
|
|
51
|
+
// the commit takes the folder as it is there — never a record or log of nobody's into the history
|
|
52
|
+
for (const f of snap.leftovers)
|
|
53
|
+
written.add(f);
|
|
50
54
|
// an archive: no agent edits its free-form folders — a person's own file in notes/ is theirs, never swept into a
|
|
51
55
|
// commit of something else (found on Windows: strom mode committed a file of the user's) — nor by the switch itself
|
|
52
56
|
const free = isArchive(tree) || def.path[0] === "mode" ? ["inputs", "output"] : ["notes", "tools", "inputs", "output"];
|
package/dist/cli/ui.js
CHANGED
|
@@ -1866,6 +1866,12 @@ export const UI = {
|
|
|
1866
1866
|
"ui.check.streetplaces": "{n, plural, one {# fact holds} other {# facts hold}} a street or a house number in the place",
|
|
1867
1867
|
"ui.error.tree.not-downloaded": "{n, plural, one {# file} other {# files}} of the research not downloaded from iCloud yet (the first: {first}) — nothing written",
|
|
1868
1868
|
"ui.error.tree.not-downloaded.hint": "open the research's folder in Finder and download them (or take the folder out of iCloud Drive), then run it again — not strom repair",
|
|
1869
|
+
"ui.error.tree.index-leftovers": "git's index still holds what an interrupted write left ({n, plural, one {# file} other {# files}}, the first: {first}) and git could not take it out — nothing written",
|
|
1870
|
+
"ui.error.tree.index-leftovers.hint": "strom repair (puts git's index back to the last sealed state; then run the command again)",
|
|
1871
|
+
"ui.error.git.index-locked": "git's index is locked (.git/index.lock) — another git is at work in the research, or one that ended mid-way left its lock",
|
|
1872
|
+
"ui.error.git.index-locked.hint": "strom repair (takes away a lock no git has held for 10 minutes; then run the command again)",
|
|
1873
|
+
"ui.error.repair.index": "git could not put its index back to the sealed state",
|
|
1874
|
+
"ui.error.repair.index.hint": "programs that may hold the research's folder closed (a sync tool, an antivirus scan, another git), then strom repair again",
|
|
1869
1875
|
"ui.error.tree.changed-outside": "the research's data was changed outside strom ({n, plural, one {# problem} other {# problems}}): nothing written",
|
|
1870
1876
|
"ui.error.tree.changed-outside.hint": "strom verify (details)\nstrom repair (restores the last sealed state)",
|
|
1871
1877
|
"ui.error.tree.changed-outside.keys.hint": "strom verify (details)\nstrom repair, then strom seal adopt (undoes only what was done outside strom — the work of both keys of this computer stays)",
|
|
@@ -3099,6 +3105,8 @@ export const UI = {
|
|
|
3099
3105
|
"ui.repair.removed": "removed {file}",
|
|
3100
3106
|
"ui.repair.from": "sealed state: {commit} · copies of replaced files: .strom/quarantine/",
|
|
3101
3107
|
"ui.repair.still": "still {n, plural, one {# problem} other {# problems}} → strom verify",
|
|
3108
|
+
"ui.repair.lock": "taken away .git/index.lock — the lock of a git that ended mid-way",
|
|
3109
|
+
"ui.repair.index": "git's index back to the sealed state: {n, plural, one {# file} other {# files}} an interrupted write had left there (nothing in the folder changed)",
|
|
3102
3110
|
"ui.error.seal.repair-in-terminal": "\"{name}\" holds work sealed with the key of the terminal's strom, which a strom started by an app cannot see: nothing repaired",
|
|
3103
3111
|
"ui.error.seal.repair-in-terminal.hint": "in a terminal of its own: strom repair, then strom seal adopt — it sees both keys and undoes only what was done outside strom",
|
|
3104
3112
|
"ui.error.back.busy": "somebody is at work on this research: a return only once the work is finished",
|
package/dist/commands/checks.js
CHANGED
|
@@ -171,10 +171,20 @@ function repair(tree) {
|
|
|
171
171
|
params: { name: tree.config.name },
|
|
172
172
|
});
|
|
173
173
|
const headSealed = head !== undefined && head.hash === sealed;
|
|
174
|
+
// a lock of git's index a git that ended mid-way left (killed with the command that ran it): no git holds it any
|
|
175
|
+
// more — taken away, else nothing could be written again (a fresh one may be a git at work: left)
|
|
176
|
+
const stale = git.staleIndexLock(tree.root);
|
|
177
|
+
if (stale)
|
|
178
|
+
fs.rmSync(stale, { force: true });
|
|
174
179
|
// Paths to compare: whatever differs between the sealed commit and the working tree.
|
|
175
180
|
const candidates = new Set();
|
|
176
|
-
|
|
181
|
+
// …and what git's index holds otherwise than the last commit (a write taken back after its git add): back to it
|
|
182
|
+
const staged = [];
|
|
183
|
+
for (const c of git.changes(tree.root, SEALED_PATHS)) {
|
|
177
184
|
candidates.add(c.path);
|
|
185
|
+
if (!" ?!".includes(c.code[0] ?? " "))
|
|
186
|
+
staged.push(c.path);
|
|
187
|
+
}
|
|
178
188
|
if (!headSealed) {
|
|
179
189
|
const r = git.runGit(tree.root, ["diff", "--name-only", "-z", sealed, "HEAD", "--", ...SEALED_PATHS]);
|
|
180
190
|
for (const p of r.stdout.split("\0").filter(Boolean))
|
|
@@ -204,7 +214,17 @@ function repair(tree) {
|
|
|
204
214
|
// commit stays unsealed and every write refused, with nothing left to repair
|
|
205
215
|
if (!headSealed)
|
|
206
216
|
tree.commit(`Repair: restore the sealed state of ${sealed.slice(0, 8)}\n\nCommits made outside strom were undone for data/, strom.json, history/ and quality/.`, SEALED_PATHS, true);
|
|
207
|
-
|
|
217
|
+
// the folder as the sealed commit, HEAD: git's index as HEAD too (a commit above put it so already)
|
|
218
|
+
else if (staged.length) {
|
|
219
|
+
const said = git.unstage(tree.root, staged);
|
|
220
|
+
if (said !== undefined)
|
|
221
|
+
throw new StromError(`git could not put its index back to the sealed state: ${said}`, {
|
|
222
|
+
hint: "programs that may hold the research's folder closed (a sync tool, an antivirus scan, another git), then strom repair again",
|
|
223
|
+
code: "repair.index",
|
|
224
|
+
details: staged.slice(0, 50),
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return { restored, quarantined, from: sealed, resealed: !headSealed, unstaged: headSealed ? staged.length : 0, lock: !!stale };
|
|
208
228
|
}
|
|
209
229
|
register({
|
|
210
230
|
path: ["repair"],
|
|
@@ -225,11 +245,15 @@ register({
|
|
|
225
245
|
const after = verifyFast(tree).findings.filter((f) => f.level === "error" && f.code !== OTHER_KEY);
|
|
226
246
|
const unite = !!tree.key && otherKeys(tree.env, tree.config.id, tree.key).length > 0 && keysToUnite(tree).length > 0;
|
|
227
247
|
const next = unite ? ui(lang, "ui.repair.unite") : undefined;
|
|
248
|
+
// what an interrupted write left (a stale lock of git's index, what it staged): said before the rest
|
|
249
|
+
const index = [...(r.lock ? [ui(lang, "ui.repair.lock")] : []), ...(r.unstaged ? [ui(lang, "ui.repair.index", { n: r.unstaged })] : [])];
|
|
228
250
|
const text = r.restored.length + r.quarantined.length === 0
|
|
229
251
|
? r.resealed
|
|
230
|
-
? lines(ui(lang, "ui.repair.resealed"), next)
|
|
231
|
-
:
|
|
232
|
-
|
|
252
|
+
? lines(...index, ui(lang, "ui.repair.resealed"), next)
|
|
253
|
+
: index.length
|
|
254
|
+
? lines(...index, after.length ? ui(lang, "ui.repair.still", { n: after.length }) : next)
|
|
255
|
+
: lines(ui(lang, "ui.repair.nothing"), next)
|
|
256
|
+
: lines(...index, ...r.restored.map((file) => ui(lang, "ui.repair.restored", { file })), ...r.quarantined.map((file) => ui(lang, "ui.repair.removed", { file })), ui(lang, "ui.repair.from", { commit: r.from.slice(0, 8) }), after.length ? ui(lang, "ui.repair.still", { n: after.length }) : next);
|
|
233
257
|
return { text, data: { ...r, ok: after.length === 0, ...(unite ? { unite: "strom seal adopt" } : {}) }, exitCode: after.length ? 1 : 0 };
|
|
234
258
|
},
|
|
235
259
|
}, {
|
package/dist/core/git.js
CHANGED
|
@@ -128,7 +128,22 @@ export function runGitLater(cwd, args, timeoutMs = 60_000) {
|
|
|
128
128
|
/** A git that failed: interrupted, refused writing into the research (git.unwritable), or its own words. */
|
|
129
129
|
function gitFailed(cwd, args, r, what = `git ${args[0]}`) {
|
|
130
130
|
const said = r.stderr.trim() || r.stdout.trim();
|
|
131
|
-
return gitInterrupted(args, r) ?? (gitRefusedWords(said) ? gitUnwritable(gitRefusedWhere(cwd, said), said) : new StromError(`${what} failed: ${said}`));
|
|
131
|
+
return gitInterrupted(args, r) ?? (gitRefusedWords(said) ? gitUnwritable(gitRefusedWhere(cwd, said), said) : indexLocked(said) ? indexLockedError(what, said) : new StromError(`${what} failed: ${said}`));
|
|
132
|
+
}
|
|
133
|
+
/** git refused because its index is locked ("Unable to create '…/index.lock': File exists"). */
|
|
134
|
+
function indexLocked(said) {
|
|
135
|
+
return /index\.lock['"]?: File exists/u.test(said);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* git's index locked: another git at work in the research, or the lock a git that ended mid-way left (killed with the
|
|
139
|
+
* command that ran it). Never "remove the file manually" for a person: strom repair takes a stale one away.
|
|
140
|
+
*/
|
|
141
|
+
function indexLockedError(what, said) {
|
|
142
|
+
return new StromError(`${what} failed: git's index is locked (.git/index.lock) — another git is at work in the research, or one that ended mid-way left its lock`, {
|
|
143
|
+
hint: "strom repair (takes away a lock no git has held for 10 minutes; then run the command again)",
|
|
144
|
+
code: "git.index-locked",
|
|
145
|
+
details: [said],
|
|
146
|
+
});
|
|
132
147
|
}
|
|
133
148
|
function git(cwd, args, input) {
|
|
134
149
|
const r = runGit(cwd, args, input);
|
|
@@ -408,16 +423,41 @@ export function changes(dir, pathspec = []) {
|
|
|
408
423
|
}
|
|
409
424
|
/**
|
|
410
425
|
* Take these paths out of what is staged, back to HEAD (a command taken back after its git add, its commit not made:
|
|
411
|
-
* nothing it wrote stays staged, seen as changed outside strom).
|
|
426
|
+
* nothing it wrote stays staged, seen as changed outside strom). Each path on the command line, in parts (pathParts —
|
|
427
|
+
* never --pathspec-from-file, which a git before 2.25 does not know). Never throws: git's words when it could not (its
|
|
428
|
+
* index held by another program, a lock a git that ended mid-way left), else undefined — the next write, or strom
|
|
429
|
+
* repair, takes the rest out (core/integrity.ts settleLeftovers).
|
|
412
430
|
*/
|
|
413
431
|
export function unstage(dir, paths) {
|
|
414
432
|
if (paths.length === 0 || !hasHead(dir))
|
|
415
|
-
return;
|
|
433
|
+
return undefined;
|
|
434
|
+
let said;
|
|
435
|
+
for (const part of pathParts(paths.map((p) => p.replace(/\\/g, "/")))) {
|
|
436
|
+
try {
|
|
437
|
+
const r = runGit(dir, ["reset", "-q", "--", ...part]);
|
|
438
|
+
if (r.status !== 0)
|
|
439
|
+
said ??= r.stderr.trim() || r.stdout.trim() || `git reset ended with ${r.status}`;
|
|
440
|
+
}
|
|
441
|
+
catch (e) {
|
|
442
|
+
said ??= e.message;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return said;
|
|
446
|
+
}
|
|
447
|
+
/** The lock git keeps on its index while it writes it ('.git/index.lock'). */
|
|
448
|
+
export function indexLock(dir) {
|
|
449
|
+
return path.join(dir, ".git", "index.lock");
|
|
450
|
+
}
|
|
451
|
+
/** How old a lock of git's index is stale: no git holds its index for minutes (it writes it in a moment). */
|
|
452
|
+
export const STALE_INDEX_LOCK_MS = 10 * 60_000;
|
|
453
|
+
/** A lock of git's index a git that ended mid-way left (stale: STALE_INDEX_LOCK_MS old), else undefined. */
|
|
454
|
+
export function staleIndexLock(dir, now = Date.now()) {
|
|
455
|
+
const lock = indexLock(dir);
|
|
416
456
|
try {
|
|
417
|
-
|
|
457
|
+
return now - fs.statSync(lock).mtimeMs >= STALE_INDEX_LOCK_MS ? lock : undefined;
|
|
418
458
|
}
|
|
419
459
|
catch {
|
|
420
|
-
|
|
460
|
+
return undefined;
|
|
421
461
|
}
|
|
422
462
|
}
|
|
423
463
|
/** File content at a revision, or undefined if it did not exist there. */
|
package/dist/core/integrity.js
CHANGED
|
@@ -34,9 +34,51 @@ export function isHistoryPath(p) {
|
|
|
34
34
|
}
|
|
35
35
|
export function snapshot(tree) {
|
|
36
36
|
if (!git.hasHead(tree.root))
|
|
37
|
-
return { changes: [], head: new Map() };
|
|
38
|
-
const
|
|
39
|
-
|
|
37
|
+
return { changes: [], head: new Map(), leftovers: [] };
|
|
38
|
+
const all = git.changes(tree.root, SEALED_PATHS);
|
|
39
|
+
const head = git.showFiles(tree.root, "HEAD", all.map((c) => c.path));
|
|
40
|
+
const leftovers = all.filter((c) => leftoverOf(tree.root, c, head.get(c.path))).map((c) => c.path);
|
|
41
|
+
const changes = leftovers.length ? all.filter((c) => !leftovers.includes(c.path)) : all;
|
|
42
|
+
return { changes, head, leftovers };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* What a write taken back after its git add left in git's index (found on Windows, 1.26.0: its files put back, the
|
|
46
|
+
* process ended or git's index held by another program before they were taken out of it — every write after it refused,
|
|
47
|
+
* "data was changed outside strom", its new log and record said deleted): a path the index holds while it is neither
|
|
48
|
+
* in the last commit nor in the folder. Nothing of it was ever in the history and nothing of it is in the folder: no
|
|
49
|
+
* change of anybody's. Only that: a file of the last commit deleted or edited (staged or not), or the index alone
|
|
50
|
+
* differing from a file of the last commit, is still said — strom repair puts that back (its index with it).
|
|
51
|
+
*/
|
|
52
|
+
function leftoverOf(root, c, committed) {
|
|
53
|
+
// added to the index ("AD": a path the last commit does not have, so git says) — never a deletion or a change of a
|
|
54
|
+
// path of the last commit, whatever was read of it
|
|
55
|
+
if (c.code[0] !== "A")
|
|
56
|
+
return false;
|
|
57
|
+
const abs = path.join(root, c.path);
|
|
58
|
+
return committed === undefined && !fs.existsSync(abs) && !inCloudOnly(abs);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Take what an interrupted write left in git's index out of it (back to the last commit) before strom writes: else its
|
|
62
|
+
* next commit would hold it — a record or a log in the history that is in no folder. Under the tree's lock. git's words
|
|
63
|
+
* when it could not (its index held, a lock left), else undefined.
|
|
64
|
+
*/
|
|
65
|
+
export function settleLeftovers(tree, snap) {
|
|
66
|
+
if (!snap.leftovers.length || tree.dryRun)
|
|
67
|
+
return undefined;
|
|
68
|
+
return git.unstage(tree.root, snap.leftovers);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Writing refused while git's index holds what an interrupted write left and git could not take it out: the way is
|
|
72
|
+
* strom repair (it takes away a lock no git holds any more), never "changed outside strom".
|
|
73
|
+
*/
|
|
74
|
+
export function leftoversError(files, said) {
|
|
75
|
+
const first = files[0] ?? "data/";
|
|
76
|
+
return new StromError(`git's index still holds what an interrupted write left (${counted(Math.max(1, files.length), "file")}, the first: ${first}) and git could not take it out — nothing written`, {
|
|
77
|
+
hint: "strom repair (puts git's index back to the last sealed state; then run the command again)",
|
|
78
|
+
code: "tree.index-leftovers",
|
|
79
|
+
params: { n: String(Math.max(1, files.length)), first },
|
|
80
|
+
details: [said, ...files.slice(0, 50)],
|
|
81
|
+
});
|
|
40
82
|
}
|
|
41
83
|
const RECORD_DIRS = new Set(Object.values(RECORD_TYPES).map((d) => `data/${d.dir}/`));
|
|
42
84
|
function isRecordPath(p) {
|
|
@@ -478,7 +520,11 @@ export function writableUnasked(tree) {
|
|
|
478
520
|
if (!tree.key)
|
|
479
521
|
return false;
|
|
480
522
|
try {
|
|
481
|
-
|
|
523
|
+
const snap = snapshot(tree);
|
|
524
|
+
// what an interrupted write left in git's index: out of it first, or no write (its commit would hold it)
|
|
525
|
+
if (settleLeftovers(tree, snap) !== undefined)
|
|
526
|
+
return false;
|
|
527
|
+
return !verifyFast(tree, snap).findings.some((f) => f.level === "error");
|
|
482
528
|
}
|
|
483
529
|
catch {
|
|
484
530
|
return false;
|
|
@@ -499,10 +545,15 @@ export function lastSealed(tree, key) {
|
|
|
499
545
|
export const REPAIR_IN_TERMINAL_HINT = "the user runs in their terminal: strom repair, then strom seal adopt (it sees both keys and undoes only what was done outside strom)";
|
|
500
546
|
/** Refuse to write on top of data that was changed outside strom. */
|
|
501
547
|
export function assertIntact(tree) {
|
|
502
|
-
const
|
|
548
|
+
const snap = snapshot(tree);
|
|
549
|
+
const { findings } = verifyFast(tree, snap);
|
|
503
550
|
const errors = findings.filter((f) => f.level === "error");
|
|
504
551
|
if (errors.length === 0) {
|
|
505
552
|
tree.requireKey();
|
|
553
|
+
// what an interrupted write left in git's index (no change of anybody's): out of it before this write commits
|
|
554
|
+
const said = settleLeftovers(tree, snap);
|
|
555
|
+
if (said !== undefined)
|
|
556
|
+
throw leftoversError(snap.leftovers, said);
|
|
506
557
|
return;
|
|
507
558
|
}
|
|
508
559
|
// the last commit sealed with another key of this computer: the person unites them (never strom repair)
|
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.26.
|
|
34
|
+
export const VERSION = "1.26.1";
|
|
35
35
|
const GITIGNORE = `# Strom Research — local state and large files are not versioned
|
|
36
36
|
.strom/
|
|
37
37
|
/media/
|
|
@@ -384,7 +384,8 @@ export class Tree {
|
|
|
384
384
|
failed ??= e;
|
|
385
385
|
}
|
|
386
386
|
}
|
|
387
|
-
// what a commit that did not happen staged (its git add done): back to HEAD, nothing seen as changed outside strom
|
|
387
|
+
// what a commit that did not happen staged (its git add done): back to HEAD, nothing seen as changed outside strom —
|
|
388
|
+
// what git could not take out now (its index held, the process ending) the next write or strom repair takes out
|
|
388
389
|
if (restored.length && !this.dryRun)
|
|
389
390
|
git.unstage(this.root, restored);
|
|
390
391
|
this.undo.clear();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strom-research",
|
|
3
|
-
"version": "1.26.
|
|
3
|
+
"version": "1.26.1",
|
|
4
4
|
"description": "Genealogical research toolkit for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"stromLayout": 2,
|
|
@@ -59,8 +59,5 @@
|
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@types/node": "^22.20.4",
|
|
61
61
|
"typescript": "^7.0.2"
|
|
62
|
-
},
|
|
63
|
-
"publishConfig": {
|
|
64
|
-
"tag": "beta"
|
|
65
62
|
}
|
|
66
63
|
}
|