summaryrefslogtreecommitdiff
path: root/lua/99/state.lua
blob: b4ac6923c774583901a007c31534651c2f76c56e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
local utils = require("99.utils")
local Agents = require("99.extensions.agents")
local Extensions = require("99.extensions")
local Tracking = require("99.state.tracking")
local Window = require("99.window")

local _99_STATE_FILE = "state"
local function default_completion()
  return { source = nil, custom_rules = {} }
end

--- @class _99.StateProps
--- @field model string
--- @field md_files string[]
--- @field prompts _99.Prompts
--- @field ai_stdout_rows number
--- @field display_errors boolean
--- @field auto_add_skills boolean
--- @field provider_override _99.Providers.BaseProvider | nil
--- @field __view_log_idx number
--- @field __tmp_dir string | nil

--- unanswered question -- will i need to queue messages one at a time or
--- just send them all...  So to prepare ill be sending around this state object
--- @class _99.State
--- @field completion _99.Completion
--- @field model string
--- @field md_files string[]
--- @field prompts _99.Prompts
--- @field ai_stdout_rows number
--- @field display_errors boolean
--- @field provider_override _99.Providers.BaseProvider?
--- @field provider_extra_args string[]
--- @field rules _99.Agents.Rules
--- @field tracking _99.State.Tracking
--- @field __tmp_dir string | nil
local State = {}
State.__index = State

--- @return _99.StateProps
local function create()
  return {
    model = "opencode/claude-sonnet-4-5",
    md_files = {},
    ai_stdout_rows = 3,
    display_errors = false,
    provider_override = nil,
    tmp_dir = nil,
  }
end

--- @param oos _99.Options | _99.State
local function get_tmp_dir(oos)
  local tmp_dir = oos.tmp_dir and type(oos.tmp_dir) == "string" and oos.tmp_dir
    or oos.__tmp_dir and oos.__tmp_dir
    or "./tmp"
  if tmp_dir then
    tmp_dir = vim.fn.expand(tmp_dir)
  end
  return tmp_dir
end

--- @param opts _99.Options
--- @return _99.State.Tracking.Serialized | nil
local function read_state_from_tmp(opts)
  local state_file = utils.named_tmp_file(get_tmp_dir(opts), _99_STATE_FILE)
  return utils.read_file_json_safe(state_file) --[[@as _99.State.Tracking.Serialized]]
end

--- @param opts _99.Options
--- @return _99.State
function State.new(opts)
  local props = create()
  local _99_state = setmetatable(props, State) --[[@as _99.State]]

  _99_state.provider_override = opts.provider
  _99_state.provider_extra_args = opts.provider_extra_args or {}
  _99_state.completion = opts.completion or default_completion()
  _99_state.completion.custom_rules = _99_state.completion.custom_rules or {}
  _99_state.completion.files = _99_state.completion.files or {}

  --- TODO: Prompt overrides would be a great thing, we just have to get there
  --- for now, i am going to have this as just a hardcoded ... thing
  _99_state.prompts = require("99.prompt-settings")

  local previous = read_state_from_tmp(opts)
  _99_state.tracking = Tracking.new(_99_state, previous)

  return _99_state
end

function State:sync()
  local tracking = self.tracking:serialize()
  local tmp = self:tmp_dir()
  local file = utils.named_tmp_file(tmp, _99_STATE_FILE)
  utils.write_file_json_safe(tracking, file)
end

--- @return string
function State:tmp_dir()
  return get_tmp_dir(self)
end

--- @return boolean
function State:active()
  _ = self
  if Window.has_active_window() then
    return true
  end

  local qf = vim.fn.getqflist({ winid = 0 })
  return qf.winid ~= 0
end

--- TODO: This is something to understand.  I bet that this is going to need
--- a lot of performance tuning.  I am just reading every file, and this could
--- take a decent amount of time if there are lots of rules.
---
--- Simple perfs:
--- 1. read 4096 bytes at a tiem instead of whole file and parse out lines
--- 2. don't show the docs
--- 3. do the operation once at setup instead of every time.
---    likely not needed to do this all the time.
function State:refresh_rules()
  self.rules = Agents.rules(self)
  Extensions.refresh(self)
end

return State