yatfa 1.0.89 → 1.0.90
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.
- package/lib/yatfa_agent/agent.rb +12 -356
- package/lib/yatfa_agent/command_builder.rb +159 -0
- package/lib/yatfa_agent/container.rb +65 -0
- package/lib/yatfa_agent/interaction.rb +163 -0
- package/package.json +1 -1
- package/setup/agent_bridge.rb +228 -0
- package/setup/claude_settings.rb +217 -0
- package/setup/repositories.rb +98 -0
- package/setup/setup-agent.rb +25 -743
- package/setup/setup-github.rb +12 -4
- package/setup/skills.rb +136 -0
- package/setup/system_prompt.rb +110 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Repository cloning and context setup
|
|
4
|
+
# Extracted from setup-agent.rb for modularity
|
|
5
|
+
#
|
|
6
|
+
# Handles git clone, timeout handling, safe.directory configuration,
|
|
7
|
+
# and REPOSITORIES_CONTEXT persistence for shell sessions.
|
|
8
|
+
#
|
|
9
|
+
# Dependencies:
|
|
10
|
+
# - Standard library requires (json, fileutils, timeout, etc.) are loaded
|
|
11
|
+
# by setup-agent.rb before this file is required
|
|
12
|
+
|
|
13
|
+
def clone_repositories!
|
|
14
|
+
return unless ENV["REPOSITORIES_CONFIG"]
|
|
15
|
+
|
|
16
|
+
begin
|
|
17
|
+
repos = JSON.parse(ENV["REPOSITORIES_CONFIG"])
|
|
18
|
+
return unless repos.is_a?(Array) && repos.any?
|
|
19
|
+
|
|
20
|
+
puts "📚 Cloning #{repos.count} repositories..."
|
|
21
|
+
|
|
22
|
+
repos.each do |repo|
|
|
23
|
+
repo_name = repo["name"]
|
|
24
|
+
github_url = repo["github_url"]
|
|
25
|
+
sandbox_path = repo["path_in_sandbox"] || "/workspace/#{repo_name}"
|
|
26
|
+
|
|
27
|
+
# Create parent directory if needed
|
|
28
|
+
parent_dir = File.dirname(sandbox_path)
|
|
29
|
+
FileUtils.mkdir_p(parent_dir) unless File.exist?(parent_dir)
|
|
30
|
+
|
|
31
|
+
# Clone repository if it doesn't exist
|
|
32
|
+
# Do NOT use --depth to allow full branch access for PR workflows
|
|
33
|
+
unless File.exist?(sandbox_path)
|
|
34
|
+
puts " 📥 Cloning #{repo_name} to #{sandbox_path}..."
|
|
35
|
+
clone_timeout = ENV.fetch("GIT_CLONE_TIMEOUT", "180").to_i
|
|
36
|
+
clone_success = begin
|
|
37
|
+
Timeout.timeout(clone_timeout) do
|
|
38
|
+
system("git", "clone", github_url, sandbox_path)
|
|
39
|
+
end
|
|
40
|
+
rescue Timeout::Error
|
|
41
|
+
# Kill orphan git clone subprocess (Timeout.timeout doesn't kill children)
|
|
42
|
+
system("pkill", "-f", "git clone #{github_url}", err: File::NULL)
|
|
43
|
+
# Clean up partial clone directory so restart doesn't skip it
|
|
44
|
+
FileUtils.rm_rf(sandbox_path) if File.exist?(sandbox_path)
|
|
45
|
+
puts "❌ git clone of #{repo_name} timed out after #{clone_timeout}s"
|
|
46
|
+
puts " The container will restart automatically."
|
|
47
|
+
exit 1
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
unless clone_success
|
|
51
|
+
puts "❌ git clone of #{repo_name} failed"
|
|
52
|
+
puts " The container will restart automatically."
|
|
53
|
+
exit 1
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
puts " ✓ #{repo_name} already exists at #{sandbox_path}"
|
|
57
|
+
# Fetch all remotes to ensure branches are up to date
|
|
58
|
+
Dir.chdir(sandbox_path) do
|
|
59
|
+
system("git", "fetch", "--all")
|
|
60
|
+
puts " ✓ Fetched all remotes for #{repo_name}"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Add repository path to git safe.directory to avoid "dubious ownership" errors
|
|
65
|
+
system("git", "config", "--global", "--add", "safe.directory", sandbox_path)
|
|
66
|
+
puts " ✓ Added #{sandbox_path} to git safe.directory"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
puts "✅ Repositories cloned"
|
|
70
|
+
|
|
71
|
+
# Track if we have a single repository for later use
|
|
72
|
+
single_repo_name = repos.count == 1 ? repos.first['name'] : nil
|
|
73
|
+
|
|
74
|
+
# Write repository context to a file for hooks to read
|
|
75
|
+
# This is more reliable than environment variables in tmux sessions
|
|
76
|
+
if ENV["REPOSITORIES_CONTEXT"]
|
|
77
|
+
repo_context_file = File.expand_path("~/.claude/repos_context.txt")
|
|
78
|
+
File.write(repo_context_file, ENV["REPOSITORIES_CONTEXT"])
|
|
79
|
+
puts "📝 Repository context written to #{repo_context_file}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Export REPOSITORIES_CONTEXT to bash profile for shell sessions
|
|
83
|
+
if ENV["REPOSITORIES_CONTEXT"]
|
|
84
|
+
profile_file = File.expand_path("~/.bashrc")
|
|
85
|
+
existing_content = File.exist?(profile_file) ? File.read(profile_file) : ""
|
|
86
|
+
|
|
87
|
+
# Remove old export line if present
|
|
88
|
+
existing_content.gsub!(/^export REPOSITORIES_CONTEXT=.*$/, "")
|
|
89
|
+
|
|
90
|
+
# Add new export at the end
|
|
91
|
+
additions = "\nexport REPOSITORIES_CONTEXT=\"#{ENV['REPOSITORIES_CONTEXT']}\"\n"
|
|
92
|
+
File.write(profile_file, existing_content + additions)
|
|
93
|
+
puts "📝 REPOSITORIES_CONTEXT exported to ~/.bashrc"
|
|
94
|
+
end
|
|
95
|
+
rescue JSON::ParserError => e
|
|
96
|
+
puts "⚠️ Failed to parse REPOSITORIES_CONFIG: #{e.message}"
|
|
97
|
+
end
|
|
98
|
+
end
|