Packages
fnord
0.4.8
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/fnord.ex
defmodule Fnord do
@moduledoc """
Fnord is a code search tool that uses OpenAI's embeddings API to index and
search code files.
"""
@doc """
Main entry point for the application. Parses command line arguments and
dispatches to the appropriate subcommand.
"""
def main(args) do
with {:ok, subcommand, opts} <- parse_options(args) do
case subcommand do
:index -> Indexer.new(opts) |> Indexer.run()
:search -> Search.run(opts)
:summary -> Summary.run(opts)
:torch -> Indexer.new(opts) |> Indexer.delete_project()
:projects -> Store.list_projects() |> Enum.each(&IO.puts(&1))
:files -> Store.new(opts.project) |> Store.list_files() |> Enum.each(&IO.puts(&1))
:watch -> Watch.run(opts)
:chat -> Chat.new(opts) |> Chat.run()
end
else
{:error, reason} -> IO.puts("Error: #{reason}")
end
end
defp parse_options(args) do
project = [
value_name: "PROJECT",
long: "--project",
short: "-p",
help: "Project name",
required: true
]
directory = [
value_name: "DIR",
long: "--dir",
short: "-d",
help: "Directory to index",
required: true
]
reindex = [
long: "--reindex",
short: "-r",
help: "Reindex the project",
default: false,
multiple: false
]
quiet = [
long: "--quiet",
short: "-q",
help: "Suppress informational output",
default: false,
multiple: false
]
query = [
value_name: "QUERY",
long: "--query",
short: "-q",
help: "Search query",
required: true
]
limit = [
value_name: "LIMIT",
long: "--limit",
short: "-l",
help: "Limit the number of results",
default: 10
]
detail = [
long: "--detail",
help: "Include AI-generated file summary",
default: false,
multiple: false
]
file = [
value_name: "FILE",
long: "--file",
short: "-f",
help: "File to summarize",
required: true
]
concurrency = [
value_name: "CONCURRENCY",
long: "--concurrency",
short: "-c",
help: "Number of concurrent threads to use",
default: 4
]
parser =
Optimus.new!(
name: "fnord",
description: "fnord - intelligent code index and search",
about: "Index and search code files",
allow_unknown_args: false,
version: get_version(),
subcommands: [
projects: [
name: "projects",
about: "List all projects",
options: []
],
files: [
name: "files",
about: "List files in a project",
options: [
project: project
]
],
torch: [
name: "torch",
about: "Delete a previously indexed project from the database",
options: [
project: project
]
],
index: [
name: "index",
about: "Index the directory",
options: [
directory: directory,
project: project,
concurrency: concurrency
],
flags: [
reindex: reindex,
quiet: quiet
]
],
search: [
name: "search",
about: "Search in the project",
options: [
project: project,
query: query,
limit: limit,
concurrency: concurrency
],
flags: [
detail: detail
]
],
summary: [
name: "summary",
about: "Get a summary of a file from the project index",
options: [
project: project,
file: file
]
],
watch: [
name: "watch",
about: "Watch for changes in the project directory using Watchman",
options: [
directory: directory,
project: project
]
],
chat: [
name: "chat",
about: "Conversational interface to the project database",
options: [
project: project,
concurrency: concurrency
]
]
]
)
with {[subcommand], result} <- Optimus.parse!(parser, args) do
options =
result.args
|> Map.merge(result.options)
|> Map.merge(result.flags)
{:ok, subcommand, options}
else
_ -> {:error, "missing or unknown subcommand"}
end
end
defp get_version do
{:ok, vsn} = :application.get_key(:fnord, :vsn)
to_string(vsn)
end
end