diff --git a/lib/sublayer/cli.rb b/lib/sublayer/cli.rb index 5944e81..00019ce 100644 --- a/lib/sublayer/cli.rb +++ b/lib/sublayer/cli.rb @@ -96,7 +96,16 @@ def generate_config_file(project_path, project_name, project_type, ai_provider, ai_model: ai_model } - TTY::File.create_file(File.join(project_path, "lib", project_name, "config", "sublayer.yml"), YAML.dump(config)) + TTY::File.create_file(File.join(project_path, "lib", project_name, "config", "sublayer.yml"), YAML.dump(config)) if project_type == "CLI" + + if project_type == "Quick Script" + config_lines = <<~CONFIG + Sublayer.configuration.ai_provider = Sublayer::Providers::#{config[:ai_provider]} + Sublayer.configuration.ai_model = "#{config[:ai_model]}" + CONFIG + project_file = File.join(project_path, "#{project_name}.rb") + File.write(project_file, File.read(project_file) + config_lines) + end end def project_type_instructions(project_type) @@ -109,7 +118,7 @@ def project_type_instructions(project_type) def replace_placeholders(project_path, project_name) # First rename the lib/PROJECT_NAME directory to lib/project_name - FileUtils.mv(File.join(project_path, "lib", "PROJECT_NAME"), File.join(project_path, "lib", project_name.gsub("-", "_").downcase)) + FileUtils.mv(File.join(project_path, "lib", "PROJECT_NAME"), File.join(project_path, "lib", project_name.gsub("-", "_").downcase)) if File.directory?(File.join(project_path, "lib", "PROJECT_NAME")) # Then walk through each file in the project and replace the placeholder content and filenames Dir.glob("#{project_path}/**/*", File::FNM_DOTMATCH).each do |file_path| @@ -147,10 +156,12 @@ def replace_placeholders(project_path, project_name) end # replace the sublayer version in the gemspec file with Sublayer::VERSION - gemspec_path = File.join(project_path, "#{project_name}.gemspec") - gemspec_content = File.read(gemspec_path) - gemspec_content.gsub!("SUBLAYER_VERSION", Sublayer::VERSION) - File.write(gemspec_path, gemspec_content) + if File.exist?(File.join(project_path, "#{project_name}.gemspec")) + gemspec_path = File.join(project_path, "#{project_name}.gemspec") + gemspec_content = File.read(gemspec_path) + gemspec_content.gsub!("SUBLAYER_VERSION", Sublayer::VERSION) + File.write(gemspec_path, gemspec_content) + end end def finalize_project(project_path, project_type) @@ -167,6 +178,7 @@ def finalize_project(project_path, project_type) puts "To get started, run:" puts " cd #{File.basename(project_path)}" puts " ./bin/#{File.basename(project_path)}" if project_type == "CLI" + puts " ruby #{File.basename(project_path)}.rb" if project_type == "Quick Script" end def display_help diff --git a/lib/sublayer/templates/cli/README.md b/lib/sublayer/templates/cli/README.md index 9bc96ce..77202b0 100644 --- a/lib/sublayer/templates/cli/README.md +++ b/lib/sublayer/templates/cli/README.md @@ -17,7 +17,6 @@ $ bin/PROJECT_NAME ``` Available commands: -- `example`: Run the example agent -- `generate`: Run the example generator +- `example`: Run the example generator - `help`: Display the help message diff --git a/lib/sublayer/templates/quick_script/README.md b/lib/sublayer/templates/quick_script/README.md new file mode 100644 index 0000000..a894635 --- /dev/null +++ b/lib/sublayer/templates/quick_script/README.md @@ -0,0 +1,16 @@ +# ProjectName + +Welcome to your new Sublayer quick script project! + +There are example Agents, Generators, and Actions in the respective folders. + +## Usage + +Create your own custom agents, generators, and actions and use them in +`project_name.rb` + +Run your script: + +``` +$ ruby project_name.rb +``` diff --git a/lib/sublayer/templates/quick_script/actions/example_action.rb b/lib/sublayer/templates/quick_script/actions/example_action.rb new file mode 100644 index 0000000..1f1394a --- /dev/null +++ b/lib/sublayer/templates/quick_script/actions/example_action.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class ExampleAction < Sublayer::Actions::Base + def initialize(input:) + @input = input + end + + def call + puts "Performing action with input: #{@input}" + end +end diff --git a/lib/sublayer/templates/quick_script/agents/example_agent.rb b/lib/sublayer/templates/quick_script/agents/example_agent.rb new file mode 100644 index 0000000..d62fd2e --- /dev/null +++ b/lib/sublayer/templates/quick_script/agents/example_agent.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class ExampleAgent < Sublayer::Agents::Base + trigger_on_files_changed { ["example_file.txt"] } + + goal_condition { @goal_reached } + + check_status do + @status_checked = true + end + + step do + @step_taken = true + @goal_reached = true + puts "Example agent step executed" + end +end diff --git a/lib/sublayer/templates/quick_script/generators/example_generator.rb b/lib/sublayer/templates/quick_script/generators/example_generator.rb new file mode 100644 index 0000000..0fa8016 --- /dev/null +++ b/lib/sublayer/templates/quick_script/generators/example_generator.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class ExampleGenerator < Sublayer::Generators::Base + llm_output_adapter type: :single_string, + name: "generated_text", + description: "A simple generated text" + + def initialize(input:) + @input = input + end + + def generate + super + end + + def prompt + <<-PROMPT + Generate a simple story based on this input: #{@input} + PROMPT + end +end diff --git a/lib/sublayer/templates/quick_script/project_name.rb b/lib/sublayer/templates/quick_script/project_name.rb new file mode 100644 index 0000000..e72608b --- /dev/null +++ b/lib/sublayer/templates/quick_script/project_name.rb @@ -0,0 +1,7 @@ +require "yaml" +require "sublayer" + +Dir[File.join(__dir__, "actions", "*.rb")].each { |file| require file } +Dir[File.join(__dir__, "agents", "*.rb")].each { |file| require file } +Dir[File.join(__dir__, "generators", "*.rb")].each { |file| require file } + diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb index 9dac1ac..7cb6b6b 100644 --- a/spec/cli_spec.rb +++ b/spec/cli_spec.rb @@ -8,7 +8,7 @@ before do allow(TTY::Prompt).to receive(:new).and_return(prompt) allow(prompt).to receive(:ask).and_return("test_project") - allow(prompt).to receive(:select).and_return("Web Service", "OpenAI") + allow(prompt).to receive(:select).and_return("CLI", "OpenAI") allow(prompt).to receive(:yes?).and_return(false) end @@ -32,7 +32,7 @@ describe "#create_new_project" do it "creates a new project with the given name" do - expect(FileUtils).to receive(:mkdir_p) + expect(FileUtils).to receive(:mkdir_p).twice expect(FileUtils).to receive(:cp_r) expect(TTY::File).to receive(:create_file) expect(cli).to receive(:replace_placeholders) diff --git a/spec/integration/quick_script_creation_spec.rb b/spec/integration/quick_script_creation_spec.rb new file mode 100644 index 0000000..aa61b65 --- /dev/null +++ b/spec/integration/quick_script_creation_spec.rb @@ -0,0 +1,45 @@ +require "spec_helper" +require "fileutils" +require "open3" +require "tmpdir" + +TMP_DIR = ENV['RUNNER_TEMP'] || Dir.tmpdir + +RSpec.describe "Quick Script Project Creation" do + let(:project_name) { "test_project" } + let(:project_path) { File.join(TMP_DIR, project_name) } + + before(:all) do + FileUtils.mkdir_p(TMP_DIR) + end + + after(:all) do + FileUtils.rm_rf(TMP_DIR) + end + + after(:each) do + FileUtils.rm_rf(project_path) + end + + it "creates a new project with all the expected files and structures" do + command = "ruby -I lib #{File.dirname(__FILE__)}/../../bin/sublayer new #{project_name}" + input = "\e[B\n\n\nn\n\n" + + output, status = Open3.capture2e(command, chdir: TMP_DIR, stdin_data: input) + + expect(status.success?).to be true + expect(output).to include("Sublayer project '#{project_name}' created successfully!") + + expect(Dir.exist?(project_path)).to be true + + %w[ + test_project.rb + agents/example_agent.rb + generators/example_generator.rb + actions/example_action.rb + README.md + ].each do |file| + expect(File.exist?(File.join(project_path, file))).to be true + end + end +end