brainiac 0.1.9 → 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 +30 -3
- data/lib/brainiac/ask.rb +95 -0
- data/lib/brainiac/config.rb +7 -0
- data/lib/brainiac/helpers.rb +64 -13
- data/lib/brainiac/version.rb +1 -1
- data/lib/brainiac.rb +1 -0
- data/templates/brainiac.json.example +1 -0
- data/templates/cli-providers/kiro.json.example +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3d90a30fad5756179777b90413b87bbd41550783c75c2e9a38f726e1a2e1ef5c
|
|
4
|
+
data.tar.gz: 32607dc0510acec6449bdb16e8a4acbec358caa94a0d8592d7a6d06e4f73e9a2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1a16401ff3896e546d5411785418228ef5ef2a360dc10fd3633a798723969d90a7d5668d8f8e908856a08bdac35e939519f94bcb79ad6f2f259d0f55dac9c525
|
|
7
|
+
data.tar.gz: 29947e9e2dacd7007a630a06be63e7e8dbc913f9e677b28ccf92a5dcf4c3659c189291c7d07971b42e06c6c0d08880d266854aa759721d701308a415dfdbb79f
|
data/README.md
CHANGED
|
@@ -202,7 +202,7 @@ After setup, `~/.brainiac/` looks like:
|
|
|
202
202
|
|
|
203
203
|
```
|
|
204
204
|
~/.brainiac/
|
|
205
|
-
├── brainiac.json # Core config (default_agent)
|
|
205
|
+
├── brainiac.json # Core config (default_agent, default_cli_provider)
|
|
206
206
|
├── agents.json # Agent registry (tokens, display names, local flag)
|
|
207
207
|
├── projects.json # Registered projects
|
|
208
208
|
├── users.json # Cross-platform user identity registry
|
|
@@ -262,6 +262,31 @@ The `agent_flag` field controls how agent identity is passed to the CLI. Differe
|
|
|
262
262
|
|
|
263
263
|
Set `agent_flag` to `null` to suppress passing the agent name entirely (for CLIs that don't support persona switching).
|
|
264
264
|
|
|
265
|
+
`readonly_args` is optional. It replaces `default_args` when a plugin asks an agent something with `readonly: true` (see [Asking an agent from a plugin](#asking-an-agent-from-a-plugin)), so it must only allow tools that read:
|
|
266
|
+
|
|
267
|
+
| CLI | `readonly_args` |
|
|
268
|
+
|-----|-----------------|
|
|
269
|
+
| Kiro CLI | `chat --no-interactive --trust-tools=fs_read` |
|
|
270
|
+
| Claude Code | `-p --restricted --strict-mcp-config --no-session-persistence --tools Read,Grep,Glob` |
|
|
271
|
+
|
|
272
|
+
A provider without `readonly_args` can't be used read-only; the call fails instead of falling back to `default_args`.
|
|
273
|
+
|
|
274
|
+
Which provider runs is decided in this order: a `[cli:X]` tag, the agent's `cli_provider` in `agents.json`, the project's `cli_provider`, then `default_cli_provider` in `brainiac.json`. With none of those set, brainiac uses the `AGENT_CLI` env var, or kiro-cli.
|
|
275
|
+
|
|
276
|
+
#### Asking an agent from a plugin
|
|
277
|
+
|
|
278
|
+
`run_agent` starts a session and returns straight away. When a plugin needs the agent's answer back (for example to decide whether an incoming report is a bug), it calls `ask_agent`, which waits and returns the reply text:
|
|
279
|
+
|
|
280
|
+
```ruby
|
|
281
|
+
reply = ask_agent(prompt, project_config: PROJECTS["my-app"], project_key: "my-app",
|
|
282
|
+
readonly: true, topic: "bug triage", timeout: 300)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
- The agent and CLI resolve the same way as `run_agent`: `agent_name:`, else the project's `agent_name`, else the default agent.
|
|
286
|
+
- `brain: true` (the default) puts the agent's role, persona and brain knowledge ahead of the prompt. `topic:` seeds the knowledge search.
|
|
287
|
+
- `readonly: true` runs the provider's `readonly_args`. Use it whenever the prompt contains text from outside (webhooks, emails, public forms).
|
|
288
|
+
- It raises `AskAgentError` on a timeout, a CLI failure, or a read-only request to a provider without `readonly_args`.
|
|
289
|
+
|
|
265
290
|
Brainiac ships with example providers during setup. Your project config references which provider to use.
|
|
266
291
|
|
|
267
292
|
#### 3. Environment Variables
|
|
@@ -269,10 +294,12 @@ Brainiac ships with example providers during setup. Your project config referenc
|
|
|
269
294
|
Most config lives in JSON files now. The default agent is set in `brainiac.json`:
|
|
270
295
|
|
|
271
296
|
```json
|
|
272
|
-
{ "default_agent": "Sherlock" }
|
|
297
|
+
{ "default_agent": "Sherlock", "default_cli_provider": "kiro" }
|
|
273
298
|
```
|
|
274
299
|
|
|
275
|
-
|
|
300
|
+
`default_cli_provider` is the CLI used when neither the agent nor the project names one (see [CLI Providers](#2-cli-providers-brainiaccli-providers)).
|
|
301
|
+
|
|
302
|
+
The default agent can also be set via environment variable (takes precedence):
|
|
276
303
|
|
|
277
304
|
```bash
|
|
278
305
|
export AI_AGENT_NAME="Sherlock"
|
data/lib/brainiac/ask.rb
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# ask_agent: a synchronous, one-off agent call for plugins that need the answer back
|
|
4
|
+
# (e.g. deciding whether an incoming report is a bug). run_agent spawns a session and
|
|
5
|
+
# returns before there's any output, so it can't do this.
|
|
6
|
+
|
|
7
|
+
class AskAgentError < StandardError; end
|
|
8
|
+
|
|
9
|
+
ANSI_ESCAPE = %r{\e\[[0-9;?]*[ -/]*[@-~]}
|
|
10
|
+
|
|
11
|
+
# Ask an agent a question and return its reply as text.
|
|
12
|
+
#
|
|
13
|
+
# The agent and CLI resolve the same way run_agent's do: agent_name, else the project's
|
|
14
|
+
# agent_name, else the default agent; cli_provider, else the agent's, the project's, then
|
|
15
|
+
# brainiac.json's default_cli_provider.
|
|
16
|
+
#
|
|
17
|
+
# brain: true puts the agent's role, persona and brain knowledge ahead of the prompt, so the
|
|
18
|
+
# whole agent answers rather than a bare model. topic seeds the knowledge search.
|
|
19
|
+
# readonly: true runs the provider's readonly_args instead of default_args. Raises
|
|
20
|
+
# AskAgentError when the provider has none: text from strangers must never reach an agent
|
|
21
|
+
# that can write files or run commands, so there's no falling back to default_args.
|
|
22
|
+
#
|
|
23
|
+
# Raises AskAgentError when the CLI times out or exits non-zero without a reply.
|
|
24
|
+
def ask_agent(prompt, project_config:, agent_name: nil, chdir: nil, readonly: false, brain: true, topic: "",
|
|
25
|
+
project_key: nil, model: nil, cli_provider: nil, timeout: 300, log_name: "ask")
|
|
26
|
+
agent_name ||= project_config["agent_name"] || AI_AGENT_NAME
|
|
27
|
+
resolved = ask_agent_cli_config(project_config, cli_provider: cli_provider, agent_name: agent_name, readonly: readonly)
|
|
28
|
+
chdir ||= resolved["repo_path"]
|
|
29
|
+
raise AskAgentError, "working directory #{chdir.inspect} doesn't exist" unless chdir && Dir.exist?(chdir)
|
|
30
|
+
|
|
31
|
+
if brain
|
|
32
|
+
context = build_brain_context(agent_name: agent_name, card_title: topic, project_key: project_key)
|
|
33
|
+
prompt = "#{context}\n## Task\n\n#{prompt}" unless context.empty?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
timestamp = Time.now.strftime("%Y%m%d-%H%M%S")
|
|
37
|
+
prompt_file = write_agent_prompt_file(prompt, log_name, timestamp)
|
|
38
|
+
output_file = prepare_output_file(resolved, log_name, timestamp)
|
|
39
|
+
cmd = build_agent_cmd(resolved, agent_config_name: agent_name.downcase.gsub(/[^a-z0-9-]/, "-"),
|
|
40
|
+
model: model || resolved["agent_model"], prompt_file: prompt_file,
|
|
41
|
+
output_file: output_file, chdir: chdir)
|
|
42
|
+
LOG.info "[Ask] #{agent_name} via #{resolved["agent_cli"]}#{" (read-only)" if readonly} in #{chdir}: #{cmd.join(" ")}"
|
|
43
|
+
|
|
44
|
+
stdout = run_ask_command(cmd, prompt_file, resolved, chdir: chdir, env: profile_spawn_env(agent_env_for(agent_name), nil),
|
|
45
|
+
timeout: timeout)
|
|
46
|
+
(read_output_file(output_file) || stdout).gsub(ANSI_ESCAPE, "").strip
|
|
47
|
+
ensure
|
|
48
|
+
FileUtils.rm_f(prompt_file) if prompt_file
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# The resolved CLI config, with readonly_args swapped in for default_args when asked.
|
|
52
|
+
def ask_agent_cli_config(project_config, cli_provider:, agent_name:, readonly:)
|
|
53
|
+
resolved = resolve_project_cli_config(project_config, cli_provider_override: cli_provider, agent_name: agent_name)
|
|
54
|
+
return resolved unless readonly
|
|
55
|
+
|
|
56
|
+
args = resolved["readonly_args"]
|
|
57
|
+
if args.to_s.strip.empty?
|
|
58
|
+
raise AskAgentError, "#{resolved["agent_cli"]} has no readonly_args in its cli-providers config, " \
|
|
59
|
+
"so it can't be run read-only"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
resolved.merge("agent_cli_args" => args)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Run the CLI and return its stdout. Kills the whole process group on timeout so the
|
|
66
|
+
# CLI's own children (tool calls, MCP servers) go with it.
|
|
67
|
+
def run_ask_command(cmd, prompt_file, resolved, chdir:, env:, timeout:)
|
|
68
|
+
stdin_data = resolved["prompt_mode"] == "flag" ? "" : File.read(prompt_file)
|
|
69
|
+
Open3.popen3(env, *cmd, chdir: chdir, pgroup: true) do |stdin, stdout, stderr, wait|
|
|
70
|
+
readers = [Thread.new { stdout.read }, Thread.new { stderr.read }]
|
|
71
|
+
begin
|
|
72
|
+
stdin.write(stdin_data)
|
|
73
|
+
rescue Errno::EPIPE
|
|
74
|
+
nil # CLI exited before reading the prompt; its exit status says why.
|
|
75
|
+
end
|
|
76
|
+
stdin.close
|
|
77
|
+
|
|
78
|
+
unless wait.join(timeout)
|
|
79
|
+
begin
|
|
80
|
+
Process.kill("TERM", -wait.pid)
|
|
81
|
+
rescue Errno::ESRCH
|
|
82
|
+
nil # Finished just as the clock ran out.
|
|
83
|
+
end
|
|
84
|
+
readers.each(&:join) # The kill closes the pipes, so these return.
|
|
85
|
+
raise AskAgentError, "#{resolved["agent_cli"]} timed out after #{timeout}s"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
out, err = readers.map(&:value)
|
|
89
|
+
if !wait.value.success? && out.strip.empty?
|
|
90
|
+
raise AskAgentError, "#{resolved["agent_cli"]} exited #{wait.value.exitstatus}: #{err.strip.lines.last(5).join}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
out
|
|
94
|
+
end
|
|
95
|
+
end
|
data/lib/brainiac/config.rb
CHANGED
|
@@ -80,6 +80,13 @@ end
|
|
|
80
80
|
|
|
81
81
|
AI_AGENT_NAME = resolve_default_agent
|
|
82
82
|
|
|
83
|
+
# --- Default CLI provider ---
|
|
84
|
+
# Last fallback for which CLI runs an agent, after the agent's and the project's
|
|
85
|
+
# cli_provider. Unset → DEFAULT_PROJECT's AGENT_CLI env var / kiro-cli.
|
|
86
|
+
def default_cli_provider
|
|
87
|
+
BRAINIAC_CONFIG["default_cli_provider"]
|
|
88
|
+
end
|
|
89
|
+
|
|
83
90
|
LOG_LEVEL = ENV.fetch("LOG_LEVEL", "info").downcase
|
|
84
91
|
LOG = Logger.new($stdout)
|
|
85
92
|
LOG.level = case LOG_LEVEL
|
data/lib/brainiac/helpers.rb
CHANGED
|
@@ -32,7 +32,7 @@ def load_cli_provider(provider_name)
|
|
|
32
32
|
config["prompt_mode"] = raw["prompt_mode"] || "stdin"
|
|
33
33
|
# Copy optional fields from raw config when present.
|
|
34
34
|
# Each field controls a specific CLI behavior — see comments in the template.
|
|
35
|
-
%w[prompt_flag list_models_command resume_flag resume_args resume_id_flag new_session_id_flag
|
|
35
|
+
%w[prompt_flag readonly_args list_models_command resume_flag resume_args resume_id_flag new_session_id_flag
|
|
36
36
|
session_list_command session_id_field session_directory_field session_updated_field
|
|
37
37
|
session_list_path session_dir output_last_message_flag cwd_flag config_override_flag
|
|
38
38
|
effort_config_key effort_map title_flag heaviness_probe settings_model_cmd].each do |key|
|
|
@@ -76,12 +76,14 @@ end
|
|
|
76
76
|
require_relative "model_parser"
|
|
77
77
|
|
|
78
78
|
# Resolve CLI config for a project by merging provider defaults with project overrides.
|
|
79
|
-
# Priority: cli_provider_override > agent-level cli_provider > project-level cli_provider >
|
|
79
|
+
# Priority: cli_provider_override > agent-level cli_provider > project-level cli_provider >
|
|
80
|
+
# brainiac.json default_cli_provider > DEFAULT_PROJECT
|
|
80
81
|
def resolve_project_cli_config(project_config, cli_provider_override: nil, agent_name: nil)
|
|
81
|
-
# Determine which CLI provider to use (priority: override > agent > project)
|
|
82
|
+
# Determine which CLI provider to use (priority: override > agent > project > default)
|
|
82
83
|
provider_name = cli_provider_override
|
|
83
84
|
provider_name ||= agent_cli_provider_for(agent_name) if agent_name
|
|
84
85
|
provider_name ||= project_config["cli_provider"]
|
|
86
|
+
provider_name ||= default_cli_provider
|
|
85
87
|
|
|
86
88
|
provider_config = load_cli_provider(provider_name)
|
|
87
89
|
|
|
@@ -704,9 +706,11 @@ def prior_session_exists?(chdir, agent_cli, session_dir: nil)
|
|
|
704
706
|
return true if File.directory?(session_dir_local)
|
|
705
707
|
|
|
706
708
|
# Fallback: look for recent session logs in tmp/ that suggest this CLI ran here before.
|
|
707
|
-
# This covers CLIs that don't leave a dotdir but do leave logs via brainiac.
|
|
709
|
+
# This covers CLIs that don't leave a dotdir but do leave logs via brainiac. The logs
|
|
710
|
+
# don't say which CLI wrote them, so only trust them when the last-CLI marker says it was this one.
|
|
708
711
|
tmp_dir = File.join(chdir, "tmp")
|
|
709
712
|
return false unless File.directory?(tmp_dir)
|
|
713
|
+
return false unless last_cli_for(chdir) == cli_name
|
|
710
714
|
|
|
711
715
|
Dir.glob(File.join(tmp_dir, "agent-*.log")).any? do |log|
|
|
712
716
|
# Only count logs from the last 24 hours as valid "resumable" sessions
|
|
@@ -716,6 +720,40 @@ rescue StandardError
|
|
|
716
720
|
false
|
|
717
721
|
end
|
|
718
722
|
|
|
723
|
+
# Marker recording which CLI binary last ran in a directory (written by run_agent).
|
|
724
|
+
def last_cli_marker_path(chdir)
|
|
725
|
+
File.join(chdir, "tmp", ".brainiac-last-cli")
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
def last_cli_for(chdir)
|
|
729
|
+
return nil unless chdir
|
|
730
|
+
|
|
731
|
+
name = File.read(last_cli_marker_path(chdir)).strip
|
|
732
|
+
name.empty? ? nil : name
|
|
733
|
+
rescue StandardError
|
|
734
|
+
nil
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
def record_last_cli(chdir, agent_cli)
|
|
738
|
+
key = cli_session_key(agent_cli)
|
|
739
|
+
return unless chdir && key
|
|
740
|
+
|
|
741
|
+
FileUtils.mkdir_p(File.join(chdir, "tmp"))
|
|
742
|
+
File.write(last_cli_marker_path(chdir), key)
|
|
743
|
+
rescue StandardError => e
|
|
744
|
+
LOG.warn "[Dispatch] Could not record last CLI for #{chdir}: #{e.message}"
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
# True when a different CLI ran in this directory more recently than agent_cli.
|
|
748
|
+
# A switched-to CLI never saw the other provider's turns, so resuming its own (older)
|
|
749
|
+
# session would hand it a lean prompt with a stale or empty history. Start fresh instead
|
|
750
|
+
# and let the full prompt (memory file + source context) carry the conversation.
|
|
751
|
+
def cli_switched_since_last_run?(chdir, agent_cli)
|
|
752
|
+
last = last_cli_for(chdir)
|
|
753
|
+
key = cli_session_key(agent_cli)
|
|
754
|
+
!last.nil? && !key.nil? && last != key
|
|
755
|
+
end
|
|
756
|
+
|
|
719
757
|
# Check if a centralized session directory has sessions matching the given cwd.
|
|
720
758
|
# Supports CLIs that store sessions as .jsonl files in date-partitioned directories (YYYY/MM/DD/)
|
|
721
759
|
# with a first-line JSON metadata object containing a "payload.cwd" field.
|
|
@@ -777,6 +815,7 @@ end
|
|
|
777
815
|
def resume_viable?(project_config:, cli_provider: nil, agent_name: nil, chdir: nil)
|
|
778
816
|
resolved = resolve_project_cli_config(project_config, cli_provider_override: cli_provider, agent_name: agent_name)
|
|
779
817
|
chdir ||= resolved["repo_path"]
|
|
818
|
+
return false if cli_switched_since_last_run?(chdir, resolved["agent_cli"])
|
|
780
819
|
return stored_cli_session_viable?(resolved, chdir) if resolved["resume_id_flag"]
|
|
781
820
|
return false unless resolved["resume_flag"] || resolved["resume_args"]
|
|
782
821
|
|
|
@@ -805,6 +844,11 @@ end
|
|
|
805
844
|
def resolve_resume(resume, resolved, chdir, session_id: nil)
|
|
806
845
|
return false unless resume
|
|
807
846
|
|
|
847
|
+
if cli_switched_since_last_run?(chdir, resolved["agent_cli"])
|
|
848
|
+
LOG.info "[Dispatch] CLI switched from #{last_cli_for(chdir)} to #{resolved["agent_cli"]} in #{chdir} — starting fresh session"
|
|
849
|
+
return false
|
|
850
|
+
end
|
|
851
|
+
|
|
808
852
|
if resolved["resume_id_flag"]
|
|
809
853
|
id = session_id.to_s.empty? ? cli_session_id_for(agent_cli: resolved["agent_cli"], worktree: chdir) : session_id
|
|
810
854
|
if id.to_s.empty?
|
|
@@ -824,16 +868,27 @@ def resolve_resume(resume, resolved, chdir, session_id: nil)
|
|
|
824
868
|
false
|
|
825
869
|
end
|
|
826
870
|
|
|
827
|
-
# Some CLIs (e.g. grok --session-id) let the caller name a new session up front.
|
|
828
|
-
# Mint a UUID
|
|
829
|
-
|
|
871
|
+
# Some CLIs (e.g. claude/grok --session-id) let the caller name a new session up front.
|
|
872
|
+
# Mint a UUID whenever we start fresh — including after a provider switch, when an older
|
|
873
|
+
# stored id exists — so the stored id always points at the latest session for this CLI.
|
|
874
|
+
def mint_cli_session_id(resolved, resuming:)
|
|
830
875
|
return nil if resuming
|
|
831
876
|
return nil unless resolved["new_session_id_flag"]
|
|
832
|
-
return nil unless stored_session.to_s.empty?
|
|
833
877
|
|
|
834
878
|
SecureRandom.uuid
|
|
835
879
|
end
|
|
836
880
|
|
|
881
|
+
# Decide resume vs. fresh start for this dispatch, then record this CLI as the last
|
|
882
|
+
# one to run here. Returns [should_resume, minted_session_id].
|
|
883
|
+
def prepare_cli_session(resume, resolved, chdir)
|
|
884
|
+
stored_session = cli_session_id_for(agent_cli: resolved["agent_cli"], worktree: chdir)
|
|
885
|
+
# Auto-resume: only if the provider supports it AND a prior session exists for this CLI here.
|
|
886
|
+
should_resume = resolve_resume(resume, resolved, chdir, session_id: stored_session)
|
|
887
|
+
minted_session_id = mint_cli_session_id(resolved, resuming: should_resume)
|
|
888
|
+
record_last_cli(chdir, resolved["agent_cli"])
|
|
889
|
+
[should_resume, minted_session_id]
|
|
890
|
+
end
|
|
891
|
+
|
|
837
892
|
# Check if intent detection says to skip dispatching the agent.
|
|
838
893
|
# Returns true if the message should be skipped, false otherwise.
|
|
839
894
|
# Only runs if a raw message is provided, an agent is named, and intent is enabled.
|
|
@@ -870,12 +925,8 @@ def run_agent(prompt, project_config:, chdir: nil, log_name: "agent", model: nil
|
|
|
870
925
|
effort ||= resolved["agent_effort"]
|
|
871
926
|
agent_config_name = agent_name&.downcase&.gsub(/[^a-z0-9-]/, "-")
|
|
872
927
|
|
|
873
|
-
stored_session = cli_session_id_for(agent_cli: resolved["agent_cli"], worktree: chdir)
|
|
874
928
|
work_item_id = find_work_item_by_worktree(chdir)&.first
|
|
875
|
-
|
|
876
|
-
# Auto-resume: only if the provider supports it AND a prior session exists for this CLI here.
|
|
877
|
-
should_resume = resolve_resume(resume, resolved, chdir, session_id: stored_session)
|
|
878
|
-
minted_session_id = mint_cli_session_id(resolved, stored_session: stored_session, resuming: should_resume)
|
|
929
|
+
should_resume, minted_session_id = prepare_cli_session(resume, resolved, chdir)
|
|
879
930
|
|
|
880
931
|
# Pre-dispatch hook — plugins can prep the working directory (e.g., copy config files, clean up)
|
|
881
932
|
Brainiac.emit(:pre_dispatch, chdir: chdir, project_config: project_config, agent_name: agent_name)
|
data/lib/brainiac/version.rb
CHANGED
data/lib/brainiac.rb
CHANGED
|
@@ -9,6 +9,7 @@ require_relative "brainiac/sessions"
|
|
|
9
9
|
require_relative "brainiac/session_history"
|
|
10
10
|
require_relative "brainiac/prompts"
|
|
11
11
|
require_relative "brainiac/helpers"
|
|
12
|
+
require_relative "brainiac/ask"
|
|
12
13
|
require_relative "brainiac/intent"
|
|
13
14
|
require_relative "brainiac/cron"
|
|
14
15
|
require_relative "brainiac/plugins"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: brainiac
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andy Davis
|
|
@@ -126,6 +126,7 @@ files:
|
|
|
126
126
|
- docs/waybar-config.md
|
|
127
127
|
- lib/brainiac.rb
|
|
128
128
|
- lib/brainiac/agents.rb
|
|
129
|
+
- lib/brainiac/ask.rb
|
|
129
130
|
- lib/brainiac/brain.rb
|
|
130
131
|
- lib/brainiac/config.rb
|
|
131
132
|
- lib/brainiac/cron.rb
|