@@ -101,11 +101,41 @@ local function get_github_token()
101
101
error (' Failed to find GitHub token' )
102
102
end
103
103
104
+ local cached_gh_apps_token = nil
105
+
106
+ --- Get the github apps token (gho_ token)
107
+ --- @return string
108
+ local function get_gh_apps_token ()
109
+ if cached_gh_apps_token then
110
+ return cached_gh_apps_token
111
+ end
112
+
113
+ async .util .scheduler ()
114
+
115
+ local config_path = utils .config_path ()
116
+ if not config_path then
117
+ error (' Failed to find config path for GitHub token' )
118
+ end
119
+
120
+ local file_path = config_path .. ' /gh/hosts.yml'
121
+ if vim .fn .filereadable (file_path ) == 1 then
122
+ local content = table.concat (vim .fn .readfile (file_path ), ' \n ' )
123
+ local token = content :match (' oauth_token:%s*([%w_]+)' )
124
+ if token then
125
+ cached_gh_apps_token = token
126
+ return token
127
+ end
128
+ end
129
+
130
+ error (' Failed to find GitHub token' )
131
+ end
132
+
104
133
--- @type table<string , CopilotChat.Provider>
105
134
local M = {}
106
135
107
136
M .copilot = {
108
137
embed = ' copilot_embeddings' ,
138
+ search = ' copilot_search' ,
109
139
110
140
get_headers = function (token )
111
141
return {
@@ -279,6 +309,7 @@ M.copilot = {
279
309
280
310
M .github_models = {
281
311
embed = ' copilot_embeddings' ,
312
+ search = ' copilot_search' ,
282
313
283
314
get_headers = function (token )
284
315
return {
@@ -360,4 +391,80 @@ M.copilot_embeddings = {
360
391
end ,
361
392
}
362
393
394
+ M .copilot_search = {
395
+ get_headers = M .copilot .get_headers ,
396
+
397
+ get_token = function ()
398
+ return get_gh_apps_token (), nil
399
+ end ,
400
+
401
+ search = function (query , repository , headers )
402
+ utils .curl_post (
403
+ ' https://api.github.com/repos/' .. repository .. ' /copilot_internal/embeddings_index' ,
404
+ {
405
+ headers = headers ,
406
+ }
407
+ )
408
+
409
+ local response , err = utils .curl_get (
410
+ ' https://api.github.com/repos/' .. repository .. ' /copilot_internal/embeddings_index' ,
411
+ {
412
+ headers = headers ,
413
+ }
414
+ )
415
+
416
+ if err then
417
+ error (err )
418
+ end
419
+
420
+ if response .status ~= 200 then
421
+ error (' Failed to check search: ' .. tostring (response .status ))
422
+ end
423
+
424
+ local body = vim .json .decode (response .body )
425
+
426
+ if
427
+ body .can_index ~= ' ok'
428
+ or not body .bm25_search_ok
429
+ or not body .lexical_search_ok
430
+ or not body .semantic_code_search_ok
431
+ or not body .semantic_doc_search_ok
432
+ or not body .semantic_indexing_enabled
433
+ then
434
+ error (' Failed to search: ' .. vim .inspect (body ))
435
+ end
436
+
437
+ local body = vim .json .encode ({
438
+ query = query ,
439
+ scopingQuery = ' (repo:' .. repository .. ' )' ,
440
+ similarity = 0.766 ,
441
+ limit = 100 ,
442
+ })
443
+
444
+ local response , err = utils .curl_post (' https://api.individual.githubcopilot.com/search/code' , {
445
+ headers = headers ,
446
+ body = utils .temp_file (body ),
447
+ })
448
+
449
+ if err then
450
+ error (err )
451
+ end
452
+
453
+ if response .status ~= 200 then
454
+ error (' Failed to search: ' .. tostring (response .body ))
455
+ end
456
+
457
+ local out = {}
458
+ for _ , result in ipairs (vim .json .decode (response .body )) do
459
+ table.insert (out , {
460
+ filename = result .path ,
461
+ filetype = result .languageName :lower (),
462
+ score = result .score ,
463
+ content = result .contents ,
464
+ })
465
+ end
466
+ return out
467
+ end ,
468
+ }
469
+
363
470
return M
0 commit comments