kotsu-cli 0.1.0__tar.gz → 0.1.1__tar.gz

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.
Files changed (138) hide show
  1. kotsu_cli-0.1.0/.github/workflows/verificar.yml → kotsu_cli-0.1.1/.github/workflows/check.yml +4 -4
  2. kotsu_cli-0.1.0/.github/workflows/publicar.yml → kotsu_cli-0.1.1/.github/workflows/publish.yml +8 -8
  3. {kotsu_cli-0.1.0 → kotsu_cli-0.1.1}/.gitignore +5 -3
  4. kotsu_cli-0.1.1/AGENTS.md +110 -0
  5. {kotsu_cli-0.1.0 → kotsu_cli-0.1.1}/PKG-INFO +65 -59
  6. {kotsu_cli-0.1.0 → kotsu_cli-0.1.1}/README.md +64 -57
  7. kotsu_cli-0.1.1/docs/images/SOURCES.md +5 -0
  8. kotsu_cli-0.1.0/docs/imagens/banner.en.svg → kotsu_cli-0.1.1/docs/images/banner.svg +4 -4
  9. kotsu_cli-0.1.0/docs/imagens/icones/lancar.svg → kotsu_cli-0.1.1/docs/images/icons/add-entry.svg +1 -1
  10. kotsu_cli-0.1.0/docs/imagens/icones/dados.svg → kotsu_cli-0.1.1/docs/images/icons/data.svg +1 -1
  11. kotsu_cli-0.1.0/docs/imagens/icones/todomes.svg → kotsu_cli-0.1.1/docs/images/icons/every-month.svg +1 -1
  12. kotsu_cli-0.1.0/docs/imagens/icones/instalar.svg → kotsu_cli-0.1.1/docs/images/icons/install.svg +1 -1
  13. kotsu_cli-0.1.0/docs/imagens/icones/parcelas.svg → kotsu_cli-0.1.1/docs/images/icons/installments.svg +1 -1
  14. kotsu_cli-0.1.0/docs/imagens/icones/teclado.svg → kotsu_cli-0.1.1/docs/images/icons/keyboard.svg +1 -1
  15. kotsu_cli-0.1.0/docs/imagens/icones/licenca.svg → kotsu_cli-0.1.1/docs/images/icons/license.svg +1 -1
  16. kotsu_cli-0.1.0/docs/imagens/icones/privado.svg → kotsu_cli-0.1.1/docs/images/icons/private.svg +1 -1
  17. kotsu_cli-0.1.0/docs/imagens/icones/estrutura.svg → kotsu_cli-0.1.1/docs/images/icons/structure.svg +1 -1
  18. kotsu_cli-0.1.0/docs/imagens/icones/temas.svg → kotsu_cli-0.1.1/docs/images/icons/themes.svg +1 -1
  19. kotsu_cli-0.1.0/instalar.ps1 → kotsu_cli-0.1.1/install.ps1 +12 -12
  20. kotsu_cli-0.1.0/instalar.sh → kotsu_cli-0.1.1/install.sh +10 -10
  21. {kotsu_cli-0.1.0 → kotsu_cli-0.1.1}/pyproject.toml +6 -7
  22. kotsu_cli-0.1.1/src/kotsu/__init__.py +3 -0
  23. kotsu_cli-0.1.1/src/kotsu/__main__.py +215 -0
  24. kotsu_cli-0.1.1/src/kotsu/domain/__init__.py +5 -0
  25. kotsu_cli-0.1.1/src/kotsu/domain/filter.py +63 -0
  26. kotsu_cli-0.1.1/src/kotsu/domain/installments.py +50 -0
  27. kotsu_cli-0.1.1/src/kotsu/domain/line.py +185 -0
  28. kotsu_cli-0.1.1/src/kotsu/domain/merge.py +509 -0
  29. kotsu_cli-0.1.1/src/kotsu/domain/models.py +95 -0
  30. kotsu_cli-0.1.1/src/kotsu/domain/money.py +10 -0
  31. kotsu_cli-0.1.1/src/kotsu/domain/month.py +57 -0
  32. kotsu_cli-0.1.1/src/kotsu/domain/recurrence.py +20 -0
  33. kotsu_cli-0.1.1/src/kotsu/domain/totals.py +17 -0
  34. kotsu_cli-0.1.1/src/kotsu/storage/__init__.py +4 -0
  35. kotsu_cli-0.1.1/src/kotsu/storage/backup.py +70 -0
  36. kotsu_cli-0.1.1/src/kotsu/storage/database.py +515 -0
  37. kotsu_cli-0.1.1/src/kotsu/storage/exchange.py +284 -0
  38. kotsu_cli-0.1.1/src/kotsu/storage/lock.py +139 -0
  39. kotsu_cli-0.1.0/src/money_cli/armazenamento/migracoes/0001_inicial.sql → kotsu_cli-0.1.1/src/kotsu/storage/migrations/0001_initial.sql +5 -4
  40. kotsu_cli-0.1.0/src/money_cli/armazenamento/migracoes/0002_recorrencia.sql → kotsu_cli-0.1.1/src/kotsu/storage/migrations/0002_recurrence.sql +3 -2
  41. kotsu_cli-0.1.0/src/money_cli/armazenamento/migracoes/0003_mesclagem.sql → kotsu_cli-0.1.1/src/kotsu/storage/migrations/0003_merge.sql +8 -8
  42. kotsu_cli-0.1.1/src/kotsu/storage/migrations/0004_english_names.sql +124 -0
  43. kotsu_cli-0.1.1/src/kotsu/storage/migrations/__init__.py +32 -0
  44. kotsu_cli-0.1.1/src/kotsu/storage/paths.py +89 -0
  45. kotsu_cli-0.1.1/src/kotsu/storage/preferences.py +41 -0
  46. kotsu_cli-0.1.1/src/kotsu/ui/__init__.py +1 -0
  47. kotsu_cli-0.1.1/src/kotsu/ui/app.py +759 -0
  48. kotsu_cli-0.1.1/src/kotsu/ui/colors.py +31 -0
  49. kotsu_cli-0.1.1/src/kotsu/ui/dialogs.py +148 -0
  50. kotsu_cli-0.1.1/src/kotsu/ui/themes.py +79 -0
  51. kotsu_cli-0.1.1/tests/conftest.py +16 -0
  52. kotsu_cli-0.1.1/tests/test_add_entry.py +96 -0
  53. kotsu_cli-0.1.1/tests/test_backup.py +103 -0
  54. kotsu_cli-0.1.1/tests/test_domain.py +81 -0
  55. kotsu_cli-0.1.1/tests/test_exchange.py +612 -0
  56. kotsu_cli-0.1.1/tests/test_layers.py +46 -0
  57. kotsu_cli-0.1.1/tests/test_line.py +160 -0
  58. kotsu_cli-0.1.1/tests/test_m2_domain.py +149 -0
  59. kotsu_cli-0.1.1/tests/test_performance_m2.py +77 -0
  60. kotsu_cli-0.1.1/tests/test_recurrence.py +180 -0
  61. kotsu_cli-0.1.1/tests/test_storage.py +213 -0
  62. kotsu_cli-0.1.1/tests/test_sync.py +167 -0
  63. kotsu_cli-0.1.1/tests/test_themes.py +107 -0
  64. kotsu_cli-0.1.1/tests/test_ui.py +66 -0
  65. kotsu_cli-0.1.1/tests/test_ui_add_entry.py +187 -0
  66. kotsu_cli-0.1.1/tests/test_ui_m2.py +238 -0
  67. kotsu_cli-0.1.1/tools/check.py +51 -0
  68. kotsu_cli-0.1.1/tools/check_install.py +103 -0
  69. kotsu_cli-0.1.1/tools/generate_vectors.py +602 -0
  70. kotsu_cli-0.1.1/tools/layers.py +118 -0
  71. kotsu_cli-0.1.1/vectors/dates.json +350 -0
  72. kotsu_cli-0.1.1/vectors/invalid.json +674 -0
  73. kotsu_cli-0.1.1/vectors/line.json +433 -0
  74. kotsu_cli-0.1.1/vectors/merge.json +1948 -0
  75. kotsu_cli-0.1.1/vectors/money.json +54 -0
  76. kotsu_cli-0.1.1/vectors/stamp.json +44 -0
  77. kotsu_cli-0.1.0/AGENTS.md +0 -91
  78. kotsu_cli-0.1.0/README.pt-BR.md +0 -226
  79. kotsu_cli-0.1.0/docs/imagens/FONTES.md +0 -5
  80. kotsu_cli-0.1.0/docs/imagens/banner.svg +0 -49
  81. kotsu_cli-0.1.0/ferramentas/camadas.py +0 -118
  82. kotsu_cli-0.1.0/ferramentas/gerar_vetores.py +0 -595
  83. kotsu_cli-0.1.0/ferramentas/testar_instalacao.py +0 -102
  84. kotsu_cli-0.1.0/ferramentas/verificar.py +0 -51
  85. kotsu_cli-0.1.0/src/money_cli/__init__.py +0 -3
  86. kotsu_cli-0.1.0/src/money_cli/__main__.py +0 -197
  87. kotsu_cli-0.1.0/src/money_cli/armazenamento/__init__.py +0 -4
  88. kotsu_cli-0.1.0/src/money_cli/armazenamento/backup.py +0 -70
  89. kotsu_cli-0.1.0/src/money_cli/armazenamento/banco.py +0 -525
  90. kotsu_cli-0.1.0/src/money_cli/armazenamento/caminhos.py +0 -72
  91. kotsu_cli-0.1.0/src/money_cli/armazenamento/migracoes/__init__.py +0 -32
  92. kotsu_cli-0.1.0/src/money_cli/armazenamento/preferencias.py +0 -31
  93. kotsu_cli-0.1.0/src/money_cli/armazenamento/trava.py +0 -123
  94. kotsu_cli-0.1.0/src/money_cli/armazenamento/troca.py +0 -285
  95. kotsu_cli-0.1.0/src/money_cli/dominio/__init__.py +0 -5
  96. kotsu_cli-0.1.0/src/money_cli/dominio/dinheiro.py +0 -10
  97. kotsu_cli-0.1.0/src/money_cli/dominio/filtro.py +0 -63
  98. kotsu_cli-0.1.0/src/money_cli/dominio/linha.py +0 -179
  99. kotsu_cli-0.1.0/src/money_cli/dominio/mes.py +0 -57
  100. kotsu_cli-0.1.0/src/money_cli/dominio/mescla.py +0 -440
  101. kotsu_cli-0.1.0/src/money_cli/dominio/parcelas.py +0 -52
  102. kotsu_cli-0.1.0/src/money_cli/dominio/recorrencia.py +0 -20
  103. kotsu_cli-0.1.0/src/money_cli/dominio/tipos.py +0 -95
  104. kotsu_cli-0.1.0/src/money_cli/dominio/totais.py +0 -17
  105. kotsu_cli-0.1.0/src/money_cli/tela/__init__.py +0 -1
  106. kotsu_cli-0.1.0/src/money_cli/tela/app.py +0 -756
  107. kotsu_cli-0.1.0/src/money_cli/tela/cores.py +0 -31
  108. kotsu_cli-0.1.0/src/money_cli/tela/perguntas.py +0 -144
  109. kotsu_cli-0.1.0/src/money_cli/tela/temas.py +0 -74
  110. kotsu_cli-0.1.0/tests/conftest.py +0 -16
  111. kotsu_cli-0.1.0/tests/test_armazenamento.py +0 -151
  112. kotsu_cli-0.1.0/tests/test_backup.py +0 -103
  113. kotsu_cli-0.1.0/tests/test_camadas.py +0 -46
  114. kotsu_cli-0.1.0/tests/test_desempenho_m2.py +0 -77
  115. kotsu_cli-0.1.0/tests/test_dominio.py +0 -81
  116. kotsu_cli-0.1.0/tests/test_lancar.py +0 -92
  117. kotsu_cli-0.1.0/tests/test_linha.py +0 -158
  118. kotsu_cli-0.1.0/tests/test_m2_dominio.py +0 -145
  119. kotsu_cli-0.1.0/tests/test_recorrencia.py +0 -185
  120. kotsu_cli-0.1.0/tests/test_sincronia.py +0 -133
  121. kotsu_cli-0.1.0/tests/test_tela.py +0 -68
  122. kotsu_cli-0.1.0/tests/test_tela_lancar.py +0 -183
  123. kotsu_cli-0.1.0/tests/test_tela_m2.py +0 -238
  124. kotsu_cli-0.1.0/tests/test_temas.py +0 -96
  125. kotsu_cli-0.1.0/tests/test_troca.py +0 -560
  126. kotsu_cli-0.1.0/vetores/carimbo.json +0 -44
  127. kotsu_cli-0.1.0/vetores/datas.json +0 -350
  128. kotsu_cli-0.1.0/vetores/dinheiro.json +0 -54
  129. kotsu_cli-0.1.0/vetores/invalidos.json +0 -674
  130. kotsu_cli-0.1.0/vetores/linha.json +0 -405
  131. kotsu_cli-0.1.0/vetores/mescla.json +0 -1948
  132. {kotsu_cli-0.1.0 → kotsu_cli-0.1.1}/LICENSE +0 -0
  133. /kotsu_cli-0.1.0/docs/imagens/divisor.svg → /kotsu_cli-0.1.1/docs/images/divider.svg +0 -0
  134. {kotsu_cli-0.1.0/docs/imagens/icones → kotsu_cli-0.1.1/docs/images/icons}/backup.svg +0 -0
  135. {kotsu_cli-0.1.0/docs/imagens/icones → kotsu_cli-0.1.1/docs/images/icons}/dev.svg +0 -0
  136. {kotsu_cli-0.1.0/docs/imagens → kotsu_cli-0.1.1/docs/images}/stack/claude.svg +0 -0
  137. {kotsu_cli-0.1.0/docs/imagens → kotsu_cli-0.1.1/docs/images}/stack/githubactions.svg +0 -0
  138. {kotsu_cli-0.1.0/docs/imagens → kotsu_cli-0.1.1/docs/images}/stack/python.svg +0 -0
@@ -1,11 +1,11 @@
1
- name: verificar
1
+ name: check
2
2
 
3
3
  on:
4
4
  push:
5
5
  pull_request:
6
6
 
7
7
  jobs:
8
- verificar:
8
+ check:
9
9
  strategy:
10
10
  fail-fast: false
11
11
  matrix:
@@ -18,6 +18,6 @@ jobs:
18
18
  with:
19
19
  python-version: ${{ matrix.python }}
20
20
  - run: python -m pip install -e ".[dev]"
21
- - run: python ferramentas/verificar.py
21
+ - run: python tools/check.py
22
22
  - run: python -m pip install pipx
23
- - run: python ferramentas/testar_instalacao.py
23
+ - run: python tools/check_install.py
@@ -1,32 +1,32 @@
1
- name: publicar
1
+ name: publish
2
2
 
3
- # Publica no PyPI quando uma tag v* (ex.: v0.1.0) é enviada. Usa Trusted Publishing: sem token.
3
+ # Publishes to PyPI when a v* tag (e.g. v0.1.0) is pushed. Uses Trusted Publishing: no token.
4
4
  on:
5
5
  push:
6
6
  tags: ["v*"]
7
7
 
8
8
  jobs:
9
- construir:
9
+ build:
10
10
  runs-on: ubuntu-latest
11
11
  steps:
12
12
  - uses: actions/checkout@v4
13
13
  - uses: actions/setup-python@v5
14
14
  with:
15
15
  python-version: "3.12"
16
- - name: Confere a versão da tag
16
+ - name: Check the tag version
17
17
  run: |
18
18
  v=$(python -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
19
- test "v$v" = "$GITHUB_REF_NAME" || { echo "tag $GITHUB_REF_NAME != versão $v"; exit 1; }
19
+ test "v$v" = "$GITHUB_REF_NAME" || { echo "tag $GITHUB_REF_NAME != version $v"; exit 1; }
20
20
  - run: pip install -e ".[dev]" build
21
- - run: python ferramentas/verificar.py
21
+ - run: python tools/check.py
22
22
  - run: python -m build
23
23
  - uses: actions/upload-artifact@v4
24
24
  with:
25
25
  name: dist
26
26
  path: dist/
27
27
 
28
- publicar:
29
- needs: construir
28
+ publish:
29
+ needs: build
30
30
  runs-on: ubuntu-latest
31
31
  environment: pypi
32
32
  permissions:
@@ -7,17 +7,19 @@ dist/
7
7
  .venv/
8
8
  venv/
9
9
 
10
- # Ferramentas
10
+ # Tools
11
11
  .pytest_cache/
12
12
  .ruff_cache/
13
13
  .coverage
14
14
  htmlcov/
15
15
 
16
- # Dados pessoais: nunca versionar bancos, backups ou exports
16
+ # Personal data: never version databases, backups or exports
17
17
  *.sqlite
18
18
  *.sqlite3
19
19
  *.sqlite-*
20
20
  *.sqlite3-*
21
+ *.mcv
22
+ *.mcp
21
23
  *.db
22
24
  *.db-journal
23
25
  *.db-wal
@@ -26,7 +28,7 @@ backups/
26
28
  *.csv
27
29
  .env
28
30
 
29
- # Editores e sistema
31
+ # Editors and system
30
32
  .vscode/
31
33
  .idea/
32
34
  .DS_Store
@@ -0,0 +1,110 @@
1
+ # AGENTS.md
2
+
3
+ Guide for anyone changing this repository, person or agent. Read it before changing code.
4
+
5
+ ## What it is
6
+
7
+ Kotsu: a terminal app (Python + Textual) for the month's income, expenses, categories,
8
+ accounts and installments. Main target: Windows Terminal, working the same on Linux.
9
+
10
+ ## Commands
11
+
12
+ ```bash
13
+ pip install -e ".[dev]"
14
+ kotsu --data ./tmp # opens the app with a test folder
15
+ python tools/check.py --quick # before every commit
16
+ python tools/check.py # before every PR (same as CI)
17
+ python tools/layers.py # only the layers rule
18
+ python tools/check_install.py # pipx install; uses the network only to install
19
+ python tools/generate_vectors.py # rewrites vectors/*.json (Android cases)
20
+ ```
21
+
22
+ ## Layers (the test fails if they are broken)
23
+
24
+ | Folder | May import | Must not |
25
+ |---|---|---|
26
+ | `src/kotsu/domain/` | only the standard library without I/O | `storage`, `ui`, `sqlite3`, `os`, `pathlib`, `io`, Textual, Rich |
27
+ | `src/kotsu/storage/` | `domain` | `ui`, Textual, Rich |
28
+ | `src/kotsu/ui/` | `domain`, `storage` | `sqlite3` directly |
29
+
30
+ `src/kotsu/__main__.py` is the assembly point and may see everything.
31
+ Financial rules (totals, installments, quick-line parser) live in `domain/`; the UI only shows.
32
+
33
+ ## Data rules
34
+
35
+ - Money is an `int` in cents, always positive; the sign comes from `kind` (income/expense).
36
+ Never `float`.
37
+ - Every entry has an account (D21): the domain and the database refuse an entry without one.
38
+ The category is optional.
39
+ - Dates are calendar dates (`datetime.date`), no time zone, stored as `YYYY-MM-DD`.
40
+ - Totals (income, expenses, balance) are never stored: SQL computes them per month.
41
+ - Month queries use the range `date >= start AND date < end` so the index is used.
42
+ Lists are paginated (`limit`, `offset`).
43
+ - On screen, a negative amount shows only in red, without a sign (`domain.money.format_cents`).
44
+ - Amounts are typed and shown in the Brazilian format (`1.234,56`) and dates as `dd/mm/yyyy`;
45
+ everything else (code, UI text, docs) is in English.
46
+
47
+ ## Database and migrations
48
+
49
+ - Every write goes through `Database.transaction()`: all or nothing. The installments of a
50
+ purchase go in a single transaction.
51
+ - Schema changed? Create `src/kotsu/storage/migrations/NNNN_name.sql` with the next number.
52
+ Never edit a published migration. Before migrating an existing database, the app copies the
53
+ file to `money.before-vN.sqlite`.
54
+ - Test every new migration with a database at the previous version.
55
+ - Migrations 0001 to 0003 still use the original Portuguese table names; 0004 renames
56
+ everything to English (and `receita`/`despesa` to `income`/`expense`).
57
+ - Recurrence (D36): `recurring` category + `recurrence` table (series template and
58
+ `generated_until`). `Database.extend_recurrences(month)` generates the missing months and
59
+ only moves forward, so a deleted month does not come back. The UI calls it when drawing,
60
+ limited to today + 24 months.
61
+ - Backup is manual only (D35): key `b` copies the database to `backups/` with date and time in
62
+ the name, without overwriting, and keeps only the 5 most recent (pruned after publishing).
63
+ The app never backs up on its own. Test clock and failures with temporary data. In-memory
64
+ (`Database.in_memory()`) makes no backup.
65
+
66
+ ## Exchange between devices (D39)
67
+
68
+ - Each device has its own database; data is joined through an exchange file
69
+ (`--export`, `--import`, `--verify`). The merge rule is pure and lives in
70
+ `domain/merge.py`; reading, writing and applying live in `storage/exchange.py`.
71
+ - Every write to `account`, `category`, `entry` and the `recurrence` template stamps
72
+ `changed_at` with `Database.stamp(c)` (one stamp per transaction). Editing an entry clears
73
+ `generated`. Deleting an entry writes the tombstone before the `DELETE`. Forgot the stamp?
74
+ The change loses to the other device on merge.
75
+ - Advancing `generated_until` does not stamp: the generated month uses the fixed `uid`
76
+ (`month_uid`) and the series template's stamp.
77
+ - A new field in a synced table goes into: the migration, `exchange.read_state`,
78
+ `exchange._apply`, `merge.validate`, the canonical form (changes the check code) and
79
+ `FORMAT` if old files stop working. Format 1 files (Portuguese keys) are translated by
80
+ `merge.upgrade_v1`.
81
+ - `vectors/*.json` are the cases shared with the Android app. Changed a domain rule
82
+ (quick line, dates, money, stamp, merge)? Add the case in `tools/generate_vectors.py`, run
83
+ it and review the JSON diff. The test fails if the files are out of date.
84
+
85
+ ## Compatibility with the Portuguese versions
86
+
87
+ Installed copies from before the English rename keep working after updating:
88
+
89
+ - Old flags (`--dados`, `--pasta-dados`, `--pasta-dados-padrao`, `--forcar`, `--exportar`,
90
+ `--importar`, `--conferir`) are still accepted, hidden from `--help`.
91
+ - `MONEY_CLI_DADOS` still works next to `KOTSU_DATA`; the `money` command still exists.
92
+ - The local folder `money-cli` is renamed to `kotsu`; `pasta_dados` in `local.toml` is read.
93
+ - `tema.toml` is read and replaced by `theme.toml`; old theme names map to the new ones.
94
+ - `kotsu.trava` from a computer not updated yet still blocks; the new lock is `kotsu.lock`.
95
+ - Dialog keys from before (`s`, `t`, `p`) still work next to the English ones.
96
+
97
+ ## How to work
98
+
99
+ - Everything in English: code, messages, UI text, documents and file names.
100
+ - New or changed product decision: describe it in the PR and update the README in the same PR.
101
+ - Nothing goes into `main` without the maintainer's approval. Work on a branch and open a PR.
102
+ - Tests use neither the network nor the real data folder (use `Database.in_memory()` or
103
+ `tmp_path`).
104
+ - The README and this file are updated in the same PR that changes what they describe.
105
+ - Fixed palette in `ui/colors.py`; change it little and on purpose.
106
+ - Never version databases, backups or exports (`.gitignore` blocks SQLite, `*.mcv`, `*.mcp`
107
+ and `*.csv`).
108
+ - Real install tests via pipx run outside the checkout on Windows/Linux CI; they need the
109
+ network only to install. Unit tests stay offline.
110
+ - Commits with the GitHub noreply e-mail, fully in English.
@@ -1,10 +1,9 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: kotsu-cli
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Cozy personal finance in your terminal: income, expenses and installments of the month on one screen.
5
5
  Project-URL: Homepage, https://github.com/Sera-DAI/kotsu
6
6
  Project-URL: Issues, https://github.com/Sera-DAI/kotsu/issues
7
- Project-URL: Português, https://github.com/Sera-DAI/kotsu/blob/main/README.pt-BR.md
8
7
  Author: Sera-DAI
9
8
  License-Expression: MIT
10
9
  License-File: LICENSE
@@ -23,11 +22,9 @@ Requires-Dist: ruff>=0.6; extra == 'dev'
23
22
  Description-Content-Type: text/markdown
24
23
 
25
24
  <p align="center">
26
- <img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/banner.en.svg" alt="Kotsu: cozy personal finance in your terminal" width="100%">
25
+ <img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/banner.svg" alt="Kotsu: cozy personal finance in your terminal" width="100%">
27
26
  </p>
28
27
 
29
- <p align="center"><b>English</b> · <a href="https://github.com/Sera-DAI/kotsu/blob/main/README.pt-BR.md">Português (Brasil)</a></p>
30
-
31
28
  <p align="center">
32
29
  <img src="https://img.shields.io/badge/python-3.11%2B-ff7fb8?style=flat-square&labelColor=1d1424&logo=python&logoColor=ffe9f4" alt="Python 3.11+">
33
30
  <img src="https://img.shields.io/badge/terminal-Windows%20%C2%B7%20Linux-ff7fb8?style=flat-square&labelColor=1d1424&logo=windowsterminal&logoColor=ffe9f4" alt="Windows Terminal and Linux">
@@ -36,14 +33,14 @@ Description-Content-Type: text/markdown
36
33
  </p>
37
34
 
38
35
  <p align="center">
39
- <img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/stack/python.svg" width="44" alt="Python" title="Python">
40
- <img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/stack/githubactions.svg" width="44" alt="GitHub Actions" title="GitHub Actions">
41
- <img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/stack/claude.svg" width="44" alt="Claude" title="Claude">
36
+ <img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/stack/python.svg" width="44" alt="Python" title="Python">
37
+ <img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/stack/githubactions.svg" width="44" alt="GitHub Actions" title="GitHub Actions">
38
+ <img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/stack/claude.svg" width="44" alt="Claude" title="Claude">
42
39
  </p>
43
40
 
44
41
  <p align="center"><sub>Built with Python, Textual, SQLite and Claude</sub></p>
45
42
 
46
- <p align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/divisor.svg" width="420" alt=""></p>
43
+ <p align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/divider.svg" width="420" alt=""></p>
47
44
 
48
45
  # Kotsu
49
46
 
@@ -51,43 +48,42 @@ Description-Content-Type: text/markdown
51
48
 
52
49
  It runs on Windows Terminal and Linux, works offline and keeps everything in a SQLite file on your computer. No account, no cloud, no telemetry, no ads.
53
50
 
54
- > The app interface is in Brazilian Portuguese for now (labels such as *receitas* = income, *despesas* = expenses, *saldo* = balance). The commands and keys below work the same in any language.
55
-
56
51
  ## Contents
57
52
 
58
53
  - [I. What it does](#i-what-it-does)
59
54
  - [II. Install](#ii-install)
60
55
  - [III. Use](#iii-use)
61
56
  - [IV. Your data and backups](#iv-your-data-and-backups)
62
- - [V. Under the hood](#v-under-the-hood)
63
- - [VI. Development](#vi-development)
64
- - [VII. License](#vii-license)
57
+ - [V. Updating from a Portuguese version](#v-updating-from-a-portuguese-version)
58
+ - [VI. Under the hood](#vi-under-the-hood)
59
+ - [VII. Development](#vii-development)
60
+ - [VIII. License](#viii-license)
65
61
 
66
62
  ## I. What it does
67
63
 
68
64
  <table>
69
65
  <tr>
70
- <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/lancar.svg" width="44" alt=""></td>
71
- <td><b>Quick line</b><br><code>89,90 mercado #alimentação @nubank</code> and Enter. No forms: the amount comes first, then account, category and date in any order.</td>
66
+ <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/add-entry.svg" width="44" alt=""></td>
67
+ <td><b>Quick line</b><br><code>89,90 groceries #food @nubank</code> and Enter. No forms: the amount comes first, then account, category and date in any order.</td>
72
68
  </tr>
73
69
  <tr>
74
- <td align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/parcelas.svg" width="44" alt=""></td>
70
+ <td align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/installments.svg" width="44" alt=""></td>
75
71
  <td><b>One screen</b><br>Income, expenses and balance for the month, one line per account (each with its own color) and the list of entries. The ← / → arrows switch months.</td>
76
72
  </tr>
77
73
  <tr>
78
- <td align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/todomes.svg" width="44" alt=""></td>
79
- <td><b>Installments and "every month"</b><br><code>120 geladeira @nubank 10x</code> becomes 10 installments, one per month. Categories marked "every month" (rent, internet, salary) show up on their own, with a <code>↻</code>.</td>
74
+ <td align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/every-month.svg" width="44" alt=""></td>
75
+ <td><b>Installments and "every month"</b><br><code>120 fridge @nubank 10x</code> becomes 10 installments, one per month. Categories marked "every month" (rent, internet, salary) show up on their own, with a <code>↻</code>.</td>
80
76
  </tr>
81
77
  <tr>
82
- <td align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/temas.svg" width="44" alt=""></td>
83
- <td><b>Two Cotton Candy themes</b><br>Night (default) and light, with hearts, a little face and "zzz… zerada" when an account is empty. The <code>t</code> key switches and your choice is saved.</td>
78
+ <td align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/themes.svg" width="44" alt=""></td>
79
+ <td><b>Two Cotton Candy themes</b><br>Night (default) and light, with hearts, a little face and "zzz… zeroed" when an account is empty. The <code>t</code> key switches and your choice is saved.</td>
84
80
  </tr>
85
81
  <tr>
86
- <td align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/teclado.svg" width="44" alt=""></td>
82
+ <td align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/keyboard.svg" width="44" alt=""></td>
87
83
  <td><b>Keyboard first</b><br>Everything has a key, and the footer reminds you which. Filter by <code>@account</code> or <code>#category</code> with <code>/</code>.</td>
88
84
  </tr>
89
85
  <tr>
90
- <td align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/privado.svg" width="44" alt=""></td>
86
+ <td align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/private.svg" width="44" alt=""></td>
91
87
  <td><b>Truly private</b><br>Your data stays on your computer. Kotsu never sends anything over the network.</td>
92
88
  </tr>
93
89
  </table>
@@ -96,21 +92,21 @@ It runs on Windows Terminal and Linux, works offline and keeps everything in a S
96
92
 
97
93
  <table>
98
94
  <tr>
99
- <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/instalar.svg" width="44" alt=""></td>
100
- <td>Requires Python 3.11 or newer and <a href="https://pipx.pypa.io/">pipx</a>. The package is not on PyPI yet: install straight from GitHub.</td>
95
+ <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/install.svg" width="44" alt=""></td>
96
+ <td>Requires Python 3.11 or newer and <a href="https://pipx.pypa.io/">pipx</a>.</td>
101
97
  </tr>
102
98
  </table>
103
99
 
104
100
  Windows Terminal (PowerShell), in one line:
105
101
 
106
102
  ```powershell
107
- irm https://raw.githubusercontent.com/Sera-DAI/kotsu/main/instalar.ps1 | iex
103
+ irm https://raw.githubusercontent.com/Sera-DAI/kotsu/main/install.ps1 | iex
108
104
  ```
109
105
 
110
106
  Linux/macOS (needs pipx; the script tells you if it is missing):
111
107
 
112
108
  ```bash
113
- curl -fsSL https://raw.githubusercontent.com/Sera-DAI/kotsu/main/instalar.sh | bash
109
+ curl -fsSL https://raw.githubusercontent.com/Sera-DAI/kotsu/main/install.sh | bash
114
110
  ```
115
111
 
116
112
  Or step by step, without a script:
@@ -136,21 +132,21 @@ Reopen the terminal and run `kotsu`. To update: `pipx upgrade kotsu-cli` (or run
136
132
  ## III. Use
137
133
 
138
134
  ```text
139
- ☁ Algodão-Doce ☁ novembro de 2026
135
+ ☁ Cotton Candy ☁ November 2026
140
136
 
141
- ♡ receitas 3.500,00 ✧ despesas 432,90 ☆ saldo 3.067,10 (◕‿◕)♡
137
+ ♡ income 3.500,00 ✧ expenses 432,90 ☆ balance 3.067,10 (◕‿◕)♡
142
138
 
143
- ♡ itaú ♥♥♥♥♥♥♥♥♥♥♥♥♥♥· -210,50 +3.500,00
144
- ♡ nubank ♥♥♥♥♥♥♥♥♥♥♥♥♥♥ -222,40
139
+ ♡ itaú ♥♥♥♥♥♥♥♥♥· income 3.500,00 expenses 210,50
140
+ ♡ nubank ♥♥♥♥♥♥♥♥♥♥ income 0,00 expenses 222,40
145
141
 
146
- Data Descrição Categoria Conta Valor
147
- 08/11 padaria alimentação nubank 12,50
148
- 07/11 mercado alimentação nubank 89,90
142
+ Date Description Category Account Amount
143
+ 08/11 bakery food nubank 12,50
144
+ 07/11 groceries food nubank 89,90
149
145
  ```
150
146
 
151
147
  | Key | Action |
152
148
  |---|---|
153
- | `l` | opens the quick line (Enter saves, Esc closes) |
149
+ | `l` | opens the quick line to log an entry (Enter saves, Esc closes) |
154
150
  | ← / → | previous / next month |
155
151
  | `/` | filters by `@account`, `#category`, both, or just a name (empty Enter or Esc clears) |
156
152
  | `e` | edits the selected entry in the quick line, date included |
@@ -166,29 +162,29 @@ Reopen the terminal and run `kotsu`. To update: `pipx upgrade kotsu-cli` (or run
166
162
  The line starts with the amount; the rest comes in any order:
167
163
 
168
164
  ```text
169
- 89,90 mercado #alimentação @nubank expense (no sign)
170
- +3500 salário @itaú income
171
- 120 geladeira #casa @nubank 10x 10 installments of 120.00, one per month
172
- 45 farmácia ontem date: ontem (yesterday), 15/10 or 15/10/2025 (default: today)
165
+ 89,90 groceries #food @nubank expense (no sign)
166
+ +3500 salary @itau income
167
+ 120 fridge #home @nubank 10x 10 installments of 120,00, one per month
168
+ 45 pharmacy yesterday date: today, yesterday, 15/10 or 15/10/2025 (default: today)
173
169
  ```
174
170
 
175
- Every entry needs an `@account`; without one the line is not saved. An account or category that does not exist yet asks whether to create it. Editing or renaming an installment asks "only this one or all?". Amounts use a decimal comma and dates are day/month, as in Brazil.
171
+ Every entry needs an `@account`; without one the line is not saved. An account or category that does not exist yet asks whether to create it. Editing or renaming an installment asks "only this one or all?" (`a` = all, `o` = only this). Amounts use a decimal comma and dates are day/month, as in Brazil.
176
172
 
177
173
  ### ↻ Categories that repeat every month
178
174
 
179
- When you create a category, Kotsu asks whether it repeats every month (or press `m` on an existing one). Every new entry in it reappears each month with the same amount, account and day (day 31 becomes the last day of the month), with no end, until you stop it. Months appear as you navigate with ← / →, up to 24 months ahead of today. Deleting, editing or renaming one asks "only this month or the following ones?".
175
+ When you create a category, Kotsu asks whether it repeats every month (or press `m` on an existing one). Every new entry in it reappears each month with the same amount, account and day (day 31 becomes the last day of the month), with no end, until you stop it. Months appear as you navigate with ← / →, up to 24 months ahead of today. Deleting, editing or renaming one asks "only this month or the upcoming ones?" (`o` = only this month, `u` = this and upcoming).
180
176
 
181
177
  ## IV. Your data and backups
182
178
 
183
179
  <table>
184
180
  <tr>
185
- <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/backup.svg" width="44" alt=""></td>
181
+ <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/backup.svg" width="44" alt=""></td>
186
182
  <td>
187
183
  <ul>
188
- <li><b>Where it lives:</b> <code>%APPDATA%\money-cli</code> on Windows and <code>~/.local/share/money-cli</code> on Linux (or the folder in the <code>MONEY_CLI_DADOS</code> variable). <code>kotsu --dados FOLDER</code> opens another folder.</li>
184
+ <li><b>Where it lives:</b> <code>%APPDATA%\kotsu</code> on Windows and <code>~/.local/share/kotsu</code> on Linux (or the folder in the <code>KOTSU_DATA</code> variable). <code>kotsu --data FOLDER</code> opens another folder.</li>
185
+ <li><b>A synced folder (two computers):</b> <code>kotsu --data-folder "G:\My Drive\Kotsu"</code> makes that folder this computer's data folder (it copies the database there the first time). Backups then go to the local folder, outside the sync. While Kotsu is open, a <code>kotsu.lock</code> file tells the other computer it is in use; <code>kotsu --force</code> opens anyway. <code>kotsu --default-data-folder</code> goes back to the local folder.</li>
189
186
  <li><b>Manual backup:</b> the <code>b</code> key creates <code>backups/money.YYYY-MM-DD-HHMMSS.sqlite</code> and keeps the 5 most recent copies. Kotsu never backs up on its own.</li>
190
- <li><b>Using two computers (Google Drive):</b> on both, run <code>kotsu --pasta-dados "G:\My Drive\Kotsu"</code> (any existing data on the computer is copied there; if both already have data, choose which one wins). Keep the folder "Available offline". Use one computer at a time: Kotsu warns if it is open on the other one and refuses to open if Drive created conflicting copies (<code>--forcar</code> skips the warning). Backups from the <code>b</code> key stay in the local folder, outside Drive. <code>kotsu --pasta-dados-padrao</code> undoes it.</li>
191
- <li><b>Merging with another device:</b> <code>kotsu --exportar data.json</code> writes everything to a file; on the other device, <code>kotsu --importar data.json</code> merges it with what is there (the most recent change to each entry wins, and deleted entries stay deleted). Do it both ways and check: <code>kotsu --conferir</code> shows a short code that is the same on both when the data is the same; <code>kotsu --conferir data.json</code> lists the differences. Before importing, Kotsu saves <code>backups/money.antes-da-troca.sqlite</code>.</li>
187
+ <li><b>Merging with another device:</b> <code>kotsu --export data.json</code> writes everything to a file; on the other device, <code>kotsu --import data.json</code> merges it with what is there (the most recent change to each entry wins, and deleted entries stay deleted). Do it both ways and check: <code>kotsu --verify</code> shows a short code that is the same on both when the data is the same; <code>kotsu --verify data.json</code> lists the differences. Before importing, Kotsu saves <code>backups/money.before-import.sqlite</code>.</li>
192
188
  <li><b>No password or encryption:</b> protect your computer and the folder as you would any personal file.</li>
193
189
  <li><b>Restore:</b> close the app, move the current <code>money.sqlite</code> elsewhere, copy the chosen backup to <code>money.sqlite</code>, open the app and check the totals.</li>
194
190
  </ul>
@@ -196,11 +192,21 @@ When you create a category, Kotsu asks whether it repeats every month (or press
196
192
  </tr>
197
193
  </table>
198
194
 
199
- ## V. Under the hood
195
+ ## V. Updating from a Portuguese version
196
+
197
+ Versions before November 2026 had Portuguese names. Updating keeps everything working:
198
+
199
+ - The database is migrated on first open (schema 4: English table and column names). A copy is kept first as `money.before-v4.sqlite` next to the database.
200
+ - `tema.toml` becomes `theme.toml`, the local folder `money-cli` becomes `kotsu`, and the old `MONEY_CLI_DADOS` variable still works.
201
+ - The old flags (`--dados`, `--pasta-dados`, `--forcar`, `--exportar`, `--importar`, `--conferir`) still work, hidden from `--help`.
202
+ - Exchange files from older versions import normally. Update **both** devices before comparing check codes: the code changed with the English names, so an old and a new version never show the same code.
203
+ - The lock file is now `kotsu.lock`; a `kotsu.trava` from a computer not updated yet is still respected.
204
+
205
+ ## VI. Under the hood
200
206
 
201
207
  <table>
202
208
  <tr>
203
- <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/estrutura.svg" width="44" alt=""></td>
209
+ <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/structure.svg" width="44" alt=""></td>
204
210
  <td>Three layers, and a test fails if one of them imports what it must not. Financial rules (totals, installments, the quick-line parser) live in the domain; the screen only displays.</td>
205
211
  </tr>
206
212
  </table>
@@ -208,23 +214,23 @@ When you create a category, Kotsu asks whether it repeats every month (or press
208
214
  ```mermaid
209
215
  %%{init: {"theme": "base", "themeVariables": {"primaryColor": "#41274f", "primaryTextColor": "#ffe9f4", "primaryBorderColor": "#ff7fb8", "lineColor": "#ffa28c", "secondaryColor": "#291b33", "tertiaryColor": "#1d1424", "fontFamily": "Segoe UI, sans-serif"}}}%%
210
216
  flowchart LR
211
- T["tela/<br>Textual: display only"] --> A["armazenamento/<br>SQLite, migrations, backup"]
212
- T --> D["dominio/<br>money in cents,<br>installments, quick line"]
217
+ T["ui/<br>Textual: display only"] --> A["storage/<br>SQLite, migrations, backup"]
218
+ T --> D["domain/<br>money in cents,<br>installments, quick line"]
213
219
  A --> D
214
220
  A --> F[("money.sqlite<br>on your computer")]
215
221
  ```
216
222
 
217
- - Money is an integer number of cents, never a `float`; the sign comes from the type (income or expense).
223
+ - Money is an integer number of cents, never a `float`; the sign comes from the kind (income or expense).
218
224
  - Every write is a transaction: all or nothing. Changed the schema? A numbered migration, with a copy of the database made first.
219
225
  - Totals are never stored: SQL computes them per month.
220
226
 
221
- Full contributor rules (in Portuguese): [AGENTS.md](AGENTS.md).
227
+ Full contributor rules: [AGENTS.md](AGENTS.md).
222
228
 
223
- ## VI. Development
229
+ ## VII. Development
224
230
 
225
231
  <table>
226
232
  <tr>
227
- <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/dev.svg" width="44" alt=""></td>
233
+ <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/dev.svg" width="44" alt=""></td>
228
234
  <td>Requires Python 3.11+. The tests never touch the network.</td>
229
235
  </tr>
230
236
  </table>
@@ -235,18 +241,18 @@ cd kotsu
235
241
  python -m venv .venv
236
242
  # Windows: .venv\Scripts\activate Linux: source .venv/bin/activate
237
243
  pip install -e ".[dev]"
238
- kotsu --dados ./tmp # uses a test folder
239
- python ferramentas/verificar.py --rapido # lint + fast tests
240
- python ferramentas/verificar.py # everything, same as CI
244
+ kotsu --data ./tmp # uses a test folder
245
+ python tools/check.py --quick # lint + fast tests
246
+ python tools/check.py # everything, same as CI
241
247
  ```
242
248
 
243
- ## VII. License
249
+ ## VIII. License
244
250
 
245
251
  <table>
246
252
  <tr>
247
- <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/icones/licenca.svg" width="44" alt=""></td>
253
+ <td width="72" align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/icons/license.svg" width="44" alt=""></td>
248
254
  <td><a href="https://github.com/Sera-DAI/kotsu/blob/main/LICENSE">MIT</a>. Made with care, little by little.</td>
249
255
  </tr>
250
256
  </table>
251
257
 
252
- <p align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/imagens/divisor.svg" width="420" alt=""></p>
258
+ <p align="center"><img src="https://raw.githubusercontent.com/Sera-DAI/kotsu/main/docs/images/divider.svg" width="420" alt=""></p>