yamine 0.7.0 → 0.8.0
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 +4 -4
- data/CHANGELOG.md +32 -0
- data/lib/ask/skills/yamine/SKILL.md +22 -0
- data/lib/yamine/cli/system.rb +28 -10
- data/lib/yamine/log.rb +15 -3
- data/lib/yamine/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 04f00c2029bf4cda65d187225d251fc594bacf538092e6a56d9c5a03f9aa47fd
|
|
4
|
+
data.tar.gz: 963f1c74d64ddb94199d42325f6d8631a5dd2d618119554a4e1a72849394c5bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2e02efba8d7c16767b0c4b8908d295f4c095f7c32f5ef90885e1ecf0a50aa68d61cb9e0c780d3729f703fcc14fc282eed46430d4efce631762dbb832ddecf408
|
|
7
|
+
data.tar.gz: 6d36c287b907fcfba07da2db3ecf1904ff4b396fb2bf8df277e0f9dfb23515e9245d574fb0bed85a034cd9f41fae14834842c722c3ac298e9f0fafedb1d30b45
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.0] — 2026-09-10
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **`--json` progress is flushed as it happens.** stdout is
|
|
8
|
+
block-buffered when it is a pipe — exactly how an agent reads the
|
|
9
|
+
stream — so the per-phase events added in 0.7.0 stayed in the buffer
|
|
10
|
+
until it filled or the process exited, making a slow boot look frozen.
|
|
11
|
+
That is the "poll and guess" behaviour the JSON stream exists to
|
|
12
|
+
replace. Every line is now flushed before the next phase runs.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- The yamine agent skill documents the boot stream: the human
|
|
17
|
+
phase lines, the `--json` contract (one flushed object per line, human
|
|
18
|
+
banner on stderr, payload last), and that failures carry the log tail
|
|
19
|
+
and path.
|
|
20
|
+
|
|
21
|
+
## [0.7.1] — 2026-09-10
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **`yamine start` now honors `YAMINE_PORT`.** `ensure_workstation!`
|
|
26
|
+
hardcoded port 443, so the documented escape hatch for CI and
|
|
27
|
+
sandboxes — "where 443 is impossible" — was ignored: with
|
|
28
|
+
`YAMINE_PORT=8443` on a non-interactive machine, `start` aborted with
|
|
29
|
+
"port 443 needs root to bind" and demanded sudo for a port the user
|
|
30
|
+
had deliberately chosen to avoid. The port and scheme now come from
|
|
31
|
+
the context, and an unprivileged port is started directly instead of
|
|
32
|
+
being treated as a setup failure. The root path is unchanged: 443 on a
|
|
33
|
+
non-interactive machine still points at `yamine setup`.
|
|
34
|
+
|
|
3
35
|
## [0.7.0] — 2026-09-10
|
|
4
36
|
|
|
5
37
|
Keeping the no-port promise when the machine's recorded port goes stale,
|
|
@@ -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
|
data/lib/yamine/cli/system.rb
CHANGED
|
@@ -700,9 +700,15 @@ module Yamine
|
|
|
700
700
|
|
|
701
701
|
|
|
702
702
|
# Quiet workstation setup for `start`: trust the CA, ensure a proxy
|
|
703
|
-
# on 443
|
|
704
|
-
# Each step is idempotent; only missing
|
|
705
|
-
# CI without a proxy fails fast rather
|
|
703
|
+
# on this run's port (443 by default — root service, sudo daemon
|
|
704
|
+
# fallback), and sync hosts. Each step is idempotent; only missing
|
|
705
|
+
# pieces run. Non-interactive CI without a proxy fails fast rather
|
|
706
|
+
# than prompting for sudo.
|
|
707
|
+
#
|
|
708
|
+
# The port comes from ctx, not a literal: YAMINE_PORT is the
|
|
709
|
+
# documented escape hatch for CI and sandboxes ("where 443 is
|
|
710
|
+
# impossible"), and hardcoding 443 here demanded root for a port
|
|
711
|
+
# those users had already chosen to avoid.
|
|
706
712
|
def ensure_workstation!(ctx)
|
|
707
713
|
# 1. CA
|
|
708
714
|
unless Yamine::Certs.trusted?(ctx.store.dir)
|
|
@@ -714,19 +720,30 @@ module Yamine
|
|
|
714
720
|
end
|
|
715
721
|
end
|
|
716
722
|
|
|
717
|
-
# 2. Proxy on
|
|
718
|
-
port =
|
|
719
|
-
tls =
|
|
723
|
+
# 2. Proxy on the port this run wants
|
|
724
|
+
port = ctx.proxy_port
|
|
725
|
+
tls = ctx.proxy_tls
|
|
720
726
|
unless Yamine::ProxyControl.listening?(port) && ProxyControl.ours?(port, tls: tls)
|
|
721
|
-
|
|
722
|
-
|
|
727
|
+
privileged = port < 1024
|
|
728
|
+
if privileged && !Yamine::ProxyControl.root? && !ctx.interactive?
|
|
729
|
+
abort_setup("Proxy is not running and port #{port} needs root to bind.", *privileged_port_hint)
|
|
723
730
|
end
|
|
724
731
|
ok =
|
|
725
732
|
if ProxyControl.root?
|
|
726
733
|
Yamine::CLI::SystemCommand.ensure_root_service(ctx)
|
|
727
734
|
elsif ctx.interactive?
|
|
728
735
|
begin
|
|
729
|
-
Yamine::ProxyControl.spawn_daemon(store: ctx.store, port: port, tls: tls, sudo:
|
|
736
|
+
Yamine::ProxyControl.spawn_daemon(store: ctx.store, port: port, tls: tls, sudo: privileged)
|
|
737
|
+
wait_for_ours(ctx, port, tls: tls)
|
|
738
|
+
rescue Yamine::ProxyNotRunningError, SystemCallError => e
|
|
739
|
+
warn " daemon start failed: #{e.message.lines.first&.strip}"
|
|
740
|
+
false
|
|
741
|
+
end
|
|
742
|
+
elsif !privileged
|
|
743
|
+
# Non-interactive but unprivileged: nothing to elevate, so
|
|
744
|
+
# start the daemon directly instead of failing.
|
|
745
|
+
begin
|
|
746
|
+
Yamine::ProxyControl.spawn_daemon(store: ctx.store, port: port, tls: tls, sudo: false)
|
|
730
747
|
wait_for_ours(ctx, port, tls: tls)
|
|
731
748
|
rescue Yamine::ProxyNotRunningError, SystemCallError => e
|
|
732
749
|
warn " daemon start failed: #{e.message.lines.first&.strip}"
|
|
@@ -736,7 +753,8 @@ module Yamine
|
|
|
736
753
|
false
|
|
737
754
|
end
|
|
738
755
|
unless ok
|
|
739
|
-
abort_setup("Proxy is not running and could not be started on port
|
|
756
|
+
abort_setup("Proxy is not running and could not be started on port #{port}.",
|
|
757
|
+
*privileged_port_hint)
|
|
740
758
|
end
|
|
741
759
|
end
|
|
742
760
|
|
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
|
-
|
|
112
|
+
emit(event.to_h)
|
|
107
113
|
end
|
|
108
114
|
|
|
109
115
|
def note(message)
|
|
110
|
-
|
|
111
|
-
|
|
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
|
data/lib/yamine/version.rb
CHANGED