brainiac 0.0.27 → 0.0.29
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/Gemfile.lock +2 -2
- data/README.md +14 -3
- data/bin/brainiac +163 -12
- data/docs/resume.md +87 -0
- data/lib/brainiac/cron.rb +3 -1
- data/lib/brainiac/handlers/shared/belt.rb +409 -0
- data/lib/brainiac/handlers/shared/git.rb +52 -27
- data/lib/brainiac/helpers.rb +221 -32
- data/lib/brainiac/intent.rb +1 -1
- data/lib/brainiac/model_parser.rb +109 -0
- data/lib/brainiac/version.rb +1 -1
- data/monitor/waybar/session_slot.rb +1 -3
- data/receiver.rb +4 -0
- data/templates/cli-providers/codex.json.example +32 -0
- data/templates/cli-providers/grok.json.example +1 -0
- data/templates/cli-providers/kiro.json.example +1 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 37f135fffb0c94919fa376fee96e12053af77062f93dadc520cce7285ee86e78
|
|
4
|
+
data.tar.gz: 553b10319590bde4fee8f89cf227059fec83d750d6ad7188d56aa5243a6cf169
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e04d26de1e9010e175b69032358e400223af29ffabde834e48b206d6cff58340fe1082262b36843fe6995aff752df2ed053793a78f416cc47d1dd4b47b881a99
|
|
7
|
+
data.tar.gz: fe32e3768064d1728a2b28d40aef900c1afb454d04e192b67a9e4f631bf117a147ebef547898709ead380b286336dee64da8a40b62cf6f10b7a327ca1bb3d505
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
brainiac (0.0.
|
|
4
|
+
brainiac (0.0.29)
|
|
5
5
|
puma (~> 7.2)
|
|
6
6
|
rackup (~> 2.3)
|
|
7
7
|
sinatra (~> 4.1)
|
|
@@ -84,7 +84,7 @@ DEPENDENCIES
|
|
|
84
84
|
CHECKSUMS
|
|
85
85
|
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
|
|
86
86
|
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
|
87
|
-
brainiac (0.0.
|
|
87
|
+
brainiac (0.0.29)
|
|
88
88
|
json (2.19.9) sha256=9b9025b7cdddafa38d316eca0b2358488e42d417045c1b90d216a9fefe46b79a
|
|
89
89
|
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
|
|
90
90
|
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
|
data/README.md
CHANGED
|
@@ -226,12 +226,23 @@ Configure which AI CLI to use for dispatching agents. Each provider is a JSON fi
|
|
|
226
226
|
|
|
227
227
|
```json
|
|
228
228
|
{
|
|
229
|
-
"
|
|
230
|
-
"
|
|
231
|
-
"
|
|
229
|
+
"binary": "kiro-cli",
|
|
230
|
+
"default_args": "chat --trust-all-tools --no-interactive",
|
|
231
|
+
"agent_flag": "--agent",
|
|
232
|
+
"model_flag": "--model"
|
|
232
233
|
}
|
|
233
234
|
```
|
|
234
235
|
|
|
236
|
+
The `agent_flag` field controls how agent identity is passed to the CLI. Different CLIs use different flags:
|
|
237
|
+
|
|
238
|
+
| CLI | `agent_flag` | Example command |
|
|
239
|
+
|-----|-------------|-----------------|
|
|
240
|
+
| Kiro CLI | `"--agent"` | `kiro-cli --agent sherlock chat --no-interactive` |
|
|
241
|
+
| Codex CLI | `"--profile"` | `codex --profile sherlock exec --sandbox workspace-write -` |
|
|
242
|
+
| Grok CLI | `null` | `grok --always-approve` (no agent identity passed) |
|
|
243
|
+
|
|
244
|
+
Set `agent_flag` to `null` to suppress passing the agent name entirely (for CLIs that don't support persona switching).
|
|
245
|
+
|
|
235
246
|
Brainiac ships with example providers during setup. Your project config references which provider to use.
|
|
236
247
|
|
|
237
248
|
#### 3. Environment Variables
|
data/bin/brainiac
CHANGED
|
@@ -205,6 +205,7 @@ def wait_for_agents_to_finish
|
|
|
205
205
|
end
|
|
206
206
|
end
|
|
207
207
|
|
|
208
|
+
# rubocop:disable Naming/PredicateMethod
|
|
208
209
|
def stop_server
|
|
209
210
|
pid = find_server_pid
|
|
210
211
|
|
|
@@ -245,6 +246,7 @@ def stop_server
|
|
|
245
246
|
false
|
|
246
247
|
end
|
|
247
248
|
end
|
|
249
|
+
# rubocop:enable Naming/PredicateMethod
|
|
248
250
|
|
|
249
251
|
# Kill a single process: TERM first, KILL if it doesn't exit within 5s.
|
|
250
252
|
def kill_pid(pid, quiet: false)
|
|
@@ -1025,6 +1027,9 @@ def brain_list
|
|
|
1025
1027
|
puts "Run 'brainiac brain init <agent-name>' to set up a new agent."
|
|
1026
1028
|
end
|
|
1027
1029
|
|
|
1030
|
+
# Model output parsing (shared with lib/brainiac/helpers.rb)
|
|
1031
|
+
require_relative "../lib/brainiac/model_parser"
|
|
1032
|
+
|
|
1028
1033
|
# Main CLI
|
|
1029
1034
|
options = {}
|
|
1030
1035
|
subcommand = ARGV.shift
|
|
@@ -1940,6 +1945,150 @@ when "provider"
|
|
|
1940
1945
|
File.write(file, JSON.pretty_generate(scaffold))
|
|
1941
1946
|
puts "Created #{file} — edit it to configure the provider."
|
|
1942
1947
|
|
|
1948
|
+
when "list-models"
|
|
1949
|
+
name = ARGV[0]
|
|
1950
|
+
unless name
|
|
1951
|
+
puts "Usage: brainiac provider list-models <name>"
|
|
1952
|
+
exit 1
|
|
1953
|
+
end
|
|
1954
|
+
file = File.join(providers_dir, "#{name}.json")
|
|
1955
|
+
unless File.exist?(file)
|
|
1956
|
+
puts "Provider '#{name}' not found."
|
|
1957
|
+
exit 1
|
|
1958
|
+
end
|
|
1959
|
+
data = JSON.parse(File.read(file))
|
|
1960
|
+
command = data["list_models_command"]
|
|
1961
|
+
if command.nil? || command.empty?
|
|
1962
|
+
puts "Provider '#{name}' has no list_models_command configured."
|
|
1963
|
+
puts "Edit #{file} and set \"list_models_command\" to a shell command that lists models."
|
|
1964
|
+
puts "Example: \"kiro-cli chat --list-models --format json\""
|
|
1965
|
+
exit 1
|
|
1966
|
+
end
|
|
1967
|
+
|
|
1968
|
+
puts "Querying models from '#{name}' (#{command})..."
|
|
1969
|
+
puts ""
|
|
1970
|
+
stdout, stderr, status = Open3.capture3(command)
|
|
1971
|
+
unless status.success?
|
|
1972
|
+
puts "Command failed (exit #{status.exitstatus}):"
|
|
1973
|
+
puts stderr.strip unless stderr.empty?
|
|
1974
|
+
exit 1
|
|
1975
|
+
end
|
|
1976
|
+
|
|
1977
|
+
models = parse_list_models_output(stdout)
|
|
1978
|
+
if models.nil? || models.empty?
|
|
1979
|
+
puts "No models found in command output."
|
|
1980
|
+
puts "Raw output:"
|
|
1981
|
+
puts stdout
|
|
1982
|
+
exit 1
|
|
1983
|
+
end
|
|
1984
|
+
|
|
1985
|
+
# Filter hidden models (e.g. codex "visibility": "hide") unless none are visible
|
|
1986
|
+
visible_models = models.select { |m| m["visibility"].nil? || m["visibility"] != "hide" }
|
|
1987
|
+
visible_models = models if visible_models.empty?
|
|
1988
|
+
|
|
1989
|
+
# Display models in a table
|
|
1990
|
+
default_model = data["default_model"]
|
|
1991
|
+
# Determine default: explicit default_model field > parsed "default" flag > first model
|
|
1992
|
+
has_explicit_default = default_model && visible_models.any? { |m| m["model_id"] == default_model }
|
|
1993
|
+
has_parsed_default = !has_explicit_default && visible_models.any? { |m| m["default"] }
|
|
1994
|
+
puts "Available models for '#{name}' (#{visible_models.size} visible, #{models.size} total):"
|
|
1995
|
+
puts ""
|
|
1996
|
+
visible_models.each do |m|
|
|
1997
|
+
model_id = m["model_id"] || "unknown"
|
|
1998
|
+
desc = m["description"] || m["display_name"] || ""
|
|
1999
|
+
rate = m["rate_multiplier"] ? "#{m["rate_multiplier"]}x" : (m["rate"] || "")
|
|
2000
|
+
marker = if has_explicit_default
|
|
2001
|
+
m["model_id"] == default_model ? "*" : " "
|
|
2002
|
+
elsif has_parsed_default
|
|
2003
|
+
m["default"] ? "*" : " "
|
|
2004
|
+
else
|
|
2005
|
+
m == visible_models.first ? "*" : " "
|
|
2006
|
+
end
|
|
2007
|
+
if desc.empty?
|
|
2008
|
+
puts " #{marker} #{model_id}"
|
|
2009
|
+
else
|
|
2010
|
+
puts format(" %<marker>s %-25<model>s %-15<rate>s %<desc>s", marker: marker, model: model_id, rate: rate, desc: desc)
|
|
2011
|
+
end
|
|
2012
|
+
end
|
|
2013
|
+
|
|
2014
|
+
# Show which are mapped vs unmapped
|
|
2015
|
+
configured = data["models"] || {}
|
|
2016
|
+
configured_ids = configured.values
|
|
2017
|
+
unmapped = visible_models.select do |m|
|
|
2018
|
+
id = m["model_id"]
|
|
2019
|
+
!configured_ids.include?(id) && !configured.key?(id)
|
|
2020
|
+
end
|
|
2021
|
+
unless unmapped.empty?
|
|
2022
|
+
puts ""
|
|
2023
|
+
puts "#{unmapped.size} model(s) not in your provider's 'models' map:"
|
|
2024
|
+
unmapped.each { |m| puts " - #{m["model_id"]}" }
|
|
2025
|
+
puts ""
|
|
2026
|
+
puts "Run 'brainiac provider sync-models #{name}' to add them."
|
|
2027
|
+
end
|
|
2028
|
+
|
|
2029
|
+
when "sync-models"
|
|
2030
|
+
name = ARGV[0]
|
|
2031
|
+
unless name
|
|
2032
|
+
puts "Usage: brainiac provider sync-models <name>"
|
|
2033
|
+
exit 1
|
|
2034
|
+
end
|
|
2035
|
+
file = File.join(providers_dir, "#{name}.json")
|
|
2036
|
+
unless File.exist?(file)
|
|
2037
|
+
puts "Provider '#{name}' not found."
|
|
2038
|
+
exit 1
|
|
2039
|
+
end
|
|
2040
|
+
data = JSON.parse(File.read(file))
|
|
2041
|
+
command = data["list_models_command"]
|
|
2042
|
+
if command.nil? || command.empty?
|
|
2043
|
+
puts "Provider '#{name}' has no list_models_command configured."
|
|
2044
|
+
exit 1
|
|
2045
|
+
end
|
|
2046
|
+
|
|
2047
|
+
stdout, stderr, status = Open3.capture3(command)
|
|
2048
|
+
unless status.success?
|
|
2049
|
+
puts "Command failed (exit #{status.exitstatus}): #{stderr.strip}"
|
|
2050
|
+
exit 1
|
|
2051
|
+
end
|
|
2052
|
+
|
|
2053
|
+
models = parse_list_models_output(stdout)
|
|
2054
|
+
if models.nil? || models.empty?
|
|
2055
|
+
puts "No models found in command output."
|
|
2056
|
+
exit 1
|
|
2057
|
+
end
|
|
2058
|
+
|
|
2059
|
+
# Build a models map from discovered models: key = short name, value = model_id
|
|
2060
|
+
existing_models = data["models"] || {}
|
|
2061
|
+
new_models = existing_models.dup
|
|
2062
|
+
added = []
|
|
2063
|
+
|
|
2064
|
+
models.each do |m|
|
|
2065
|
+
model_id = m["model_id"]
|
|
2066
|
+
next unless model_id
|
|
2067
|
+
|
|
2068
|
+
# Skip hidden models (e.g. codex internal models)
|
|
2069
|
+
next if m["visibility"] == "hide"
|
|
2070
|
+
|
|
2071
|
+
# Skip if already mapped (as key or value)
|
|
2072
|
+
next if new_models.value?(model_id) || new_models.key?(model_id)
|
|
2073
|
+
|
|
2074
|
+
# Generate a short key: strip common prefixes, use the base name
|
|
2075
|
+
short_key = generate_short_model_key(model_id)
|
|
2076
|
+
# If the short key already exists, use the full model_id as the key
|
|
2077
|
+
short_key = model_id if new_models.key?(short_key)
|
|
2078
|
+
new_models[short_key] = model_id
|
|
2079
|
+
added << "#{short_key} => #{model_id}"
|
|
2080
|
+
end
|
|
2081
|
+
|
|
2082
|
+
if added.empty?
|
|
2083
|
+
puts "All discovered models are already mapped. Nothing to sync."
|
|
2084
|
+
exit 0
|
|
2085
|
+
end
|
|
2086
|
+
|
|
2087
|
+
data["models"] = new_models
|
|
2088
|
+
File.write(file, JSON.pretty_generate(data))
|
|
2089
|
+
puts "Synced #{added.size} new model(s) to #{file}:"
|
|
2090
|
+
added.each { |a| puts " + #{a}" }
|
|
2091
|
+
|
|
1943
2092
|
else
|
|
1944
2093
|
puts <<~HELP
|
|
1945
2094
|
Usage: brainiac provider <command>
|
|
@@ -1948,6 +2097,8 @@ when "provider"
|
|
|
1948
2097
|
list List configured CLI providers
|
|
1949
2098
|
show <name> Show provider configuration
|
|
1950
2099
|
add <name> Create a new provider config
|
|
2100
|
+
list-models <name> Query available models from the CLI provider
|
|
2101
|
+
sync-models <name> Add discovered models to provider config
|
|
1951
2102
|
HELP
|
|
1952
2103
|
end
|
|
1953
2104
|
|
|
@@ -3474,7 +3625,7 @@ when "plugin"
|
|
|
3474
3625
|
gem_name = "brainiac-#{plugin_name}"
|
|
3475
3626
|
|
|
3476
3627
|
# Determine the base repo path (strip worktree suffix like --branch-name)
|
|
3477
|
-
base_path = current_path.sub(
|
|
3628
|
+
base_path = current_path.sub(%r{--[^/]+$}, "")
|
|
3478
3629
|
unless Dir.exist?(base_path)
|
|
3479
3630
|
puts "Error: Base repo not found at #{base_path}"
|
|
3480
3631
|
exit 1
|
|
@@ -3503,9 +3654,7 @@ when "plugin"
|
|
|
3503
3654
|
# Fetch latest to make sure the branch is available
|
|
3504
3655
|
puts "Fetching latest from origin..."
|
|
3505
3656
|
_out, _err, fetch_status = Open3.capture3("git", "fetch", "origin", chdir: base_path)
|
|
3506
|
-
unless fetch_status.success?
|
|
3507
|
-
puts "Warning: git fetch failed — continuing with local state."
|
|
3508
|
-
end
|
|
3657
|
+
puts "Warning: git fetch failed — continuing with local state." unless fetch_status.success?
|
|
3509
3658
|
|
|
3510
3659
|
# Check if a worktree already exists for this branch
|
|
3511
3660
|
worktree_list, _, wt_status = Open3.capture3("git", "worktree", "list", "--porcelain", chdir: base_path)
|
|
@@ -3513,18 +3662,19 @@ when "plugin"
|
|
|
3513
3662
|
|
|
3514
3663
|
if wt_status.success?
|
|
3515
3664
|
# Parse porcelain output to find worktrees on the target branch
|
|
3516
|
-
|
|
3665
|
+
worktree_blocks = worktree_list.split("\n\n").map do |block|
|
|
3517
3666
|
wt = {}
|
|
3518
3667
|
block.each_line do |line|
|
|
3519
3668
|
case line
|
|
3520
3669
|
when /^worktree (.+)/
|
|
3521
3670
|
wt[:path] = Regexp.last_match(1).strip
|
|
3522
|
-
when
|
|
3671
|
+
when %r{^branch refs/heads/(.+)}
|
|
3523
3672
|
wt[:branch] = Regexp.last_match(1).strip
|
|
3524
3673
|
end
|
|
3525
3674
|
end
|
|
3526
3675
|
wt
|
|
3527
|
-
end
|
|
3676
|
+
end
|
|
3677
|
+
worktrees = worktree_blocks.select { |wt| wt[:path] && wt[:branch] }
|
|
3528
3678
|
|
|
3529
3679
|
target_worktree = worktrees.find { |wt| wt[:branch] == branch_name }
|
|
3530
3680
|
end
|
|
@@ -3541,11 +3691,9 @@ when "plugin"
|
|
|
3541
3691
|
File.write(plugins_file, JSON.pretty_generate(plugins_config))
|
|
3542
3692
|
puts "✓ Switched plugin '#{plugin_name}' to branch '#{branch_name}'"
|
|
3543
3693
|
puts " Path: #{new_path}"
|
|
3544
|
-
puts " Restart the server to apply: brainiac restart"
|
|
3545
3694
|
else
|
|
3546
3695
|
# Check if branch exists remotely or locally
|
|
3547
|
-
|
|
3548
|
-
check_cmd, _, check_status = Open3.capture3("git", "rev-parse", "--verify", "origin/#{branch_name}", chdir: base_path)
|
|
3696
|
+
_, _, check_status = Open3.capture3("git", "rev-parse", "--verify", "origin/#{branch_name}", chdir: base_path)
|
|
3549
3697
|
branch_exists = check_status.success?
|
|
3550
3698
|
|
|
3551
3699
|
unless branch_exists
|
|
@@ -3576,7 +3724,10 @@ when "plugin"
|
|
|
3576
3724
|
_, _, local_check = Open3.capture3("git", "rev-parse", "--verify", branch_name, chdir: base_path)
|
|
3577
3725
|
if !local_check.success? && check_status.success?
|
|
3578
3726
|
# Remote branch exists but not local — create tracking branch in worktree
|
|
3579
|
-
_, stderr, wt_status = Open3.capture3(
|
|
3727
|
+
_, stderr, wt_status = Open3.capture3(
|
|
3728
|
+
"git", "worktree", "add", "--track", "-b", branch_name, worktree_dir,
|
|
3729
|
+
"origin/#{branch_name}", chdir: base_path
|
|
3730
|
+
)
|
|
3580
3731
|
else
|
|
3581
3732
|
# Local branch exists — use it directly
|
|
3582
3733
|
_, stderr, wt_status = Open3.capture3("git", "worktree", "add", worktree_dir, branch_name, chdir: base_path)
|
|
@@ -3592,8 +3743,8 @@ when "plugin"
|
|
|
3592
3743
|
File.write(plugins_file, JSON.pretty_generate(plugins_config))
|
|
3593
3744
|
puts "✓ Switched plugin '#{plugin_name}' to branch '#{branch_name}'"
|
|
3594
3745
|
puts " Worktree: #{worktree_dir}"
|
|
3595
|
-
puts " Restart the server to apply: brainiac restart"
|
|
3596
3746
|
end
|
|
3747
|
+
puts " Restart the server to apply: brainiac restart"
|
|
3597
3748
|
|
|
3598
3749
|
else
|
|
3599
3750
|
puts "Usage: brainiac plugin <command>"
|
data/docs/resume.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Resume Session Integration
|
|
2
|
+
|
|
3
|
+
Brainiac supports resuming prior agent sessions instead of starting fresh. Two patterns exist:
|
|
4
|
+
|
|
5
|
+
## Flag-Based Resume (e.g. Kiro `--resume`, Grok `-c`)
|
|
6
|
+
|
|
7
|
+
The CLI appends a flag to the existing command. The base command structure stays the same.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
kiro-cli --agent sherlock chat --trust-all-tools --no-interactive --resume
|
|
11
|
+
grok --always-approve -c
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Provider config:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"resume_flag": "--resume"
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Subcommand-Based Resume (e.g. Codex `exec resume --last`)
|
|
23
|
+
|
|
24
|
+
The CLI changes the subcommand entirely. The base command structure is replaced.
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
codex exec --full-auto → codex exec resume --last --full-auto
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Provider config:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"resume_flag": null,
|
|
35
|
+
"resume_args": "exec resume --last --full-auto",
|
|
36
|
+
"session_dir": "~/.codex/sessions"
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
When `resume_args` is set, it replaces `default_args` entirely during resume. The `session_dir` field tells Brainiac where to look for prior sessions (for CLIs that store session state centrally rather than in the project directory).
|
|
41
|
+
|
|
42
|
+
## Plugin Integration Contract
|
|
43
|
+
|
|
44
|
+
Plugins that want to support resume MUST:
|
|
45
|
+
|
|
46
|
+
1. **Use `resume_viable?`** to check whether a session can be resumed:
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
can_resume = resume_viable?(project_config: config, chdir: worktree_path)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
2. **Pass `resume: true` to `run_agent`** — core handles the rest:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
run_agent(prompt, project_config: config, chdir: worktree_path, resume: can_resume)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Plugins MUST NOT:
|
|
59
|
+
- Check `resolved["resume_flag"]` directly (misses `resume_args` providers)
|
|
60
|
+
- Call `resolve_resume` directly (internal to `run_agent`)
|
|
61
|
+
- Build their own resume command logic
|
|
62
|
+
|
|
63
|
+
## How It Works Internally
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
Plugin calls run_agent(..., resume: true)
|
|
67
|
+
→ run_agent calls resolve_resume(true, resolved, chdir)
|
|
68
|
+
→ resolve_resume checks resume_flag OR resume_args is configured
|
|
69
|
+
→ resolve_resume calls prior_session_exists?(chdir, cli, session_dir:)
|
|
70
|
+
→ For centralized session dirs: scans .jsonl files for matching cwd
|
|
71
|
+
→ For local session dirs: checks for .grok/, .kiro-cli/, or recent logs
|
|
72
|
+
→ Returns :resume_args, flag string, or false
|
|
73
|
+
→ run_agent passes result to build_agent_cmd
|
|
74
|
+
→ :resume_args → replace default_args with resume_args
|
|
75
|
+
→ String flag → append to command
|
|
76
|
+
→ false → normal command (no resume)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Session Detection
|
|
80
|
+
|
|
81
|
+
### Local (flag-based CLIs)
|
|
82
|
+
|
|
83
|
+
Checks for CLI-specific dotdirs (`.grok/`, `.kiro-cli/`) or recent agent logs in `tmp/` (last 24 hours).
|
|
84
|
+
|
|
85
|
+
### Centralized (subcommand-based CLIs)
|
|
86
|
+
|
|
87
|
+
Scans `session_dir` for `.jsonl` files modified in the last 24 hours whose first-line JSON metadata contains a `payload.cwd` matching the target working directory. Handles symlink resolution (e.g. `/var/folders` vs `/private/var/folders` on macOS).
|
data/lib/brainiac/cron.rb
CHANGED
|
@@ -596,10 +596,12 @@ def build_cron_agent_cmd(job, project, prompt_file: nil)
|
|
|
596
596
|
resolved = resolve_project_cli_config(project, agent_name: job[:agent])
|
|
597
597
|
agent_flag = resolved.key?("agent_flag") ? resolved["agent_flag"] : "--agent"
|
|
598
598
|
cmd = [resolved["agent_cli"]]
|
|
599
|
+
# cwd_flag: pass the working directory as a CLI argument (e.g. -C for Codex CLI).
|
|
600
|
+
cmd.push(resolved["cwd_flag"], project["repo_path"]) if resolved["cwd_flag"] && project["repo_path"]
|
|
599
601
|
cmd.push(agent_flag, agent_config_name) if agent_flag
|
|
600
602
|
cmd.concat(resolved["agent_cli_args"].split)
|
|
601
603
|
cmd.push(resolved["agent_model_flag"], job[:model]) if resolved["agent_model_flag"]&.length&.positive? && job[:model]
|
|
602
|
-
cmd
|
|
604
|
+
append_effort_to_cmd(cmd, job[:effort], resolved)
|
|
603
605
|
cmd.push(resolved["prompt_flag"], prompt_file) if prompt_file && resolved["prompt_mode"] == "flag" && resolved["prompt_flag"]
|
|
604
606
|
cmd
|
|
605
607
|
end
|