@gricha/perry 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -314,6 +314,76 @@ export function createRouter(ctx) {
314
314
  const listSSHKeys = os.output(z.array(SSHKeyInfoSchema)).handler(async () => {
315
315
  return discoverSSHKeys();
316
316
  });
317
+ const GitHubRepoSchema = z.object({
318
+ name: z.string(),
319
+ fullName: z.string(),
320
+ cloneUrl: z.string(),
321
+ sshUrl: z.string(),
322
+ private: z.boolean(),
323
+ description: z.string().nullable(),
324
+ updatedAt: z.string(),
325
+ });
326
+ const listGitHubRepos = os
327
+ .input(z.object({
328
+ search: z.string().optional(),
329
+ perPage: z.number().optional().default(30),
330
+ page: z.number().optional().default(1),
331
+ }))
332
+ .output(z.object({
333
+ configured: z.boolean(),
334
+ repos: z.array(GitHubRepoSchema),
335
+ hasMore: z.boolean(),
336
+ }))
337
+ .handler(async ({ input }) => {
338
+ const config = ctx.config.get();
339
+ const token = config.agents?.github?.token;
340
+ if (!token) {
341
+ return { configured: false, repos: [], hasMore: false };
342
+ }
343
+ try {
344
+ const params = new URLSearchParams({
345
+ per_page: String(input.perPage),
346
+ page: String(input.page),
347
+ sort: 'updated',
348
+ direction: 'desc',
349
+ });
350
+ const url = input.search
351
+ ? `https://api.github.com/search/repositories?q=${encodeURIComponent(input.search)}+user:@me&${params}`
352
+ : `https://api.github.com/user/repos?${params}`;
353
+ const response = await fetch(url, {
354
+ headers: {
355
+ Authorization: `Bearer ${token}`,
356
+ Accept: 'application/vnd.github+json',
357
+ 'X-GitHub-Api-Version': '2022-11-28',
358
+ },
359
+ });
360
+ if (!response.ok) {
361
+ if (response.status === 401) {
362
+ return { configured: false, repos: [], hasMore: false };
363
+ }
364
+ throw new Error(`GitHub API error: ${response.status}`);
365
+ }
366
+ const data = await response.json();
367
+ const items = input.search ? data.items : data;
368
+ const repos = items.map((repo) => ({
369
+ name: repo.name,
370
+ fullName: repo.full_name,
371
+ cloneUrl: repo.clone_url,
372
+ sshUrl: repo.ssh_url,
373
+ private: repo.private,
374
+ description: repo.description,
375
+ updatedAt: repo.updated_at,
376
+ }));
377
+ const linkHeader = response.headers.get('Link');
378
+ const hasMore = linkHeader?.includes('rel="next"') ?? false;
379
+ return { configured: true, repos, hasMore };
380
+ }
381
+ catch (err) {
382
+ throw new ORPCError('INTERNAL_SERVER_ERROR', {
383
+ message: `Failed to fetch GitHub repos: ${err.message}`,
384
+ });
385
+ }
386
+ });
317
387
  async function listHostSessions(input) {
318
388
  const limit = input.limit ?? 50;
319
389
  const offset = input.offset ?? 0;
@@ -816,20 +886,6 @@ export function createRouter(ctx) {
816
886
  homeDir: os_module.homedir(),
817
887
  };
818
888
  });
819
- const updateHostAccess = os
820
- .input(z.object({ enabled: z.boolean() }))
821
- .handler(async ({ input }) => {
822
- const currentConfig = ctx.config.get();
823
- const newConfig = { ...currentConfig, allowHostAccess: input.enabled };
824
- ctx.config.set(newConfig);
825
- await saveAgentConfig(newConfig, ctx.configDir);
826
- return {
827
- enabled: input.enabled,
828
- hostname: os_module.hostname(),
829
- username: os_module.userInfo().username,
830
- homeDir: os_module.homedir(),
831
- };
832
- });
833
889
  const listModels = os
834
890
  .input(z.object({
835
891
  agentType: z.enum(['claude-code', 'opencode']),
@@ -913,9 +969,11 @@ export function createRouter(ctx) {
913
969
  models: {
914
970
  list: listModels,
915
971
  },
972
+ github: {
973
+ listRepos: listGitHubRepos,
974
+ },
916
975
  host: {
917
976
  info: getHostInfo,
918
- updateAccess: updateHostAccess,
919
977
  },
920
978
  info: getInfo,
921
979
  config: {