feat(scraper): add precision extraction, start_time, and submit support

Problem: problem pages contain floating-point precision requirements and
contest start timestamps that were not being extracted or stored. The
submit workflow also needed a foundation in the scraper layer.

Solution: add extract_precision() to base.py and propagate through all
scrapers into cache. Add start_time to ContestSummary and extract it
from AtCoder and Codeforces. Add SubmitResult model, abstract submit()
method, submit CLI case with get_language_id() resolution, stdin/env_extra
support in run_scraper, and a full AtCoder submit implementation; stub
the remaining platforms.
This commit is contained in:
Barrett Ruth 2026-03-03 14:51:42 -05:00 committed by Barrett Ruth
parent 865e3b5928
commit 90bd13580b
9 changed files with 245 additions and 20 deletions

View file

@ -56,6 +56,12 @@ local function run_scraper(platform, subcommand, args, opts)
env.PYTHONPATH = ''
env.CONDA_PREFIX = ''
if opts and opts.env_extra then
for k, v in pairs(opts.env_extra) do
env[k] = v
end
end
if opts and opts.ndjson then
local uv = vim.uv
local stdout = uv.new_pipe(false)
@ -126,6 +132,9 @@ local function run_scraper(platform, subcommand, args, opts)
end
local sysopts = { text = true, timeout = 30000, env = env, cwd = plugin_path }
if opts and opts.stdin then
sysopts.stdin = opts.stdin
end
if opts and opts.sync then
local result = vim.system(cmd, sysopts):wait()
return syshandle(result)
@ -228,6 +237,7 @@ function M.scrape_all_tests(platform, contest_id, callback)
memory_mb = ev.memory_mb or 0,
interactive = ev.interactive or false,
multi_test = ev.multi_test or false,
precision = ev.precision,
problem_id = ev.problem_id,
})
end
@ -236,4 +246,21 @@ function M.scrape_all_tests(platform, contest_id, callback)
})
end
function M.submit(platform, contest_id, problem_id, language, source_code, credentials, callback)
local creds_json = vim.json.encode(credentials)
run_scraper(platform, 'submit', { contest_id, problem_id, language }, {
stdin = source_code,
env_extra = { CP_CREDENTIALS = creds_json },
on_exit = function(result)
if type(callback) == 'function' then
if result and result.success then
callback(result.data or { success = true })
else
callback({ success = false, error = result and result.error or 'unknown' })
end
end
end,
})
end
return M