portage-ucp-client 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88904b38d834b4f1b1343d35f50db2149828dc76edd179a778c511cb17119880
4
- data.tar.gz: 334b55de228968238f9737e079ee719119232c81c631dcda00be1bd68e7c44d2
3
+ metadata.gz: 8ca449d6a513f5b79171362c5fbd7830812fecf99abc5b60d88e98c6362faf10
4
+ data.tar.gz: fa8e0a0f2a00f3b62431303aafabfb94228e9fecae184c1d5ab9df3752240b46
5
5
  SHA512:
6
- metadata.gz: ba6fbffe20114f8c1d328dd7399f792a4dbaa81d03fb589366e8ec312c8efd08299b349aa5c0eaa9fd16254c4af9c4e3d9881387ae61163fb0d40ecebb92a7dc
7
- data.tar.gz: 5dbce7d84c0b54d8068be7d95713855b94e765a6c945ea4c9e13bc86c02bf19683b87b6db8431173eb27b46363df3838bc264147259a470c430cf3a0ee48c79d
6
+ metadata.gz: 15a8962035eef888342055b2307304c89fa97e180c1a2ebb70e9ae25cbf8bd35212d95f1b83a09afa0d27c0a6003bba92b3a844fc58145b04d0eed759fc4d366
7
+ data.tar.gz: ed79009feffcc06418784907007b210250edc1e95182c48a8c8408f8de3db226da082cc55f3d50bc532707ebe682618a4b7040963001c963c068497a12a79364
data/CHANGELOG.md CHANGED
@@ -4,6 +4,24 @@ All notable changes to this project are documented here. Format loosely follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.0.0/); this project is
5
5
  pre-1.0, so APIs may still shift between minor versions.
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ## [0.3.0] - 2026-09-14
10
+
11
+ - `Session` gains `#create_payment_enrollment(idempotency_key: nil)` /
12
+ `#get_payment_enrollment(enrollment_id:)`, covering the new
13
+ `app.portage-ucp.payment_enrollment` capability (docs/plans/agentic-payments.md
14
+ Phase 1). `create_payment_enrollment` is added to `MUTATING_ACTIONS`, so a
15
+ caller that omits `idempotency_key:` still gets one generated.
16
+ - Every transport (http, stdio, loopback) and `Session` grow an optional
17
+ `meta:` kwarg, threaded through the same way `correlation_id` already
18
+ reaches the server from `traceparent` — additive only, no caller passing
19
+ `meta:` is required to change.
20
+ - Widened the `portage-ucp` dependency pin from `~> 0.4` to `~> 0.5` —
21
+ `#create_payment_enrollment`/`#get_payment_enrollment` need the
22
+ `app.portage-ucp.payment_enrollment` capability, only present from
23
+ `portage-ucp` 0.5.0 on.
24
+
7
25
  ## [0.2.0] - 2026-08-21
8
26
 
9
27
  - `Session#create_checkout`/`#update_checkout` gain an optional `fulfillment:`
@@ -18,7 +18,7 @@ module Portage
18
18
  # must branch on it themselves.
19
19
  class Session
20
20
  MUTATING_ACTIONS = %w[create_cart update_cart cancel_cart create_checkout update_checkout
21
- complete_checkout cancel_checkout].freeze
21
+ complete_checkout cancel_checkout create_payment_enrollment].freeze
22
22
 
23
23
  # @param capabilities [Array<String>, nil] reverse-domain capability
24
24
  # names advertised by the server, when known upfront (Client.discover
@@ -38,21 +38,26 @@ module Portage
38
38
  capabilities&.include?(capability_name)
39
39
  end
40
40
 
41
- def search_catalog(query:, limit: 20) = call("search_catalog", query: query, limit: limit)
42
- def get_product(product_id:) = call("get_product", product_id: product_id)
41
+ def search_catalog(query:, limit: 20,
42
+ meta: nil)
43
+ call("search_catalog", meta: meta, query: query, limit: limit)
44
+ end
45
+
46
+ def get_product(product_id:, meta: nil) = call("get_product", meta: meta, product_id: product_id)
47
+ def lookup_catalog(product_ids:, meta: nil) = call("lookup_catalog", meta: meta, product_ids: product_ids)
43
48
 
44
- def get_cart(cart_id:) = call("get_cart", cart_id: cart_id)
49
+ def get_cart(cart_id:, meta: nil) = call("get_cart", meta: meta, cart_id: cart_id)
45
50
 
46
- def create_cart(line_items:, idempotency_key: nil)
47
- call("create_cart", line_items: line_items, idempotency_key: idempotency_key)
51
+ def create_cart(line_items:, idempotency_key: nil, meta: nil)
52
+ call("create_cart", meta: meta, line_items: line_items, idempotency_key: idempotency_key)
48
53
  end
49
54
 
50
- def update_cart(cart_id:, line_items:, idempotency_key: nil)
51
- call("update_cart", cart_id: cart_id, line_items: line_items, idempotency_key: idempotency_key)
55
+ def update_cart(cart_id:, line_items:, idempotency_key: nil, meta: nil)
56
+ call("update_cart", meta: meta, cart_id: cart_id, line_items: line_items, idempotency_key: idempotency_key)
52
57
  end
53
58
 
54
- def cancel_cart(cart_id:, idempotency_key: nil)
55
- call("cancel_cart", cart_id: cart_id, idempotency_key: idempotency_key)
59
+ def cancel_cart(cart_id:, idempotency_key: nil, meta: nil)
60
+ call("cancel_cart", meta: meta, cart_id: cart_id, idempotency_key: idempotency_key)
56
61
  end
57
62
 
58
63
  # `fulfillment:` (dev.ucp.shopping.fulfillment) is only exercised over
@@ -61,36 +66,48 @@ module Portage
61
66
  # (a Portage::Ucp::CheckoutFulfillment for loopback). Over stdio/HTTP
62
67
  # it would need a JSON wire shape this gem doesn't build yet, so
63
68
  # callers on those transports should leave it nil.
64
- def create_checkout(line_items:, idempotency_key: nil, fulfillment: nil)
65
- call("create_checkout", line_items: line_items, idempotency_key: idempotency_key,
69
+ def create_checkout(line_items:, idempotency_key: nil, fulfillment: nil, meta: nil)
70
+ call("create_checkout", meta: meta, line_items: line_items, idempotency_key: idempotency_key,
66
71
  **(fulfillment ? { fulfillment: fulfillment } : {}))
67
72
  end
68
73
 
69
- def get_checkout(checkout_id:) = call("get_checkout", checkout_id: checkout_id)
74
+ def get_checkout(checkout_id:, meta: nil) = call("get_checkout", meta: meta, checkout_id: checkout_id)
70
75
 
71
- def update_checkout(checkout_id:, line_items:, idempotency_key: nil, fulfillment: nil)
72
- call("update_checkout", checkout_id: checkout_id, line_items: line_items, idempotency_key: idempotency_key,
76
+ def update_checkout(checkout_id:, line_items:, idempotency_key: nil, fulfillment: nil, meta: nil)
77
+ call("update_checkout", meta: meta, checkout_id: checkout_id, line_items: line_items,
78
+ idempotency_key: idempotency_key,
73
79
  **(fulfillment ? { fulfillment: fulfillment } : {}))
74
80
  end
75
81
 
76
- def complete_checkout(checkout_id:, payment_token:, idempotency_key: nil)
82
+ def complete_checkout(checkout_id:, payment_token:, idempotency_key: nil, meta: nil)
77
83
  Portage::Ucp::PaymentTokenGuard.validate!(payment_token)
78
- call("complete_checkout", checkout_id: checkout_id, payment_token: payment_token,
84
+ call("complete_checkout", meta: meta, checkout_id: checkout_id, payment_token: payment_token,
79
85
  idempotency_key: idempotency_key)
80
86
  end
81
87
 
82
- def cancel_checkout(checkout_id:, idempotency_key: nil)
83
- call("cancel_checkout", checkout_id: checkout_id, idempotency_key: idempotency_key)
88
+ def cancel_checkout(checkout_id:, idempotency_key: nil, meta: nil)
89
+ call("cancel_checkout", meta: meta, checkout_id: checkout_id, idempotency_key: idempotency_key)
90
+ end
91
+
92
+ def get_order(order_id:, meta: nil) = call("get_order", meta: meta, order_id: order_id)
93
+ def link_identity(oauth_token:, meta: nil) = call("link_identity", meta: meta, oauth_token: oauth_token)
94
+
95
+ # app.portage-ucp.payment_enrollment (Portage extension, §ref
96
+ # docs/plans/agentic-payments.md Phase 1) — not every adapter
97
+ # advertises this, check #advertises? first.
98
+ def create_payment_enrollment(idempotency_key: nil, meta: nil)
99
+ call("create_payment_enrollment", meta: meta, idempotency_key: idempotency_key)
84
100
  end
85
101
 
86
- def get_order(order_id:) = call("get_order", order_id: order_id)
87
- def link_identity(oauth_token:) = call("link_identity", oauth_token: oauth_token)
102
+ def get_payment_enrollment(enrollment_id:, meta: nil)
103
+ call("get_payment_enrollment", meta: meta, enrollment_id: enrollment_id)
104
+ end
88
105
 
89
106
  private
90
107
 
91
- def call(action, **arguments)
108
+ def call(action, meta: nil, **arguments)
92
109
  arguments[:idempotency_key] ||= SecureRandom.uuid if MUTATING_ACTIONS.include?(action)
93
- @transport.call_tool(name: action, arguments: arguments)
110
+ @transport.call_tool(name: action, arguments: arguments, meta: meta)
94
111
  end
95
112
  end
96
113
  end
@@ -12,8 +12,8 @@ module Portage
12
12
  @client.connect
13
13
  end
14
14
 
15
- def call_tool(name:, arguments:)
16
- response = @client.call_tool(name: name, arguments: arguments)
15
+ def call_tool(name:, arguments:, meta: nil)
16
+ response = @client.call_tool(name: name, arguments: arguments, meta: meta)
17
17
  ToolResult.extract(response, symbol_keys: false)
18
18
  end
19
19
  end
@@ -15,10 +15,11 @@ module Portage
15
15
  @next_id = 0
16
16
  end
17
17
 
18
- def call_tool(name:, arguments:)
18
+ def call_tool(name:, arguments:, meta: nil)
19
19
  @next_id += 1
20
20
  response = @server.handle(
21
- { jsonrpc: "2.0", id: @next_id, method: "tools/call", params: { name: name, arguments: arguments } }
21
+ { jsonrpc: "2.0", id: @next_id, method: "tools/call",
22
+ params: { name: name, arguments: arguments, **(meta ? { _meta: meta } : {}) } }
22
23
  )
23
24
  ToolResult.extract(response, symbol_keys: true)
24
25
  end
@@ -12,8 +12,8 @@ module Portage
12
12
  @client.connect
13
13
  end
14
14
 
15
- def call_tool(name:, arguments:)
16
- response = @client.call_tool(name: name, arguments: arguments)
15
+ def call_tool(name:, arguments:, meta: nil)
16
+ response = @client.call_tool(name: name, arguments: arguments, meta: meta)
17
17
  ToolResult.extract(response, symbol_keys: false)
18
18
  end
19
19
  end
@@ -1,7 +1,7 @@
1
1
  module Portage
2
2
  module Ucp
3
3
  module Client
4
- VERSION = "0.2.0".freeze
4
+ VERSION = "0.3.0".freeze
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: portage-ucp-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Whitbread
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-09-14 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: mcp
@@ -29,14 +30,14 @@ dependencies:
29
30
  requirements:
30
31
  - - "~>"
31
32
  - !ruby/object:Gem::Version
32
- version: '0.2'
33
+ version: '0.5'
33
34
  type: :runtime
34
35
  prerelease: false
35
36
  version_requirements: !ruby/object:Gem::Requirement
36
37
  requirements:
37
38
  - - "~>"
38
39
  - !ruby/object:Gem::Version
39
- version: '0.2'
40
+ version: '0.5'
40
41
  - !ruby/object:Gem::Dependency
41
42
  name: rspec
42
43
  requirement: !ruby/object:Gem::Requirement
@@ -99,6 +100,7 @@ description: 'Every other portage-ucp gem lets a Ruby program expose a commerce
99
100
  as the client. Three transports behind one interface (loopback over an in-process
100
101
  Adapter, stdio, Streamable HTTP) — callers never know which they got. Depends only
101
102
  on portage-ucp + the mcp gem''s client half; no adapter gem is a dependency.'
103
+ email:
102
104
  executables: []
103
105
  extensions: []
104
106
  extra_rdoc_files: []
@@ -121,6 +123,7 @@ metadata:
121
123
  source_code_uri: https://github.com/tomtom87/Portage/tree/main/portage-ucp-client
122
124
  changelog_uri: https://github.com/tomtom87/Portage/blob/main/portage-ucp-client/CHANGELOG.md
123
125
  rubygems_mfa_required: 'true'
126
+ post_install_message:
124
127
  rdoc_options: []
125
128
  require_paths:
126
129
  - lib
@@ -135,7 +138,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
138
  - !ruby/object:Gem::Version
136
139
  version: '0'
137
140
  requirements: []
138
- rubygems_version: 4.0.18
141
+ rubygems_version: 3.5.22
142
+ signing_key:
139
143
  specification_version: 4
140
144
  summary: Client-side SDK for portage-ucp — act as the shopper's agent against any
141
145
  UCP/MCP server