yamine 0.7.1 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96bdebf9dc726c4caf747a07f2599bbde292a975e3395bd7cf43b1daf752bea3
4
- data.tar.gz: 4abda73bc87a74f344070a3d69e87d470b788f05d04abfa4d6fb5783649fea20
3
+ metadata.gz: 46a9c0208ca1d5581c3c25d45b60370a6e37c7dd4fcf721bda7a5573fc1c70db
4
+ data.tar.gz: 0b534671965987794b3872969dcc3065dfca5532a401f12701e531a0779e7820
5
5
  SHA512:
6
- metadata.gz: 627bc6d9fcb038635d90ec9b49eb7a321fae414cb58ed584b02f4bcc7fbd8fd3a49fe98b610d7fb033564c416ab8ccdbed1b87c5ef6983ef7c70023eca351110
7
- data.tar.gz: 19a0c6f70d82fddf4385c616e820d04d00a12d60be5016a13ce12054da5bf82aeb5fc7a47940d030518645eda95dac28a1957502d7df139715da65695681863f
6
+ metadata.gz: 339e64fabec8dab3c019bfdec8ec8f9f558dc4700b647fd462c4898e4f8796f93c1b65078d9ff171c338f38c70d055a8185b1d21bb547c63831bd816c5b7c6de
7
+ data.tar.gz: a71d56eef8327103f46a050307bb01095810ccd70085f3728a430617d3230cf567ffe3e9a04047428d6988d63efa7dd6965546bbb5e689f270991f8d4cc55d6d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.8.1] — 2026-09-10
4
+
5
+ ### Fixed
6
+
7
+ - **An already-correct `/etc/hosts` no longer reports a failure.**
8
+ `Hosts.sync` rewrote the file unconditionally, so on a normal machine
9
+ (where `/etc/hosts` is root-owned) it raised `Errno::EACCES`, returned
10
+ false, and made `yamine start` print "could not write /etc/hosts (try
11
+ sudo yamine hosts sync)" on every boot — pointing at an elevated write
12
+ for a file that already had exactly the right block. `synced?` existed
13
+ for precisely this guard but `sync` never consulted it. `sync` is now a
14
+ no-op returning true when the block already matches, and the setup step
15
+ reports "already lists N hostname(s)" instead of implying a failure.
16
+ Chrome/Firefox/Edge resolve `*.localhost` natively anyway; the file only
17
+ matters for Safari and custom TLDs.
18
+
19
+
20
+ ## [0.8.0] — 2026-09-10
21
+
22
+ ### Fixed
23
+
24
+ - **`--json` progress is flushed as it happens.** stdout is
25
+ block-buffered when it is a pipe — exactly how an agent reads the
26
+ stream — so the per-phase events added in 0.7.0 stayed in the buffer
27
+ until it filled or the process exited, making a slow boot look frozen.
28
+ That is the "poll and guess" behaviour the JSON stream exists to
29
+ replace. Every line is now flushed before the next phase runs.
30
+
31
+ ### Changed
32
+
33
+ - The yamine agent skill documents the boot stream: the human
34
+ phase lines, the `--json` contract (one flushed object per line, human
35
+ banner on stderr, payload last), and that failures carry the log tail
36
+ and path.
37
+
3
38
  ## [0.7.1] — 2026-09-10
4
39
 
5
40
  ### Fixed
@@ -46,6 +46,28 @@ yamine log [-f] # tail the web process log
46
46
  stable URLs, background ones are supervised without routes. A process
47
47
  that exits cleans up the whole tree.
48
48
 
49
+ The boot narrates every phase — deps, db, schema, and each process's
50
+ healthcheck — one line per phase, so a slow boot is never a black box:
51
+
52
+ ```
53
+ [deps] ok (479ms) dependencies satisfied
54
+ [web] ok (2.2s) healthcheck /up returned 2xx-3xx
55
+ ```
56
+
57
+ With `--json` the same events stream to stdout as one JSON object per
58
+ line, flushed as they happen (safe to read incrementally), and the
59
+ human banner moves to stderr — so stdout stays parseable and the final
60
+ payload is the last line:
61
+
62
+ ```
63
+ {"phase":"deps","action":"deps","status":"ok","duration_ms":479,...}
64
+ {"phase":"process","action":"web","status":"ok","duration_ms":2223,...}
65
+ {"ok":true,"service":"myapp","urls":{"web":"https://myapp.localhost"},...}
66
+ ```
67
+
68
+ On failure the payload carries the failed phase, that process's log tail,
69
+ and the log path — no need to go digging.
70
+
49
71
  ## Cross-service wiring
50
72
 
51
73
  ```bash
@@ -220,6 +220,8 @@ module Yamine
220
220
  hostnames = ctx.store.load_routes.map { |r| r["hostname"] }
221
221
  if hostnames.empty?
222
222
  puts " No routes registered yet — hosts sync will happen on the next boot."
223
+ elsif Yamine::Hosts.synced?(hostnames)
224
+ puts " /etc/hosts already lists #{hostnames.length} hostname(s)."
223
225
  elsif Yamine::Hosts.sync(hostnames)
224
226
  puts " Synced #{hostnames.length} hostname(s) to /etc/hosts."
225
227
  else
@@ -758,8 +760,12 @@ module Yamine
758
760
  end
759
761
  end
760
762
 
761
- # 3. Hosts (best-effort: only needed for Safari; warn, don't fail)
762
- unless Hosts.sync(ctx.store.load_routes.map { |r| r["hostname"] })
763
+ # 3. Hosts (best-effort: only needed for Safari and custom TLDs —
764
+ # Chrome/Firefox/Edge resolve *.localhost natively). Already-synced
765
+ # is the common case and must stay silent: warning there sent
766
+ # people to a sudo write for a file that needed nothing.
767
+ hostnames = ctx.store.load_routes.map { |r| r["hostname"] }
768
+ unless hostnames.empty? || Yamine::Hosts.synced?(hostnames) || Hosts.sync(hostnames)
763
769
  warn "Warning: could not write /etc/hosts (try sudo yamine hosts sync)."
764
770
  end
765
771
  end
data/lib/yamine/hosts.rb CHANGED
@@ -41,7 +41,20 @@ module Yamine
41
41
  names
42
42
  end
43
43
 
44
+ # Bring the managed block to exactly these hostnames. Idempotent: when
45
+ # the block already matches, this is a no-op returning true.
46
+ #
47
+ # The short-circuit is load-bearing, not an optimization. /etc/hosts is
48
+ # root-owned on a normal machine, so a rewrite fails without sudo — and
49
+ # `setup` and every boot's workstation check run this. Without the
50
+ # guard, a machine whose hosts file was already correct got a
51
+ # "could not write /etc/hosts (try sudo yamine hosts sync)" warning on
52
+ # every run, sending people to an elevated write for a file that
53
+ # needed nothing. (Chrome/Firefox/Edge resolve *.localhost natively;
54
+ # /etc/hosts only matters for Safari and custom TLDs.)
44
55
  def sync(hostnames, path = PATH)
56
+ return true if synced?(hostnames, path)
57
+
45
58
  content = read(path)
46
59
  block = managed_block(hostnames)
47
60
  if content.include?(BEGIN_MARKER)
data/lib/yamine/log.rb CHANGED
@@ -96,6 +96,12 @@ module Yamine
96
96
 
97
97
  # One JSON object per line — the agent contract. Same events, no
98
98
  # prose.
99
+ #
100
+ # Every line is flushed. stdout is block-buffered when it is a pipe
101
+ # or a file, which is exactly how an agent reads it, so without the
102
+ # flush the whole progress stream stays invisible until the buffer
103
+ # fills or the process exits — the "poll and guess" behaviour the
104
+ # JSON stream exists to replace, now with extra steps.
99
105
  class Json
100
106
  def initialize(io = $stdout)
101
107
  @io = io
@@ -103,12 +109,18 @@ module Yamine
103
109
 
104
110
  def event(event)
105
111
  require "json"
106
- @io.puts JSON.generate(event.to_h)
112
+ emit(event.to_h)
107
113
  end
108
114
 
109
115
  def note(message)
110
- require "json"
111
- @io.puts JSON.generate({ note: message })
116
+ emit({ note: message })
117
+ end
118
+
119
+ private
120
+
121
+ def emit(payload)
122
+ @io.puts JSON.generate(payload)
123
+ @io.flush if @io.respond_to?(:flush)
112
124
  end
113
125
  end
114
126
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yamine
4
- VERSION = "0.7.1"
4
+ VERSION = "0.8.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yamine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaka Ruto