aircon 0.1.0 → 0.2.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 +9 -9
- data/lib/aircon/cli.rb +6 -1
- data/lib/aircon/commands/up.rb +32 -4
- data/lib/aircon/configuration.rb +18 -3
- data/lib/aircon/version.rb +1 -1
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9d51871327109dc3145685c8ff1b808658592ebc527baaab88fc7d54d3a2b5d1
|
|
4
|
+
data.tar.gz: 60ddec11a21faf68d0c8d43beae7a424d935e82df72c0be5e09ff90a2102829b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 23e48ab217b5c812dffac335ff9dbebb72233379dbf601fe86369e2fa38960b798d1bd325ddbde3164951927a798a60ca9c129aa87b49f2e2333cdafae5a9934
|
|
7
|
+
data.tar.gz: 8d93936b25ce81e580a5741706cd3e7a6cd4ae1bc46776e6db1a25864a51ca2c08b42f33d8e583b84c05bd040c2e42fa646e3c7d03d486ef7723ca4ecfbae8b8
|
data/README.md
CHANGED
|
@@ -97,7 +97,7 @@ aircon up my-feature -d # start detached (no interactive shell)
|
|
|
97
97
|
5. Installs Claude Code inside the container if not already present (`curl -fsSL https://claude.ai/install.sh | bash`).
|
|
98
98
|
6. Adds `~/.local/bin` to `PATH` in `/etc/bash.bashrc` so `claude` is available in all sessions.
|
|
99
99
|
7. Writes `GH_TOKEN` and `GITHUB_PERSONAL_ACCESS_TOKEN` to `/etc/bash.bashrc` (if `gh_token` is set).
|
|
100
|
-
8.
|
|
100
|
+
8. Injects Claude Code credentials based on `credentials_source`: copies from macOS Keychain (`keychain`), from `~/.claude/.credentials.json` (`file`), or sets `CLAUDE_CODE_OAUTH_TOKEN` in `/etc/bash.bashrc` (`oauth_token`).
|
|
101
101
|
9. Sets `git config user.email` and `git config user.name` globally inside the container.
|
|
102
102
|
10. Configures `git` to authenticate GitHub URLs with your token (covers both `https://github.com/` and `git@github.com:`).
|
|
103
103
|
11. Checks out the branch:
|
|
@@ -177,7 +177,11 @@ app_name: my-app
|
|
|
177
177
|
# GitHub personal access token — authenticates git and gh inside the container
|
|
178
178
|
gh_token: <%= ENV['GITHUB_TOKEN'] %>
|
|
179
179
|
|
|
180
|
-
#
|
|
180
|
+
# How to obtain Claude Code credentials: "keychain" (macOS), "file", or "oauth_token"
|
|
181
|
+
credentials_source: keychain
|
|
182
|
+
|
|
183
|
+
# Claude Code OAuth token — used when credentials_source is "oauth_token"
|
|
184
|
+
# Falls back to CLAUDE_CODE_OAUTH_TOKEN env var if not set here.
|
|
181
185
|
claude_code_oauth_token: <%= ENV['CLAUDE_CODE_OAUTH_TOKEN'] %>
|
|
182
186
|
|
|
183
187
|
# Workspace folder path inside the container
|
|
@@ -210,7 +214,8 @@ init_script: .aircon/aircon_init.sh
|
|
|
210
214
|
| `compose_file` | `.aircon/docker-compose.yml` | Docker Compose file to use |
|
|
211
215
|
| `app_name` | basename of cwd | App name passed to Compose as `AIRCON_APP_NAME` |
|
|
212
216
|
| `gh_token` | `nil` | GitHub token; sets `GH_TOKEN` and `GITHUB_PERSONAL_ACCESS_TOKEN` in the container |
|
|
213
|
-
| `
|
|
217
|
+
| `credentials_source` | `keychain` | `keychain` (macOS), `file` (~/.claude/.credentials.json), or `oauth_token` |
|
|
218
|
+
| `claude_code_oauth_token` | `nil` | OAuth token for `oauth_token` mode; falls back to `CLAUDE_CODE_OAUTH_TOKEN` env var |
|
|
214
219
|
| `workspace_path` | `/workspace` | Workspace folder path inside the container |
|
|
215
220
|
| `claude_config_path` | `~/.claude.json` | Host path to `claude.json` |
|
|
216
221
|
| `claude_dir_path` | `~/.claude` | Host path to `.claude/` directory |
|
|
@@ -233,12 +238,7 @@ init_script: .aircon/aircon_init.sh
|
|
|
233
238
|
## Releasing to RubyGems
|
|
234
239
|
|
|
235
240
|
1. Bump the version in `lib/aircon/version.rb`.
|
|
236
|
-
2.
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
gem build aircon.gemspec
|
|
240
|
-
gem push aircon-<version>.gem
|
|
241
|
-
```
|
|
241
|
+
2. run `bundle exec rake release`.
|
|
242
242
|
|
|
243
243
|
You'll be prompted for your RubyGems credentials on first push. Subsequent pushes use the stored API key at `~/.gem/credentials`.
|
|
244
244
|
|
data/lib/aircon/cli.rb
CHANGED
|
@@ -70,7 +70,11 @@ module Aircon
|
|
|
70
70
|
# GitHub personal access token (supports ERB)
|
|
71
71
|
# gh_token: <%= ENV['GITHUB_TOKEN'] %>
|
|
72
72
|
|
|
73
|
-
# Claude Code
|
|
73
|
+
# How to obtain Claude Code credentials: "keychain" (macOS), "file", or "oauth_token"
|
|
74
|
+
# credentials_source: keychain
|
|
75
|
+
|
|
76
|
+
# Claude Code OAuth token — used when credentials_source is "oauth_token" (supports ERB)
|
|
77
|
+
# Falls back to CLAUDE_CODE_OAUTH_TOKEN env var if not set here.
|
|
74
78
|
# claude_code_oauth_token: <%= ENV['CLAUDE_CODE_OAUTH_TOKEN'] %>
|
|
75
79
|
|
|
76
80
|
# Workspace folder path inside the container
|
|
@@ -185,6 +189,7 @@ module Aircon
|
|
|
185
189
|
COMPOSE_TEMPLATE = <<~'YAML'
|
|
186
190
|
services:
|
|
187
191
|
app:
|
|
192
|
+
image: ${AIRCON_APP_NAME:-aircon}-app:latest
|
|
188
193
|
build:
|
|
189
194
|
context: ..
|
|
190
195
|
dockerfile: .aircon/Dockerfile
|
data/lib/aircon/commands/up.rb
CHANGED
|
@@ -80,6 +80,8 @@ module Aircon
|
|
|
80
80
|
FileUtils.mkdir_p(File.join(staging, ".claude"))
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
write_credentials(File.join(staging, ".claude", ".credentials.json"))
|
|
84
|
+
|
|
83
85
|
home = @config.container_home
|
|
84
86
|
rewrite_paths(staging, home)
|
|
85
87
|
user = @config.container_user
|
|
@@ -106,6 +108,29 @@ module Aircon
|
|
|
106
108
|
end
|
|
107
109
|
end
|
|
108
110
|
|
|
111
|
+
def write_credentials(dest)
|
|
112
|
+
case @config.credentials_source
|
|
113
|
+
when "keychain"
|
|
114
|
+
out, status = Open3.capture2(
|
|
115
|
+
"security", "find-generic-password",
|
|
116
|
+
"-a", ENV.fetch("USER", "unknown"),
|
|
117
|
+
"-w", "-s", "Claude Code-credentials"
|
|
118
|
+
)
|
|
119
|
+
if status.success?
|
|
120
|
+
File.write(dest, out)
|
|
121
|
+
else
|
|
122
|
+
warn "Warning: Could not read credentials from keychain."
|
|
123
|
+
end
|
|
124
|
+
when "file"
|
|
125
|
+
src = File.expand_path("~/.claude/.credentials.json")
|
|
126
|
+
if File.exist?(src)
|
|
127
|
+
FileUtils.cp(src, dest)
|
|
128
|
+
else
|
|
129
|
+
warn "Warning: Credentials file not found at #{src}"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
109
134
|
def setup_container(container, branch)
|
|
110
135
|
home = @config.container_home
|
|
111
136
|
|
|
@@ -125,10 +150,13 @@ module Aircon
|
|
|
125
150
|
"echo 'export GITHUB_PERSONAL_ACCESS_TOKEN=\"#{@config.gh_token}\"' >> /etc/bash.bashrc")
|
|
126
151
|
end
|
|
127
152
|
|
|
128
|
-
if @config.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
153
|
+
if @config.credentials_source == "oauth_token"
|
|
154
|
+
token = @config.claude_code_oauth_token || ENV["CLAUDE_CODE_OAUTH_TOKEN"]
|
|
155
|
+
if token && !token.to_s.empty?
|
|
156
|
+
system("docker", "exec", "-u", "root", container, "bash", "-c",
|
|
157
|
+
"grep -qF 'export CLAUDE_CODE_OAUTH_TOKEN=' /etc/bash.bashrc 2>/dev/null || " \
|
|
158
|
+
"echo 'export CLAUDE_CODE_OAUTH_TOKEN=\"#{token}\"' >> /etc/bash.bashrc")
|
|
159
|
+
end
|
|
132
160
|
end
|
|
133
161
|
|
|
134
162
|
# Configure git and create branch
|
data/lib/aircon/configuration.rb
CHANGED
|
@@ -6,11 +6,13 @@ require "erb"
|
|
|
6
6
|
module Aircon
|
|
7
7
|
class Configuration
|
|
8
8
|
CONFIG_FILE = ".aircon/aircon.yml"
|
|
9
|
+
VALID_CREDENTIALS_SOURCES = %w[keychain file oauth_token].freeze
|
|
9
10
|
|
|
10
11
|
DEFAULTS = {
|
|
11
12
|
"compose_file" => ".aircon/docker-compose.yml",
|
|
12
13
|
"app_name" => nil,
|
|
13
14
|
"gh_token" => nil,
|
|
15
|
+
"credentials_source" => "keychain",
|
|
14
16
|
"claude_code_oauth_token" => nil,
|
|
15
17
|
"workspace_path" => nil,
|
|
16
18
|
"claude_config_path" => "~/.claude.json",
|
|
@@ -22,9 +24,9 @@ module Aircon
|
|
|
22
24
|
"init_script" => ".aircon/aircon_init.sh"
|
|
23
25
|
}.freeze
|
|
24
26
|
|
|
25
|
-
attr_reader :compose_file, :app_name, :gh_token, :
|
|
26
|
-
:claude_config_path, :claude_dir_path, :service, :git_email,
|
|
27
|
-
:container_user, :init_script
|
|
27
|
+
attr_reader :compose_file, :app_name, :gh_token, :credentials_source, :claude_code_oauth_token,
|
|
28
|
+
:workspace_path, :claude_config_path, :claude_dir_path, :service, :git_email,
|
|
29
|
+
:git_name, :container_user, :init_script
|
|
28
30
|
|
|
29
31
|
def initialize(dir: Dir.pwd)
|
|
30
32
|
attrs = DEFAULTS.dup
|
|
@@ -40,6 +42,7 @@ module Aircon
|
|
|
40
42
|
@compose_file = attrs["compose_file"]
|
|
41
43
|
@app_name = attrs["app_name"] || File.basename(dir)
|
|
42
44
|
@gh_token = attrs["gh_token"]
|
|
45
|
+
@credentials_source = attrs["credentials_source"]
|
|
43
46
|
@claude_code_oauth_token = attrs["claude_code_oauth_token"]
|
|
44
47
|
@workspace_path = attrs["workspace_path"] || "/workspace"
|
|
45
48
|
@claude_config_path = attrs["claude_config_path"]
|
|
@@ -49,10 +52,22 @@ module Aircon
|
|
|
49
52
|
@git_name = attrs["git_name"]
|
|
50
53
|
@container_user = attrs["container_user"]
|
|
51
54
|
@init_script = attrs["init_script"]
|
|
55
|
+
|
|
56
|
+
validate!
|
|
52
57
|
end
|
|
53
58
|
|
|
54
59
|
def container_home
|
|
55
60
|
@container_user == "root" ? "/root" : "/home/#{@container_user}"
|
|
56
61
|
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def validate!
|
|
66
|
+
return if VALID_CREDENTIALS_SOURCES.include?(@credentials_source)
|
|
67
|
+
|
|
68
|
+
raise ArgumentError,
|
|
69
|
+
"Invalid credentials_source: #{@credentials_source.inspect}. " \
|
|
70
|
+
"Must be one of: #{VALID_CREDENTIALS_SOURCES.join(', ')}"
|
|
71
|
+
end
|
|
57
72
|
end
|
|
58
73
|
end
|
data/lib/aircon/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aircon
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Philip Nguyen
|
|
@@ -23,6 +23,20 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '1.3'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rake
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
26
40
|
- !ruby/object:Gem::Dependency
|
|
27
41
|
name: rspec
|
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|