agentf 0.4.4 → 0.4.5
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/agentf/agents/debugger.rb +1 -0
- data/lib/agentf/cli/install.rb +10 -1
- data/lib/agentf/installer.rb +151 -16
- data/lib/agentf/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 375fdc4ce17f8fe753e2f99a1ac35ee5a4ce2ac8b592812b924a4b755faf7827
|
|
4
|
+
data.tar.gz: 7d45fb33f315c8cd15fb4297556d063603d763fe3a0f9e79906a259f1dac6808
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4eb3d691ed13cae8b2780955eb4e059c878f1ad3f219ffe577d439b1695a7d5d3408d6770f2a7d1a3d45e78df678993a882eb130003e4bcc5c5e5759b7508051
|
|
7
|
+
data.tar.gz: 635accb75b7532c51cee21c02a5d54b9df35010e2db3c46efe3e788452cdaca5f9b35bfdc538969227dd0808cf4b3b37d1e0821f73f8c9431f2ec54dca12ea2e
|
data/lib/agentf/cli/install.rb
CHANGED
|
@@ -16,6 +16,7 @@ module Agentf
|
|
|
16
16
|
global_root: Dir.home,
|
|
17
17
|
local_root: Dir.pwd,
|
|
18
18
|
dry_run: false,
|
|
19
|
+
install_deps: true,
|
|
19
20
|
only_agents: nil,
|
|
20
21
|
only_commands: nil
|
|
21
22
|
}
|
|
@@ -32,7 +33,9 @@ module Agentf
|
|
|
32
33
|
installer = Agentf::Installer.new(
|
|
33
34
|
global_root: @options[:global_root],
|
|
34
35
|
local_root: @options[:local_root],
|
|
35
|
-
dry_run: @options[:dry_run]
|
|
36
|
+
dry_run: @options[:dry_run],
|
|
37
|
+
install_deps: @options[:install_deps],
|
|
38
|
+
verbose: @options.fetch(:verbose, false)
|
|
36
39
|
)
|
|
37
40
|
|
|
38
41
|
results = installer.install(
|
|
@@ -66,6 +69,9 @@ module Agentf
|
|
|
66
69
|
scope_val = parse_single_option(args, "--scope=") || parse_single_option(args, "-s=")
|
|
67
70
|
@options[:scope] = scope_val.downcase if scope_val
|
|
68
71
|
|
|
72
|
+
# Extract --install-deps flag
|
|
73
|
+
@options[:install_deps] = !args.delete("--install-deps").nil?
|
|
74
|
+
|
|
69
75
|
# Extract --global-root and --local-root
|
|
70
76
|
global_root = parse_single_option(args, "--global-root=")
|
|
71
77
|
@options[:global_root] = File.expand_path(global_root) if global_root
|
|
@@ -83,6 +89,9 @@ module Agentf
|
|
|
83
89
|
if command_val
|
|
84
90
|
@options[:only_commands] = command_val.split(",").map { |item| item.strip.downcase }.reject(&:empty?)
|
|
85
91
|
end
|
|
92
|
+
|
|
93
|
+
# Extract --verbose flag
|
|
94
|
+
@options[:verbose] = !args.delete("--verbose").nil?
|
|
86
95
|
end
|
|
87
96
|
|
|
88
97
|
def show_help
|
data/lib/agentf/installer.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "fileutils"
|
|
4
4
|
require "yaml"
|
|
5
|
+
require "open3"
|
|
6
|
+
require "json"
|
|
5
7
|
|
|
6
8
|
module Agentf
|
|
7
9
|
class Installer
|
|
@@ -44,10 +46,12 @@ module Agentf
|
|
|
44
46
|
}
|
|
45
47
|
}.freeze
|
|
46
48
|
|
|
47
|
-
def initialize(global_root: Dir.home, local_root: Dir.pwd, dry_run: false)
|
|
49
|
+
def initialize(global_root: Dir.home, local_root: Dir.pwd, dry_run: false, verbose: false, install_deps: true)
|
|
48
50
|
@global_root = global_root
|
|
49
51
|
@local_root = local_root
|
|
50
52
|
@dry_run = dry_run
|
|
53
|
+
@verbose = verbose
|
|
54
|
+
@install_deps = install_deps
|
|
51
55
|
end
|
|
52
56
|
|
|
53
57
|
def install(
|
|
@@ -74,14 +78,62 @@ module Agentf
|
|
|
74
78
|
end
|
|
75
79
|
|
|
76
80
|
writes = []
|
|
77
|
-
roots_for(scope)
|
|
81
|
+
roots = roots_for(scope)
|
|
82
|
+
roots.each do |root|
|
|
78
83
|
writes.concat(write_agents(root: root, layout: layout, provider: provider, only_agents: only_agents))
|
|
79
84
|
writes.concat(write_commands(root: root, layout: layout, provider: provider, only_commands: only_commands))
|
|
80
85
|
writes.concat(write_opencode_helpers(root: root)) if provider.to_s == "opencode"
|
|
81
86
|
end
|
|
87
|
+
|
|
88
|
+
# Optionally install dependencies for opencode helper package.json
|
|
89
|
+
if provider.to_s == "opencode" && @install_deps
|
|
90
|
+
roots.each do |root|
|
|
91
|
+
package_json_path = File.join(root, ".opencode/package.json")
|
|
92
|
+
if @dry_run
|
|
93
|
+
# In dry-run, report that package.json would be written/installed
|
|
94
|
+
writes << write_manifest(package_json_path, render_opencode_package_json)
|
|
95
|
+
else
|
|
96
|
+
result = install_deps_in(root)
|
|
97
|
+
writes << result if result
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
82
102
|
writes
|
|
83
103
|
end
|
|
84
104
|
|
|
105
|
+
def install_deps_in(root)
|
|
106
|
+
pkg_dir = File.join(root, ".opencode")
|
|
107
|
+
pkg_json = File.join(pkg_dir, "package.json")
|
|
108
|
+
unless File.exist?(pkg_json)
|
|
109
|
+
warn "No .opencode/package.json at #{pkg_json}, skipping install" if @verbose
|
|
110
|
+
return { "path" => pkg_json, "status" => "skipped", "reason" => "missing package.json" }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
managers = [
|
|
114
|
+
{ cmd: ["bun", "install"], check: ["bun", "--version"] },
|
|
115
|
+
{ cmd: ["npm", "install"], check: ["npm", "--version"] },
|
|
116
|
+
{ cmd: ["yarn", "install"], check: ["yarn", "--version"] }
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
managers.each do |m|
|
|
120
|
+
stdout, stderr, status = Open3.capture3(*m[:check])
|
|
121
|
+
next unless status.success?
|
|
122
|
+
|
|
123
|
+
puts "Running #{m[:cmd].first} install in #{pkg_dir}" if @verbose
|
|
124
|
+
out, err, st = Open3.capture3(*m[:cmd], chdir: pkg_dir)
|
|
125
|
+
if st.success?
|
|
126
|
+
puts out if @verbose && !out.to_s.strip.empty?
|
|
127
|
+
return { "path" => pkg_dir, "status" => "installed", "manager" => m[:cmd].first }
|
|
128
|
+
else
|
|
129
|
+
warn "Install with #{m[:cmd].first} failed: #{err}" unless @verbose
|
|
130
|
+
return { "path" => pkg_dir, "status" => "error", "manager" => m[:cmd].first, "error" => err }
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
{ "path" => pkg_dir, "status" => "no_manager_found" }
|
|
135
|
+
end
|
|
136
|
+
|
|
85
137
|
def roots_for(scope)
|
|
86
138
|
case scope
|
|
87
139
|
when "global"
|
|
@@ -124,13 +176,15 @@ module Agentf
|
|
|
124
176
|
render_opencode_plugin
|
|
125
177
|
)
|
|
126
178
|
writes << write_manifest(
|
|
127
|
-
File.join(root, ".opencode/
|
|
128
|
-
|
|
179
|
+
File.join(root, ".opencode/tsconfig.json"),
|
|
180
|
+
render_opencode_tsconfig
|
|
129
181
|
)
|
|
182
|
+
writes << write_package_json(root)
|
|
130
183
|
writes << write_manifest(
|
|
131
|
-
File.join(root, "opencode.
|
|
132
|
-
|
|
184
|
+
File.join(root, ".opencode/memory/agentf-redis-schema.md"),
|
|
185
|
+
render_opencode_memory_schema
|
|
133
186
|
)
|
|
187
|
+
writes << write_opencode_json(root)
|
|
134
188
|
writes
|
|
135
189
|
end
|
|
136
190
|
|
|
@@ -151,11 +205,21 @@ module Agentf
|
|
|
151
205
|
end
|
|
152
206
|
|
|
153
207
|
def write_manifest(path, payload)
|
|
154
|
-
|
|
208
|
+
if @dry_run
|
|
209
|
+
return { "path" => path, "status" => "planned" }
|
|
210
|
+
end
|
|
155
211
|
|
|
156
212
|
FileUtils.mkdir_p(File.dirname(path))
|
|
157
|
-
|
|
158
|
-
|
|
213
|
+
begin
|
|
214
|
+
File.write(path, payload)
|
|
215
|
+
if @verbose
|
|
216
|
+
puts "WROTE: #{path}"
|
|
217
|
+
end
|
|
218
|
+
{ "path" => path, "status" => "written" }
|
|
219
|
+
rescue StandardError => e
|
|
220
|
+
warn "ERROR writing #{path}: #{e.message}"
|
|
221
|
+
{ "path" => path, "status" => "error", "error" => e.message }
|
|
222
|
+
end
|
|
159
223
|
end
|
|
160
224
|
|
|
161
225
|
def render_agent_manifest(klass, provider:)
|
|
@@ -354,11 +418,12 @@ module Agentf
|
|
|
354
418
|
|
|
355
419
|
def render_opencode_plugin
|
|
356
420
|
<<~'TYPESCRIPT'
|
|
357
|
-
|
|
358
|
-
import {
|
|
359
|
-
import
|
|
360
|
-
import
|
|
361
|
-
import
|
|
421
|
+
// tools:
|
|
422
|
+
import { execFile } from "child_process";
|
|
423
|
+
import { promisify } from "util";
|
|
424
|
+
import path from "path";
|
|
425
|
+
import { type Plugin, tool } from "@opencode-ai/plugin";
|
|
426
|
+
import fs from "fs";
|
|
362
427
|
|
|
363
428
|
const execFileAsync = promisify(execFile);
|
|
364
429
|
|
|
@@ -495,7 +560,7 @@ module Agentf
|
|
|
495
560
|
await ensureAgentfPreflight(process.env.PWD || process.cwd());
|
|
496
561
|
|
|
497
562
|
return {
|
|
498
|
-
|
|
563
|
+
tool: {
|
|
499
564
|
"agentf-code-glob": tool({
|
|
500
565
|
description: "Find files using project glob patterns via Agentf code CLI.",
|
|
501
566
|
args: {
|
|
@@ -632,11 +697,81 @@ module Agentf
|
|
|
632
697
|
<<~JSON
|
|
633
698
|
{
|
|
634
699
|
"$schema": "https://opencode.ai/config.json",
|
|
635
|
-
"plugin": ["
|
|
700
|
+
"plugin": ["./.opencode/plugins/agentf-plugin"]
|
|
636
701
|
}
|
|
637
702
|
JSON
|
|
638
703
|
end
|
|
639
704
|
|
|
705
|
+
def write_opencode_json(root)
|
|
706
|
+
path = File.join(root, "opencode.json")
|
|
707
|
+
new_content = JSON.parse(render_opencode_json)
|
|
708
|
+
|
|
709
|
+
return write_manifest(path, JSON.pretty_generate(new_content)) unless File.exist?(path)
|
|
710
|
+
|
|
711
|
+
begin
|
|
712
|
+
existing = JSON.parse(File.read(path))
|
|
713
|
+
rescue StandardError => e
|
|
714
|
+
warn "Failed to parse existing opencode.json: #{e.message}"
|
|
715
|
+
return write_manifest(path, JSON.pretty_generate(new_content))
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
merged = existing.dup
|
|
719
|
+
merged_plugins = Array(existing["plugin"]) + Array(new_content["plugin"])
|
|
720
|
+
merged["plugin"] = merged_plugins.uniq
|
|
721
|
+
|
|
722
|
+
write_manifest(path, JSON.pretty_generate(merged))
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
def render_opencode_tsconfig
|
|
726
|
+
<<~JSON
|
|
727
|
+
{
|
|
728
|
+
"compilerOptions": {
|
|
729
|
+
"target": "ESNext",
|
|
730
|
+
"module": "ESNext",
|
|
731
|
+
"moduleResolution": "bundler",
|
|
732
|
+
"types": ["node"],
|
|
733
|
+
"strict": true,
|
|
734
|
+
"skipLibCheck": true,
|
|
735
|
+
"baseUrl": ".",
|
|
736
|
+
"paths": {
|
|
737
|
+
"@opencode-ai/plugin": ["./node_modules/@opencode-ai/plugin"]
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
"include": ["plugins/**/*.ts"]
|
|
741
|
+
}
|
|
742
|
+
JSON
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
def render_opencode_package_json
|
|
746
|
+
<<~JSON
|
|
747
|
+
{
|
|
748
|
+
"name": "agentf-opencode-helpers",
|
|
749
|
+
"private": true,
|
|
750
|
+
"dependencies": {
|
|
751
|
+
"@opencode-ai/plugin": "^1.2.24"
|
|
752
|
+
},
|
|
753
|
+
"devDependencies": {
|
|
754
|
+
"@types/node": "^25.4.0"
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
JSON
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
def write_package_json(root)
|
|
761
|
+
package_json_path = File.join(root, ".opencode/package.json")
|
|
762
|
+
new_content = render_opencode_package_json
|
|
763
|
+
return write_manifest(package_json_path, new_content) unless File.exist?(package_json_path)
|
|
764
|
+
|
|
765
|
+
existing = JSON.parse(File.read(package_json_path))
|
|
766
|
+
new_package_json = JSON.parse(new_content)
|
|
767
|
+
|
|
768
|
+
merged = existing.dup
|
|
769
|
+
merged["dependencies"] = (existing["dependencies"] || {}).merge(new_package_json["dependencies"] || {})
|
|
770
|
+
merged["devDependencies"] = (existing["devDependencies"] || {}).merge(new_package_json["devDependencies"] || {})
|
|
771
|
+
|
|
772
|
+
write_manifest(package_json_path, JSON.pretty_generate(merged))
|
|
773
|
+
end
|
|
774
|
+
|
|
640
775
|
def render_opencode_memory_schema
|
|
641
776
|
<<~MARKDOWN
|
|
642
777
|
# Redis Memory Schema
|
data/lib/agentf/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: agentf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Neal Deters
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: redis
|
|
@@ -86,7 +86,7 @@ description: |2
|
|
|
86
86
|
Redis-backed semantic, episodic, and graph-style memory. It includes a
|
|
87
87
|
unified CLI, MCP server tools, and install/update workflows for generated
|
|
88
88
|
agent/command manifests.
|
|
89
|
-
email:
|
|
89
|
+
email:
|
|
90
90
|
executables:
|
|
91
91
|
- agentf
|
|
92
92
|
extensions: []
|
|
@@ -147,7 +147,7 @@ metadata:
|
|
|
147
147
|
homepage_uri: https://github.com/nealdeters/agentf
|
|
148
148
|
source_code_uri: https://github.com/nealdeters/agentf
|
|
149
149
|
rubygems_mfa_required: 'true'
|
|
150
|
-
post_install_message:
|
|
150
|
+
post_install_message:
|
|
151
151
|
rdoc_options: []
|
|
152
152
|
require_paths:
|
|
153
153
|
- lib
|
|
@@ -162,8 +162,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
162
162
|
- !ruby/object:Gem::Version
|
|
163
163
|
version: '0'
|
|
164
164
|
requirements: []
|
|
165
|
-
rubygems_version: 3.
|
|
166
|
-
signing_key:
|
|
165
|
+
rubygems_version: 3.5.22
|
|
166
|
+
signing_key:
|
|
167
167
|
specification_version: 4
|
|
168
168
|
summary: Ruby multi-agent workflow engine with Redis memory
|
|
169
169
|
test_files: []
|