diff options
| author | theprimeagain <the.primeagen@gmail.com> | 2026-02-28 08:29:50 -0700 |
|---|---|---|
| committer | theprimeagain <the.primeagen@gmail.com> | 2026-02-28 08:29:50 -0700 |
| commit | 06b6a3aef56a49b6af1b2dbd990a2e8df0f93a76 (patch) | |
| tree | 7a2560b395278c801124426d4ff67d122ec79dd7 | |
| parent | 79efd670b87057583315fc5c53367c9b37e32247 (diff) | |
| download | a4-06b6a3aef56a49b6af1b2dbd990a2e8df0f93a76.tar.xz a4-06b6a3aef56a49b6af1b2dbd990a2e8df0f93a76.zip | |
broken: tracking is almost complete other than testing... the testing is
broken and vibe coded
| -rw-r--r-- | TODO.md | 8 | ||||
| -rw-r--r-- | lua/99/init.lua | 9 | ||||
| -rw-r--r-- | lua/99/prompt.lua | 1 | ||||
| -rw-r--r-- | lua/99/state.lua | 6 | ||||
| -rw-r--r-- | lua/99/state/tracking.lua | 69 | ||||
| -rw-r--r-- | lua/99/test/tracking_spec.lua | 86 | ||||
| -rw-r--r-- | lua/99/window/status-window.lua | 2 |
7 files changed, 171 insertions, 10 deletions
@@ -1,3 +1,11 @@ +* marks. I need to think more about marks and qfix lists. When items get shifted around + i want the qfix list to stay as true as possible. so every time one opens, we should + recreate exactly what are the items based on some marks. + * tracking will have to store marks and make them easy to delete based on + request. + * also some impliciation on deserialization. we will need to make sure we keep + track of marks after deserialization + * vibe and search sessions. we sometimes need to call a session and ask for a follow up about what happpened for more changes. * how to get that? * opencode run --format json --agent build -m openai/gpt-5.3-codex "your prompt" > /tmp/opencode.jsonl diff --git a/lua/99/init.lua b/lua/99/init.lua index 797c5a5..743bc75 100644 --- a/lua/99/init.lua +++ b/lua/99/init.lua @@ -283,10 +283,12 @@ function _99.open_tutorial(context) end function _99.open() - local requests = _99_state:requests() + local requests = _99_state.tracking.history local str_requests = {} for _, r in ipairs(requests) do - table.insert(str_requests, r:summary()) + if r.state == "success" then + table.insert(str_requests, r:summary()) + end end for i = 1, #requests do str_requests[i] = string.format("%d: %s", i, requests[i]:summary()) @@ -432,7 +434,7 @@ function _99.stop_all_requests() end function _99.clear_previous_requests() - _99_state:clear_history() + _99_state.tracking:clear_history() end --- if you touch this function you will be fired @@ -457,6 +459,7 @@ function _99.setup(opts) vim.api.nvim_create_autocmd("VimLeavePre", { callback = function() _99.stop_all_requests() + _99_state:sync() end, }) diff --git a/lua/99/prompt.lua b/lua/99/prompt.lua index 326039b..7691244 100644 --- a/lua/99/prompt.lua +++ b/lua/99/prompt.lua @@ -118,6 +118,7 @@ function Prompt.deserialize(_99, data) data = data.data, operation = data.data.type, user_prompt = data.user_prompt, + started_at = Time.now(), xid = get_id(), }, Prompt) assert(prompt:valid(), "prompt is not valid from data") diff --git a/lua/99/state.lua b/lua/99/state.lua index 3a262b1..7d94c07 100644 --- a/lua/99/state.lua +++ b/lua/99/state.lua @@ -59,10 +59,10 @@ local function get_tmp_dir(oos) end --- @param opts _99.Options ---- @return _99.StateProps | nil +--- @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.StateProps]] + return utils.read_file_json_safe(state_file) --[[@as _99.State.Tracking.Serialized]] end --- @param opts _99.Options @@ -81,7 +81,7 @@ function State.new(opts) _99_state.prompts = require("99.prompt-settings") local previous = read_state_from_tmp(opts) - _99_state.tracking = Tracking.new(_99_state) + _99_state.tracking = Tracking.new(_99_state, previous) return _99_state end diff --git a/lua/99/state/tracking.lua b/lua/99/state/tracking.lua index 0e3da08..83b23a0 100644 --- a/lua/99/state/tracking.lua +++ b/lua/99/state/tracking.lua @@ -3,10 +3,25 @@ local Prompt = require("99.prompt") --- @class _99.State.Tracking.Serialized --- @field requests _99.Prompt.Serialized[] +--- @class _99.State.Tracking.Config.Options.Counts +--- @field vibe number | nil +--- @field search number | nil +--- @field tutorial number | nil +--- @field visual number | nil +--- +--- @class _99.State.Tracking.Config.Options +--- @field serialize_counts _99.State.Tracking.Config.Options.Counts | nil + +--- @class _99.State.Tracking.Config +--- @field serialize_counts table<_99.Prompt.Operation, number> + --- @class _99.State.Tracking +--- @docs base --- @field history _99.Prompt[] --- @field id_to_request table<number, _99.Prompt> +--- @field setup fun(opts: _99.State.Tracking.Config.Options): nil local Tracking = {} +Tracking.__index = Tracking --- @param _99 _99.State --- @param previous_state _99.State.Tracking.Serialized | nil @@ -60,7 +75,7 @@ function Tracking:clear_history() self.history = keep end -function Tracking:active_request_count() +function Tracking:active() local count = 0 for _, r in pairs(self.history) do if r.state == "requesting" then @@ -84,13 +99,61 @@ end --- @return _99.State.Tracking.Serialized function Tracking:serialize() - local requests = {} + local sc = Tracking.__config.serialize_count + + --- @type table<_99.Prompt.Operation, _99.Prompt[]> + local all_requests = {} for _, r in ipairs(self.history) do - table.insert(requests, r:serialize()) + local op = r.operation + all_requests[op] = all_requests[op] or {} + if r.state == "success" and sc[op] > 0 then + table.insert(all_requests[op], r) + end + end + for op, _ in pairs(sc) do + local r = all_requests[op] + table.sort(r, function(a, b) + return a.started_at > b.started_at + end) + end + + local requests = {} + for op, max in pairs(sc) do + local count = 0 + for _, request in ipairs(all_requests[op] or {}) do + if count >= max then + break + end + table.insert(requests, request:serialize()) + count = count + 1 + end end + return { requests = requests, } end +Tracking.__config = { + serialize_count = { + vibe = 1, + search = 1, + tutorial = 3, + visual = 0, + }, +} + +--- @param opts _99.State.Tracking.Config.Options +function Tracking.setup(opts) + local config = Tracking.__config + local opts_sa = opts.serialize_counts + if opts_sa then + local sa = config.serialize_count + sa.vibe = opts_sa.vibe or sa.vibe + sa.search = opts_sa.search or sa.search + sa.tutorial = opts_sa.tutorial or sa.tutorial + sa.visual = opts_sa.visual or sa.visual + end +end + return Tracking diff --git a/lua/99/test/tracking_spec.lua b/lua/99/test/tracking_spec.lua new file mode 100644 index 0000000..535f203 --- /dev/null +++ b/lua/99/test/tracking_spec.lua @@ -0,0 +1,86 @@ +-- luacheck: globals describe it assert +local Prompt = require("99.prompt") +local Tracking = require("99.state.tracking") +local eq = assert.are.same + +local function data_for(operation) + if operation == "tutorial" then + return { + type = "tutorial", + xid = 1, + buffer = 0, + window = 0, + tutorial = {}, + } + end + + if operation == "visual" then + return { + type = "visual", + buffer = 0, + file_type = "lua", + range = { + start_row = 1, + start_col = 1, + end_row = 1, + end_col = 1, + }, + } + end + + if operation == "vibe" then + return { + type = "vibe", + response = "", + qfix_items = {}, + } + end + + return { + type = "search", + response = "", + qfix_items = {}, + } +end + +local function track_request(state, operation, started_at, status) + local prompt = Prompt.deserialize(state, { + user_prompt = string.format("%s-%d", operation, started_at), + data = data_for(operation), + }) + prompt.started_at = started_at + prompt.state = status + state.tracking:track(prompt) +end + +describe("tracking", function() + it("serialize respects Tracking.serialized_counts", function() + local state = {} + state.tracking = Tracking.new(state, nil) + + local expected_total = 0 + local started_at = 0 + for operation, count in pairs(Tracking.serialize_counts) do + expected_total = expected_total + count + for _ = 1, count + 2 do + started_at = started_at + 1 + track_request(state, operation, started_at, "success") + end + + started_at = started_at + 1 + track_request(state, operation, started_at, "failed") + end + + local serialized = state.tracking:serialize() + local actual_counts = {} + for _, request in ipairs(serialized.requests) do + local operation = request.data.type + actual_counts[operation] = (actual_counts[operation] or 0) + 1 + end + + eq(expected_total, #serialized.requests) + for operation, count in pairs(Tracking.serialize_counts) do + eq(count, actual_counts[operation] or 0) + end + end) +end) diff --git a/lua/99/window/status-window.lua b/lua/99/window/status-window.lua index d1cc58e..bea4857 100644 --- a/lua/99/window/status-window.lua +++ b/lua/99/window/status-window.lua @@ -98,7 +98,7 @@ function StatusWindow:_run_loop() end local throb = Throbber.new(function(throb) - local count = self._99:active_request_count() + local count = self._99.tracking:active_request_count() local win_valid = Window.valid(win) if count == 0 or not win_valid then |
