baid 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/lib/baid/claude_md_writer.rb +47 -0
- data/lib/baid/claude_settings_writer.rb +42 -0
- data/lib/baid/cli.rb +16 -11
- data/lib/baid/commands/init.rb +34 -16
- data/lib/baid/commands/skills.rb +98 -0
- data/lib/baid/git_hook_writer.rb +48 -0
- data/lib/baid/sub_agent_writer.rb +32 -0
- data/lib/baid.rb +6 -3
- metadata +7 -4
- data/lib/baid/commands/install.rb +0 -38
- data/lib/baid/commands/search.rb +0 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 25c6623df08284d0d26b7168752a7fb1d36267d06b4dd53f03d85f9eca251636
|
|
4
|
+
data.tar.gz: c349b2671a0c71f624e1a93e69475fc5ac74bc3b399a7b119928ad82dd4fc459
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 723af1e4232b451ba29f84be06ee506ae75fcda4c628fd55594c8a3f2dae476dad3952dd8c08aa802ae6842f04d4fafc7e204e56fc5a491f8ab62d46c87b7b2b
|
|
7
|
+
data.tar.gz: 1a021dd07862bcdc77347cb60c54d3bdaae50e332c5d1595396723a689479690e7efac0a66303fc9fd276fe702d1603e6720857d2025ecba1426cb75d248e3eb
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Baid
|
|
4
|
+
class ClaudeMdWriter
|
|
5
|
+
AGENT_CLAUDE_MD_PATHS = {
|
|
6
|
+
"claude_code" => "CLAUDE.md",
|
|
7
|
+
"cursor" => File.join(".cursor", "rules", "BAID.md"),
|
|
8
|
+
"opencode" => File.join(".opencode", "AGENTS.md"),
|
|
9
|
+
"gemini" => "GEMINI.md",
|
|
10
|
+
"antigravity" => File.join(".agent", "AGENTS.md")
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
BAID_SECTION_MARKER = "<!-- baid-managed-section -->"
|
|
14
|
+
|
|
15
|
+
def self.write(instructions, agents, project_dir = ".")
|
|
16
|
+
agents.each do |agent|
|
|
17
|
+
path_template = AGENT_CLAUDE_MD_PATHS[agent[:name]]
|
|
18
|
+
next unless path_template
|
|
19
|
+
|
|
20
|
+
full_path = File.join(project_dir, path_template)
|
|
21
|
+
FileUtils.mkdir_p(File.dirname(full_path))
|
|
22
|
+
write_or_append(full_path, instructions)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.write_or_append(path, instructions)
|
|
27
|
+
baid_block = "#{BAID_SECTION_MARKER}\n#{instructions}\n#{BAID_SECTION_MARKER}"
|
|
28
|
+
|
|
29
|
+
if File.exist?(path)
|
|
30
|
+
existing = File.read(path)
|
|
31
|
+
if existing.include?(BAID_SECTION_MARKER)
|
|
32
|
+
updated = existing.gsub(
|
|
33
|
+
/#{Regexp.escape(BAID_SECTION_MARKER)}.*?#{Regexp.escape(BAID_SECTION_MARKER)}/m,
|
|
34
|
+
baid_block
|
|
35
|
+
)
|
|
36
|
+
File.write(path, updated)
|
|
37
|
+
else
|
|
38
|
+
File.open(path, "a") { |f| f.write("\n#{baid_block}\n") }
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
File.write(path, "#{baid_block}\n")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private_class_method :write_or_append
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Baid
|
|
4
|
+
class ClaudeSettingsWriter
|
|
5
|
+
SETTINGS_PATH = File.join(".claude", "settings.json")
|
|
6
|
+
|
|
7
|
+
def self.write(hook_configs, agents, project_dir = ".")
|
|
8
|
+
return unless agents.any? { |a| a[:name] == "claude_code" }
|
|
9
|
+
|
|
10
|
+
claude_hooks = hook_configs["claude_code"]
|
|
11
|
+
return unless claude_hooks
|
|
12
|
+
|
|
13
|
+
full_path = File.join(project_dir, SETTINGS_PATH)
|
|
14
|
+
FileUtils.mkdir_p(File.dirname(full_path))
|
|
15
|
+
|
|
16
|
+
existing = load_settings(full_path)
|
|
17
|
+
existing["hooks"] ||= []
|
|
18
|
+
|
|
19
|
+
new_hooks = claude_hooks["hooks"] || []
|
|
20
|
+
new_hooks.each do |new_hook|
|
|
21
|
+
existing["hooks"].reject! { |h| h["event"] == new_hook["event"] && baid_hook?(h) }
|
|
22
|
+
existing["hooks"] << new_hook
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
File.write(full_path, JSON.pretty_generate(existing))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.baid_hook?(hook)
|
|
29
|
+
Array(hook["hooks"]).any? { |h| h["tool"]&.start_with?("baid_") }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.load_settings(path)
|
|
33
|
+
return {} unless File.exist?(path)
|
|
34
|
+
|
|
35
|
+
JSON.parse(File.read(path))
|
|
36
|
+
rescue JSON::ParserError
|
|
37
|
+
{}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private_class_method :load_settings, :baid_hook?
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/baid/cli.rb
CHANGED
|
@@ -32,22 +32,12 @@ module Baid
|
|
|
32
32
|
Commands::Reconfigure.new.execute
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
desc "install SKILL_NAME", "Install a skill into your project"
|
|
36
|
-
def install(skill_name)
|
|
37
|
-
Commands::Install.new.execute(skill_name)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
desc "search QUERY", "Search for skills in the registry"
|
|
41
|
-
def search(query)
|
|
42
|
-
Commands::Search.new.execute(query)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
35
|
desc "update", "Update all installed skills to latest versions"
|
|
46
36
|
def update
|
|
47
37
|
Commands::Update.new.execute
|
|
48
38
|
end
|
|
49
39
|
|
|
50
|
-
desc "skills SUBCOMMAND", "Manage
|
|
40
|
+
desc "skills SUBCOMMAND", "Manage skills"
|
|
51
41
|
subcommand "skills", Class.new(Thor) {
|
|
52
42
|
namespace "skills"
|
|
53
43
|
|
|
@@ -60,6 +50,21 @@ module Baid
|
|
|
60
50
|
def show(workspace_slug, skill_id = nil)
|
|
61
51
|
Commands::Skills.new.show(workspace_slug, skill_id)
|
|
62
52
|
end
|
|
53
|
+
|
|
54
|
+
desc "search QUERY", "Search for skills in the registry"
|
|
55
|
+
def search(query)
|
|
56
|
+
Commands::Skills.new.search(query)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
desc "download SKILL_NAME", "Download and install a skill into your project"
|
|
60
|
+
def download(skill_name)
|
|
61
|
+
Commands::Skills.new.download(skill_name)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
desc "clean", "Remove all installed skills"
|
|
65
|
+
def clean
|
|
66
|
+
Commands::Skills.new.clean
|
|
67
|
+
end
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
desc "workspace SUBCOMMAND", "Manage workspaces"
|
data/lib/baid/commands/init.rb
CHANGED
|
@@ -20,15 +20,29 @@ module Baid
|
|
|
20
20
|
puts "Configured MCP for #{agent[:name]}"
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
result = smart_init(agents)
|
|
24
|
+
|
|
25
|
+
if result[:claude_md_instructions] && !result[:claude_md_instructions].empty?
|
|
26
|
+
ClaudeMdWriter.write(result[:claude_md_instructions], agents, @project_dir)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if result[:agent_configs]&.any?
|
|
30
|
+
SubAgentWriter.write(result[:agent_configs], agents, @project_dir)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if result[:hook_configs]&.any?
|
|
34
|
+
ClaudeSettingsWriter.write(result[:hook_configs], agents, @project_dir)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
tech_stack = result[:tech_stack] || []
|
|
38
|
+
GitHookWriter.write(tech_stack, @project_dir)
|
|
24
39
|
|
|
25
40
|
config_path = File.join(@project_dir, ".baid", "config.yml")
|
|
26
41
|
FileUtils.mkdir_p(File.dirname(config_path))
|
|
27
42
|
config = {
|
|
28
43
|
"agents" => agents.map { |a| a[:name] },
|
|
29
|
-
"
|
|
44
|
+
"tech_stack" => tech_stack
|
|
30
45
|
}
|
|
31
|
-
config["tech_stack"] = init_result[:tech_stack] if init_result[:tech_stack]&.any?
|
|
32
46
|
File.write(config_path, config.to_yaml)
|
|
33
47
|
|
|
34
48
|
puts "Baid initialized with #{agents.length} agent(s)."
|
|
@@ -39,7 +53,7 @@ module Baid
|
|
|
39
53
|
def smart_init(agents)
|
|
40
54
|
token = Config.load_token
|
|
41
55
|
workspace = Config.load_active_workspace
|
|
42
|
-
return
|
|
56
|
+
return default_result unless token && workspace
|
|
43
57
|
|
|
44
58
|
puts "Analyzing project..."
|
|
45
59
|
scan = ProjectScanner.scan(@project_dir)
|
|
@@ -51,33 +65,37 @@ module Baid
|
|
|
51
65
|
package_files: scan[:package_files]
|
|
52
66
|
})
|
|
53
67
|
|
|
54
|
-
return
|
|
68
|
+
return default_result unless response.code == 200
|
|
55
69
|
|
|
56
70
|
data = JSON.parse(response.body)
|
|
57
71
|
tech_stack = data["tech_stack"] || []
|
|
58
72
|
answers = present_questions(data["questions"] || [])
|
|
59
73
|
|
|
74
|
+
puts "Configuring workspace..."
|
|
60
75
|
setup_response = client.post("/init/setup", {
|
|
61
76
|
workspace_slug: workspace,
|
|
62
77
|
tech_stack: tech_stack,
|
|
63
78
|
answers: answers,
|
|
64
|
-
agents: agents.map { |a| a[:name] }
|
|
65
|
-
recommended_skills: data["recommended_skills"] || []
|
|
79
|
+
agents: agents.map { |a| a[:name] }
|
|
66
80
|
})
|
|
67
81
|
|
|
68
|
-
return
|
|
82
|
+
return default_result.merge(tech_stack: tech_stack) unless setup_response.code == 200
|
|
69
83
|
|
|
70
84
|
setup_data = JSON.parse(setup_response.body)
|
|
71
|
-
skills = setup_data["skills"] || []
|
|
72
85
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
{
|
|
87
|
+
tech_stack: tech_stack,
|
|
88
|
+
agent_configs: setup_data["agent_configs"] || {},
|
|
89
|
+
hook_configs: setup_data["hook_configs"] || {},
|
|
90
|
+
claude_md_instructions: setup_data["claude_md_instructions"]
|
|
91
|
+
}
|
|
92
|
+
rescue StandardError => e
|
|
93
|
+
puts "Warning: Smart init failed — #{e.message}"
|
|
94
|
+
default_result
|
|
95
|
+
end
|
|
77
96
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
{ skills: [], tech_stack: [] }
|
|
97
|
+
def default_result
|
|
98
|
+
{ tech_stack: [], agent_configs: {}, hook_configs: {}, claude_md_instructions: nil }
|
|
81
99
|
end
|
|
82
100
|
|
|
83
101
|
def present_questions(questions)
|
data/lib/baid/commands/skills.rb
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
module Baid
|
|
4
4
|
module Commands
|
|
5
5
|
class Skills
|
|
6
|
+
def initialize(project_dir: ".")
|
|
7
|
+
@project_dir = project_dir
|
|
8
|
+
end
|
|
9
|
+
|
|
6
10
|
def list(workspace_slug = nil)
|
|
7
11
|
workspace_slug = resolve_workspace(workspace_slug)
|
|
8
12
|
|
|
@@ -58,6 +62,100 @@ module Baid
|
|
|
58
62
|
puts "Agents: #{(data['agents'] || []).join(', ')}"
|
|
59
63
|
end
|
|
60
64
|
|
|
65
|
+
def search(query)
|
|
66
|
+
client = ApiClient.new
|
|
67
|
+
response = client.get("/skills/search", q: query)
|
|
68
|
+
data = JSON.parse(response.body)
|
|
69
|
+
skills = data["skills"] || []
|
|
70
|
+
|
|
71
|
+
if skills.empty?
|
|
72
|
+
puts "No skills found for '#{query}'."
|
|
73
|
+
return
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
puts format("%-25s %-40s %-10s %s", "NAME", "DESCRIPTION", "VERSION", "WORKSPACE")
|
|
77
|
+
puts "-" * 90
|
|
78
|
+
skills.each do |skill|
|
|
79
|
+
puts format("%-25s %-40s %-10s %s",
|
|
80
|
+
skill["name"],
|
|
81
|
+
(skill["description"] || "")[0..38],
|
|
82
|
+
skill["version"],
|
|
83
|
+
skill["workspace"])
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def download(skill_name)
|
|
88
|
+
client = ApiClient.new
|
|
89
|
+
response = client.get("/skills/resolve", name: skill_name)
|
|
90
|
+
|
|
91
|
+
if response.code != 200
|
|
92
|
+
puts "Skill '#{skill_name}' not found."
|
|
93
|
+
return
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
data = JSON.parse(response.body)
|
|
97
|
+
skill = data["skill"]
|
|
98
|
+
|
|
99
|
+
config = Config.load_project_config
|
|
100
|
+
agents = (config["agents"] || []).map do |name|
|
|
101
|
+
AgentDetector::AGENTS.find { |a| a[:name] == name }
|
|
102
|
+
end.compact
|
|
103
|
+
|
|
104
|
+
SkillWriter.write(skill, agents, @project_dir)
|
|
105
|
+
|
|
106
|
+
config["installed_skills"] ||= []
|
|
107
|
+
config["installed_skills"] << skill["name"] unless config["installed_skills"].include?(skill["name"])
|
|
108
|
+
Config.save_project_config(config)
|
|
109
|
+
|
|
110
|
+
puts "Installed #{skill['name']}@#{skill['version']}"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def clean
|
|
114
|
+
config = Config.load_project_config
|
|
115
|
+
installed = config["installed_skills"] || []
|
|
116
|
+
|
|
117
|
+
if installed.empty?
|
|
118
|
+
puts "No skills installed."
|
|
119
|
+
return
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
prompt = TTY::Prompt.new
|
|
123
|
+
puts "Installed skills: #{installed.join(', ')}"
|
|
124
|
+
confirmed = prompt.yes?("This will remove all installed skills. Are you sure?")
|
|
125
|
+
|
|
126
|
+
unless confirmed
|
|
127
|
+
puts "Aborted."
|
|
128
|
+
return
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Document removed skills
|
|
132
|
+
baid_dir = File.join(@project_dir, ".baid")
|
|
133
|
+
FileUtils.mkdir_p(baid_dir)
|
|
134
|
+
removed_file = File.join(baid_dir, "removed_skills.md")
|
|
135
|
+
|
|
136
|
+
timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S")
|
|
137
|
+
content = "# Removed Skills\n\n"
|
|
138
|
+
content += "Removed on #{timestamp}\n\n"
|
|
139
|
+
installed.each { |name| content += "- #{name}\n" }
|
|
140
|
+
|
|
141
|
+
File.write(removed_file, content)
|
|
142
|
+
|
|
143
|
+
# Remove skill files from all agent directories
|
|
144
|
+
agents = (config["agents"] || []).map do |name|
|
|
145
|
+
AgentDetector::AGENTS.find { |a| a[:name] == name }
|
|
146
|
+
end.compact
|
|
147
|
+
|
|
148
|
+
installed.each do |skill_name|
|
|
149
|
+
SkillWriter.remove(skill_name, agents, @project_dir)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Clear installed_skills from config
|
|
153
|
+
config["installed_skills"] = []
|
|
154
|
+
Config.save_project_config(config)
|
|
155
|
+
|
|
156
|
+
puts "Removed #{installed.length} skill(s). Details saved to .baid/removed_skills.md"
|
|
157
|
+
end
|
|
158
|
+
|
|
61
159
|
private
|
|
62
160
|
|
|
63
161
|
def resolve_workspace(workspace_slug)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Baid
|
|
4
|
+
class GitHookWriter
|
|
5
|
+
BAID_MARKER = "# baid-managed"
|
|
6
|
+
|
|
7
|
+
DEFAULT_COMMANDS = {
|
|
8
|
+
"ruby" => "bundle exec rubocop --autocorrect-all -f quiet && bundle exec rspec --fail-fast",
|
|
9
|
+
"node" => "npm run lint && npm test",
|
|
10
|
+
"python" => "ruff check . && pytest"
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
BAID_END_MARKER = "# end baid-managed"
|
|
14
|
+
|
|
15
|
+
def self.write(tech_stack, project_dir = ".")
|
|
16
|
+
hooks_dir = File.join(project_dir, ".git", "hooks")
|
|
17
|
+
return unless Dir.exist?(hooks_dir)
|
|
18
|
+
|
|
19
|
+
commands = build_commands(tech_stack)
|
|
20
|
+
return if commands.empty?
|
|
21
|
+
|
|
22
|
+
hook_path = File.join(hooks_dir, "pre-commit")
|
|
23
|
+
baid_section = "#{BAID_MARKER}: pre-commit hook\n#{commands.join("\n")}\n#{BAID_END_MARKER}"
|
|
24
|
+
|
|
25
|
+
if File.exist?(hook_path)
|
|
26
|
+
existing = File.read(hook_path)
|
|
27
|
+
if existing.include?(BAID_MARKER)
|
|
28
|
+
content = existing.sub(/#{Regexp.escape(BAID_MARKER)}.*?#{Regexp.escape(BAID_END_MARKER)}/m, baid_section)
|
|
29
|
+
else
|
|
30
|
+
content = existing.rstrip + "\n\n#{baid_section}\n"
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
content = "#!/bin/sh\n#{baid_section}\n"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
File.write(hook_path, content)
|
|
37
|
+
FileUtils.chmod(0o755, hook_path)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.build_commands(tech_stack)
|
|
41
|
+
DEFAULT_COMMANDS.filter_map do |stack_key, command|
|
|
42
|
+
command if tech_stack.any? { |t| t.include?(stack_key) }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private_class_method :build_commands
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Baid
|
|
4
|
+
class SubAgentWriter
|
|
5
|
+
AGENT_SUB_AGENT_DIRS = {
|
|
6
|
+
"claude_code" => File.join(".claude", "agents"),
|
|
7
|
+
"cursor" => File.join(".cursor", "agents"),
|
|
8
|
+
"opencode" => File.join(".opencode", "agents")
|
|
9
|
+
}.freeze
|
|
10
|
+
|
|
11
|
+
def self.write(agent_configs, agents, project_dir = ".")
|
|
12
|
+
agents.each do |agent|
|
|
13
|
+
dir_template = AGENT_SUB_AGENT_DIRS[agent[:name]]
|
|
14
|
+
next unless dir_template
|
|
15
|
+
|
|
16
|
+
config = agent_configs[agent[:name]]
|
|
17
|
+
next unless config&.dig("sub_agents")
|
|
18
|
+
|
|
19
|
+
full_dir = File.join(project_dir, dir_template)
|
|
20
|
+
FileUtils.mkdir_p(full_dir)
|
|
21
|
+
|
|
22
|
+
config["sub_agents"].each do |sub_agent|
|
|
23
|
+
filename = File.basename(sub_agent["filename"].to_s)
|
|
24
|
+
next if filename.empty?
|
|
25
|
+
|
|
26
|
+
file_path = File.join(full_dir, filename)
|
|
27
|
+
File.write(file_path, sub_agent["content"])
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/baid.rb
CHANGED
|
@@ -8,7 +8,7 @@ require "fileutils"
|
|
|
8
8
|
require "tty-prompt"
|
|
9
9
|
|
|
10
10
|
module Baid
|
|
11
|
-
VERSION = "0.
|
|
11
|
+
VERSION = "0.3.0"
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
require_relative "baid/config"
|
|
@@ -20,10 +20,13 @@ require_relative "baid/commands/login"
|
|
|
20
20
|
require_relative "baid/commands/logout"
|
|
21
21
|
require_relative "baid/commands/whoami"
|
|
22
22
|
require_relative "baid/skill_writer"
|
|
23
|
+
require_relative "baid/claude_md_writer"
|
|
24
|
+
require_relative "baid/sub_agent_writer"
|
|
25
|
+
require_relative "baid/git_hook_writer"
|
|
26
|
+
require_relative "baid/claude_settings_writer"
|
|
23
27
|
require_relative "baid/commands/init"
|
|
24
28
|
require_relative "baid/commands/reconfigure"
|
|
25
|
-
|
|
26
|
-
require_relative "baid/commands/search"
|
|
29
|
+
|
|
27
30
|
require_relative "baid/commands/update"
|
|
28
31
|
require_relative "baid/skills_sh_scraper"
|
|
29
32
|
require_relative "baid/commands/skills"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: baid
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Baid Team
|
|
@@ -93,6 +93,7 @@ dependencies:
|
|
|
93
93
|
- - "~>"
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
95
|
version: '3.18'
|
|
96
|
+
description: Manage AI agent skills, sub-agents, and hooks across workspaces
|
|
96
97
|
executables:
|
|
97
98
|
- baid
|
|
98
99
|
extensions: []
|
|
@@ -102,22 +103,24 @@ files:
|
|
|
102
103
|
- lib/baid.rb
|
|
103
104
|
- lib/baid/agent_detector.rb
|
|
104
105
|
- lib/baid/api_client.rb
|
|
106
|
+
- lib/baid/claude_md_writer.rb
|
|
107
|
+
- lib/baid/claude_settings_writer.rb
|
|
105
108
|
- lib/baid/cli.rb
|
|
106
109
|
- lib/baid/commands/init.rb
|
|
107
|
-
- lib/baid/commands/install.rb
|
|
108
110
|
- lib/baid/commands/login.rb
|
|
109
111
|
- lib/baid/commands/logout.rb
|
|
110
112
|
- lib/baid/commands/reconfigure.rb
|
|
111
|
-
- lib/baid/commands/search.rb
|
|
112
113
|
- lib/baid/commands/skills.rb
|
|
113
114
|
- lib/baid/commands/update.rb
|
|
114
115
|
- lib/baid/commands/whoami.rb
|
|
115
116
|
- lib/baid/commands/workspace.rb
|
|
116
117
|
- lib/baid/config.rb
|
|
118
|
+
- lib/baid/git_hook_writer.rb
|
|
117
119
|
- lib/baid/mcp_configurator.rb
|
|
118
120
|
- lib/baid/project_scanner.rb
|
|
119
121
|
- lib/baid/skill_writer.rb
|
|
120
122
|
- lib/baid/skills_sh_scraper.rb
|
|
123
|
+
- lib/baid/sub_agent_writer.rb
|
|
121
124
|
homepage: https://baid.dev
|
|
122
125
|
licenses:
|
|
123
126
|
- MIT
|
|
@@ -138,5 +141,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
138
141
|
requirements: []
|
|
139
142
|
rubygems_version: 3.6.9
|
|
140
143
|
specification_version: 4
|
|
141
|
-
summary: CLI for
|
|
144
|
+
summary: CLI for Baid — AI agent skill management for development teams
|
|
142
145
|
test_files: []
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Baid
|
|
4
|
-
module Commands
|
|
5
|
-
class Install
|
|
6
|
-
def initialize(project_dir: ".")
|
|
7
|
-
@project_dir = project_dir
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def execute(skill_name)
|
|
11
|
-
client = ApiClient.new
|
|
12
|
-
response = client.get("/skills/resolve", name: skill_name)
|
|
13
|
-
|
|
14
|
-
if response.code != 200
|
|
15
|
-
puts "Skill '#{skill_name}' not found."
|
|
16
|
-
return
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
data = JSON.parse(response.body)
|
|
20
|
-
skill = data["skill"]
|
|
21
|
-
|
|
22
|
-
config = Config.load_project_config
|
|
23
|
-
agents = (config["agents"] || []).map do |name|
|
|
24
|
-
AgentDetector::AGENTS.find { |a| a[:name] == name }
|
|
25
|
-
end.compact
|
|
26
|
-
|
|
27
|
-
SkillWriter.write(skill, agents, @project_dir)
|
|
28
|
-
|
|
29
|
-
# Update installed_skills in config
|
|
30
|
-
config["installed_skills"] ||= []
|
|
31
|
-
config["installed_skills"] << skill["name"] unless config["installed_skills"].include?(skill["name"])
|
|
32
|
-
Config.save_project_config(config)
|
|
33
|
-
|
|
34
|
-
puts "Installed #{skill['name']}@#{skill['version']}"
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
data/lib/baid/commands/search.rb
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Baid
|
|
4
|
-
module Commands
|
|
5
|
-
class Search
|
|
6
|
-
def execute(query)
|
|
7
|
-
client = ApiClient.new
|
|
8
|
-
response = client.get("/skills/search", q: query)
|
|
9
|
-
data = JSON.parse(response.body)
|
|
10
|
-
skills = data["skills"] || []
|
|
11
|
-
|
|
12
|
-
if skills.empty?
|
|
13
|
-
puts "No skills found for '#{query}'."
|
|
14
|
-
return
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
puts format("%-25s %-40s %-10s %s", "NAME", "DESCRIPTION", "VERSION", "WORKSPACE")
|
|
18
|
-
puts "-" * 90
|
|
19
|
-
skills.each do |skill|
|
|
20
|
-
puts format("%-25s %-40s %-10s %s",
|
|
21
|
-
skill["name"],
|
|
22
|
-
(skill["description"] || "")[0..38],
|
|
23
|
-
skill["version"],
|
|
24
|
-
skill["workspace"])
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|