diffbroker 0.13.1 → 0.14.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/lib/diffbroker/access_help.rb +35 -0
- data/lib/diffbroker/cli.rb +3 -1
- data/lib/diffbroker/daemon.rb +3 -1
- data/lib/diffbroker/repo_scanner.rb +10 -1
- data/lib/diffbroker/version.rb +1 -1
- data/lib/diffbroker.rb +1 -0
- data/plugin/.claude-plugin/plugin.json +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 432bb946c0772a58cf38c9234bc6f717c79f4aa727aad1bebb7b07f17c9c5909
|
|
4
|
+
data.tar.gz: 812611ec01f56bb33748565704829e4cc0b46267319d893a161ff88e0b5ee189
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c748db09f1bba8074c246fa20634dddd77ad96603441f82402ca9b42302cbc5df5b21913bea1b2900af1b2130bf7bc2a3b4cd1d85ae325ea5ce828705136d728
|
|
7
|
+
data.tar.gz: fa95a2a4958005c0d49858e20bc71b840686ec02b12eeb7117f95710a83a049e8333dd3939667e4698a0f5589886f7d808aeee2099cabf286958a41f1177baf9
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Diffbroker
|
|
4
|
+
# What `diffbroker status` says about folders the scan was refused: the folders and, on macOS, the steps that give the
|
|
5
|
+
# program access (Full Disk Access). Devices says the same in the browser (devices/_scan_roots). Which program needs the
|
|
6
|
+
# grant depends on how the companion runs, so both are named: the Ruby that runs the background service and the terminal.
|
|
7
|
+
module AccessHelp
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def lines(paths, macos: RbConfig::CONFIG["host_os"].to_s.include?("darwin"), ruby: ruby_path)
|
|
11
|
+
return [] if paths.empty?
|
|
12
|
+
|
|
13
|
+
lines = [ "Folders the system would not let the companion read (their repositories are not found):" ]
|
|
14
|
+
lines += paths.map { " #{_1}" }
|
|
15
|
+
lines += macos ? macos_steps(ruby) : [ " Check who may read them (`ls -ld <folder>`): the companion runs as #{ENV["USER"] || "your user"}." ]
|
|
16
|
+
lines
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def macos_steps(ruby)
|
|
20
|
+
[
|
|
21
|
+
"To allow it (macOS):",
|
|
22
|
+
" 1. Open System Settings > Privacy & Security > Full Disk Access.",
|
|
23
|
+
" 2. Click + and add the program that runs the companion: #{ruby}",
|
|
24
|
+
" (in the file picker press Cmd+Shift+G to type a path). A companion you start by hand in a terminal uses that",
|
|
25
|
+
" terminal app's access instead: add the terminal there.",
|
|
26
|
+
" 3. Run `diffbroker restart`.",
|
|
27
|
+
"Or keep your code outside cloud folders (Dropbox, iCloud Drive), which macOS protects."
|
|
28
|
+
]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ruby_path = File.realpath(RbConfig.ruby)
|
|
32
|
+
rescue SystemCallError
|
|
33
|
+
RbConfig.ruby
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/diffbroker/cli.rb
CHANGED
|
@@ -303,9 +303,11 @@ module Diffbroker
|
|
|
303
303
|
@out.puts "Roots: #{config.roots.join(", ")} (plus the projects Claude Code and Codex know)"
|
|
304
304
|
@out.puts "Worktrees: #{config.worktree_root}"
|
|
305
305
|
@out.puts "Task worktrees: #{Worktree.new(root: config.worktree_root).list.size} (running or kept; `diffbroker clean` removes finished ones)"
|
|
306
|
-
|
|
306
|
+
scanner = config.repo_scanner
|
|
307
|
+
repositories = scanner.scan
|
|
307
308
|
@out.puts "Repositories found: #{repositories.size}"
|
|
308
309
|
repositories.each { @out.puts " #{_1["full_name"]} #{_1["path"]}" }
|
|
310
|
+
AccessHelp.lines(scanner.unreadable).each { @out.puts _1 }
|
|
309
311
|
end
|
|
310
312
|
|
|
311
313
|
# What the daemon wrote about itself (DaemonState), next to what this installed version and service would run.
|
data/lib/diffbroker/daemon.rb
CHANGED
|
@@ -242,7 +242,9 @@ module Diffbroker
|
|
|
242
242
|
def rescan(client)
|
|
243
243
|
@repositories = @scanner.scan
|
|
244
244
|
@scanned_at = @clock.call
|
|
245
|
-
|
|
245
|
+
payload = { "repositories" => @repositories }
|
|
246
|
+
payload["unreadable"] = @scanner.unreadable if @scanner.respond_to?(:unreadable) # Devices explains how to grant access
|
|
247
|
+
client.perform("repositories", payload)
|
|
246
248
|
end
|
|
247
249
|
|
|
248
250
|
# The plan limits change slowly and reading them can wait on the network, so: every few minutes, off the tick's thread.
|
|
@@ -21,6 +21,11 @@ module Diffbroker
|
|
|
21
21
|
|
|
22
22
|
# `exclude` (the task worktrees) is skipped everywhere. `ignored` (folders the user removed) is skipped by everything
|
|
23
23
|
# found by itself; `explicit_roots` (folders the user added) are scanned even inside an ignored folder.
|
|
24
|
+
# Folders the last scan was refused (macOS answers EPERM for Dropbox, iCloud, Desktop and the like until the program has
|
|
25
|
+
# been given access; other systems say EACCES). Reported to the server so Devices can explain how to grant it.
|
|
26
|
+
MAX_UNREADABLE = 20
|
|
27
|
+
attr_reader :unreadable
|
|
28
|
+
|
|
24
29
|
def initialize(roots:, depth: 3, exclude: [], hints: [], home: Dir.home, explicit_roots: [], ignored: [])
|
|
25
30
|
@roots = roots
|
|
26
31
|
@explicit_roots = explicit_roots
|
|
@@ -30,10 +35,12 @@ module Diffbroker
|
|
|
30
35
|
@depth = depth
|
|
31
36
|
@exclude = exclude.map { File.expand_path(_1) }
|
|
32
37
|
@skip = @exclude + @ignored
|
|
38
|
+
@unreadable = []
|
|
33
39
|
end
|
|
34
40
|
|
|
35
41
|
def scan
|
|
36
42
|
found = {}
|
|
43
|
+
@unreadable = []
|
|
37
44
|
@roots.each { |root| walk(File.expand_path(root), 0, found, @depth, @skip) if File.directory?(root) }
|
|
38
45
|
@explicit_roots.each { |root| walk(File.expand_path(root), 0, found, @depth, @exclude) if File.directory?(root) }
|
|
39
46
|
parents = @hints.filter_map { |hint| add_hint(File.expand_path(hint), found) }.map { File.dirname(_1) }.uniq
|
|
@@ -79,8 +86,10 @@ module Diffbroker
|
|
|
79
86
|
path = File.join(dir, child)
|
|
80
87
|
walk(path, level + 1, found, limit, skip) if File.directory?(path) && !File.symlink?(path)
|
|
81
88
|
end
|
|
89
|
+
rescue Errno::EPERM, Errno::EACCES
|
|
90
|
+
@unreadable << dir if @unreadable.size < MAX_UNREADABLE && !@unreadable.include?(dir)
|
|
82
91
|
rescue SystemCallError
|
|
83
|
-
nil #
|
|
92
|
+
nil # gone meanwhile, or not a folder: nothing to report
|
|
84
93
|
end
|
|
85
94
|
|
|
86
95
|
def remote_names(dir) = GitContext.remote_urls(dir).filter_map { |_name, url| self.class.full_name_from(url) }.uniq
|
data/lib/diffbroker/version.rb
CHANGED
data/lib/diffbroker.rb
CHANGED
|
@@ -32,6 +32,7 @@ module Diffbroker
|
|
|
32
32
|
autoload :Launcher, File.expand_path("diffbroker/launcher", __dir__)
|
|
33
33
|
autoload :Maintenance, File.expand_path("diffbroker/maintenance", __dir__)
|
|
34
34
|
autoload :LocalRelay, File.expand_path("diffbroker/local_relay", __dir__)
|
|
35
|
+
autoload :AccessHelp, File.expand_path("diffbroker/access_help", __dir__)
|
|
35
36
|
autoload :Login, File.expand_path("diffbroker/login", __dir__)
|
|
36
37
|
autoload :Neutralizer, File.expand_path("diffbroker/neutralizer", __dir__)
|
|
37
38
|
autoload :PlanUsage, File.expand_path("diffbroker/plan_usage", __dir__)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: diffbroker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.14.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yuri Sidorov (@newstler)
|
|
@@ -34,6 +34,7 @@ files:
|
|
|
34
34
|
- LICENSE.txt
|
|
35
35
|
- exe/diffbroker
|
|
36
36
|
- lib/diffbroker.rb
|
|
37
|
+
- lib/diffbroker/access_help.rb
|
|
37
38
|
- lib/diffbroker/agent_projects.rb
|
|
38
39
|
- lib/diffbroker/agents.rb
|
|
39
40
|
- lib/diffbroker/agents/base.rb
|