claude-inbox 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 +4 -4
- data/README.md +160 -152
- data/exe/claude-inbox +23 -4
- data/lib/claude_inbox/agents_client.rb +57 -55
- data/lib/claude_inbox/app.rb +42 -26
- data/lib/claude_inbox/config.rb +24 -0
- data/lib/claude_inbox/dialog.rb +3 -1
- data/lib/claude_inbox/images.rb +37 -6
- data/lib/claude_inbox/job_state.rb +23 -8
- data/lib/claude_inbox/keymap.rb +1 -1
- data/lib/claude_inbox/new_session_form.rb +29 -39
- data/lib/claude_inbox/painter.rb +32 -0
- data/lib/claude_inbox/palette.rb +4 -7
- data/lib/claude_inbox/peek.rb +2 -2
- data/lib/claude_inbox/poller.rb +4 -3
- data/lib/claude_inbox/pull_requests.rb +5 -5
- data/lib/claude_inbox/records.rb +7 -2
- data/lib/claude_inbox/remote/http.rb +137 -0
- data/lib/claude_inbox/remote/icon.png +0 -0
- data/lib/claude_inbox/remote/icon.svg +8 -0
- data/lib/claude_inbox/remote/listener.rb +436 -0
- data/lib/claude_inbox/remote/page.html +477 -0
- data/lib/claude_inbox/remote/pairing.rb +111 -0
- data/lib/claude_inbox/remote/pairing_dialog.rb +93 -0
- data/lib/claude_inbox/remote/start.rb +202 -0
- data/lib/claude_inbox/remote.rb +10 -0
- data/lib/claude_inbox/renderer.rb +57 -57
- data/lib/claude_inbox/session.rb +7 -21
- data/lib/claude_inbox/session_request.rb +151 -0
- data/lib/claude_inbox/sessions.rb +0 -1
- data/lib/claude_inbox/settings.rb +19 -7
- data/lib/claude_inbox/store.rb +0 -2
- data/lib/claude_inbox/subprocess.rb +9 -1
- data/lib/claude_inbox/terminal.rb +9 -3
- data/lib/claude_inbox/text.rb +7 -1
- data/lib/claude_inbox/trust.rb +23 -0
- data/lib/claude_inbox/vt_screen.rb +1 -1
- data/lib/claude_inbox.rb +1 -1
- metadata +14 -1
|
@@ -7,21 +7,33 @@ module ClaudeInbox
|
|
|
7
7
|
# settings files it reads, most specific wins. Values are strings, or
|
|
8
8
|
# nil when nothing sets them — then the CLI decides at launch.
|
|
9
9
|
module Settings
|
|
10
|
-
Defaults = Struct.new(:model, :effort, :permission_mode)
|
|
10
|
+
Defaults = Struct.new(:model, :effort, :permission_mode, :remote)
|
|
11
11
|
|
|
12
12
|
def self.defaults(cwd, home: Dir.home)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
].map { |path| read(path) }
|
|
13
|
+
user = read(File.join(home, ".claude", "settings.json"))
|
|
14
|
+
project = read(File.join(cwd, ".claude", "settings.json"))
|
|
15
|
+
local = read(File.join(cwd, ".claude", "settings.local.json"))
|
|
16
|
+
layers = [user, project, local]
|
|
18
17
|
Defaults.new(
|
|
19
18
|
model: pick(layers, "model"),
|
|
20
19
|
effort: pick(layers, "effortLevel"),
|
|
21
|
-
permission_mode: pick(layers, "permissions", "defaultMode")
|
|
20
|
+
permission_mode: pick(layers, "permissions", "defaultMode"),
|
|
21
|
+
remote: remote_control(user, project, local, read(File.join(home, ".claude.json")))
|
|
22
22
|
)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
# "Enable Remote Control for all sessions" in /config. The CLI lets a
|
|
26
|
+
# repo turn it off but only user scope turn it on, and still honours the
|
|
27
|
+
# copy older versions kept in ~/.claude.json.
|
|
28
|
+
def self.remote_control(user, project, local, legacy)
|
|
29
|
+
return "no" if project["remoteControlAtStartup"] == false || local["remoteControlAtStartup"] == false
|
|
30
|
+
[user, legacy].each do |h|
|
|
31
|
+
v = h["remoteControlAtStartup"]
|
|
32
|
+
return v ? "yes" : "no" if [true, false].include?(v)
|
|
33
|
+
end
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
|
|
25
37
|
def self.read(path)
|
|
26
38
|
JSON.parse(File.read(path))
|
|
27
39
|
rescue Errno::ENOENT, Errno::EACCES, JSON::ParserError
|
data/lib/claude_inbox/store.rb
CHANGED
|
@@ -10,8 +10,16 @@ module ClaudeInbox
|
|
|
10
10
|
def success? = status.success?
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
# Children start in the environment from before Bundler, or every ruby a
|
|
14
|
+
# session runs, in any project, loads our Gemfile. Handed to exec rather
|
|
15
|
+
# than set on ENV, which the poll and background threads share.
|
|
16
|
+
CHILD_ENV = defined?(Bundler.unbundled_env) ? Bundler.unbundled_env.freeze : nil
|
|
17
|
+
|
|
13
18
|
module_function
|
|
14
19
|
|
|
20
|
+
# argv as exec and Process.spawn take it, with CHILD_ENV in place of ours.
|
|
21
|
+
def command(*argv) = CHILD_ENV ? [CHILD_ENV, *argv, {unsetenv_others: true}] : argv
|
|
22
|
+
|
|
15
23
|
def capture(*argv, chdir: nil)
|
|
16
24
|
out_r, out_w = IO.pipe
|
|
17
25
|
err_r, err_w = IO.pipe
|
|
@@ -23,7 +31,7 @@ module ClaudeInbox
|
|
|
23
31
|
out_r.close
|
|
24
32
|
err_r.close
|
|
25
33
|
Dir.chdir(chdir) if chdir
|
|
26
|
-
exec(*argv)
|
|
34
|
+
exec(*command(*argv))
|
|
27
35
|
rescue SystemCallError => e
|
|
28
36
|
$stderr.write(e.message)
|
|
29
37
|
exit! 127
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require "io/console"
|
|
4
4
|
require "tty-cursor"
|
|
5
5
|
require "tty-screen"
|
|
6
|
-
require_relative "
|
|
6
|
+
require_relative "painter"
|
|
7
7
|
|
|
8
8
|
module ClaudeInbox
|
|
9
9
|
# The screen the inbox draws on: the alt screen and the mouse and wheel
|
|
@@ -40,10 +40,16 @@ module ClaudeInbox
|
|
|
40
40
|
@size = nil
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
# The tty's mode is kept as found, not assumed: `cooked!` sets a stock
|
|
44
|
+
# mode that differs from a shell's (istrip on, imaxbel off), and the
|
|
45
|
+
# shell inherits whatever is left on quit.
|
|
43
46
|
def enter
|
|
44
47
|
@out.print ALT_ON, WHEEL_KEYS_ON, MOUSE_ON, PASTE_ON, TTY::Cursor.hide, TTY::Cursor.clear_screen
|
|
45
48
|
@out.flush
|
|
46
|
-
|
|
49
|
+
if @input.respond_to?(:raw!) && @input.tty?
|
|
50
|
+
@mode = @input.console_mode
|
|
51
|
+
@input.raw!
|
|
52
|
+
end
|
|
47
53
|
@restored = false
|
|
48
54
|
resized
|
|
49
55
|
end
|
|
@@ -52,7 +58,7 @@ module ClaudeInbox
|
|
|
52
58
|
def restore
|
|
53
59
|
return if @restored
|
|
54
60
|
@restored = true
|
|
55
|
-
@input.
|
|
61
|
+
@input.console_mode = @mode if @mode && @input.tty?
|
|
56
62
|
@out.print TTY::Cursor.show, PASTE_OFF, MOUSE_OFF, WHEEL_KEYS_OFF, ALT_OFF
|
|
57
63
|
@out.flush
|
|
58
64
|
rescue
|
data/lib/claude_inbox/text.rb
CHANGED
|
@@ -13,6 +13,12 @@ module ClaudeInbox
|
|
|
13
13
|
|
|
14
14
|
def strip_ansi(s) = s.gsub(ANSI, "")
|
|
15
15
|
|
|
16
|
+
# Control characters as \xNN, so quoted text can't reach the terminal
|
|
17
|
+
# as an escape. Bytes that aren't UTF-8 become U+FFFD.
|
|
18
|
+
def printable(s)
|
|
19
|
+
String.new(s.to_s, encoding: Encoding::UTF_8).scrub("\uFFFD").gsub(/[[:cntrl:]]/) { |c| format("\\x%02x", c.ord) }
|
|
20
|
+
end
|
|
21
|
+
|
|
16
22
|
def width(s) = Unicode::DisplayWidth.of(strip_ansi(s))
|
|
17
23
|
|
|
18
24
|
# Truncate plain (uncolored) text to `w` columns, appending an ellipsis
|
|
@@ -57,7 +63,7 @@ module ClaudeInbox
|
|
|
57
63
|
s = truncate(strip_ansi(s), w)
|
|
58
64
|
cur = width(s)
|
|
59
65
|
end
|
|
60
|
-
s + (" " *
|
|
66
|
+
s + (" " * [w - cur, 0].max)
|
|
61
67
|
end
|
|
62
68
|
|
|
63
69
|
# Greedy word wrap on display width. Words wider than `w` are split.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module ClaudeInbox
|
|
6
|
+
# The directories whose trust dialog has been accepted, read from where
|
|
7
|
+
# the CLI keeps the answer (see docs/cli-quirks.md). For choosing which
|
|
8
|
+
# directories to offer and in what order, never as a gate: whether a
|
|
9
|
+
# session may start somewhere stays the CLI's call.
|
|
10
|
+
module Trust
|
|
11
|
+
def self.projects(path: File.join(Dir.home, ".claude.json"))
|
|
12
|
+
data = JSON.parse(File.read(path))
|
|
13
|
+
projects = data["projects"] if data.is_a?(Hash)
|
|
14
|
+
return [] unless projects.is_a?(Hash)
|
|
15
|
+
projects.filter_map do |dir, entry|
|
|
16
|
+
dir if dir.start_with?("/") && !dir.include?("\0") &&
|
|
17
|
+
entry.is_a?(Hash) && entry["hasTrustDialogAccepted"] == true
|
|
18
|
+
end
|
|
19
|
+
rescue SystemCallError, IOError, JSON::ParserError
|
|
20
|
+
[]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -90,7 +90,7 @@ module ClaudeInbox
|
|
|
90
90
|
n = nums[0] || 1
|
|
91
91
|
case final
|
|
92
92
|
when "H", "f"
|
|
93
|
-
@row = (
|
|
93
|
+
@row = (n - 1).clamp(0, @rows - 1)
|
|
94
94
|
@col = ((nums[1] || 1) - 1).clamp(0, @cols - 1)
|
|
95
95
|
when "A" then @row = [@row - n, 0].max
|
|
96
96
|
when "B" then @row = [@row + n, @rows - 1].min
|
data/lib/claude_inbox.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: claude-inbox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jordan Byron
|
|
@@ -107,6 +107,7 @@ files:
|
|
|
107
107
|
- lib/claude_inbox.rb
|
|
108
108
|
- lib/claude_inbox/agents_client.rb
|
|
109
109
|
- lib/claude_inbox/app.rb
|
|
110
|
+
- lib/claude_inbox/config.rb
|
|
110
111
|
- lib/claude_inbox/debug.rb
|
|
111
112
|
- lib/claude_inbox/dialog.rb
|
|
112
113
|
- lib/claude_inbox/images.rb
|
|
@@ -115,6 +116,7 @@ files:
|
|
|
115
116
|
- lib/claude_inbox/logs.rb
|
|
116
117
|
- lib/claude_inbox/mouse.rb
|
|
117
118
|
- lib/claude_inbox/new_session_form.rb
|
|
119
|
+
- lib/claude_inbox/painter.rb
|
|
118
120
|
- lib/claude_inbox/palette.rb
|
|
119
121
|
- lib/claude_inbox/paste.rb
|
|
120
122
|
- lib/claude_inbox/peek.rb
|
|
@@ -123,8 +125,18 @@ files:
|
|
|
123
125
|
- lib/claude_inbox/rate_limits.rb
|
|
124
126
|
- lib/claude_inbox/reaper.rb
|
|
125
127
|
- lib/claude_inbox/records.rb
|
|
128
|
+
- lib/claude_inbox/remote.rb
|
|
129
|
+
- lib/claude_inbox/remote/http.rb
|
|
130
|
+
- lib/claude_inbox/remote/icon.png
|
|
131
|
+
- lib/claude_inbox/remote/icon.svg
|
|
132
|
+
- lib/claude_inbox/remote/listener.rb
|
|
133
|
+
- lib/claude_inbox/remote/page.html
|
|
134
|
+
- lib/claude_inbox/remote/pairing.rb
|
|
135
|
+
- lib/claude_inbox/remote/pairing_dialog.rb
|
|
136
|
+
- lib/claude_inbox/remote/start.rb
|
|
126
137
|
- lib/claude_inbox/renderer.rb
|
|
127
138
|
- lib/claude_inbox/session.rb
|
|
139
|
+
- lib/claude_inbox/session_request.rb
|
|
128
140
|
- lib/claude_inbox/sessions.rb
|
|
129
141
|
- lib/claude_inbox/settings.rb
|
|
130
142
|
- lib/claude_inbox/slash_commands.rb
|
|
@@ -138,6 +150,7 @@ files:
|
|
|
138
150
|
- lib/claude_inbox/text.rb
|
|
139
151
|
- lib/claude_inbox/text_buffer.rb
|
|
140
152
|
- lib/claude_inbox/theme.rb
|
|
153
|
+
- lib/claude_inbox/trust.rb
|
|
141
154
|
- lib/claude_inbox/vt_screen.rb
|
|
142
155
|
homepage: https://github.com/jordanbyron/claude-inbox
|
|
143
156
|
licenses:
|