caruso 0.7.0 → 0.7.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: 8f7f1e5f2c4af1c26c2592aaa0cd5be588fa105ae3e7c8faf009275e881b2800
4
- data.tar.gz: d740248a46af8e1559f7b02fb70b2660ff907b66e1acd7522c4e7a2692255938
3
+ metadata.gz: e27842f0328ffd84a7b184987157b7bae790284f304d190896ad566250da4de2
4
+ data.tar.gz: 156462c94584cd858bf0bc30fe83ad71e1796c3022088147eb03dd39e4cc0712
5
5
  SHA512:
6
- metadata.gz: f77816058f4901d123ba754005869b7e40d8f15be411df9c9fa1c96a261513a4aa420886396aa2cc32f719beaf5876b7ab102c4ee1e9105980402e4c5192a549
7
- data.tar.gz: 7d85e8b21768c2978db8b29089920baa39a679163561eeba8ce8e012ad807068ff866d39a37e9411f1dec861232e5c19387c00daf4bb83e6e11673b294df1709
6
+ metadata.gz: c404d5dbe4128f2c63e8ab01ac39760aa1e131d73eeb80d7c4a5ca23fb47dde2d9f2f90508625d2c60d60903942e622e62bc14adc690fe5c43657acc8ca26e96
7
+ data.tar.gz: 530cb46037d8b3a67dfe3e8fca939d008b41d6ec580049392779ab047ada81321f4faadc17b00d2a2f77ff847f3bee92704929ec05803a15753fbfcbaf9824d7
data/.rubocop.yml CHANGED
@@ -60,6 +60,7 @@ Metrics/ClassLength:
60
60
  - 'spec/**/*'
61
61
  - 'lib/caruso/cli.rb' # CLI class has many Thor commands
62
62
  - 'lib/caruso/fetcher.rb' # Fetcher handles multiple sources
63
+ - 'lib/caruso/adapters/hook_adapter.rb' # Hook translation has many methods
63
64
 
64
65
  # Prefer descriptive block parameter names
65
66
  Lint/UnusedBlockArgument:
@@ -7,9 +7,7 @@ require_relative "base"
7
7
  module Caruso
8
8
  module Adapters
9
9
  class HookAdapter < Base
10
- # Claude Code events that map to Cursor events.
11
- # Each CC event maps to a single Cursor event name.
12
- # Matchers are lost in translation (Cursor has no matcher concept).
10
+ # CC events map to Cursor events; matchers are lost (Cursor has no matcher concept).
13
11
  EVENT_MAP = {
14
12
  "PreToolUse" => "beforeShellExecution",
15
13
  "PostToolUse" => "afterShellExecution",
@@ -17,11 +15,10 @@ module Caruso
17
15
  "Stop" => "stop"
18
16
  }.freeze
19
17
 
20
- # PostToolUse with Write|Edit matchers should map to afterFileEdit instead.
21
- # We detect this via the matcher pattern.
18
+ # PostToolUse with Write|Edit matchers maps to afterFileEdit instead.
22
19
  FILE_EDIT_MATCHERS = /\A(Write|Edit|Write\|Edit|Edit\|Write|Notebook.*)\z/i
23
20
 
24
- # Events that have no Cursor equivalent and must be skipped.
21
+ # Events with no Cursor equivalent.
25
22
  UNSUPPORTED_EVENTS = %w[
26
23
  SessionStart
27
24
  SessionEnd
@@ -31,8 +28,7 @@ module Caruso
31
28
  PermissionRequest
32
29
  ].freeze
33
30
 
34
- # After adapt(), contains the translated hook commands keyed by event.
35
- # Used by callers to track which hooks were installed for clean uninstall.
31
+ # Contains translated hook commands keyed by event (for clean uninstall tracking).
36
32
  attr_reader :translated_hooks
37
33
 
38
34
  def adapt
@@ -65,8 +61,6 @@ module Caruso
65
61
  private
66
62
 
67
63
  def find_hooks_file
68
- # files array contains the hooks.json path passed in by the Dispatcher.
69
- # Also matches .caruso_inline_hooks.json written by Fetcher for inline plugin.json hooks.
70
64
  files.find { |f| File.basename(f) =~ /hooks\.json\z/ }
71
65
  end
72
66
 
@@ -151,9 +145,7 @@ module Caruso
151
145
  end
152
146
 
153
147
  def plugin_root_from_hooks_file(hooks_file)
154
- # ${CLAUDE_PLUGIN_ROOT} refers to the plugin root directory.
155
- # hooks.json is typically at <plugin_root>/hooks/hooks.json,
156
- # so the plugin root is the parent of the hooks/ directory.
148
+ # Plugin root is parent of hooks/ dir (hooks.json is at <plugin_root>/hooks/hooks.json)
157
149
  hooks_dir = File.dirname(hooks_file)
158
150
  if File.basename(hooks_dir) == "hooks"
159
151
  File.dirname(hooks_dir)
@@ -174,7 +166,11 @@ module Caruso
174
166
  command = hook["command"]
175
167
  return unless command&.include?("${CLAUDE_PLUGIN_ROOT}")
176
168
 
177
- relative_path = command.sub("${CLAUDE_PLUGIN_ROOT}/", "")
169
+ # Extract path after placeholder (handles "python3 ${CLAUDE_PLUGIN_ROOT}/script.py")
170
+ match = command.match(%r{\$\{CLAUDE_PLUGIN_ROOT\}/([^\s]+)})
171
+ return unless match
172
+
173
+ relative_path = match[1]
178
174
  source_path = File.join(plugin_root, relative_path)
179
175
  return unless File.exist?(source_path)
180
176
 
data/lib/caruso/cli.rb CHANGED
@@ -29,6 +29,9 @@ module Caruso
29
29
  # Read marketplace name from marketplace.json
30
30
  marketplace_name = fetcher.extract_marketplace_name
31
31
 
32
+ # Register in the persistent marketplace registry (only after name is known)
33
+ fetcher.register_marketplace(marketplace_name)
34
+
32
35
  config_manager.add_marketplace(marketplace_name, url, source: source, ref: options[:ref])
33
36
 
34
37
  puts "Added marketplace '#{marketplace_name}' from #{url}"
@@ -72,6 +72,10 @@ module Caruso
72
72
  url = source_config["url"] || source_config["repo"]
73
73
  url = "https://github.com/#{url}.git" if source_config["source"] == "github" && !url.match?(/\Ahttps?:/)
74
74
 
75
+ # Store these for later registration
76
+ @clone_url = url
77
+ @clone_source_type = source_config["source"] || "git"
78
+
75
79
  URI.parse(url).path.split("/").last.sub(".git", "")
76
80
  target_path = cache_dir
77
81
 
@@ -80,10 +84,6 @@ module Caruso
80
84
  FileUtils.mkdir_p(File.dirname(target_path))
81
85
  Git.clone(url, target_path)
82
86
  checkout_ref if @ref
83
-
84
- # Add to registry
85
- source_type = source_config["source"] || "git"
86
- @registry.add_marketplace(@marketplace_name, url, target_path, ref: @ref, source: source_type)
87
87
  end
88
88
 
89
89
  target_path
@@ -92,6 +92,15 @@ module Caruso
92
92
  nil
93
93
  end
94
94
 
95
+ # Register the marketplace in the registry after name is known.
96
+ # Must be called after extract_marketplace_name or when marketplace_name is set.
97
+ def register_marketplace(name)
98
+ return unless @clone_url # Only register if we cloned something
99
+
100
+ @marketplace_name = name
101
+ @registry.add_marketplace(name, @clone_url, cache_dir, ref: @ref, source: @clone_source_type)
102
+ end
103
+
95
104
  def extract_marketplace_name
96
105
  marketplace_data = load_marketplace
97
106
  name = marketplace_data["name"]
@@ -106,7 +115,25 @@ module Caruso
106
115
  private
107
116
 
108
117
  def load_marketplace
109
- if local_path?
118
+ # Check github_repo? BEFORE local_path? because owner/repo format (e.g., "anthropics/claude-code")
119
+ # doesn't start with https:// but should be treated as a GitHub repo, not a local path
120
+ if github_repo?
121
+ # Clone repo and read marketplace.json from it
122
+ repo_path = clone_git_repo("url" => @marketplace_uri, "source" => "github")
123
+ # Try standard locations
124
+ json_path = File.join(repo_path, ".claude-plugin", "marketplace.json")
125
+ json_path = File.join(repo_path, "marketplace.json") unless File.exist?(json_path)
126
+
127
+ unless File.exist?(json_path)
128
+ raise "Could not find marketplace.json in #{@marketplace_uri}"
129
+ end
130
+
131
+ # Update marketplace_uri to point to the local file so relative paths work
132
+ @marketplace_uri = json_path
133
+ @base_dir = repo_path # Base dir is the repo root, regardless of where json is
134
+
135
+ JSON.parse(SafeFile.read(json_path))
136
+ elsif local_path?
110
137
  # If marketplace_uri is a directory, find marketplace.json in it
111
138
  if SafeDir.exist?(@marketplace_uri)
112
139
  json_path = File.join(@marketplace_uri, ".claude-plugin", "marketplace.json")
@@ -126,22 +153,6 @@ module Caruso
126
153
  end
127
154
 
128
155
  JSON.parse(SafeFile.read(@marketplace_uri))
129
- elsif github_repo?
130
- # Clone repo and read marketplace.json from it
131
- repo_path = clone_git_repo("url" => @marketplace_uri, "source" => "github")
132
- # Try standard locations
133
- json_path = File.join(repo_path, ".claude-plugin", "marketplace.json")
134
- json_path = File.join(repo_path, "marketplace.json") unless File.exist?(json_path)
135
-
136
- unless File.exist?(json_path)
137
- raise "Could not find marketplace.json in #{@marketplace_uri}"
138
- end
139
-
140
- # Update marketplace_uri to point to the local file so relative paths work
141
- @marketplace_uri = json_path
142
- @base_dir = repo_path # Base dir is the repo root, regardless of where json is
143
-
144
- JSON.parse(SafeFile.read(json_path))
145
156
  else
146
157
  response = Faraday.get(@marketplace_uri)
147
158
  JSON.parse(response.body)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Caruso
4
- VERSION = "0.7.0"
4
+ VERSION = "0.7.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caruso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philipp Comans