agentf 0.4.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3518ac253ce03fcc05439cf5b749bd91e07aea398b15b7870072b3bfe58b0d24
4
- data.tar.gz: f95d3efeee0551c59ed2e8d575a4598ac889872f37bf73987c710064d0ff5ee8
3
+ metadata.gz: 375fdc4ce17f8fe753e2f99a1ac35ee5a4ce2ac8b592812b924a4b755faf7827
4
+ data.tar.gz: 7d45fb33f315c8cd15fb4297556d063603d763fe3a0f9e79906a259f1dac6808
5
5
  SHA512:
6
- metadata.gz: 04703b74db04fac1840b7307100187b40bc33c3873d36ca2b34a92ee389551aa6292702bd494d9d62f4ceb27767e0873a3e8c56e40e75dd5f004cff2cf7d0bfb
7
- data.tar.gz: a4bca497545c5ec43c63b192a2687378328cbd1aa940c99b761d2f30286cb5be2f0e1a4a98e6c1949b0e8ec5960c66fe84c15fa56dcfaa52c12d59243a5e147a
6
+ metadata.gz: 4eb3d691ed13cae8b2780955eb4e059c878f1ad3f219ffe577d439b1695a7d5d3408d6770f2a7d1a3d45e78df678993a882eb130003e4bcc5c5e5759b7508051
7
+ data.tar.gz: 635accb75b7532c51cee21c02a5d54b9df35010e2db3c46efe3e788452cdaca5f9b35bfdc538969227dd0808cf4b3b37d1e0821f73f8c9431f2ec54dca12ea2e
@@ -80,6 +80,7 @@ module Agentf
80
80
 
81
81
  {
82
82
  "success" => true,
83
+ "error" => nil,
83
84
  "analysis" => {
84
85
  "error_type" => analysis.error_type,
85
86
  "possible_causes" => analysis.possible_causes,
@@ -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
@@ -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).each do |root|
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/memory/agentf-redis-schema.md"),
128
- render_opencode_memory_schema
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.json"),
132
- render_opencode_json
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
- return { "path" => path, "status" => "planned" } if @dry_run
208
+ if @dry_run
209
+ return { "path" => path, "status" => "planned" }
210
+ end
155
211
 
156
212
  FileUtils.mkdir_p(File.dirname(path))
157
- File.write(path, payload)
158
- { "path" => path, "status" => "written" }
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:)
@@ -353,12 +417,13 @@ module Agentf
353
417
  end
354
418
 
355
419
  def render_opencode_plugin
356
- <<~TYPESCRIPT
357
- import { execFile } from "node:child_process";
358
- import { promisify } from "node:util";
359
- import path from "node:path";
360
- import { type Plugin, tool } from "@opencode-ai/plugin/tool";
361
- import fs from "node:fs";
420
+ <<~'TYPESCRIPT'
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
- tools: {
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": ["./opencode/plugins/agentf-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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Agentf
4
- VERSION = "0.4.3"
4
+ VERSION = "0.4.5"
5
5
  end
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.3
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-09 00:00:00.000000000 Z
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.0.3.1
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: []