ask-computer 0.1.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.
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: computer.use_computer
3
+ description: Drive desktop apps in the background via Cua Driver and query encrypted Computer History — screenshots, clicks, typing, sandboxed VMs, and prior-run context
4
+ ---
5
+
6
+ Use this skill when you need to automate desktop applications, inspect screen state, or resume prior work using Computer History.
7
+
8
+ ## Prerequisites
9
+
10
+ Cua Driver must be installed. If `Ask::Computer.driver.start` fails, tell the user how to install it:
11
+
12
+ ```bash
13
+ /bin/bash -c "$(curl -fsSL https://cua.ai/driver/install.sh)"
14
+ # then follow post-install instructions at https://cua.ai/docs/tutorials/drive-your-first-app
15
+ ```
16
+
17
+ For Computer History (prior-run context), the daemon must be a nightly build with the preview admitted and history enabled:
18
+
19
+ ```bash
20
+ cua-driver history enable
21
+ cua-driver history status
22
+ ```
23
+
24
+ All history access is permission-gated and metadata-only. Never assume history is available.
25
+
26
+ ## Step 1: Discover and Check History
27
+
28
+ Before broader desktop inspection, check whether history is available — but only when the user asks to continue, resume, recall recent activity, or explain what a prior Cua run did. Do not query history for unrelated tasks.
29
+
30
+ ```ruby
31
+ require "ask-computer"
32
+
33
+ driver = Ask::Computer.driver
34
+ driver.start
35
+
36
+ history = Ask::Computer.history
37
+ status = history.status
38
+
39
+ # status fields: supported, admitted, enabled, paused, encrypted, profile,
40
+ # retention_days, quota_bytes, bytes_used, dropped_events, health
41
+ # health values: ready, disabled, paused, not_admitted, key_locked, key_unavailable,
42
+ # storage_corrupt, quota_reached, events_dropped, writer_stopped
43
+
44
+ if status.enabled? && status.healthy?
45
+ result = history.recent(limit: 20)
46
+ # result.events => Array<Ask::Computer::Event> (CloudEvents 1.0, see references/history.md)
47
+ # result.metadata_only? => true (always — no screenshots or typed text)
48
+ else
49
+ # Continue without history. Preserve the reason (disabled/paused/unhealthy) in reasoning.
50
+ end
51
+ ```
52
+
53
+ If `history_status` or `history_query` is not advertised, or permission is denied, continue without history. Do not retry with a broader tool, read files directly, or ask the model to reconstruct history.
54
+
55
+ ## Step 2: Drive the Desktop
56
+
57
+ Use the computer tools to observe and act. Always verify state changes with a screenshot after acting.
58
+
59
+ ```ruby
60
+ # Observe
61
+ sandbox = Ask::Computer.sandbox
62
+ image = sandbox.screenshot # or driver.call_tool("computer_screenshot", {})
63
+
64
+ # Act (background — does not steal cursor or focus)
65
+ driver.call_tool("computer_click", { x: 120, y: 80 })
66
+ driver.call_tool("computer_type", { text: "Hello" })
67
+ driver.call_tool("computer_key", { key: "Enter" })
68
+
69
+ # Or via Ask::Tool subclasses (for agent sessions)
70
+ # Ask::Tools::Computer::Screenshot, Click, Type, Key, HistoryStatus, HistoryQuery
71
+ ```
72
+
73
+ Prefer accessibility-aware targeting when available over raw coordinates. After each state-changing action, re-screenshot to confirm the change.
74
+
75
+ ## Step 3: Query History with Bounded Reads
76
+
77
+ Events are ordered by `data.sequence` ascending. Treat missing sequence numbers as gap evidence. Paginate toward older records with `until_sequence`; toward newer with `since_sequence`. Bounds are inclusive — subtract/add 1 for non-overlapping pages.
78
+
79
+ ```ruby
80
+ # Filtered query
81
+ history.query(limit: 20, session_id: "abc", since_sequence: 40, until_sequence: 100)
82
+
83
+ # Paginate through all recent history (newest-first, bounded pages)
84
+ history.each_page(limit: 50) do |page|
85
+ page.events.each { |e| puts "#{e.type} seq=#{e.data[:sequence]}" }
86
+ end
87
+
88
+ # Ergonomic: maps RFC error codes to typed errors
89
+ # HistoryNotAdmitted, HistoryKeyLocked, HistoryStorageCorrupt, InvalidHistoryQuery, etc.
90
+ ```
91
+
92
+ Handle health warnings explicitly:
93
+
94
+ - `dropped_events > 0` or `health == "events_dropped"` → treat interval as incomplete.
95
+ - `health == "quota_reached"` → history after that point is incomplete.
96
+ - `health == "storage_corrupt"` → stop querying; direct user to `cua-driver history delete --yes` if they accept data loss.
97
+ - `health == "key_locked"` → user must unlock Keychain/Credential Manager; do not prompt via another tool.
98
+
99
+ ## Step 4: Use History as a Lead, Not a Transcript
100
+
101
+ Returned events contain only: time, sequence, session/action IDs, capability, optional `application` (`bundle_id`, `display_name`), outcome/route/delivery/evidence categories. They never contain screenshots, typed text, clipboard, tool args/results, window titles, or URLs.
102
+
103
+ Treat events as hints. Use an identified `application` or `capability` to locate the app, then verify live state (screenshot, accessibility tree) before acting. Never treat history as a complete transcript.
104
+
105
+ ## Sandbox VMs (Optional)
106
+
107
+ For isolated or parallel runs, use sandboxed VMs:
108
+
109
+ ```ruby
110
+ sandbox = Ask::Computer.sandbox
111
+
112
+ sandbox.ephemeral(:linux) do |vm|
113
+ vm.shell("echo hello")
114
+ vm.screenshot
115
+ vm.click(100, 200)
116
+ vm.type("Hello from sandbox")
117
+ end
118
+ # vm.destroy is called automatically on block exit
119
+ ```
120
+
121
+ Requires a driver that advertises `sandbox_create` / `sandbox_*` tools. Degrade gracefully when unavailable.
@@ -0,0 +1,80 @@
1
+ # Computer History Reference
2
+
3
+ Detailed schema for `Ask::Computer::History` responses. The live contract is the Cua RFC; this file is a local summary so the skill stays compact.
4
+
5
+ ## Status Response
6
+
7
+ ```
8
+ {
9
+ supported: bool, admitted: bool, enabled: bool, paused: bool,
10
+ encrypted: bool, profile: String, retention_days: int (default 7),
11
+ quota_bytes: int (default 104857600), bytes_used: int,
12
+ dropped_events: int, health: String
13
+ }
14
+ ```
15
+
16
+ Health values:
17
+
18
+ | health | meaning |
19
+ |---|---|
20
+ | ready | Healthy |
21
+ | disabled | Capture off |
22
+ | paused | Capture paused, history still queryable |
23
+ | not_admitted | Daemon not started with preview flag |
24
+ | key_unavailable / key_locked / key_corrupt / key_destroy_failed | Credential store issue |
25
+ | storage_unavailable / storage_corrupt | Encrypted store unreadable |
26
+ | quota_reached | Store at quota, new events may be incomplete |
27
+ | events_dropped | Nonblocking writer dropped events |
28
+ | writer_stopped | Writer unavailable |
29
+
30
+ ## Event (CloudEvents 1.0, dataschema urn:cua-driver:schema:history-event:v0)
31
+
32
+ Each `history_query` event:
33
+
34
+ ```
35
+ {
36
+ specversion, id, source, type, subject, time, datacontenttype, dataschema,
37
+ data: {
38
+ session_id, action_id, sequence, platform, process_model, capability,
39
+ caller_category,
40
+ application?: { bundle_id?, display_name? },
41
+ payload: { kind, effect?, route?, delivery?, delivered_count?, evidence_kinds?[] }
42
+ }
43
+ }
44
+ ```
45
+
46
+ ### Event Types
47
+
48
+ | type | payload kind |
49
+ |---|---|
50
+ | cua-driver.history.control.v0 | control |
51
+ | cua-driver.history.action_started.v0 | action_started |
52
+ | cua-driver.history.action_completed.v0 | action_completed |
53
+ | cua-driver.history.session_started.v0 | session |
54
+ | cua-driver.history.session_ended.v0 | session |
55
+ | cua-driver.history.access.v0 | access |
56
+ | cua-driver.history.health.v0 | health |
57
+
58
+ Ordering: `data.sequence` ascending. `limit` keeps newest N then returns them ascending. No pagination token — page with `since_sequence` / `until_sequence` (inclusive).
59
+
60
+ ## Error Codes
61
+
62
+ Tool failures map to typed errors via `Ask::Computer::Error.from_code`:
63
+
64
+ - `invalid_history_query` / `invalid_history_query_range` → `InvalidHistoryQuery*`
65
+ - `history_preview_not_admitted` → `HistoryNotAdmitted`
66
+ - `history_key_*` → `HistoryKey*`
67
+ - `history_storage_*` → `HistoryStorage*`
68
+ - `history_quota_reached` → `HistoryQuotaReached`
69
+ - `history_writer_stopped` → `HistoryWriterStopped`
70
+ - `history_events_dropped` → `HistoryEventsDropped`
71
+
72
+ Permission denials surface as `Ask::Computer::PermissionDenied` (do not retry with a broader tool).
73
+
74
+ ## Storage Profile
75
+
76
+ CBOR Sequence of COSE_Encrypt0, CloudEvents JSON inside, ChaCha20-Poly1305, HKDF per chunk, root key in platform credential store (Keychain / Credential Manager / Secret Service). No plaintext fallback.
77
+
78
+ For full spec see:
79
+ - https://github.com/trycua/cua/blob/main/libs/cua-driver/docs/computer-history-preview.md
80
+ - https://github.com/trycua/cua/blob/main/libs/cua-driver/docs/computer-history-agent-integration-rfc.md
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ask/tools"
4
+
5
+ module Ask
6
+ module Tools
7
+ module Computer
8
+ class Click < Ask::Tool
9
+ description "Click at screen coordinates via Cua Driver. Background click — does not steal cursor."
10
+
11
+ param :x, type: :integer, desc: "X coordinate in screen pixels", required: true
12
+ param :y, type: :integer, desc: "Y coordinate in screen pixels", required: true
13
+ param :button, type: :string, desc: "Mouse button: left, right, middle", required: false
14
+
15
+ def execute(x:, y:, button: "left")
16
+ driver = Ask::Computer.driver
17
+ result = driver.call_tool("computer_click", { x: Integer(x), y: Integer(y), button: button.to_s })
18
+ Ask::Result.ok(data: result)
19
+ rescue Ask::Computer::Error => e
20
+ Ask::Result.error(message: e.message, metadata: { error_class: e.class.name })
21
+ rescue ArgumentError => e
22
+ Ask::Result.error(message: e.message)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ask/tools"
4
+
5
+ module Ask
6
+ module Tools
7
+ module Computer
8
+ class HistoryQuery < Ask::Tool
9
+ description "Query encrypted Computer History for a bounded slice of metadata-only events. " \
10
+ "Returns at most 200 events ordered by sequence. Requires history.query capability. " \
11
+ "Check history_status first. Results are metadata-only — no screenshots or typed text."
12
+
13
+ param :limit, type: :integer, desc: "Max events to return (1..200, default 50)", required: false
14
+ param :session_id, type: :string, desc: "Opaque session ID filter (1..128 chars)", required: false
15
+ param :since_sequence, type: :integer, desc: "Inclusive lower sequence bound (>=1)", required: false
16
+ param :until_sequence, type: :integer, desc: "Inclusive upper sequence bound (>=1)", required: false
17
+
18
+ def execute(limit: 50, session_id: nil, since_sequence: nil, until_sequence: nil)
19
+ history = Ask::Computer.history
20
+ result = history.query(
21
+ limit: limit,
22
+ session_id: session_id,
23
+ since_sequence: since_sequence,
24
+ until_sequence: until_sequence
25
+ )
26
+
27
+ Ask::Result.ok(data: {
28
+ events: result.events.map { |e| serialize_event(e) },
29
+ metadata_only: result.metadata_only,
30
+ model_context_disclosure: result.model_context_disclosure
31
+ })
32
+ rescue Ask::Computer::InvalidHistoryQuery, Ask::Computer::InvalidHistoryQueryRange => e
33
+ Ask::Result.error(message: e.message, metadata: { error_class: e.class.name, code: e.class.name })
34
+ rescue Ask::Computer::Error => e
35
+ Ask::Result.error(message: e.message, metadata: { error_class: e.class.name })
36
+ end
37
+
38
+ private
39
+
40
+ def serialize_event(event)
41
+ {
42
+ specversion: event.specversion,
43
+ id: event.id,
44
+ source: event.source,
45
+ type: event.type,
46
+ subject: event.subject,
47
+ time: event.time,
48
+ datacontenttype: event.datacontenttype,
49
+ dataschema: event.dataschema,
50
+ data: event.data
51
+ }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ask/tools"
4
+
5
+ module Ask
6
+ module Tools
7
+ module Computer
8
+ class HistoryStatus < Ask::Tool
9
+ description "Check Cua Computer History status — whether capture is enabled, " \
10
+ "paused, healthy, and how much encrypted storage is used. " \
11
+ "Call this before history_query."
12
+
13
+ def execute
14
+ history = Ask::Computer.history
15
+ status = history.status
16
+
17
+ Ask::Result.ok(data: {
18
+ supported: status.supported,
19
+ admitted: status.admitted,
20
+ enabled: status.enabled,
21
+ paused: status.paused,
22
+ encrypted: status.encrypted,
23
+ profile: status.profile,
24
+ retention_days: status.retention_days,
25
+ quota_bytes: status.quota_bytes,
26
+ bytes_used: status.bytes_used,
27
+ dropped_events: status.dropped_events,
28
+ health: status.health
29
+ })
30
+ rescue Ask::Computer::Error => e
31
+ Ask::Result.error(message: e.message, metadata: { error_class: e.class.name })
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ask/tools"
4
+
5
+ module Ask
6
+ module Tools
7
+ module Computer
8
+ class InstallerSetup < Ask::Tool
9
+ description "Install Cua Driver (if missing) and optionally enable Computer History. " \
10
+ "Use dry_run: true to preview the shell command without executing it. " \
11
+ "Channel is stable or nightly."
12
+
13
+ param :channel, type: :string, desc: "stable or nightly", required: false
14
+ param :enable_history, type: :boolean, desc: "Enable Computer History after install", required: false
15
+ param :dry_run, type: :boolean, desc: "Preview only, do not run installer", required: false
16
+
17
+ def execute(channel: "stable", enable_history: false, dry_run: false)
18
+ steps = Ask::Computer::Installer.setup(
19
+ channel: channel,
20
+ enable_history: enable_history,
21
+ dry_run: dry_run
22
+ )
23
+ Ask::Result.ok(data: {
24
+ steps: steps.map { |name, r| { name: name.to_s, ok: r.ok?, message: r.message, command: r.command } }
25
+ })
26
+ rescue StandardError => e
27
+ Ask::Result.error(message: e.message, metadata: { error_class: e.class.name })
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ask/tools"
4
+
5
+ module Ask
6
+ module Tools
7
+ module Computer
8
+ class InstallerStatus < Ask::Tool
9
+ description "Check whether Cua Driver is installed and report its version and " \
10
+ "Computer History health. Read-only, safe to call without the daemon."
11
+
12
+ def execute
13
+ s = Ask::Computer::Installer.status
14
+ Ask::Result.ok(data: {
15
+ installed: s[:installed],
16
+ version: s[:version],
17
+ bin: s[:bin],
18
+ history: s[:history]
19
+ })
20
+ rescue StandardError => e
21
+ Ask::Result.error(message: e.message, metadata: { error_class: e.class.name })
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ask/tools"
4
+
5
+ module Ask
6
+ module Tools
7
+ module Computer
8
+ class Key < Ask::Tool
9
+ description "Press a key or key combination via Cua Driver (e.g. Enter, Tab, Control+C)."
10
+
11
+ param :key, type: :string, desc: "Key or combination to press", required: true
12
+
13
+ def execute(key:)
14
+ driver = Ask::Computer.driver
15
+ result = driver.call_tool("computer_key", { key: key.to_s })
16
+ Ask::Result.ok(data: result)
17
+ rescue Ask::Computer::Error => e
18
+ Ask::Result.error(message: e.message, metadata: { error_class: e.class.name })
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ask/tools"
4
+
5
+ module Ask
6
+ module Tools
7
+ module Computer
8
+ class Screenshot < Ask::Tool
9
+ description "Capture a screenshot of the current desktop via Cua Driver. " \
10
+ "Returns an image that vision models can analyze."
11
+
12
+ def execute
13
+ sandbox = Ask::Computer.sandbox
14
+ image = sandbox.screenshot
15
+ Ask::Result.ok(data: image)
16
+ rescue Ask::Computer::Error => e
17
+ Ask::Result.error(message: e.message, metadata: { error_class: e.class.name })
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ask/tools"
4
+
5
+ module Ask
6
+ module Tools
7
+ module Computer
8
+ class Type < Ask::Tool
9
+ description "Type text via Cua Driver. Sends keystrokes in the background."
10
+
11
+ param :text, type: :string, desc: "Text to type", required: true
12
+
13
+ def execute(text:)
14
+ driver = Ask::Computer.driver
15
+ result = driver.call_tool("computer_type", { text: text.to_s })
16
+ Ask::Result.ok(data: result)
17
+ rescue Ask::Computer::Error => e
18
+ Ask::Result.error(message: e.message, metadata: { error_class: e.class.name })
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ask"
4
+ require "ask/tools"
5
+ require_relative "ask/computer/version"
6
+ require_relative "ask/computer/errors"
7
+ require_relative "ask/computer/config"
8
+ require_relative "ask/computer/context"
9
+ require_relative "ask/computer"
10
+ require_relative "ask/computer/driver"
11
+ require_relative "ask/computer/app"
12
+ require_relative "ask/computer/history"
13
+ require_relative "ask/computer/sandbox"
14
+ require_relative "ask/computer/installer"
15
+ require_relative "ask/computer/cli"
16
+ require_relative "ask/tools/computer/history_status"
17
+ require_relative "ask/tools/computer/history_query"
18
+ require_relative "ask/tools/computer/screenshot"
19
+ require_relative "ask/tools/computer/click"
20
+ require_relative "ask/tools/computer/type"
21
+ require_relative "ask/tools/computer/key"
22
+ require_relative "ask/tools/computer/installer_status"
23
+ require_relative "ask/tools/computer/installer_setup"
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ask-computer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kaka Ruto
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ask-core
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 0.11.3
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 0.11.3
26
+ - !ruby/object:Gem::Dependency
27
+ name: ask-mcp
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.4.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 0.4.0
40
+ - !ruby/object:Gem::Dependency
41
+ name: ask-tools
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.6.2
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.6.2
54
+ - !ruby/object:Gem::Dependency
55
+ name: minitest
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '5.25'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '5.25'
68
+ - !ruby/object:Gem::Dependency
69
+ name: mocha
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.1'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.1'
82
+ - !ruby/object:Gem::Dependency
83
+ name: rake
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '13.0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '13.0'
96
+ description: Drive desktop apps in the background via Cua Driver — screenshots, clicks,
97
+ typing, sandboxed VMs, and encrypted Computer History. Wraps Cua's MCP tools as
98
+ Ask::Tool subclasses and ships a bundled computer.use_computer skill.
99
+ email:
100
+ - kaka@myrrlabs.com
101
+ executables:
102
+ - ask-computer
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - CHANGELOG.md
107
+ - LICENSE
108
+ - README.md
109
+ - exe/ask-computer
110
+ - lib/ask-computer.rb
111
+ - lib/ask/computer.rb
112
+ - lib/ask/computer/app.rb
113
+ - lib/ask/computer/cli.rb
114
+ - lib/ask/computer/config.rb
115
+ - lib/ask/computer/context.rb
116
+ - lib/ask/computer/driver.rb
117
+ - lib/ask/computer/errors.rb
118
+ - lib/ask/computer/history.rb
119
+ - lib/ask/computer/installer.rb
120
+ - lib/ask/computer/sandbox.rb
121
+ - lib/ask/computer/version.rb
122
+ - lib/ask/skills/computer.use_computer/SKILL.md
123
+ - lib/ask/skills/computer.use_computer/references/history.md
124
+ - lib/ask/tools/computer/click.rb
125
+ - lib/ask/tools/computer/history_query.rb
126
+ - lib/ask/tools/computer/history_status.rb
127
+ - lib/ask/tools/computer/installer_setup.rb
128
+ - lib/ask/tools/computer/installer_status.rb
129
+ - lib/ask/tools/computer/key.rb
130
+ - lib/ask/tools/computer/screenshot.rb
131
+ - lib/ask/tools/computer/type.rb
132
+ homepage: https://github.com/ask-rb/ask-computer
133
+ licenses:
134
+ - MIT
135
+ metadata:
136
+ homepage_uri: https://github.com/ask-rb/ask-computer
137
+ source_code_uri: https://github.com/ask-rb/ask-computer
138
+ changelog_uri: https://github.com/ask-rb/ask-computer/blob/main/CHANGELOG.md
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '3.2'
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubygems_version: 4.0.18
154
+ specification_version: 4
155
+ summary: Computer use for the ask-rb ecosystem
156
+ test_files: []