yamine 0.10.2 → 0.10.3

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: 06f020588bc63954dd44b5a99b598995ec3e6f562c03756b867d26ff44178af8
4
- data.tar.gz: 97f1613f7ad01d1362e4098651048addd3a4a738912c6bd83427e3ea9453ad8d
3
+ metadata.gz: 9db7f2ecccb27a731e287afd46aee1e3bcea4654ccaed6f44e1fa622ec4ba4c4
4
+ data.tar.gz: aa2ad6be04141dc6b4f3dabf89c67b8ff93dc8c4d296369735f2ddc8cda9201d
5
5
  SHA512:
6
- metadata.gz: 3f03809157db470e905542751e16d8a6cb6edd6b91a78637f20e85fb5670e6b30e15f717d1bbaed714c70b077a756fe97744bfb27521304606b2d661dea57eab
7
- data.tar.gz: 83bb42d5eb49f6ee4007d04fa3e1b13024a46044d1afc7756a126f43384f60cb9c6ca57d7440d77ffcbacd37b9d95b04dbf8eb933bbf1676a10440e4951bdba7
6
+ metadata.gz: a0787fe2e1c69fa0842fae4a4048b2eb42187ee3ce43a4b850db0e9956d32aa3c7be7c733b81574e1d619bb1f33542de31489b987fc3fde06d0351875777eac9
7
+ data.tar.gz: 5441bf6b2c0bf9fd8d375d22386d906c8ff71c1f35db7f8845c31dfe78fecc45c00134aec213c548e14a4bf3b6b803bb9b6e5f7b673b08c23db575f70ad832ec
data/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.10.3] — 2026-09-11
4
+
5
+ ### Added
6
+
7
+ - **`yamine start` waits by default** (was opt-in `--wait`). Every HTTP
8
+ process is spawned concurrently, each `healthcheck: { path: /up,
9
+ timeout: 30 }` or TCP accept is polled, and routes are registered only
10
+ when all are healthy (`ready:` + `WaitPayload` with `--json`). On
11
+ failure everything spawned (including background children) is killed and
12
+ the CLI exits 1 with the failed process's own `log/yamine-<name>.log`
13
+ tail and no half-booted routes. `--wait` is kept as a no-op alias;
14
+ `--no-wait` restores the old sequential fire-and-forget path.
15
+ - `Yamine::Readiness` phased events (`phase`/`action`/`status`/
16
+ `duration_ms`/`detail`), `check_deps` pre-flight, `wait_healthy`
17
+ (healthcheck path or TCP accept), concurrent `wait_all` (one thread per
18
+ process, dead-PID short-circuit), per-phase timeouts (deps 30s, db 15s,
19
+ schema 90s, process 45s or per-healthcheck). `Yamine::WaitPayload`
20
+ success/failure payloads. `Runner#spawn_http`/`adopt`/`spawned?`, `boot_run`
21
+ output is logged and `Database.exists?` splits from `ensure_exists` for
22
+ provenance without a second probe.
23
+ - Top-level `db: false` opts out of per-worktree databases (validated
24
+ boolean-or-mapping, `x-` extensions still ignored), `db.schema_load`
25
+ moves to top-level `db`. Template discovery checks `ENV` then top-level
26
+ `env.clear` then per-process `env.clear`.
27
+
28
+ ### Fixed
29
+
30
+ - **`yamine --force` (and bare `yamine --wait`/`--no-wait`) no longer hits
31
+ the "no longer supported" error.** Boot-flag dispatch now routes bare
32
+ `yamine --flag` to `run_inferred` instead of the legacy single-name
33
+ path, and `--help`/`--version` are handled before boot. `run_named`
34
+ now guides `unknown flag \`--flag\`` toward `--help`.
35
+ - **`yamine` no longer wastes a 2s health wait before reporting the
36
+ ownership conflict.** The conflict you hit (`"anywaye.localhost" is
37
+ already registered by a running agent "kaka@...` + stale background
38
+ jobs already spawned) now fails before any spawn, `prune_stale` discards
39
+ crashed state, and the message distinguishes same-agent-different-dir
40
+ ("stop the other instance") from foreign agent ("work in your own
41
+ worktree"). Guidance now says `yamine start --force (or bare \`yamine
42
+ --force\`)`.
43
+ - **Credentials-only `DATABASE_URL`s no longer share silently.** When no
44
+ template exists but `database.yml`/`Gemfile` proves server-backed, boot
45
+ warns loudly with the `env.clear` + `local.secrets` fix. Injection is
46
+ still `DATABASE_URL`, no `ask-auth` dep, no Rails load at boot.
47
+
3
48
  ## [0.10.2] — 2026-09-10
4
49
 
5
50
  ### Added
@@ -46,8 +46,12 @@ module Yamine
46
46
  end
47
47
 
48
48
  def run_named(ctx, name, _args)
49
- $stderr.puts "Error: `yamine #{name}` is no longer supported."
50
- $stderr.puts " All processes come from config/local.yml. Run `yamine init` to create one."
49
+ if name.to_s.start_with?("-")
50
+ $stderr.puts "Error: unknown flag `#{name}`. Try `yamine --help` or `yamine start --help`."
51
+ else
52
+ $stderr.puts "Error: `yamine #{name}` is no longer supported."
53
+ $stderr.puts " All processes come from config/local.yml. Run `yamine init` to create one."
54
+ end
51
55
  exit 1
52
56
  end
53
57
 
@@ -298,20 +302,32 @@ module Yamine
298
302
  # Compares our worktree dir (spec.dir) against the owner's: same
299
303
  # dir + same agent is a restart, anything else names the owner.
300
304
  def check_worktree_ownership!(ctx, resolved, force:)
305
+ return if force
306
+
301
307
  mine = Agent.name
302
308
  here = File.expand_path(Dir.pwd)
309
+ # Stale pids (agent died, worktree deleted) must not block a restart.
310
+ ctx.store.prune_stale
303
311
  Resolver.hostnames(resolved).each do |hostname|
304
312
  entry = ctx.store.find(hostname)
305
313
  next unless entry
306
314
  next unless entry["pid"] != 0 && ProxyControl.pid_alive?(entry["pid"])
307
315
  next if entry["agent"] == mine && entry.dig("spec", "dir") == here
308
- next if force
309
316
 
310
317
  owner = entry["agent"] && !entry["agent"].empty? ? "agent #{entry["agent"].inspect}" : "PID #{entry["pid"]}"
311
318
  dir = entry.dig("spec", "dir")
312
- $stderr.puts "Error: #{hostname} is live and owned by #{owner}#{dir ? " (#{dir})" : ""}."
313
- $stderr.puts " Work in your own worktree (each branch gets its own URL), or take over explicitly:"
314
- $stderr.puts " yamine start --force"
319
+ same_agent = entry["agent"] == mine
320
+ same_dir = entry.dig("spec", "dir") == here
321
+ if same_agent && !same_dir
322
+ $stderr.puts "Error: #{hostname} was started from a different directory by the same agent #{mine.inspect}:"
323
+ $stderr.puts " running: #{dir || "(unknown)"}"
324
+ $stderr.puts " current: #{here}"
325
+ $stderr.puts " Stop the other instance first (`yamine stop` there) or take over explicitly:"
326
+ else
327
+ $stderr.puts "Error: #{hostname} is live and owned by #{owner}#{dir ? " (#{dir})" : ""}."
328
+ $stderr.puts " Work in your own worktree (each branch gets its own URL), or take over explicitly:"
329
+ end
330
+ $stderr.puts " yamine start --force (or bare `yamine --force`)"
315
331
  exit 1
316
332
  end
317
333
  end
data/lib/yamine/cli.rb CHANGED
@@ -25,9 +25,21 @@ module Yamine
25
25
 
26
26
  def run(argv)
27
27
  args = argv.dup
28
- if args.empty? || (!SUBCOMMANDS.include?(args.first) && !args.first.start_with?("-"))
28
+ if args.empty?
29
29
  return BootCommand.run_inferred(Context.new, args)
30
30
  end
31
+ # --help / --version are handled by `help` below, not by boot.
32
+ if args.first&.start_with?("-")
33
+ first = args.first.to_s
34
+ if %w[--help -h --version -v].include?(first)
35
+ return help if %w[--help -h].include?(first)
36
+ return (puts "yamine #{VERSION}"; 0) if %w[--version -v].include?(first)
37
+ end
38
+ return BootCommand.run_inferred(Context.new, args)
39
+ end
40
+ unless SUBCOMMANDS.include?(args.first)
41
+ return BootCommand.run_named(Context.new, args.first, args[1..])
42
+ end
31
43
 
32
44
  cmd = args.shift
33
45
  ctx = Context.new
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yamine
4
- VERSION = "0.10.2"
4
+ VERSION = "0.10.3"
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.10.2
4
+ version: 0.10.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaka Ruto