summaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
authortheprimeagain <the.primeagen@gmail.com>2026-02-28 08:29:50 -0700
committertheprimeagain <the.primeagen@gmail.com>2026-02-28 08:29:50 -0700
commit06b6a3aef56a49b6af1b2dbd990a2e8df0f93a76 (patch)
tree7a2560b395278c801124426d4ff67d122ec79dd7 /lua
parent79efd670b87057583315fc5c53367c9b37e32247 (diff)
downloada4-06b6a3aef56a49b6af1b2dbd990a2e8df0f93a76.tar.xz
a4-06b6a3aef56a49b6af1b2dbd990a2e8df0f93a76.zip
broken: tracking is almost complete other than testing... the testing is
broken and vibe coded
Diffstat (limited to 'lua')
-rw-r--r--lua/99/init.lua9
-rw-r--r--lua/99/prompt.lua1
-rw-r--r--lua/99/state.lua6
-rw-r--r--lua/99/state/tracking.lua69
-rw-r--r--lua/99/test/tracking_spec.lua86
-rw-r--r--lua/99/window/status-window.lua2
6 files changed, 163 insertions, 10 deletions
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