docs/refactor: add AI disclosure and clean up code style

This commit is contained in:
2026-04-18 00:00:45 +02:00
parent 4f2ce0349c
commit 56ccfe63b6
5 changed files with 50 additions and 31 deletions

View File

@@ -53,3 +53,10 @@ Place a `.jasper_config.json` file at the root of the project (next to `.git`):
4. The timer is **started**. A libuv countdown is armed; after `inactivity_timeout` minutes of silence the timer is **paused**. 4. The timer is **started**. A libuv countdown is armed; after `inactivity_timeout` minutes of silence the timer is **paused**.
5. Any cursor movement or keystroke resets the countdown (and resumes the timer if it was paused). 5. Any cursor movement or keystroke resets the countdown (and resumes the timer if it was paused).
6. On `VimLeave` the timer is **stopped**. 6. On `VimLeave` the timer is **stopped**.
$
## AI Disclosure
This project was written entirely with the assistance of
[GitHub Copilot](https://github.com/features/copilot) using the
**Claude Sonnet 4.6** model.

View File

@@ -12,9 +12,6 @@ local JASPER_URL = "https://jasper.4sigma.it"
--- @return string|nil error message --- @return string|nil error message
local function curl(args) local function curl(args)
-- Append -w to get the HTTP status on a separate last line -- Append -w to get the HTTP status on a separate last line
local full_args = vim.list_extend(vim.list_slice(args, 1), { "-s", "-w", "\n%{http_code}" })
-- args already contains the URL; rebuild properly:
-- Actually we receive the full arg list already. Add -w trick.
table.insert(args, "-w") table.insert(args, "-w")
table.insert(args, "\n%{http_code}") table.insert(args, "\n%{http_code}")
@@ -41,7 +38,8 @@ end
local function get(path, token) local function get(path, token)
return curl({ return curl({
"curl", "curl",
"-H", "Authorization: Token " .. token, "-H",
"Authorization: Token " .. token,
JASPER_URL .. path, JASPER_URL .. path,
}) })
end end
@@ -52,8 +50,11 @@ end
--- @return table|nil, number, string|nil --- @return table|nil, number, string|nil
local function post(path, token, form) local function post(path, token, form)
local args = { local args = {
"curl", "-X", "POST", "curl",
"-H", "Authorization: Token " .. token, "-X",
"POST",
"-H",
"Authorization: Token " .. token,
} }
if form then if form then
for k, v in pairs(form) do for k, v in pairs(form) do
@@ -84,6 +85,9 @@ function M.get_timers(token)
if status ~= 200 then if status ~= 200 then
return nil, "unexpected HTTP status " .. status return nil, "unexpected HTTP status " .. status
end end
if not data then
return nil, "empty response"
end
local timers_dict = data.data and data.data.timers local timers_dict = data.data and data.data.timers
if type(timers_dict) ~= "table" then if type(timers_dict) ~= "table" then
return nil, "unexpected response shape" return nil, "unexpected response shape"
@@ -108,6 +112,9 @@ function M.start_timer(token, timer_id)
if status ~= 200 then if status ~= 200 then
return false, "HTTP " .. status return false, "HTTP " .. status
end end
if not data then
return true, nil
end
if data.error ~= nil and data.error ~= vim.NIL then if data.error ~= nil and data.error ~= vim.NIL then
return false, tostring(data.error) return false, tostring(data.error)
end end
@@ -127,6 +134,9 @@ function M.stop_timer(token, timer_id)
if status ~= 200 then if status ~= 200 then
return false, "HTTP " .. status return false, "HTTP " .. status
end end
if not data then
return true, nil
end
if data.error ~= nil and data.error ~= vim.NIL then if data.error ~= nil and data.error ~= vim.NIL then
return false, tostring(data.error) return false, tostring(data.error)
end end
@@ -140,17 +150,16 @@ end
--- @return boolean ok --- @return boolean ok
--- @return string|nil error --- @return string|nil error
function M.create_timer(token, timer_id, attivita_id) function M.create_timer(token, timer_id, attivita_id)
local data, status, err = post( local data, status, err = post("/api/v1/timer/" .. timer_id .. "/attivita/", token, { attivita_id = attivita_id })
"/api/v1/timer/" .. timer_id .. "/attivita/",
token,
{ attivita_id = attivita_id }
)
if err then if err then
return false, err return false, err
end end
if status ~= 200 then if status ~= 200 then
return false, "HTTP " .. status return false, "HTTP " .. status
end end
if not data then
return true, nil
end
if data.error ~= nil and data.error ~= vim.NIL then if data.error ~= nil and data.error ~= vim.NIL then
return false, tostring(data.error) return false, tostring(data.error)
end end

View File

@@ -47,9 +47,12 @@ end
--- @return string|nil error message --- @return string|nil error message
function M.login(username, password) function M.login(username, password)
local result = vim.system({ local result = vim.system({
"curl", "-s", "curl",
"--data-urlencode", "username=" .. username, "-s",
"--data-urlencode", "password=" .. password, "--data-urlencode",
"username=" .. username,
"--data-urlencode",
"password=" .. password,
JASPER_URL .. "/api/v1/token/login/", JASPER_URL .. "/api/v1/token/login/",
}, { text = true }):wait() }, { text = true }):wait()

View File

@@ -4,7 +4,7 @@
local M = {} local M = {}
local config = require("jasper.config") local config = require("jasper.config")
local timer = require("jasper.timer") local timer = require("jasper.timer")
--- Setup the plugin. --- Setup the plugin.
--- ---
@@ -36,19 +36,14 @@ function M.setup(opts)
end end
if not project_cfg.attivita_id then if not project_cfg.attivita_id then
vim.notify( vim.notify("[Jasper] .jasper_config.json found but 'attivita_id' is missing", vim.log.levels.WARN)
"[Jasper] .jasper_config.json found but 'attivita_id' is missing",
vim.log.levels.WARN
)
return return
end end
-- Merge: project file values < global setup() opts (global opts take priority) -- Merge: project file values < global setup() opts (global opts take priority)
local effective_opts = { local effective_opts = {
attivita_id = project_cfg.attivita_id, attivita_id = project_cfg.attivita_id,
inactivity_timeout = opts.inactivity_timeout inactivity_timeout = opts.inactivity_timeout or project_cfg.inactivity_timeout or 10,
or project_cfg.inactivity_timeout
or 10,
} }
timer.setup(effective_opts) timer.setup(effective_opts)

View File

@@ -3,19 +3,19 @@
local M = {} local M = {}
local api = require("jasper.api") local api = require("jasper.api")
local auth = require("jasper.auth") local auth = require("jasper.auth")
--- Internal state (one instance per Neovim session). --- Internal state (one instance per Neovim session).
local state = { local state = {
token = nil, ---@type string|nil token = nil, ---@type string|nil
timer_id = nil, ---@type number|nil timer_id = nil, ---@type number|nil
attivita_id = nil, ---@type number|nil attivita_id = nil, ---@type number|nil
running = false, running = false,
-- inactivity_ms: milliseconds of silence before the timer is auto-paused -- inactivity_ms: milliseconds of silence before the timer is auto-paused
inactivity_ms = 10 * 60 * 1000, inactivity_ms = 10 * 60 * 1000,
uv_timer = nil, ---@type uv_timer_t|nil uv_timer = nil, ---@type uv.uv_timer_t|nil
augroup = nil, ---@type number|nil augroup = nil, ---@type number|nil
} }
-- --------------------------------------------------------------------------- -- ---------------------------------------------------------------------------
@@ -128,7 +128,7 @@ end
--- @param token string --- @param token string
--- @param timer_id number --- @param timer_id number
local function begin_tracking(token, timer_id) local function begin_tracking(token, timer_id)
state.token = token state.token = token
state.timer_id = timer_id state.timer_id = timer_id
-- Create the libuv timer used for inactivity detection -- Create the libuv timer used for inactivity detection
@@ -170,6 +170,11 @@ local function on_token_ready(token)
return return
end end
if not timers then
notify("Cannot fetch timers: empty response", vim.log.levels.ERROR)
return
end
local timer_id, terr = find_or_create_timer(token, state.attivita_id, timers) local timer_id, terr = find_or_create_timer(token, state.attivita_id, timers)
if not timer_id then if not timer_id then
notify(terr or "Cannot get timer", vim.log.levels.ERROR) notify(terr or "Cannot get timer", vim.log.levels.ERROR)
@@ -182,7 +187,7 @@ end
--- Entry point called on VimEnter. --- Entry point called on VimEnter.
--- @param opts table { attivita_id, inactivity_timeout } --- @param opts table { attivita_id, inactivity_timeout }
function M.setup(opts) function M.setup(opts)
state.attivita_id = opts.attivita_id state.attivita_id = opts.attivita_id
state.inactivity_ms = (opts.inactivity_timeout or 10) * 60 * 1000 state.inactivity_ms = (opts.inactivity_timeout or 10) * 60 * 1000
local token = auth.get_token() local token = auth.get_token()