ace-herdr 0.6.0 → 0.6.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: 5e3b1b413921a28b8ebd2437c424f885d11ec65bcf886fdb173101b8ce5ca8de
4
- data.tar.gz: a4ebad7d9470e1f7f1e74e6b7a66d3ced20605f13bb323c67f5abc51993978ee
3
+ metadata.gz: cff3b8e4bd486d4b0e4e9a914fbdfe7010ffd1bc2a2be82babd93acf273e875d
4
+ data.tar.gz: 1b2e18f9c0faef285ff1e4003ff65b49565227a95ce4d80321cf43108486ff8c
5
5
  SHA512:
6
- metadata.gz: b53397db1e608164a19390d073ae7420b602ec1a8152b975f11d6dd3443dda4da4ff5208644aecf7f2bb7bfc269034c6813eac283683eed4ea916b1b01c52795
7
- data.tar.gz: e716fc0fe8329fffda5b2c18c81395432b3257b4fee3118207f21e016f69185454f4ea2661fda6f8ba3aa42eebaf0aaca773fed7e20d7899ff08e6c139f2cb18
6
+ metadata.gz: ccc1d8b7fc65614ff262c9a84cf431e0a964057426a49e3cd981a38909c85f22752d31bb3b0924f26ccee69eb74487fa41a46a4fef8ab50fcd607cda64f921bd
7
+ data.tar.gz: 0c0f22e240507331336df50b2ebc8966a4b390ae6728b6ccb86b1628eba228d6a82ffa81db19439d2974d124a015bf06a02770558dec1911b40b22a51d2131e6
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.1] - 2026-10-16
11
+
12
+ ### Fixed
13
+
14
+ - Share native immutable session normalization between Inbox and process admission so real Pi path selectors bind their session UUID without weakening ancestry, foreground owner or live-session checks.
15
+
16
+ ### Changed
17
+
18
+ - Follow the ace-hitl-contract 0.3 request-envelope line (dependency floor).
19
+
10
20
  ## [0.6.0] - 2026-10-16
11
21
 
12
22
  ### Added
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Herdr
5
+ module Atoms
6
+ # Herdr reports Pi sessions as paths and Codex sessions as IDs. Both
7
+ # consumers bind the same immutable UUID; names never identify a session.
8
+ module NativeAgentSession
9
+ UUID = /\A[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}\z/
10
+ PI_PATH = /_([0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12})\.jsonl\z/
11
+
12
+ def self.normalize(session, agent:)
13
+ return nil unless %w[codex pi].include?(agent) && session.is_a?(Hash) && session["agent"] == agent
14
+
15
+ value = session["value"]
16
+ return nil unless value.is_a?(String) && value.valid_encoding? && !value.include?("\0")
17
+
18
+ kind = session["kind"]
19
+ if agent == "pi" && kind == "path"
20
+ return nil unless value.start_with?("/") && value.bytesize <= 4096
21
+
22
+ value = PI_PATH.match(value)&.captures&.first
23
+ kind = "id"
24
+ end
25
+ return nil unless kind == "id" && value.is_a?(String) && UUID.match?(value)
26
+
27
+ {"agent" => agent, "kind" => "id", "value" => value}
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../errors"
4
+ require_relative "../atoms/native_agent_session"
4
5
  require "digest"
5
6
  require "json"
6
7
  require "time"
@@ -22,8 +23,6 @@ module Ace
22
23
 
23
24
  EVENT = /\A[A-Za-z0-9][A-Za-z0-9._-]{0,127}\z/
24
25
  TARGET_IDENTITY = %w[session pane terminal_id agent thread thread_kind].freeze
25
- THREAD_ID = /\A[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}\z/
26
- PI_PATH = /_([0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12})\.jsonl\z/
27
26
  # Single validator for Pi queue event ids, shared by enqueue and
28
27
  # delivery observation so the two sites can never disagree again.
29
28
  PI_EVENT_ID = /\A(?:inb|wnk)-[a-z0-9-]{8,64}\z/
@@ -577,7 +576,7 @@ module Ace
577
576
  def validate_expected_target!(target)
578
577
  unless target.is_a?(Hash) && TARGET_IDENTITY.all? { |key| target[key].is_a?(String) && !target[key].empty? } &&
579
578
  %w[codex pi].include?(target["agent"]) && target["thread_kind"] == "id" &&
580
- THREAD_ID.match?(target["thread"]) && target["terminal_id"].bytesize <= 64
579
+ Atoms::NativeAgentSession::UUID.match?(target["thread"]) && target["terminal_id"].bytesize <= 64
581
580
  raise ValidationError, "accepted original native target is incomplete or invalid"
582
581
  end
583
582
  end
@@ -627,21 +626,12 @@ module Ace
627
626
  raise ValidationError, "unsupported native agent" unless %w[codex pi].include?(agent)
628
627
  session = pane["agent_session"]
629
628
  raise IdentityDriftError, "native session identity is unavailable" unless session.is_a?(Hash) && session["agent"] == agent
630
- thread = session["value"].to_s
631
- kind = session["kind"]
632
- if agent == "pi" && kind == "path"
633
- thread = PI_PATH.match(thread)&.captures&.first.to_s
634
- kind = "id"
635
- end
636
- # Only an immutable session UUID may carry a binding: a name
637
- # survives an agent restart in the same pane/terminal, so a reused
638
- # session could inherit an old event.
639
- unless kind == "id" && THREAD_ID.match?(thread)
629
+ normalized = Atoms::NativeAgentSession.normalize(session, agent: agent)
630
+ unless normalized
640
631
  raise ValidationError,
641
- "native queue binding requires an immutable session id " \
642
- "(got #{kind.inspect})"
632
+ "native queue binding requires an immutable session id (got #{session['kind'].inspect})"
643
633
  end
644
- raise ValidationError, "Pi queue requires a session ID" if agent == "pi" && kind != "id"
634
+ thread, kind = normalized.values_at("value", "kind")
645
635
  raw_terminal = pane["terminal_id"]
646
636
  terminal = raw_terminal.to_s.strip if raw_terminal.is_a?(String) || raw_terminal.is_a?(Integer)
647
637
  if terminal.nil? || terminal.empty? || terminal.bytesize > 64
@@ -4,6 +4,7 @@ require "ace/runtime"
4
4
  require "digest"
5
5
  require "fileutils"
6
6
  require "json"
7
+ require_relative "../atoms/native_agent_session"
7
8
 
8
9
  module Ace
9
10
  module Herdr
@@ -124,12 +125,10 @@ module Ace
124
125
  process.is_a?(Hash) && process["pid"] == owner.dig("process_identity", "pid")
125
126
  end
126
127
 
127
- session = native["agent_session"]
128
+ session = Atoms::NativeAgentSession.normalize(native["agent_session"], agent: native["agent"])
128
129
  workspace = native["workspace_id"] || native["session_id"]
129
130
  terminal = native["terminal_id"]
130
- next nil unless session.is_a?(Hash) && session["kind"] == "id" &&
131
- session["value"].is_a?(String) && session["value"].match?(Inbox::THREAD_ID) &&
132
- session["agent"] == native["agent"] && native["agent"].is_a?(String) &&
131
+ next nil unless session &&
133
132
  workspace.is_a?(String) && !workspace.empty? &&
134
133
  (terminal.is_a?(String) || terminal.is_a?(Integer)) && !terminal.to_s.empty?
135
134
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ace
4
4
  module Herdr
5
- VERSION = "0.6.0"
5
+ VERSION = "0.6.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ace-herdr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Czyz
@@ -49,14 +49,14 @@ dependencies:
49
49
  requirements:
50
50
  - - "~>"
51
51
  - !ruby/object:Gem::Version
52
- version: 0.2.1
52
+ version: 0.3.0
53
53
  type: :runtime
54
54
  prerelease: false
55
55
  version_requirements: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: 0.2.1
59
+ version: 0.3.0
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: ace-runtime
62
62
  requirement: !ruby/object:Gem::Requirement
@@ -219,6 +219,7 @@ files:
219
219
  - lib/ace/herdr.rb
220
220
  - lib/ace/herdr/atoms/answer_digest.rb
221
221
  - lib/ace/herdr/atoms/json_find.rb
222
+ - lib/ace/herdr/atoms/native_agent_session.rb
222
223
  - lib/ace/herdr/cli.rb
223
224
  - lib/ace/herdr/cli/commands/capture.rb
224
225
  - lib/ace/herdr/cli/commands/close.rb