aboutsummaryrefslogtreecommitdiff
path: root/CHANGELOG.md
blob: b0296f890cd0a6a6712a24e143ad6b4aadf5258c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# Changelog

## Unreleased

## 0.0.7 — 2026-09-14

Security and correctness hardening, from a threat model (spec §15.1) and the
tests that hold it.

- File names, paths and tool messages can no longer control the terminal:
  control characters, bidirectional controls and invalid UTF-8 are printed
  as escapes (`\x1b`, `\u202e`) everywhere krino prints them.
- A placeholder can no longer rename a file to "", "." or "..", or add a
  ".." to a destination; such a step is skipped with a reason.
- A file swapped between planning and applying - for a symlink, or for
  another file with the same size and modification time - is not acted on.
- Undo refuses a trash entry name that is not a plain name inside the
  Trash, and a trashinfo whose path is not absolute.
- Undo reverses a file its run renamed and then moved, moved twice, or
  moved and then sent to the Trash. Before, undo judged the first step
  against the disk as it is now, found its destination empty (the later
  step had moved the file on) and refused the whole file as "missing". Found
  by the new generated apply-and-undo test.
- Folding maps the capital sharp s (ẞ) to "SS", as the other capitals
  already were: "STRAẞE" in a document now matches the keyword "straße".
- Folding replaces invalid UTF-8 with U+FFFD first, so a stray invalid byte
  no longer stops the letter after it from losing its accent.
- `krino new` refuses a directory whose path is not valid UTF-8 with that
  reason, instead of reporting a broken template.
- The keyword cache is also discarded when normalisation changes, so answers
  cached before these fixes are recomputed once.
- Builds need Go 1.25 or newer and use the Go 1.26.8 toolchain, which an
  older `go` downloads itself. `golang.org/x/text` is updated to v0.41.0.
  This fixes an infinite loop a crafted file's text could cause
  (GO-2026-5970) and, through the toolchain, the XML nesting guard
  (GO-2026-6088) and the `os/exec` and `os` fixes govulncheck reported.
- Tests: fuzz targets for every decoder of outside data (`make fuzz`), a
  generated apply-and-undo round trip (`KRINO_PROPERTY_RUNS`),
  enum-completeness tests, `make race` and `make vulncheck`.

## 0.0.6 — 2026-09-14

- Choosing per file: `w` now applies what was decided and quits krino,
  instead of going on to the next directory, so a long review can be done a
  session at a time. Files never reached are not logged as declined; the
  outcome line counts them as "not reviewed".
- Each choice is echoed on its own red line under the file (`→ yes`,
  `→ trash`, ...).
- Enter is ignored at the review prompts instead of being reported as a
  wrong key.

## 0.0.5 — 2026-09-14

- Keyword cache: for each file whose text it extracts, krino records which
  content keywords the text contains, in `~/.cache/krino/NAME.cache`, and
  answers content tests from it while the file is unchanged. A rerun over
  the same files extracts nothing: on a real downloads folder a dry run
  went from 12.8 s to 0.13 s. No text and no file names are stored. A
  changed file, a new keyword, or a changed extraction tool means reading
  again; failures are never cached. `krino check` shows where the cache is.
- Choosing per file: `t` sends the file to the Trash and `d` deletes it
  permanently, after a `y` to confirm, instead of what its rules planned;
  both are logged under the rule `(review)`. "Done, apply chosen so far"
  moves from `d` to `w`, in undo's review too.

## 0.0.4 — 2026-09-14

- `max-size` setting: files larger than it are skipped as "too big", in
  `(defaults ...)` or a directory file.
- `(exclude COND...)` sets files aside before any rule sees them, by type or
  extension, name regex, content, or any other condition; all conditions in
  one form must hold. In `krino.conf` it applies to every directory, in a
  directory file to that directory. Excluded files are counted in the plan
  and listed with the form that matched under `-v`; `explain` traces every
  exclusion and `check` lists them.
- `--min-age DURATION` overrides every directory's `min-age` for one run,
  e.g. `krino -n --min-age 0` to include files written a moment ago.
- `krino init` and `krino new` write commented examples of all three.

## 0.0.3 — 2026-09-14

- The plan is shown as one block per file instead of a table: the file's
  name, each step, then the rule and the reason it matched. On a terminal
  every line wraps to its width, with continuation lines indented under
  their own column; piped output is never wrapped.
- Choosing per file (`c`) shows that same full block for each file, not only
  its steps.
- `-P` / `--no-pager` prints the plan straight out instead of through the
  pager.
- A duplicate's original is shown with `~` for the home directory.

## 0.0.2 — 2026-09-14

- Duplicates are found, never deleted. A rule combining `(duplicate)` with
  `(delete)` or `(delete permanent)` is refused by `krino check` and every
  run, and a file that is a duplicate under any duplicate scope its
  directory's rules use gets no delete step from any rule. This replaces
  0.0.1's known limitation: duplicate conditions with different scopes can no
  longer delete every copy of a group, only move copies aside.
- Coloured output on a terminal, in the terminal's own 16-colour palette:
  actions by kind, rule names, skipped steps and reasons, warnings, the
  outcome counts and the prompt keys. `--no-color`, before or after any
  subcommand, turns it off, as `NO_COLOR` does.

## 0.0.1 — 2026-09-13

- Per-directory rule files, a main file listing which directories run, and a
  template for new ones.
- Conditions with `and`, `or` and `not` over type, name, path, content, size,
  age and duplicates.
- Actions copy, move, rename and delete (to Trash by default), chained.
- Plan, review and approve — all files or per file — with `-y` to skip
  review.
- A log of every step, and `krino undo`.
- Placeholders in destinations and new names.
- Builds for Linux, FreeBSD and OpenBSD.

Performance: no threshold or target for 0.0.1. These were measured during
development and are reported rather than promised — throughput is dominated
by external content extractors, not by krino itself:

- Full plans over a real folder of about 265 files, 164 of them needing text
  extraction through `pdftotext` at roughly 80 ms each, measured between
  about 13 and 20 s across runs.
- A synthetic benchmark during development planned a generated tree of 4,405
  files needing no extraction in 1.09 s. That benchmark is not `make bench`,
  whose generated tree is smaller.

Files that share a byte size but differ in content — six templated invoices,
for instance — are still told apart, because the duplicate check hashes the
first and last 64 KiB and then the whole file rather than trusting size.

Known limitation: `(duplicate)` conditions with different scopes can elect
different originals for the same content, and within one directory's rules
this can select every copy for deletion — see `krino.conf(5)`, DUPLICATES.