neocities-red 1.1.2 → 1.2.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +30 -16
  3. data/.gitignore +9 -0
  4. data/.rubocop.yml +1 -0
  5. data/CHANGELOG.md +95 -0
  6. data/Gemfile +2 -1
  7. data/Gemfile.lock +21 -18
  8. data/README.md +187 -20
  9. data/lib/neocities_red/cli.rb +156 -31
  10. data/lib/neocities_red/cli_display.rb +200 -5
  11. data/lib/neocities_red/client.rb +84 -77
  12. data/lib/neocities_red/errors.rb +20 -0
  13. data/lib/neocities_red/services/common/exclusions.rb +69 -0
  14. data/lib/neocities_red/services/common/pizza.rb +34 -21
  15. data/lib/neocities_red/services/common/worker_pool.rb +54 -0
  16. data/lib/neocities_red/services/file/folder_uploader.rb +39 -25
  17. data/lib/neocities_red/services/file/list.rb +60 -30
  18. data/lib/neocities_red/services/file/remover.rb +27 -12
  19. data/lib/neocities_red/services/file/uploader.rb +33 -13
  20. data/lib/neocities_red/services/site/differencer.rb +42 -12
  21. data/lib/neocities_red/services/site/exporter.rb +120 -7
  22. data/lib/neocities_red/services/site/informer.rb +29 -4
  23. data/lib/neocities_red/services/site/pusher.rb +74 -38
  24. data/lib/neocities_red/version.rb +2 -1
  25. data/lib/neocities_red.rb +32 -13
  26. data/neocities-red.gemspec +11 -6
  27. data/spec/neocities_red/cli_display_spec.rb +0 -6
  28. data/spec/neocities_red/cli_spec.rb +86 -0
  29. data/spec/neocities_red/client_spec.rb +7 -50
  30. data/spec/neocities_red/services/common/exclusions_spec.rb +47 -0
  31. data/spec/neocities_red/services/common/worker_pool_spec.rb +48 -0
  32. data/spec/neocities_red/services/file/folder_uploader_spec.rb +8 -6
  33. data/spec/neocities_red/services/file/list_spec.rb +13 -10
  34. data/spec/neocities_red/services/file/remover_spec.rb +15 -21
  35. data/spec/neocities_red/services/file/uploader_spec.rb +25 -20
  36. data/spec/neocities_red/services/site/differencer_spec.rb +33 -8
  37. data/spec/neocities_red/services/site/exporter_spec.rb +105 -38
  38. data/spec/neocities_red/services/site/informer_spec.rb +3 -3
  39. data/spec/neocities_red/services/site/pusher_spec.rb +1 -1
  40. data/spec/spec_helper.rb +1 -1
  41. metadata +11 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 923e790fe28d24ed2aa82bb797def9013c02ec6589d164e19eb279745dca708c
4
- data.tar.gz: f14fde703e682d58a9ad1239300371830cea5d55ed17c0e669a91cee72342477
3
+ metadata.gz: ef7b7c412b2db9911f08da1e341094af9e73cdc5f15ccd1b64187acc98c6df9a
4
+ data.tar.gz: 33e7e3e703787840f0e69985859f9d3e80a6560f40c81cd115df88388021eec1
5
5
  SHA512:
6
- metadata.gz: df338f92b78a165e3d605c5db8ca08473aaca1732c4a359e40c593f3da852041c9fa5f715f0f5e55fe577d176e6e79eaa4d4dc1a19cb8fb65dafeb2c216df379
7
- data.tar.gz: dfb0104e424c14d3706cb63e6c158f9cd7d646660bddf197e89024ce7142a6c538126afb9e18c3531d23989f34b132b023621ffb6c90cf0f3665db6d9bdff94b
6
+ metadata.gz: f683232f030fdd8c2b2b0e6a99dc20edd2bb035a929f38c87c708e4f34513154343b159b35aa38a0fe0579101b6b4cddba2e72a24c90d0e0d5ee9782ad05c3a7
7
+ data.tar.gz: b960d354732fa8836ea390a9953a0db14321d55ad74d293302eb9bd0f6d7323677b9a81c294a81c2490a81349f0ae47b7c0d18560ce25198ca8381a3f5dd5f0f
@@ -8,17 +8,21 @@ on:
8
8
 
9
9
  jobs:
10
10
  lint:
11
- name: Lint (ubuntu-latest)
11
+ name: Lint (Ruby ${{ matrix.ruby-version }})
12
12
  runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby-version: ['3.4', '3.5', '4.0']
13
17
 
14
18
  steps:
15
19
  - name: Checkout repository
16
20
  uses: actions/checkout@v4
17
21
 
18
- - name: Set up Ruby 4.0.0
22
+ - name: Set up Ruby ${{ matrix.ruby-version }}
19
23
  uses: ruby/setup-ruby@v1
20
24
  with:
21
- ruby-version: 4.0.0
25
+ ruby-version: ${{ matrix.ruby-version }}
22
26
  bundler-cache: true
23
27
 
24
28
  - name: Debug versions
@@ -31,59 +35,65 @@ jobs:
31
35
  run: bundle exec rubocop
32
36
 
33
37
  test_linux:
34
- name: Test (ubuntu-latest)
38
+ name: Test (Ruby ${{ matrix.ruby-version }}, ubuntu-latest)
35
39
  runs-on: ubuntu-latest
40
+ strategy:
41
+ fail-fast: false
42
+ matrix:
43
+ ruby-version: ['3.4', '3.5', '4.0']
36
44
 
37
45
  steps:
38
46
  - name: Checkout repository
39
47
  uses: actions/checkout@v4
40
48
 
41
- - name: Set up Ruby 4.0.0
49
+ - name: Set up Ruby ${{ matrix.ruby-version }}
42
50
  uses: ruby/setup-ruby@v1
43
51
  with:
44
- ruby-version: 4.0.0
52
+ ruby-version: ${{ matrix.ruby-version }}
45
53
  bundler-cache: true
46
54
 
47
55
  - name: Run tests
48
56
  run: bundle exec rspec
49
57
 
50
58
  test_non_linux:
51
- name: Test (${{ matrix.os }})
59
+ name: Test (Ruby ${{ matrix.ruby-version }}, ${{ matrix.os }})
52
60
  runs-on: ${{ matrix.os }}
53
61
  strategy:
54
62
  fail-fast: false
55
63
  matrix:
56
64
  os: [macos-latest, windows-latest]
65
+ ruby-version: ['3.4', '4.0']
57
66
 
58
67
  steps:
59
68
  - name: Checkout repository
60
69
  uses: actions/checkout@v4
61
70
 
62
- - name: Set up Ruby 4.0.0
71
+ - name: Set up Ruby ${{ matrix.ruby-version }}
63
72
  uses: ruby/setup-ruby@v1
64
73
  with:
65
- ruby-version: 4.0.0
74
+ ruby-version: ${{ matrix.ruby-version }}
66
75
  bundler-cache: true
67
76
 
68
77
  - name: Run tests
69
78
  run: bundle exec rspec
70
79
 
71
80
  smoke_unix:
72
- name: Start CLI (${{ matrix.os }})
81
+ name: Start CLI (Ruby ${{ matrix.ruby-version }}, ${{ matrix.os }})
73
82
  runs-on: ${{ matrix.os }}
74
83
  strategy:
75
84
  fail-fast: false
76
85
  matrix:
77
86
  os: [ubuntu-latest, macos-latest]
87
+ ruby-version: ['3.4', '4.0']
78
88
 
79
89
  steps:
80
90
  - name: Checkout repository
81
91
  uses: actions/checkout@v4
82
92
 
83
- - name: Set up Ruby 4.0.0
93
+ - name: Set up Ruby ${{ matrix.ruby-version }}
84
94
  uses: ruby/setup-ruby@v1
85
95
  with:
86
- ruby-version: 4.0.0
96
+ ruby-version: ${{ matrix.ruby-version }}
87
97
  bundler-cache: true
88
98
 
89
99
  - name: Start CLI
@@ -92,17 +102,21 @@ jobs:
92
102
  bundle exec bin/neocities-red
93
103
 
94
104
  smoke_windows:
95
- name: Start CLI (windows-latest)
105
+ name: Start CLI (Ruby ${{ matrix.ruby-version }}, windows-latest)
96
106
  runs-on: windows-latest
107
+ strategy:
108
+ fail-fast: false
109
+ matrix:
110
+ ruby-version: ['3.4', '4.0']
97
111
 
98
112
  steps:
99
113
  - name: Checkout repository
100
114
  uses: actions/checkout@v4
101
115
 
102
- - name: Set up Ruby 4.0.0
116
+ - name: Set up Ruby ${{ matrix.ruby-version }}
103
117
  uses: ruby/setup-ruby@v1
104
118
  with:
105
- ruby-version: 4.0.0
119
+ ruby-version: ${{ matrix.ruby-version }}
106
120
  bundler-cache: true
107
121
 
108
122
  - name: Start CLI
@@ -124,7 +138,7 @@ jobs:
124
138
  usesh: true
125
139
  prepare: |
126
140
  pkg install -y ca_root_nss git rubygem-bundler
127
- pkg install -y ruby34
141
+ pkg install -y ruby
128
142
  run: |
129
143
  RUBY_BIN="$(command -v ruby34 || command -v ruby)"
130
144
  "$RUBY_BIN" -v
data/.gitignore CHANGED
@@ -33,6 +33,15 @@ Thumbs.db
33
33
  coverage/
34
34
  *.lcov
35
35
 
36
+ # YARD documentation
37
+ doc/
38
+ .yardoc
39
+
40
+ # Jekyll site (docs/) local build output
41
+ docs/_site/
42
+ docs/.jekyll-cache/
43
+ docs/.sass-cache/
44
+
36
45
  # Temporary files
37
46
  tmp/
38
47
  *.log
data/.rubocop.yml CHANGED
@@ -9,6 +9,7 @@ AllCops:
9
9
  - "vendor/**/*"
10
10
  - "tmp/**/*"
11
11
  - "spec/fixtures/**/*"
12
+ - "docs/**/*"
12
13
 
13
14
  Layout/LineLength:
14
15
  Max: 150
data/CHANGELOG.md ADDED
@@ -0,0 +1,95 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [1.2.0] — 2026-08-04
11
+
12
+ ### Changed
13
+
14
+ - Major architecture refactor with namespaced services (`file/`, `site/`, `common/`)
15
+ - Renamed gem to `neocities-red`
16
+
17
+ ### Added
18
+
19
+ - YARD documentation
20
+
21
+ ### Removed
22
+
23
+ - Unused legacy code
24
+
25
+ ## [1.1.2] — 2026-08-04
26
+
27
+ ### Changed
28
+
29
+ - Bumped rubocop to 1.88.2, rubocop-rspec to 3.10.2, faraday to 2.14.3
30
+
31
+ ## [1.1.1] — 2026-06-22
32
+
33
+ ### Fixed
34
+
35
+ - Config for Windows/FreeBSD platforms
36
+ - Purge no longer removes already-removed files
37
+
38
+ ### Changed
39
+
40
+ - `upload` accepts a single parameter
41
+ - Bumped rake to 13.4.2
42
+
43
+ ## [1.1.0] — 2026-04-25
44
+
45
+ ### Changed
46
+
47
+ - Added Rails/Thor CLI framework, refactored `cli.rb`
48
+
49
+ ## [1.0.6] — 2026-04-14
50
+
51
+ ### Fixed
52
+
53
+ - Tests and lint fixes
54
+ - Added `faraday-retry` for flaky API/SSL handling
55
+
56
+ ## [1.0.4] — 2026-03-29
57
+
58
+ ### Changed
59
+
60
+ - CLI version display updated
61
+
62
+ ## [1.0.2] — 2026-02-11
63
+
64
+ ### Added
65
+
66
+ - Multithreaded parallel uploads
67
+ - Fixed recursive uploading in `upload` method
68
+
69
+ ## [1.0.1] — 2026-02-07
70
+
71
+ ### Added
72
+
73
+ - Folder uploading support
74
+
75
+ ## [1.0.0] — 2026-02-11
76
+
77
+ ### Added
78
+
79
+ - Initial release of `neocities-red` (fork of `neocities-ruby`)
80
+ - Recursive uploads with smart diffing
81
+ - `push`, `upload`, `delete`, `diff`, `list`, `info`, `pull` commands
82
+ - Parallel upload workers
83
+ - Automatic retries
84
+ - Config file with `NEOCITIES_API_KEY` support
85
+
86
+ [Unreleased]: https://github.com/o-200/neocities-red/compare/v1.2.0...HEAD
87
+ [1.2.0]: https://github.com/o-200/neocities-red/compare/v1.1.2...v1.2.0
88
+ [1.1.2]: https://github.com/o-200/neocities-red/compare/v1.1.1...v1.1.2
89
+ [1.1.1]: https://github.com/o-200/neocities-red/compare/v1.1.0...v1.1.1
90
+ [1.1.0]: https://github.com/o-200/neocities-red/compare/v1.0.6...v1.1.0
91
+ [1.0.6]: https://github.com/o-200/neocities-red/compare/v1.0.4...v1.0.6
92
+ [1.0.4]: https://github.com/o-200/neocities-red/compare/v1.0.2...v1.0.4
93
+ [1.0.2]: https://github.com/o-200/neocities-red/compare/v1.0.1...v1.0.2
94
+ [1.0.1]: https://github.com/o-200/neocities-red/compare/v1.0.0...v1.0.1
95
+ [1.0.0]: https://github.com/o-200/neocities-red/releases/tag/v1.0.0
data/Gemfile CHANGED
@@ -6,7 +6,8 @@ gemspec
6
6
 
7
7
  group :test, :development do
8
8
  gem "rspec"
9
- gem "rubocop", "~> 1.88.2"
9
+ gem "rubocop", "~> 1.91.0"
10
10
  gem "rubocop-rspec", "~> 3.10.2"
11
11
  gem "webmock"
12
+ gem "yard"
12
13
  end
data/Gemfile.lock CHANGED
@@ -1,17 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- neocities-red (1.1.2)
4
+ neocities-red (1.2.0)
5
5
  faraday (~> 2.14.3)
6
6
  faraday-follow_redirects
7
7
  faraday-multipart
8
8
  faraday-retry
9
9
  fiddle
10
- pastel (~> 0.8, = 0.8.0)
11
- rake (~> 13, >= 13.3.0)
10
+ pastel (= 0.8.0)
11
+ rake (~> 13)
12
12
  thor (~> 1.5.0, >= 1.5.0)
13
- tty-prompt (~> 0.23, = 0.23.1)
14
- tty-table (~> 0.12, = 0.12.0)
13
+ tty-prompt (= 0.23.1)
14
+ tty-table (= 0.12.0)
15
15
  whirly (~> 0.3, >= 0.3.0)
16
16
 
17
17
  GEM
@@ -25,7 +25,7 @@ GEM
25
25
  bigdecimal
26
26
  rexml
27
27
  diff-lcs (1.6.2)
28
- faraday (2.14.3)
28
+ faraday (2.14.4)
29
29
  faraday-net_http (>= 2.0, < 3.5)
30
30
  json
31
31
  logger
@@ -39,14 +39,14 @@ GEM
39
39
  faraday (~> 2.0)
40
40
  fiddle (1.1.8)
41
41
  hashdiff (1.2.1)
42
- json (2.21.2)
42
+ json (3.0.2)
43
43
  language_server-protocol (3.17.0.6)
44
44
  lint_roller (1.1.0)
45
45
  logger (1.7.0)
46
46
  multipart-post (2.4.1)
47
47
  net-http (0.9.1)
48
48
  uri (>= 0.11.1)
49
- parallel (2.1.0)
49
+ parallel (2.2.0)
50
50
  parser (3.3.12.0)
51
51
  ast (~> 2.4.1)
52
52
  racc
@@ -72,8 +72,8 @@ GEM
72
72
  diff-lcs (>= 1.2.0, < 2.0)
73
73
  rspec-support (~> 3.13.0)
74
74
  rspec-support (3.13.7)
75
- rubocop (1.88.2)
76
- json (~> 2.3)
75
+ rubocop (1.91.0)
76
+ json (>= 2.3)
77
77
  language_server-protocol (~> 3.17.0.2)
78
78
  lint_roller (~> 1.1.0)
79
79
  parallel (>= 1.10)
@@ -114,7 +114,7 @@ GEM
114
114
  unicode-display_width (2.6.0)
115
115
  unicode_utils (1.4.0)
116
116
  uri (1.1.1)
117
- webmock (3.26.2)
117
+ webmock (3.26.4)
118
118
  addressable (>= 2.8.0)
119
119
  crack (>= 0.3.2)
120
120
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -122,6 +122,7 @@ GEM
122
122
  json
123
123
  unicode-display_width (>= 1.1)
124
124
  wisper (2.0.1)
125
+ yard (0.9.45)
125
126
 
126
127
  PLATFORMS
127
128
  ruby
@@ -130,9 +131,10 @@ PLATFORMS
130
131
  DEPENDENCIES
131
132
  neocities-red!
132
133
  rspec
133
- rubocop (~> 1.88.2)
134
+ rubocop (~> 1.91.0)
134
135
  rubocop-rspec (~> 3.10.2)
135
136
  webmock
137
+ yard
136
138
 
137
139
  CHECKSUMS
138
140
  addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af
@@ -141,21 +143,21 @@ CHECKSUMS
141
143
  bundler (4.0.17) sha256=214e21431b5665dd2f99df8a5511c6b151d7a72e8015c8b38f8b775b61cbb6c1
142
144
  crack (1.0.1) sha256=ff4a10390cd31d66440b7524eb1841874db86201d5b70032028553130b6d4c7e
143
145
  diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
144
- faraday (2.14.3) sha256=1882247e6766615c8220b4392bf1d27f6ebb63d8e28267587cef1fb0bf37f278
146
+ faraday (2.14.4) sha256=9bb4408c44621b0dbaaaa39e5dbfc4dbe58cc6751b6eb94d16ae9e1f2f2fab6e
145
147
  faraday-follow_redirects (0.5.0) sha256=5cde93c894b30943a5d2b93c2fe9284216a6b756f7af406a1e55f211d97d10ad
146
148
  faraday-multipart (1.2.0) sha256=7d89a949693714176f612323ca13746a2ded204031a6ba528adee788694ef757
147
149
  faraday-net_http (3.4.4) sha256=0e78af151747ed1b00f33e25973b4bc220d7f16c00c39676817c8b12331eb588
148
150
  faraday-retry (2.4.0) sha256=7b79c48fb7e56526faf247b12d94a680071ff40c9fda7cf1ec1549439ad11ebe
149
151
  fiddle (1.1.8) sha256=7fa8ee3627271497f3add5503acdbc3f40b32f610fc1cf49634f083ef3f32eee
150
152
  hashdiff (1.2.1) sha256=9c079dbc513dfc8833ab59c0c2d8f230fa28499cc5efb4b8dd276cf931457cd1
151
- json (2.21.2) sha256=1f1d3b7cf2b3ba1a69beca0bb6db13d5438b80bff3cd54cdaaa620b9b07c1c6a
153
+ json (3.0.2) sha256=8e6d7e7b11384c21230430cef90b71f14849a34a1f4452796670f7c981bd19df
152
154
  language_server-protocol (3.17.0.6) sha256=5ef2c0c138f8267e1bc631d3328347d354f96724b0af22f2c79516120443b7f0
153
155
  lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
154
156
  logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
155
157
  multipart-post (2.4.1) sha256=9872d03a8e552020ca096adadbf5e3cb1cd1cdd6acd3c161136b8a5737cdb4a8
156
- neocities-red (1.1.2)
158
+ neocities-red (1.2.0)
157
159
  net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996
158
- parallel (2.1.0) sha256=b35258865c2e31134c5ecb708beaaf6772adf9d5efae28e93e99260877b09356
160
+ parallel (2.2.0) sha256=e1059c5fd7b649558a0aec38a769f06a42942bdb40503d005a59c352fe011cd8
159
161
  parser (3.3.12.0) sha256=21a6d7f755d5a24dfbdc6e6b772e4e879a52e7631a88bc5a3a134606052c9828
160
162
  pastel (0.8.0) sha256=481da9fb7d2f6e6b1a08faf11fa10363172dc40fd47848f096ae21209f805a75
161
163
  prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
@@ -170,7 +172,7 @@ CHECKSUMS
170
172
  rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
171
173
  rspec-mocks (3.13.8) sha256=086ad3d3d17533f4237643de0b5c42f04b66348c28bf6b9c2d3f4a3b01af1d47
172
174
  rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
173
- rubocop (1.88.2) sha256=8def251c90cd955feb4daa3edc0ab56893250c4ce90ef81e6c80c03f9a939bbf
175
+ rubocop (1.91.0) sha256=9c82b7bf391c5d7e3798c5b9996e22a1fe3bd7468e351dfdeb96140c058296d0
174
176
  rubocop-ast (1.50.0) sha256=b9ca88300da0803ee222ad20cdb30494c0a784eed06fdc35d254b06d662788db
175
177
  rubocop-rspec (3.10.2) sha256=0b3e2ecc592cd10ecbf0095bb58d1e357905276e069643523cc19eb7495f65e2
176
178
  ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
@@ -186,9 +188,10 @@ CHECKSUMS
186
188
  unicode-display_width (2.6.0) sha256=12279874bba6d5e4d2728cef814b19197dbb10d7a7837a869bab65da943b7f5a
187
189
  unicode_utils (1.4.0) sha256=b922d0cf2313b6b7136ada6645ce7154ffc86418ca07d53b058efe9eb72f2a40
188
190
  uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
189
- webmock (3.26.2) sha256=774556f2ea6371846cca68c01769b2eac0d134492d21f6d0ab5dd643965a4c90
191
+ webmock (3.26.4) sha256=8d8da206d217ebe6968cfb09c77f4533c23074e1432bad865f3994eacbaad50d
190
192
  whirly (0.4.0) sha256=3ffdf9097e711097442f6d83c91b8fc431d73224863f75b48f06fb850b3e596e
191
193
  wisper (2.0.1) sha256=ce17bc5c3a166f241a2e6613848b025c8146fce2defba505920c1d1f3f88fae6
194
+ yard (0.9.45) sha256=52e211493f7cb8a3ebf7e104a25a1e73937a3103092545d34cb88fafebb3dc51
192
195
 
193
196
  BUNDLED WITH
194
197
  4.0.17
data/README.md CHANGED
@@ -24,14 +24,14 @@ Built for performance, reliability, and real-world workflows (especially static
24
24
  - **Recursive uploads** out of the box
25
25
  - **SSG-friendly** (Jekyll, Hugo, Eleventy, etc.)
26
26
  - **Namespaced services** grouped by domain (`file/`, `site/`, `common/`)
27
+ - **Incremental `pull`** — skips files unchanged since your last pull
28
+ - **`.gitignore`-aware `push`** — respects your ignore rules by default
27
29
 
28
30
  ---
29
31
 
30
- ## Installation
31
-
32
- ### Requirements
32
+ ## Requirements
33
33
 
34
- - **Ruby 3.4+** (tested, supports 4.x)
34
+ - **Ruby 3.4+** (CI-tested against 3.4, 3.5, and 4.0 on Linux, macOS, Windows, and FreeBSD)
35
35
 
36
36
  Not a programmer?
37
37
 
@@ -40,7 +40,7 @@ Not a programmer?
40
40
 
41
41
  ---
42
42
 
43
- ### Install
43
+ ## Installation
44
44
 
45
45
  ```bash
46
46
  gem install neocities-red
@@ -55,6 +55,47 @@ neocities-red help
55
55
  neocities-red help push
56
56
  ```
57
57
 
58
+ On first authenticated command you'll be prompted for your sitename/username and
59
+ password — the resulting API key is stored locally for future runs.
60
+
61
+ ```bash
62
+ neocities-red push .
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Authentication
68
+
69
+ The CLI resolves credentials in this order:
70
+
71
+ 1. **`--api-key` flag** — `neocities-red --api-key <key> push .`
72
+ 2. **`NEOCITIES_API_KEY` environment variable**
73
+ 3. **Stored config** — the API key saved by a previous interactive login
74
+ 4. **Interactive login** — prompts for sitename/username and password
75
+
76
+ For non-interactive logins you can also set:
77
+
78
+ | Variable | Purpose |
79
+ | --- | --- |
80
+ | `NEOCITIES_API_KEY` | API key used as a Bearer token |
81
+ | `NEOCITIES_SITENAME` | Default sitename/username for the login prompt |
82
+ | `NEOCITIES_PASSWORD` | Default password for the login prompt |
83
+
84
+ The config file is stored per platform:
85
+
86
+ | Platform | Location |
87
+ | --- | --- |
88
+ | Linux | `$XDG_CONFIG_HOME/neocities/config.json` (defaults to `~/.config/neocities/config.json`) |
89
+ | macOS | `~/Library/Application Support/neocities/config.json` |
90
+ | Windows | `%LOCALAPPDATA%\neocities\config.json` |
91
+ | FreeBSD / other | `~/.neocities/config.json` |
92
+
93
+ Remove the stored key with:
94
+
95
+ ```bash
96
+ neocities-red logout -y
97
+ ```
98
+
58
99
  ---
59
100
 
60
101
  ## CLI Commands
@@ -62,36 +103,142 @@ neocities-red help push
62
103
  ```text
63
104
  push Recursively upload a local directory to your site
64
105
  upload Upload individual files/folders to your site
65
- delete Delete remote files
66
- diff Compare local directory with remote
67
- list List remote files
68
- info Show site info
69
- pull Download latest remote files
70
- logout Remove stored API key from config
71
- version Print gem version
72
- pizza Easter egg
106
+ delete Delete files from your site
107
+ diff Compare your local directory with your site
108
+ list List files from your site
109
+ info Show information and stats for your site
110
+ pull Get the most recent version of files from your site
111
+ purge Remove all files from your site (development only)
112
+ logout Remove the stored API key from the config
113
+ version Print the gem version
114
+ pizza Order a free pizza
115
+ help Show help for a command
73
116
  ```
74
117
 
75
- ### `push` options
118
+ ### `push`
119
+
120
+ Recursively upload a local directory to your Neocities site. Respects
121
+ `.gitignore` rules by default.
76
122
 
77
123
  | Flag | Description |
78
124
  | --- | --- |
79
125
  | `--no-gitignore` | Ignore `.gitignore` filtering and upload matching files |
80
126
  | `--ignore-dotfiles` | Skip dotfiles/dot-directories |
81
- | `-e`, `--exclude` | Exclude file/directory paths |
127
+ | `-e`, `--exclude` | Exclude file/directory paths (repeatable) |
82
128
  | `--dry-run` | Show intended actions without mutating remote |
83
- | `--optimized` | Skip files that already match remote hash |
129
+ | `--optimized` | Skip files whose SHA1 hash already matches the server |
84
130
  | `--prune` | Delete remote files that do not exist locally |
85
131
 
86
- Examples:
87
-
88
132
  ```bash
89
133
  neocities-red push .
90
134
  neocities-red push . --optimized --ignore-dotfiles
91
135
  neocities-red push . -e node_modules -e .git
136
+ neocities-red push . --dry-run
137
+ neocities-red push . --prune
138
+ ```
139
+
140
+ ### `diff`
141
+
142
+ Compare a local directory with the remote site and show added, modified, and
143
+ removed files.
144
+
145
+ | Flag | Description |
146
+ | --- | --- |
147
+ | `--ignore-dotfiles` | Skip dotfiles/dot-directories |
148
+ | `-e`, `--exclude` | Exclude file/directory paths (repeatable) |
149
+
150
+ ```bash
151
+ neocities-red diff .
152
+ neocities-red diff ./my-website --ignore-dotfiles
92
153
  neocities-red diff . -e secret.txt
93
154
  ```
94
155
 
156
+ ### `upload`
157
+
158
+ Upload an individual file or folder to your site.
159
+
160
+ ```bash
161
+ neocities-red upload index.html
162
+ neocities-red upload assets/ images/assets
163
+ ```
164
+
165
+ ### `list`
166
+
167
+ List files from your Neocities site.
168
+
169
+ | Flag | Description |
170
+ | --- | --- |
171
+ | `-d`, `--detail` | Show a detailed table with size, SHA1 hash, and last-updated timestamp |
172
+ | `-a`, `--all` | List the entire site (ignore the path argument) |
173
+
174
+ ```bash
175
+ neocities-red list
176
+ neocities-red list images -d
177
+ neocities-red list -a
178
+ ```
179
+
180
+ ### `info`
181
+
182
+ Show information and statistics for a site (defaults to your own site).
183
+
184
+ ```bash
185
+ neocities-red info
186
+ neocities-red info fauux
187
+ ```
188
+
189
+ ### `pull`
190
+
191
+ Download the most recent version of files from your site. Skips files that
192
+ haven't changed since your last pull.
193
+
194
+ | Flag | Description |
195
+ | --- | --- |
196
+ | `-q`, `--quiet` | Show a spinner instead of per-file output |
197
+
198
+ ```bash
199
+ neocities-red pull
200
+ neocities-red pull --quiet
201
+ ```
202
+
203
+ ### `delete`
204
+
205
+ Delete one or more files from your site.
206
+
207
+ ```bash
208
+ neocities-red delete old.html
209
+ neocities-red delete old.html archived/old.css
210
+ ```
211
+
212
+ ### `purge`
213
+
214
+ Delete **everything** from your site. Intended for development sites only —
215
+ use with care.
216
+
217
+ | Flag | Description |
218
+ | --- | --- |
219
+ | `-y`, `--yes` | Confirm the destructive action (required) |
220
+ | `--dry-run` | Show what would be deleted without deleting |
221
+
222
+ ```bash
223
+ neocities-red purge -y
224
+ neocities-red purge -y --dry-run
225
+ ```
226
+
227
+ ### `logout`
228
+
229
+ Remove the stored API key from the config. Requires confirmation.
230
+
231
+ ```bash
232
+ neocities-red logout -y
233
+ ```
234
+
235
+ ### `version` & `pizza`
236
+
237
+ ```bash
238
+ neocities-red version # print the gem version
239
+ neocities-red pizza # order a free pizza (easter egg)
240
+ ```
241
+
95
242
  ---
96
243
 
97
244
  ## Library Usage
@@ -109,7 +256,10 @@ client.list(remote_path)
109
256
  client.info(sitename)
110
257
  ```
111
258
 
112
- ---
259
+ The client supports both API-key (`api_key:`) and basic-auth
260
+ (`sitename:`/`password:`) authentication, retries transient failures (429/5xx)
261
+ automatically, and exposes low-level helpers like `upload_hash`,
262
+ `delete_wrapper_with_dry_run`, `key`, and `download`.
113
263
 
114
264
  ### Advanced: Services
115
265
 
@@ -132,7 +282,24 @@ Current service namespaces:
132
282
 
133
283
  - `NeocitiesRed::Services::File` (`Uploader`, `FolderUploader`, `List`, `Remover`)
134
284
  - `NeocitiesRed::Services::Site` (`Pusher`, `Differencer`, `Exporter`, `Informer`)
135
- - `NeocitiesRed::Services::Common` (`Pizza`)
285
+ - `NeocitiesRed::Services::Common` (`Exclusions`, `WorkerPool`, `Pizza`)
286
+
287
+ ---
288
+
289
+ ## Development
290
+
291
+ ```bash
292
+ bundle install
293
+ bundle exec rspec # run the test suite
294
+ bundle exec rubocop # run the linter
295
+ bundle exec ruby bin/neocities-red # run the CLI from source
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Changelog
301
+
302
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
136
303
 
137
304
  ---
138
305