agent-cli-runtime 0.1.0 → 0.1.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: 59030c0c124438712ef78cc86c61a0d26ce929ff424ea468493e0c899f660599
4
- data.tar.gz: fe1ccdd4b7c38c75dbd5491b20eefde6d60e493e4ceec116cbc3c2181f159559
3
+ metadata.gz: 59315cc0411f928db6beb1ecea2a7f96986c26e7436ea60d14d105c7b0252c71
4
+ data.tar.gz: 073dfc6f68dabb86a4307a6dbf0a61a3238f6dea32256ac04432d174ea8acf6f
5
5
  SHA512:
6
- metadata.gz: 4f794b419f2503d453e08c60e49a0c39d21eb7fd096a658fc18fd159c2b13803e5259f7c0bcb69f1033e1f964d818789db9713ada5eeaecd624710af65806506
7
- data.tar.gz: 6746e8807b5da2ee77b9e48828db7cb7de5aea48553961be867143a5b09110ca59de3ff40f3a34fbaeb38df6b763d728f9727586cfd5bb2126982a6c22e85327
6
+ metadata.gz: abca7ef13599eae3e161b085ee97e334a3a665fd9a8de01ae0bbb3719cb9034edda857e6ad12c188936cd3b2e696811488b28505c6aa8edf6cff25aabda02959
7
+ data.tar.gz: e8d831b5884967165f4422472b6bce5510f76fd581173955536eadd871e851358f3017a851865cc64530b0ffa42b47c8bfe5549d709978e8ef6a54b270a2f30b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1 - 2026-08-11
4
+
5
+ - Expose each profile's immutable credential-environment key inventory so
6
+ orchestrators can isolate named subscription/session bindings without
7
+ embedding provider-specific compatibility tables.
8
+ - Expose each profile's configuration-directory override and home-relative
9
+ default so orchestrators can detect subscription-session aliases without
10
+ maintaining a second provider-specific table.
11
+ - Include Claude's ambient auth-token override in the isolation inventory so a
12
+ named subscription binding cannot be silently replaced by caller state.
13
+ - Preserve an optional immutable provider signal in observable results so a
14
+ trusted orchestrator can carry structured transport evidence without moving
15
+ provider-health classification into the compatibility package.
16
+
3
17
  ## 0.1.0 - 2026-07-26
4
18
 
5
19
  - Add immutable profiles for Claude Code, Codex CLI, Pi, and Grok CLI.
data/README.md CHANGED
@@ -1,13 +1,10 @@
1
1
  # Agent CLI Runtime
2
2
 
3
- `agent-cli-runtime` is a small Ruby library for tools that need to describe
4
- and inspect locally installed headless agent CLIs without owning an agent
5
- orchestration system.
6
-
7
- It ships immutable profiles for Claude Code, Codex CLI, Pi, and Grok CLI;
8
- compiles provider-neutral requests into argv/stdin; reports typed capability
9
- evidence; extracts usage from provider JSON events; and exposes an honest local
10
- diagnostic command.
3
+ `agent-cli-runtime` is a small Ruby library for tools that integrate with
4
+ locally installed headless agent CLIs. It ships immutable profiles for Claude
5
+ Code, Codex CLI, Pi, and Grok CLI and compiles provider-neutral requests into
6
+ argv/stdin. It also reports typed capability evidence, extracts usage from
7
+ provider JSON events, and exposes an honest local diagnostic command.
11
8
 
12
9
  ## Install
13
10
 
@@ -42,11 +39,11 @@ Compilation does not execute the returned command. Unsupported requested
42
39
  controls raise `AgentCliRuntime::UnsupportedCapability` with typed evidence
43
40
  instead of silently widening the request.
44
41
 
45
- `permission_mode: nil` deliberately preserves Hive's existing trusted,
46
- headless behavior: providers with a bypass flag receive that flag. Consumers
47
- that do not want this compatibility path should pass `"read-only"` or
48
- `"workspace-write"` explicitly. A profile raises instead of pretending to
49
- enforce a mode its CLI cannot represent.
42
+ `permission_mode: nil` selects the profile's default non-interactive permission
43
+ flags, which may include a provider's bypass flag. Pass `"read-only"` or
44
+ `"workspace-write"` explicitly when the integration requires that constraint.
45
+ A profile raises instead of pretending to enforce a mode its CLI cannot
46
+ represent.
50
47
 
51
48
  ## Public API
52
49
 
@@ -76,6 +73,9 @@ profile = AgentCliRuntime::Profile.new(
76
73
  min_version: "1.2.0",
77
74
  prompt_style: :stdin,
78
75
  read_only_flags: ["--sandbox", "read-only"],
76
+ credential_environment_keys: ["ACME_API_KEY", "ACME_OAUTH_TOKEN"],
77
+ configuration_environment_key: "ACME_HOME",
78
+ default_configuration_directory: ".acme",
79
79
  cli_capabilities: {
80
80
  safe_mode: ["--safe-mode"]
81
81
  },
@@ -100,9 +100,26 @@ AgentCliRuntime.compile(request)
100
100
  Custom capability names cannot shadow the standard capability vocabulary.
101
101
  Capability checks use discrete argv, inspect the installed CLI's help, and
102
102
  fail closed when a declared option is not advertised.
103
+ `credential_environment_keys` is an immutable compatibility inventory for
104
+ orchestrators that isolate a named CLI session; it contains variable names,
105
+ never their values.
106
+ `configuration_environment_key` and `default_configuration_directory` describe
107
+ where the CLI owns its subscription/session state. `configuration_directory`
108
+ resolves that location from a caller-supplied home and environment without
109
+ reading credentials or deciding authentication policy.
103
110
 
104
111
  ## Inspect local prerequisites
105
112
 
113
+ ```ruby
114
+ probe = AgentCliRuntime.probe(:codex)
115
+ probe.ready
116
+ probe.version
117
+ probe.auth_configuration.status
118
+
119
+ # Returns the ready probe or raises AgentCliRuntime::ProbeError.
120
+ AgentCliRuntime.prepare!(:codex)
121
+ ```
122
+
106
123
  ```sh
107
124
  agent-runtime probe codex
108
125
  agent-runtime probe --all --json
@@ -120,37 +137,48 @@ configuration presence, and declared capabilities. `configured` means a
120
137
  recognized local file or environment variable is present. It does not mean the
121
138
  credential is valid, the provider is online, or the account has quota.
122
139
 
123
- ## Scope and compatibility
124
-
125
- The library does not spawn or supervise agents, retry work, run workflows,
126
- accept artifacts, or interpret Hive state. Provider flags and event formats are
127
- SemVer-governed public behavior. Additive fields are compatible within 0.1.x;
128
- removing or changing an existing field or meaning requires a new minor version
129
- while the gem remains pre-1.0.
130
-
131
- Development remains in the Hive monorepo under
132
- `components/agent-cli-runtime`. Hive is the primary consumer and HiveBench is
133
- the first named external adopter. The Hive maintainer team owns compatibility,
134
- security response, and releases for the package.
140
+ ## Normalize provider output
135
141
 
136
- ## Development
137
-
138
- ```sh
139
- cd components/agent-cli-runtime
140
- bundle exec rake test
141
- gem build agent-cli-runtime.gemspec
142
+ ```ruby
143
+ usage = AgentCliRuntime.extract_usage(
144
+ :codex,
145
+ "type" => "turn.completed",
146
+ "usage" => {
147
+ "input_tokens" => 120,
148
+ "output_tokens" => 42
149
+ }
150
+ )
151
+ # => { input: 120, output: 42, cached: 0, model: nil }
152
+
153
+ result = AgentCliRuntime.observe(
154
+ :codex,
155
+ exit_code: 0,
156
+ timed_out: false,
157
+ status: :completed,
158
+ usage: usage,
159
+ final_message: "Review complete"
160
+ )
161
+ result.status # => :completed
162
+ result.usage # => the normalized usage hash
142
163
  ```
143
164
 
144
- The root suite includes these package tests plus Hive/package parity coverage;
145
- run `bundle exec rake test:agent_cli_runtime` from the repository root for the
146
- standalone component gate alone.
165
+ Malformed or unrelated events return `nil` from `extract_usage`; they do not
166
+ invent zero-token usage. `observe` returns a frozen
167
+ `AgentCliRuntime::ObservableResult` with bounded, redacted diagnostics. A
168
+ trusted caller may also supply an already-normalized `provider_signal`; the
169
+ runtime carries that optional immutable value but does not classify failures or
170
+ own provider-health policy.
171
+
172
+ ## Compatibility
147
173
 
148
- Release instructions live in the repository's `docs/RELEASING.md`. Releases
149
- use component-scoped tags and publish exact preverified gem bytes through
150
- RubyGems trusted publishing.
174
+ Provider flags, event formats, and public value-object fields are
175
+ SemVer-governed behavior. Additive fields are compatible within 0.1.x; removing
176
+ or changing an existing field or meaning requires a new minor version while the
177
+ gem remains pre-1.0.
151
178
 
152
179
  ## Security
153
180
 
154
181
  Diagnostics are bounded and redact common credential forms. The library never
155
182
  prints credential file contents or environment values. Report vulnerabilities
156
- through the Hive repository’s security policy.
183
+ privately through the
184
+ [package security policy](https://github.com/ivankuznetsov/agent-cli-runtime/security/policy).
@@ -12,19 +12,18 @@ Gem::Specification.new do |spec|
12
12
  result normalization for Claude Code, Codex CLI, Pi, and Grok CLI. It does
13
13
  not spawn agents or claim live provider health, quota, or credential validity.
14
14
  DESC
15
- spec.homepage = "https://github.com/ivankuznetsov/hive"
15
+ spec.homepage = "https://github.com/ivankuznetsov/agent-cli-runtime"
16
16
  spec.license = "MIT"
17
17
  spec.required_ruby_version = ">= 3.4.0"
18
18
 
19
19
  spec.metadata = {
20
20
  "homepage_uri" => spec.homepage,
21
- "source_code_uri" =>
22
- "https://github.com/ivankuznetsov/hive/tree/main/components/agent-cli-runtime",
21
+ "source_code_uri" => spec.homepage,
23
22
  "changelog_uri" =>
24
- "https://github.com/ivankuznetsov/hive/blob/main/components/agent-cli-runtime/CHANGELOG.md",
23
+ "#{spec.homepage}/blob/main/CHANGELOG.md",
25
24
  "bug_tracker_uri" => "https://github.com/ivankuznetsov/hive/issues",
26
25
  "documentation_uri" =>
27
- "https://github.com/ivankuznetsov/hive/blob/main/components/agent-cli-runtime/README.md",
26
+ "#{spec.homepage}/blob/main/README.md",
28
27
  "rubygems_mfa_required" => "true"
29
28
  }
30
29
 
@@ -25,7 +25,9 @@ module AgentCliRuntime
25
25
  :budget_flag, :output_format_flags, :version_flag,
26
26
  :min_version, :prompt_style, :model_argument_builder,
27
27
  :effort_argument_builder, :launcher_identity,
28
- :cli_capabilities, :declared_capability_support
28
+ :cli_capabilities, :declared_capability_support,
29
+ :credential_environment_keys, :configuration_environment_key,
30
+ :default_configuration_directory
29
31
 
30
32
  def initialize(name:, bin_default:, headless_flag:, version_flag:,
31
33
  env_bin_override_keys: [], permission_skip_flag: nil,
@@ -35,7 +37,9 @@ module AgentCliRuntime
35
37
  prompt_style: :positional, model_argument_builder: nil,
36
38
  effort_argument_builder: nil, launcher_identity: nil,
37
39
  usage_extractor: nil, auth_configuration_probe: nil,
38
- cli_capabilities: {}, raw_cli_arguments_supported: false)
40
+ cli_capabilities: {}, raw_cli_arguments_supported: false,
41
+ credential_environment_keys: [], configuration_environment_key: nil,
42
+ default_configuration_directory: nil)
39
43
  normalized_prompt_style = prompt_style.to_sym
40
44
  unless PROMPT_STYLES.include?(normalized_prompt_style)
41
45
  raise ArgumentError,
@@ -65,6 +69,15 @@ module AgentCliRuntime
65
69
  @auth_configuration_probe = auth_configuration_probe
66
70
  @cli_capabilities = normalize_cli_capabilities(cli_capabilities)
67
71
  @raw_cli_arguments_supported = raw_cli_arguments_supported == true
72
+ @credential_environment_keys = immutable_environment_keys(
73
+ credential_environment_keys
74
+ )
75
+ @configuration_environment_key = optional_environment_key(
76
+ configuration_environment_key
77
+ )
78
+ @default_configuration_directory = optional_relative_directory(
79
+ default_configuration_directory
80
+ )
68
81
  @declared_capability_support = build_declared_capability_support
69
82
  freeze
70
83
  end
@@ -200,6 +213,24 @@ module AgentCliRuntime
200
213
  nil
201
214
  end
202
215
 
216
+ def configuration_directory(home: nil, env: ENV)
217
+ if @configuration_environment_key
218
+ configured = env[@configuration_environment_key].to_s
219
+ unless configured.empty?
220
+ unless File.absolute_path?(configured)
221
+ raise ArgumentError,
222
+ "#{@configuration_environment_key} must be an absolute directory"
223
+ end
224
+ return File.expand_path(configured)
225
+ end
226
+ end
227
+ return nil unless @default_configuration_directory
228
+
229
+ base = home || env["HOME"]
230
+ base = Dir.home if base.to_s.empty?
231
+ File.expand_path(@default_configuration_directory, base)
232
+ end
233
+
203
234
  def require_cli_capability!(capability)
204
235
  capability_name = capability.to_sym
205
236
  flags = @cli_capabilities[capability_name]
@@ -229,6 +260,35 @@ module AgentCliRuntime
229
260
  Array(values).map { |value| immutable_string(value) }.freeze
230
261
  end
231
262
 
263
+ def immutable_environment_keys(values)
264
+ keys = immutable_strings(values)
265
+ invalid = keys.find { |key| !key.match?(/\A[A-Z][A-Z0-9_]*\z/) }
266
+ raise ArgumentError, "invalid credential environment key #{invalid.inspect}" if invalid
267
+ raise ArgumentError, "credential environment keys must be unique" if keys.uniq.length != keys.length
268
+
269
+ keys
270
+ end
271
+
272
+ def optional_environment_key(value)
273
+ return nil if value.nil?
274
+
275
+ key = immutable_string(value)
276
+ unless key.match?(/\A[A-Z][A-Z0-9_]*\z/)
277
+ raise ArgumentError, "invalid configuration environment key #{key.inspect}"
278
+ end
279
+ key
280
+ end
281
+
282
+ def optional_relative_directory(value)
283
+ return nil if value.nil?
284
+
285
+ path = immutable_string(value)
286
+ if path.empty? || File.absolute_path?(path)
287
+ raise ArgumentError, "default configuration directory must be relative"
288
+ end
289
+ path
290
+ end
291
+
232
292
  def normalize_tool_scope_flags(flags)
233
293
  unless flags.is_a?(Hash)
234
294
  raise ArgumentError, "tool_scope_flags must be a Hash"
@@ -1,5 +1,52 @@
1
1
  module AgentCliRuntime
2
2
  module Profiles
3
+ PI_CREDENTIAL_ENVIRONMENT_KEYS = %w[
4
+ AI_GATEWAY_API_KEY
5
+ ANTHROPIC_API_KEY
6
+ ANTHROPIC_AUTH_TOKEN
7
+ ANTHROPIC_OAUTH_TOKEN
8
+ ANT_LING_API_KEY
9
+ AWS_ACCESS_KEY_ID
10
+ AWS_BEARER_TOKEN_BEDROCK
11
+ AWS_CONTAINER_CREDENTIALS_FULL_URI
12
+ AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
13
+ AWS_PROFILE
14
+ AWS_SECRET_ACCESS_KEY
15
+ AWS_SESSION_TOKEN
16
+ AWS_WEB_IDENTITY_TOKEN_FILE
17
+ AZURE_OPENAI_API_KEY
18
+ BASETEN_API_KEY
19
+ CEREBRAS_API_KEY
20
+ CLOUDFLARE_API_KEY
21
+ COPILOT_GITHUB_TOKEN
22
+ DEEPSEEK_API_KEY
23
+ FIREWORKS_API_KEY
24
+ GEMINI_API_KEY
25
+ GOOGLE_APPLICATION_CREDENTIALS
26
+ GOOGLE_CLOUD_API_KEY
27
+ GROQ_API_KEY
28
+ HF_TOKEN
29
+ KIMI_API_KEY
30
+ MINIMAX_API_KEY
31
+ MINIMAX_CN_API_KEY
32
+ MISTRAL_API_KEY
33
+ MOONSHOT_API_KEY
34
+ NVIDIA_API_KEY
35
+ OPENCODE_API_KEY
36
+ OPENAI_API_KEY
37
+ OPENROUTER_API_KEY
38
+ QWEN_TOKEN_PLAN_API_KEY
39
+ RADIUS_API_KEY
40
+ TOGETHER_API_KEY
41
+ XAI_API_KEY
42
+ XIAOMI_API_KEY
43
+ XIAOMI_TOKEN_PLAN_AMS_API_KEY
44
+ XIAOMI_TOKEN_PLAN_CN_API_KEY
45
+ XIAOMI_TOKEN_PLAN_SGP_API_KEY
46
+ ZAI_API_KEY
47
+ ZAI_CODING_CN_API_KEY
48
+ ].freeze
49
+
3
50
  module_function
4
51
 
5
52
  def names
@@ -78,6 +125,11 @@ module AgentCliRuntime
78
125
  effort_argument_builder: ->(effort) { [ "--effort", effort ] },
79
126
  launcher_identity: "claude-code/v1",
80
127
  usage_extractor: UsageExtractors::CLAUDE,
128
+ credential_environment_keys: %w[
129
+ ANTHROPIC_API_KEY ANTHROPIC_AUTH_TOKEN CLAUDE_API_KEY
130
+ ],
131
+ configuration_environment_key: "CLAUDE_CONFIG_DIR",
132
+ default_configuration_directory: ".claude",
81
133
  raw_cli_arguments_supported: true,
82
134
  auth_configuration_probe: lambda do |home:, env:|
83
135
  if env_configured?(env, "ANTHROPIC_API_KEY")
@@ -117,6 +169,9 @@ module AgentCliRuntime
117
169
  ->(effort) { [ "-c", "model_reasoning_effort=#{effort}" ] },
118
170
  launcher_identity: "codex-cli/v1",
119
171
  usage_extractor: UsageExtractors::CODEX,
172
+ credential_environment_keys: %w[OPENAI_API_KEY],
173
+ configuration_environment_key: "CODEX_HOME",
174
+ default_configuration_directory: ".codex",
120
175
  auth_configuration_probe: lambda do |home:, env:|
121
176
  if env_configured?(env, "OPENAI_API_KEY")
122
177
  AuthConfiguration.new(status: :configured, source: "environment")
@@ -140,6 +195,9 @@ module AgentCliRuntime
140
195
  model_argument_builder: ->(model) { [ "--model", model ] },
141
196
  launcher_identity: "pi-coding-agent/v1",
142
197
  usage_extractor: UsageExtractors::PI,
198
+ credential_environment_keys: PI_CREDENTIAL_ENVIRONMENT_KEYS,
199
+ configuration_environment_key: "PI_CODING_AGENT_DIR",
200
+ default_configuration_directory: ".pi/agent",
143
201
  auth_configuration_probe: lambda do |home:, env:|
144
202
  directory = env["PI_CODING_AGENT_DIR"]
145
203
  path =
@@ -169,6 +227,9 @@ module AgentCliRuntime
169
227
  ->(effort) { [ "--reasoning-effort", effort ] },
170
228
  launcher_identity: "grok-cli/v1",
171
229
  usage_extractor: UsageExtractors::GROK,
230
+ credential_environment_keys: %w[GROK_AUTH_PATH XAI_API_KEY GROK_CODE_XAI_API_KEY],
231
+ configuration_environment_key: "GROK_HOME",
232
+ default_configuration_directory: ".grok",
172
233
  auth_configuration_probe: lambda do |home:, env:|
173
234
  if env_configured?(env, "XAI_API_KEY", "GROK_CODE_XAI_API_KEY")
174
235
  AuthConfiguration.new(status: :configured, source: "environment")
@@ -116,7 +116,8 @@ module AgentCliRuntime
116
116
  final_message: raw[:final_message],
117
117
  diagnostic: Redactor.diagnostic(
118
118
  raw[:error_message] || raw[:limit_text]
119
- )
119
+ ),
120
+ provider_signal: raw[:provider_signal]
120
121
  )
121
122
  end
122
123
 
@@ -154,10 +154,11 @@ module AgentCliRuntime
154
154
 
155
155
  ObservableResult = Data.define(
156
156
  :provider, :launcher_identity, :exit_code, :timed_out, :status,
157
- :usage, :final_message, :diagnostic
157
+ :usage, :final_message, :diagnostic, :provider_signal
158
158
  ) do
159
159
  def initialize(provider:, launcher_identity:, exit_code:, timed_out:,
160
- status:, usage:, final_message:, diagnostic:)
160
+ status:, usage:, final_message:, diagnostic:,
161
+ provider_signal: nil)
161
162
  super(
162
163
  provider: provider.to_sym,
163
164
  launcher_identity: Immutable.string(launcher_identity),
@@ -167,7 +168,8 @@ module AgentCliRuntime
167
168
  usage: usage&.dup&.freeze,
168
169
  final_message:
169
170
  final_message.nil? ? nil : Immutable.string(final_message),
170
- diagnostic: diagnostic.nil? ? nil : Immutable.string(diagnostic)
171
+ diagnostic: diagnostic.nil? ? nil : Immutable.string(diagnostic),
172
+ provider_signal: provider_signal&.dup&.freeze
171
173
  )
172
174
  end
173
175
  end
@@ -1,3 +1,3 @@
1
1
  module AgentCliRuntime
2
- VERSION = "0.1.0".freeze
2
+ VERSION = "0.1.1".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agent-cli-runtime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Kuznetsov
@@ -91,15 +91,15 @@ files:
91
91
  - lib/agent_cli_runtime/usage_extractors.rb
92
92
  - lib/agent_cli_runtime/values.rb
93
93
  - lib/agent_cli_runtime/version.rb
94
- homepage: https://github.com/ivankuznetsov/hive
94
+ homepage: https://github.com/ivankuznetsov/agent-cli-runtime
95
95
  licenses:
96
96
  - MIT
97
97
  metadata:
98
- homepage_uri: https://github.com/ivankuznetsov/hive
99
- source_code_uri: https://github.com/ivankuznetsov/hive/tree/main/components/agent-cli-runtime
100
- changelog_uri: https://github.com/ivankuznetsov/hive/blob/main/components/agent-cli-runtime/CHANGELOG.md
98
+ homepage_uri: https://github.com/ivankuznetsov/agent-cli-runtime
99
+ source_code_uri: https://github.com/ivankuznetsov/agent-cli-runtime
100
+ changelog_uri: https://github.com/ivankuznetsov/agent-cli-runtime/blob/main/CHANGELOG.md
101
101
  bug_tracker_uri: https://github.com/ivankuznetsov/hive/issues
102
- documentation_uri: https://github.com/ivankuznetsov/hive/blob/main/components/agent-cli-runtime/README.md
102
+ documentation_uri: https://github.com/ivankuznetsov/agent-cli-runtime/blob/main/README.md
103
103
  rubygems_mfa_required: 'true'
104
104
  rdoc_options: []
105
105
  require_paths: