|
| 1 | +describe("agent", function() |
| 2 | + local assert = require("luassert") |
| 3 | + local stub = require("luassert.stub") |
| 4 | + local agent = require("hjdivad.agent") |
| 5 | + |
| 6 | + local original_agents_prompt |
| 7 | + local original_agents_vadnu |
| 8 | + local stdpath_stub |
| 9 | + local getcwd_stub |
| 10 | + local original_cmd |
| 11 | + local original_defer_fn |
| 12 | + |
| 13 | + local function restore_env() |
| 14 | + vim.env.AGENTS_PROMPT = original_agents_prompt |
| 15 | + vim.env.AGENTS_VADNU = original_agents_vadnu |
| 16 | + end |
| 17 | + |
| 18 | + before_each(function() |
| 19 | + original_agents_prompt = vim.env.AGENTS_PROMPT |
| 20 | + original_agents_vadnu = vim.env.AGENTS_VADNU |
| 21 | + vim.env.AGENTS_PROMPT = nil |
| 22 | + vim.env.AGENTS_VADNU = nil |
| 23 | + original_cmd = vim.cmd |
| 24 | + original_defer_fn = vim.defer_fn |
| 25 | + end) |
| 26 | + |
| 27 | + after_each(function() |
| 28 | + restore_env() |
| 29 | + |
| 30 | + if stdpath_stub then |
| 31 | + stdpath_stub:revert() |
| 32 | + stdpath_stub = nil |
| 33 | + end |
| 34 | + |
| 35 | + if getcwd_stub then |
| 36 | + getcwd_stub:revert() |
| 37 | + getcwd_stub = nil |
| 38 | + end |
| 39 | + |
| 40 | + vim.cmd = original_cmd |
| 41 | + vim.defer_fn = original_defer_fn |
| 42 | + end) |
| 43 | + |
| 44 | + describe("_agent_paths", function() |
| 45 | + it("uses cache prompt paths as fallbacks", function() |
| 46 | + stdpath_stub = stub(vim.fn, "stdpath", function(name) |
| 47 | + assert.equals("cache", name) |
| 48 | + return "/cache" |
| 49 | + end) |
| 50 | + |
| 51 | + assert.same({ |
| 52 | + prompt = "/cache/prompt/github/repo.prompt.md", |
| 53 | + vadnu = "/cache/prompt/github/repo.vadnu.md", |
| 54 | + }, agent._agent_paths("/Users/me/github/repo")) |
| 55 | + end) |
| 56 | + |
| 57 | + it("uses env var paths without expanding them", function() |
| 58 | + stdpath_stub = stub(vim.fn, "stdpath", function() |
| 59 | + return "/cache" |
| 60 | + end) |
| 61 | + vim.env.AGENTS_PROMPT = "relative/prompt.md" |
| 62 | + vim.env.AGENTS_VADNU = "~/relative/vadnu.md" |
| 63 | + |
| 64 | + assert.same({ |
| 65 | + prompt = "relative/prompt.md", |
| 66 | + vadnu = "~/relative/vadnu.md", |
| 67 | + }, agent._agent_paths("/Users/me/github/repo")) |
| 68 | + end) |
| 69 | + |
| 70 | + it("falls back independently for unset env vars", function() |
| 71 | + stdpath_stub = stub(vim.fn, "stdpath", function() |
| 72 | + return "/cache" |
| 73 | + end) |
| 74 | + vim.env.AGENTS_PROMPT = "prompt.md" |
| 75 | + |
| 76 | + assert.same({ |
| 77 | + prompt = "prompt.md", |
| 78 | + vadnu = "/cache/prompt/github/repo.vadnu.md", |
| 79 | + }, agent._agent_paths("/Users/me/github/repo")) |
| 80 | + end) |
| 81 | + end) |
| 82 | + |
| 83 | + describe("_ensure_vadnu_file", function() |
| 84 | + it("creates vadnu.md with initial sections when missing", function() |
| 85 | + local path = vim.fn.tempname() .. "/vadnu.md" |
| 86 | + |
| 87 | + agent._ensure_vadnu_file(path) |
| 88 | + |
| 89 | + assert.same({ "## Stack", "## Tasks" }, vim.fn.readfile(path)) |
| 90 | + end) |
| 91 | + |
| 92 | + it("leaves existing vadnu.md content alone", function() |
| 93 | + local path = vim.fn.tempname() .. "/vadnu.md" |
| 94 | + vim.fn.mkdir(vim.fn.fnamemodify(path, ":h"), "p") |
| 95 | + vim.fn.writefile({ "custom" }, path) |
| 96 | + |
| 97 | + agent._ensure_vadnu_file(path) |
| 98 | + |
| 99 | + assert.same({ "custom" }, vim.fn.readfile(path)) |
| 100 | + end) |
| 101 | + end) |
| 102 | + |
| 103 | + describe("StartAgent", function() |
| 104 | + it("opens the three-column agent layout with terminals on the left and vadnu above prompt in the middle", function() |
| 105 | + local root = vim.fn.tempname() |
| 106 | + vim.env.AGENTS_VADNU = root .. "/vadnu.md" |
| 107 | + vim.env.AGENTS_PROMPT = root .. "/prompt.md" |
| 108 | + getcwd_stub = stub(vim.fn, "getcwd", function() |
| 109 | + return "/Users/me/github/repo" |
| 110 | + end) |
| 111 | + |
| 112 | + local commands = {} |
| 113 | + local deferred |
| 114 | + local defer_delay |
| 115 | + vim.cmd = function(cmd) |
| 116 | + table.insert(commands, cmd) |
| 117 | + end |
| 118 | + vim.defer_fn = function(callback, delay) |
| 119 | + deferred = callback |
| 120 | + defer_delay = delay |
| 121 | + end |
| 122 | + |
| 123 | + agent.StartAgent("cursor") |
| 124 | + |
| 125 | + assert.same({ |
| 126 | + "tabnew", |
| 127 | + "rightbelow vsplit", |
| 128 | + "rightbelow vsplit", |
| 129 | + "term cursor-agent --force --approve-mcps", |
| 130 | + "wincmd h", |
| 131 | + "edit " .. vim.fn.fnameescape(vim.env.AGENTS_VADNU), |
| 132 | + "rightbelow split", |
| 133 | + "edit " .. vim.fn.fnameescape(vim.env.AGENTS_PROMPT), |
| 134 | + "wincmd h", |
| 135 | + "terminal", |
| 136 | + "rightbelow split", |
| 137 | + "terminal", |
| 138 | + "wincmd l", |
| 139 | + }, commands) |
| 140 | + assert.same({ "## Stack", "## Tasks" }, vim.fn.readfile(vim.env.AGENTS_VADNU)) |
| 141 | + assert.equals(0, vim.fn.filereadable(vim.env.AGENTS_PROMPT)) |
| 142 | + |
| 143 | + assert.is_function(deferred) |
| 144 | + assert.equals(100, defer_delay) |
| 145 | + deferred() |
| 146 | + assert.equals("wincmd =", commands[#commands]) |
| 147 | + end) |
| 148 | + end) |
| 149 | +end) |
0 commit comments