Packages
fnord
0.5.5
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/cmd/index/notes.ex
defmodule Cmd.Index.Notes do
# ----------------------------------------------------------------------------
# Options
# ----------------------------------------------------------------------------
defp defrag?(idx), do: Map.get(idx.opts, :defrag_notes, false)
# -----------------------------------------------------------------------------
# Notes clean up
# -----------------------------------------------------------------------------
def defrag(idx) do
if defrag?(idx) do
original_notes = get_notes(idx)
original_count = Enum.count(original_notes)
with {:ok, consolidated} <- consolidate_saved_notes(idx, original_notes),
{:ok, fact_checked} <- fact_check_saved_notes(idx, consolidated),
:ok <- confirm_updated_notes(idx, fact_checked, original_count) do
save_updated_notes(idx, fact_checked)
else
:aborted -> UI.warn("Defragmenting notes", "Aborted at user request")
error -> UI.warn("Defragmenting notes", inspect(error))
end
end
end
defp get_notes(idx) do
idx.project
|> Store.Project.notes()
|> Enum.reduce([], fn note, acc ->
with {:ok, text} <- Store.Project.Note.read_note(note) do
[text | acc]
else
_ -> acc
end
end)
|> Enum.reverse()
end
defp confirm_updated_notes(_idx, notes, original_count) do
new_count = Enum.count(notes)
difference =
((new_count - original_count) / original_count * 100)
|> Float.round(0)
|> trunc()
|> abs()
IO.puts("# Defragmented Notes")
notes
|> Enum.each(fn note ->
with {:ok, {topic, facts}} <- Store.Project.Note.parse_string(note) do
IO.puts("\n## #{topic}")
facts
|> Enum.map(&"- #{&1}")
|> Enum.each(&IO.puts/1)
else
{:error, :invalid_format, type} ->
msg = "Invalid note format (improperly formatted #{to_string(type)}: #{note}"
IO.puts(:stderr, msg)
IO.puts(:stderr, "Cancelling defragmentation")
end
end)
IO.puts("""
/-----------------------------------------------------------
| There is a #{difference}% change in note count:
| * Original: #{original_count}
| * Updated: #{new_count}
\-----------------------------------------------------------
""")
if UI.confirm("Replace your saved notes with the updated list?") do
:ok
else
:aborted
end
end
defp save_updated_notes(idx, notes) do
count = Enum.count(notes)
Cmd.Index.UI.spin("Updating notes", fn ->
{:ok, queue} =
Queue.start_link(fn text ->
idx.project
|> Store.Project.Note.new()
|> Store.Project.Note.write(text)
end)
UI.report_step("Clearing old notes")
Store.Project.reset_notes(idx.project)
# queue files
UI.report_step("Saving consolidated notes")
Enum.each(notes, &Queue.queue(queue, &1))
# wait on queue to complete
Queue.shutdown(queue)
Queue.join(queue)
{"#{count} notes saved", :ok}
end)
UI.info("Notes saved.")
end
defp validate_notes(notes_string) do
notes_string
|> parse_topic_list()
|> Enum.reduce_while([], fn text, acc ->
if Store.Project.Note.is_valid_format?(text) do
{:cont, [text | acc]}
else
{:halt, :invalid_format}
end
end)
|> case do
:invalid_format -> {:error, :invalid_format}
notes -> {:ok, notes}
end
end
defp parse_topic_list(input_str) do
input_str
|> String.trim("```")
|> String.trim("'''")
|> String.trim("\"\"\"")
|> String.trim()
|> String.split("\n")
|> Enum.map(&String.trim/1)
end
# ----------------------------------------------------------------------------
# Consolidating saved notes
# ----------------------------------------------------------------------------
defp consolidate_saved_notes(_idx, []) do
UI.info("Consolidating prior research", "Nothing to do")
{:ok, []}
end
defp consolidate_saved_notes(_idx, original_notes) do
original_count = Enum.count(original_notes)
UI.report_step("Consolidating prior research", "Analyzing #{original_count} notes")
with args = %{notes: original_notes},
{:ok, consolidated} <- AI.Agent.NotesConsolidator.get_response(AI.new(), args),
{:ok, notes} <- validate_notes(consolidated) do
{:ok, notes}
end
end
# ----------------------------------------------------------------------------
# Fact-checking
# ----------------------------------------------------------------------------
defp fact_check_saved_notes(_idx, []) do
UI.info("Fact-checking prior research", "Nothing to do")
{:ok, []}
end
defp fact_check_saved_notes(_idx, original_notes) do
original_count = Enum.count(original_notes)
UI.report_step("Fact-checking prior research", "Analyzing #{original_count} notes")
with args = %{notes: original_notes},
{:ok, consolidated} <- AI.Agent.NotesVerifier.get_response(AI.new(), args),
{:ok, notes} <- validate_notes(consolidated) do
{:ok, notes}
end
end
end