Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "2.0.4"
".": "3.0.0"
}
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## [3.0.0](https://github.com/zbirenbaum/copilot.lua/compare/v2.0.4...v3.0.0) (2026-06-11)


### ⚠ BREAKING CHANGES

* remove support for apps.json as it is not used anymore by LSP

### Bug Fixes

* remove support for apps.json as it is not used anymore by LSP ([6afee36](https://github.com/zbirenbaum/copilot.lua/commit/6afee363c52b6063a11b409ed20a3f1ab95325ab))

## [2.0.4](https://github.com/zbirenbaum/copilot.lua/compare/v2.0.3...v2.0.4) (2026-05-15)


Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,15 @@ To sign in with a different account:
:Copilot auth signin
```

To view your current authentication token information:
To view your current authentication status:

```
:Copilot auth info
```

Credentials are stored in:
- **Linux/macOS:** `~/.config/github-copilot/apps.json` (or `$XDG_CONFIG_HOME/github-copilot/apps.json`)
- **Windows:** `~/AppData/Local/github-copilot/apps.json`
Credentials are stored by the Copilot Language Server in:
- **Linux/macOS:** `~/.config/github-copilot/auth.db` (or `$XDG_CONFIG_HOME/github-copilot/auth.db`)
- **Windows:** `~/AppData/Local/github-copilot/auth.db`

</details>

Expand Down
44 changes: 18 additions & 26 deletions lua/copilot/auth/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -152,34 +152,26 @@ function M.find_config_path()
logger.error("could not find config path")
end

---@return table|nil
function M.get_creds()
local filename = M.find_config_path() .. "/github-copilot/apps.json"

if vim.fn.filereadable(filename) == 0 then
logger.error("Copilot auth file could not be read from:" .. filename)
return
end

local filedata = vim.api.nvim_eval("readfile('" .. filename .. "')")

if not filedata or #filedata == 0 then
logger.error("Copilot's apps.json file not found or empty, make sure to sign in first")
return
end

local appsdata = vim.json.decode(filedata[1])
return appsdata
end

function M.info()
local info = M.get_creds()
if not info then
logger.error("no GitHub Copilot token found, make sure to sign in first")
return
end
c.use_client(function(client)
api.check_status(
client,
{},
---@param status copilot_check_status_data
function(err, status)
if err then
logger.error("failed to retrieve authentication status: " .. tostring(err))
return
end

logger.notify("GitHub Copilot token information: ", info)
if status.user then
logger.notify("Authenticated as GitHub user: " .. status.user .. " (status: " .. status.status .. ")")
else
logger.error("not authenticated (status: " .. status.status .. "), make sure to sign in first")
end
end
)
end)
end

---@class copilot_auth_cache
Expand Down
49 changes: 39 additions & 10 deletions lua/copilot/health.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local M = {}

local api = require("copilot.api")
local auth = require("copilot.auth")
local c = require("copilot.client")
local config = require("copilot.config")
Expand Down Expand Up @@ -35,13 +36,13 @@ function M.check()
end

local config_path = auth.find_config_path()
local creds_ok, creds = pcall(auth.get_creds)
if creds_ok and creds then
ok("Local credentials file found")
info("Location: `" .. (config_path or "unknown") .. "/github-copilot/apps.json`")
local auth_db_path = (config_path or "unknown") .. "/github-copilot/auth.db"
if config_path and vim.fn.filereadable(auth_db_path) == 1 then
ok("Local credentials found")
info("Location: `" .. auth_db_path .. "`")
else
info("No local credentials file found")
info("Expected location: `" .. (config_path or "unknown") .. "/github-copilot/apps.json`")
info("No local credentials found")
info("Expected location: `" .. auth_db_path .. "`")
info("Run `:Copilot auth` to authenticate")
end

Expand All @@ -63,11 +64,39 @@ function M.check()
ok("LSP client is available and running")
info("Client ID: " .. tostring(client.id))

local lsp_authenticated = auth.is_authenticated()
if lsp_authenticated then
ok("LSP authentication status: authenticated")
vim.wait(2000, function()
return c.initialized
end, 50)

if not c.initialized then
warn("LSP client is running but has not finished initializing")
info("This is not an authentication problem, retry `:checkhealth copilot` once Copilot is active")
else
warn("LSP authentication status: not authenticated")
local done = false
local status_err, status = nil, nil
api.check_status(
client,
{},
---@param status_data copilot_check_status_data
function(err, status_data)
status_err, status = err, status_data
done = true
end
)
vim.wait(5000, function()
return done
end, 50)

if not done then
warn("LSP authentication status: no response from server (timed out)")
elseif status_err then
warn("LSP authentication status: " .. tostring(status_err))
elseif status and status.user then
ok("LSP authentication status: authenticated as `" .. status.user .. "`")
else
warn("LSP authentication status: not authenticated (status: " .. (status and status.status or "unknown") .. ")")
info("Run `:Copilot auth signin` to authenticate")
end
end
info("For detailed authentication status, run `:Copilot status`")

Expand Down
10 changes: 8 additions & 2 deletions tests/stubs/lsp_server.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ local logger = require("copilot.logger")
local M = {}

M.messages = {}

local numbers_as_arrays_text = " 19,20,21\n 22,23,24\n 25,26,27\n}\n{\n"
.. " 28,29,30\n 31,32,33\n 34,35,36\n}\n{\n"
.. " 37,38,39\n 40,41,42\n 43,44,45\n}\n{\n"
.. " 46,47,48\n 49,50,51\n 52,53,54\n}"

M.completion_responses = {
["numbers_with_spaces.txt"] = {
completions = {
Expand Down Expand Up @@ -78,7 +84,7 @@ M.completion_responses = {
["numbers_as_arrays.txt"] = {
completions = {
{
displayText = " 19,20,21\n 22,23,24\n 25,26,27\n}\n{\n 28,29,30\n 31,32,33\n 34,35,36\n}\n{\n 37,38,39\n 40,41,42\n 43,44,45\n}\n{\n 46,47,48\n 49,50,51\n 52,53,54\n}",
displayText = numbers_as_arrays_text,
docVersion = 30,
position = {
character = 0,
Expand All @@ -94,7 +100,7 @@ M.completion_responses = {
line = 11,
},
},
text = " 19,20,21\n 22,23,24\n 25,26,27\n}\n{\n 28,29,30\n 31,32,33\n 34,35,36\n}\n{\n 37,38,39\n 40,41,42\n 43,44,45\n}\n{\n 46,47,48\n 49,50,51\n 52,53,54\n}",
text = numbers_as_arrays_text,
uuid = "1df58ae9-3e93-4e6a-b514-218a9fe7e816",
},
},
Expand Down
25 changes: 23 additions & 2 deletions tests/test_auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ T["auth()"]["auth before attaching, should not give error"] = function()
return has_passed()
end, 50)

return messages
return messages
]])

u.expect_match(messages, ".*Authenticated as GitHub user.*")
Expand Down Expand Up @@ -66,12 +66,33 @@ T["auth()"]["auth issue replication"] = function()
return has_passed()
end, 50)

return messages
return messages
]])

u.expect_match(messages, ".*Online.*")
end

T["auth()"]["auth info reports authentication status from the LSP"] = function()
child.configure_copilot()
child.cmd("Copilot auth info")

local messages = child.lua([[
local messages = ""
local function has_passed()
messages = vim.api.nvim_exec("messages", { output = true }) or ""
return string.find(messages, ".*Authenticated as GitHub user: someUser.*") ~= nil
end

vim.wait(5000, function()
return has_passed()
end, 50)

return messages
]])

u.expect_match(messages, ".*Authenticated as GitHub user: someUser.*")
end

T["auth()"]["is_authenticated when not authed returns false"] = function()
child.configure_copilot()

Expand Down
4 changes: 0 additions & 4 deletions tests/test_client_lifecycle.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
local child_helper = require("tests.child_helper")
local child = child_helper.new_child_neovim("test_client_lifecycle")
local u = require("tests.utils")
local eq = MiniTest.expect.equality

local T = MiniTest.new_set({
Expand Down Expand Up @@ -31,9 +30,6 @@ T["client lifecycle()"]["ensure_client_started with starting guard prevents dupl
-- Simulate the guard being set (as if startup is in progress)
child.lua("c.client_starting = true")

-- Store original client id
local original_id = child.lua("return c.id")

-- Try to start another client - should be blocked by the guard
child.lua([[
c.id = nil
Expand Down
23 changes: 23 additions & 0 deletions tests/test_health.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
local eq = MiniTest.expect.equality
local child_helper = require("tests.child_helper")
local child = child_helper.new_child_neovim("test_health")
local u = require("tests.utils")

local T = MiniTest.new_set({
hooks = {
Expand Down Expand Up @@ -33,6 +34,28 @@ T["health()"]["check runs without error when client is not started"] = function(
eq(result, true)
end

T["health()"]["reports auth.db as local credentials location"] = function()
child.configure_copilot()
child.cmd("checkhealth copilot")

local output = child.lua([[
return table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), "\n")
]])

u.expect_match(output, "auth%.db")
end

T["health()"]["reports LSP authentication status without requiring a buffer attach"] = function()
child.configure_copilot()
child.cmd("checkhealth copilot")

local output = child.lua([[
return table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), "\n")
]])

u.expect_match(output, "authentication status: authenticated as `someUser`")
end

T["health()"]["check runs without error when client is disabled"] = function()
child.lua([[
local lsp = require("copilot.lsp")
Expand Down
4 changes: 2 additions & 2 deletions tests/test_panel.lua
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ end
T["panel.utils()"] = MiniTest.new_set()

T["panel.utils()"]["panel_uri_from_doc_uri"] = function()
local panel_uri = ""
local panel_uri

if vim.fn.has("win32") > 0 then
panel_uri = "copilot:///C:/Users/antoi/AppData/Local/nvim-data/lazy/copilot.lua/lua/copilot/suggestion/init.lua"
Expand All @@ -75,7 +75,7 @@ T["panel.utils()"]["panel_uri_from_doc_uri"] = function()
end

T["panel.utils()"]["panel_uri_to_doc_uri"] = function()
local doc_uri = ""
local doc_uri

if vim.fn.has("win32") > 0 then
doc_uri = "file:///C:/Users/antoi/AppData/Local/nvim-data/lazy/copilot.lua/lua/copilot/suggestion/init.lua"
Expand Down
Loading