tasker-rb 0.1.1 → 0.1.2

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: 1bded962229b0c776f66831e441e237da58b844fe480ef89708c59e32afae2d9
4
- data.tar.gz: 5d2ca6ccb24aa8f929ea48dc94bf4ddcb07269161729cde97888038fd64683a1
3
+ metadata.gz: 6c505f5e0ee2615e50e4bd56c0c6e3fd7900837dcaf8454f828e197f15f9328d
4
+ data.tar.gz: a4fbdabbf56b6798bc0b73d16fe894d3b10e92a554a9245a361c2724f16c5a43
5
5
  SHA512:
6
- metadata.gz: a62d25a0019c424bf4a441ba4b97bb53331da6f0b83ddfe3e3057b08c1fff42ffba6c4c9b1f253ff98b372063eca39cc44bf210ccad666fa7f6d1442e8ee04c0
7
- data.tar.gz: 89dc13bc48ade930463e5f15fb866efc96ee442ca2a8404277e66741854cbf9dc9a67e1755e81bbc9dfac4ab62c967edc66f14b5c27c534a817eb8e56e49bec8
6
+ metadata.gz: c847a219fe05381929501d8789c40e2be73436910461b92219c96d4510eb6ef51eb8bf371ad8555532e3fe4f6111af5706272600c603d90fb884f0c65fba02e1
7
+ data.tar.gz: 213e3946bef1bc91de6f9e69614509f48061079233e71697658e8eec556fa6f12a5e940e8d509671a10b77fbf4216ec22e2d529646147ba638735b25f861b31e
data/README.md CHANGED
@@ -2,32 +2,9 @@
2
2
 
3
3
  Ruby FFI bindings for the high-performance Tasker Core Rust orchestration engine.
4
4
 
5
- ## Status: Foundation Complete ✅
5
+ ## Status
6
6
 
7
- The foundational structure has been successfully implemented and tested:
8
-
9
- - ✅ **Monorepo Integration**: Successfully integrated into the main tasker-core repository
10
- - ✅ **Cargo Workspace**: Properly configured as a workspace member
11
- - ✅ **Magnus FFI Setup**: Basic Ruby module initialization working
12
- - ✅ **Rust Compilation**: All Rust code compiles successfully
13
- - ✅ **Build System**: CI/CD workflows configured for cross-platform testing
14
-
15
- ## Current Implementation
16
-
17
- This is a **foundational version** that establishes the structure:
18
-
19
- ```rust
20
- // Ruby module available:
21
- TaskerCore::RUST_VERSION # "0.1.0"
22
- TaskerCore::STATUS # "foundation"
23
- TaskerCore::FEATURES # "module_init"
24
-
25
- // Error classes defined:
26
- TaskerCore::Error
27
- TaskerCore::OrchestrationError
28
- TaskerCore::DatabaseError
29
- TaskerCore::FFIError
30
- ```
7
+ Production ready. Ruby FFI bindings provide full step handler execution via Magnus.
31
8
 
32
9
  ## Development Commands
33
10
 
@@ -45,15 +22,6 @@ rake spec
45
22
  rake setup
46
23
  ```
47
24
 
48
- ## Next Phase: Full Implementation
49
-
50
- The next development phase will implement:
51
-
52
- 1. **Complete WorkflowCoordinator API**
53
- 2. **Ruby ↔ Rust type conversions**
54
- 3. **Framework adapter for Rails integration**
55
- 4. **Performance benchmarks and validation**
56
-
57
25
  ## Architecture
58
26
 
59
27
  This gem follows the **delegation-based architecture**:
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "tasker-rb"
3
- version = "0.1.1"
3
+ version = "0.1.2"
4
4
  edition = "2021"
5
5
  description = "Ruby bindings for tasker-core: High-performance workflow orchestration"
6
6
  readme = "../../../../README.md"
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TaskerCore
4
+ # High-level client wrapper around the TaskerCore FFI client methods.
5
+ #
6
+ # The raw FFI exposes `TaskerCore::FFI.client_create_task(hash)` and similar
7
+ # methods that require callers to construct complete request hashes with all
8
+ # required fields (initiator, source_system, reason, etc.) and return plain
9
+ # hashes. This module provides keyword-argument methods with sensible defaults
10
+ # and wraps responses into typed `ClientTypes::*` Dry::Struct objects.
11
+ #
12
+ # @example Creating a task with defaults
13
+ # response = TaskerCore::Client.create_task(
14
+ # name: 'process_order',
15
+ # namespace: 'ecommerce',
16
+ # context: { order_id: 123 }
17
+ # )
18
+ # response.task_uuid # => "550e8400-..."
19
+ # response.status # => "pending"
20
+ #
21
+ # @example Getting a task
22
+ # task = TaskerCore::Client.get_task("550e8400-...")
23
+ # task.name # => "process_order"
24
+ # task.namespace # => "ecommerce"
25
+ #
26
+ # @example Listing tasks with filters
27
+ # list = TaskerCore::Client.list_tasks(namespace: 'ecommerce', limit: 10)
28
+ # list.tasks.size # => 3
29
+ # list.pagination # => { "total_count" => 42, ... }
30
+ module Client
31
+ module_function
32
+
33
+ # Create a task via the orchestration API.
34
+ #
35
+ # @param name [String] Named task template name
36
+ # @param namespace [String] Task namespace (default: "default")
37
+ # @param context [Hash] Workflow context passed to step handlers
38
+ # @param version [String] Template version (default: "1.0.0")
39
+ # @param initiator [String] Who initiated the request
40
+ # @param source_system [String] Originating system
41
+ # @param reason [String] Reason for creating the task
42
+ # @param options [Hash] Additional TaskRequest fields
43
+ # @return [ClientTypes::TaskResponse, Hash] Typed response or raw hash on schema mismatch
44
+ def create_task(name:, namespace: 'default', context: {}, version: '1.0.0',
45
+ initiator: 'tasker-core-ruby', source_system: 'tasker-core',
46
+ reason: 'Task requested', **options)
47
+ request = {
48
+ 'name' => name,
49
+ 'namespace' => namespace,
50
+ 'version' => version,
51
+ 'context' => deep_to_hash(context),
52
+ 'initiator' => initiator,
53
+ 'source_system' => source_system,
54
+ 'reason' => reason
55
+ }
56
+ options.each { |k, v| request[k.to_s] = v }
57
+
58
+ response = TaskerCore::FFI.client_create_task(request)
59
+ wrap_response(response, Types::ClientTaskResponse)
60
+ end
61
+
62
+ # Get a task by UUID.
63
+ #
64
+ # @param task_uuid [String] The task UUID
65
+ # @return [ClientTypes::TaskResponse, Hash] Typed response or raw hash
66
+ def get_task(task_uuid)
67
+ response = TaskerCore::FFI.client_get_task(task_uuid.to_s)
68
+ wrap_response(response, Types::ClientTaskResponse)
69
+ end
70
+
71
+ # List tasks with optional filtering and pagination.
72
+ #
73
+ # @param limit [Integer] Maximum number of results (default: 50)
74
+ # @param offset [Integer] Pagination offset (default: 0)
75
+ # @param namespace [String, nil] Filter by namespace
76
+ # @param status [String, nil] Filter by status
77
+ # @return [ClientTypes::TaskListResponse, Hash] Typed response or raw hash
78
+ def list_tasks(limit: 50, offset: 0, namespace: nil, status: nil)
79
+ response = TaskerCore::FFI.client_list_tasks(limit, offset, namespace, status)
80
+ wrap_response(response, Types::ClientTaskListResponse)
81
+ end
82
+
83
+ # Cancel a task by UUID.
84
+ #
85
+ # @param task_uuid [String] The task UUID
86
+ # @return [Hash] Cancellation result
87
+ def cancel_task(task_uuid)
88
+ TaskerCore::FFI.client_cancel_task(task_uuid.to_s)
89
+ end
90
+
91
+ # List workflow steps for a task.
92
+ #
93
+ # @param task_uuid [String] The task UUID
94
+ # @return [Array<ClientTypes::StepResponse>, Array<Hash>] Typed steps or raw hashes
95
+ def list_task_steps(task_uuid)
96
+ response = TaskerCore::FFI.client_list_task_steps(task_uuid.to_s)
97
+ return response unless response.is_a?(Array)
98
+
99
+ response.map { |step| wrap_response(step, Types::ClientStepResponse) }
100
+ end
101
+
102
+ # Get a specific workflow step.
103
+ #
104
+ # @param task_uuid [String] The task UUID
105
+ # @param step_uuid [String] The step UUID
106
+ # @return [ClientTypes::StepResponse, Hash] Typed response or raw hash
107
+ def get_step(task_uuid, step_uuid)
108
+ response = TaskerCore::FFI.client_get_step(task_uuid.to_s, step_uuid.to_s)
109
+ wrap_response(response, Types::ClientStepResponse)
110
+ end
111
+
112
+ # Get audit history for a workflow step.
113
+ #
114
+ # @param task_uuid [String] The task UUID
115
+ # @param step_uuid [String] The step UUID
116
+ # @return [Array<ClientTypes::StepAuditResponse>, Array<Hash>] Typed audit entries or raw hashes
117
+ def get_step_audit_history(task_uuid, step_uuid)
118
+ response = TaskerCore::FFI.client_get_step_audit_history(task_uuid.to_s, step_uuid.to_s)
119
+ return response unless response.is_a?(Array)
120
+
121
+ response.map { |entry| wrap_response(entry, Types::ClientStepAuditResponse) }
122
+ end
123
+
124
+ # Check orchestration API health.
125
+ #
126
+ # @return [ClientTypes::HealthResponse, Hash] Typed response or raw hash
127
+ def health_check
128
+ response = TaskerCore::FFI.client_health_check
129
+ wrap_response(response, Types::ClientHealthResponse)
130
+ end
131
+
132
+ # @api private
133
+ # Wrap a raw FFI hash response into a Dry::Struct type.
134
+ # Falls back to the raw hash if the schema doesn't match,
135
+ # providing forward-compatibility when the API adds new fields.
136
+ def wrap_response(raw, type_class)
137
+ return raw unless raw.is_a?(Hash)
138
+
139
+ # Dry::Struct requires symbolized keys; raw FFI returns string keys
140
+ type_class.new(raw.transform_keys(&:to_sym))
141
+ rescue Dry::Struct::Error, KeyError, Dry::Types::ConstraintError
142
+ raw
143
+ end
144
+
145
+ # @api private
146
+ # Recursively convert ActionController::Parameters (and similar) to plain hashes/arrays.
147
+ def deep_to_hash(obj)
148
+ case obj
149
+ when Hash
150
+ obj.transform_values { |v| deep_to_hash(v) }
151
+ when Array
152
+ obj.map { |v| deep_to_hash(v) }
153
+ else
154
+ # Handle ActionController::Parameters if available (Rails contexts)
155
+ if obj.respond_to?(:to_unsafe_h)
156
+ obj.to_unsafe_h.transform_values { |v| deep_to_hash(v) }
157
+ else
158
+ obj
159
+ end
160
+ end
161
+ end
162
+
163
+ private_class_method :wrap_response, :deep_to_hash
164
+ end
165
+ end
@@ -125,7 +125,7 @@ module TaskerCore
125
125
  # @return [Boolean] true if responds to method
126
126
  def responds_to_method?(klass, method_name)
127
127
  # Check instance methods (most common case)
128
- klass.instance_methods.include?(method_name) ||
128
+ klass.method_defined?(method_name) ||
129
129
  # Check if the class itself responds (for class methods)
130
130
  klass.respond_to?(method_name)
131
131
  end
@@ -3,7 +3,7 @@
3
3
  module TaskerCore
4
4
  # Version synchronization with the core Rust crate
5
5
  # This should be kept in sync with the Cargo.toml version
6
- VERSION = '0.1.1'
6
+ VERSION = '0.1.2'
7
7
 
8
8
  def self.version_info
9
9
  {
data/lib/tasker_core.rb CHANGED
@@ -138,6 +138,7 @@ require_relative 'tasker_core/internal'
138
138
  require_relative 'tasker_core/template_discovery'
139
139
  require_relative 'tasker_core/test_environment'
140
140
  require_relative 'tasker_core/types'
141
+ require_relative 'tasker_core/client'
141
142
  require_relative 'tasker_core/models'
142
143
  require_relative 'tasker_core/handlers'
143
144
  require_relative 'tasker_core/batch_processing/batch_worker_context'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tasker-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pete Taylor
@@ -233,6 +233,7 @@ files:
233
233
  - lib/tasker_core/batch_processing/batch_aggregation_scenario.rb
234
234
  - lib/tasker_core/batch_processing/batch_worker_context.rb
235
235
  - lib/tasker_core/bootstrap.rb
236
+ - lib/tasker_core/client.rb
236
237
  - lib/tasker_core/domain_events.rb
237
238
  - lib/tasker_core/domain_events/base_publisher.rb
238
239
  - lib/tasker_core/domain_events/base_subscriber.rb
@@ -268,7 +269,6 @@ files:
268
269
  - lib/tasker_core/step_handler/mixins/decision.rb
269
270
  - lib/tasker_core/subscriber.rb
270
271
  - lib/tasker_core/task_handler/base.rb
271
- - lib/tasker_core/tasker_rb.so
272
272
  - lib/tasker_core/template_discovery.rb
273
273
  - lib/tasker_core/tracing.rb
274
274
  - lib/tasker_core/types.rb
Binary file