From cbf78068f1474b771ee1164515f71ac16076407e Mon Sep 17 00:00:00 2001 From: Abdou TOP Date: Fri, 12 Jun 2026 09:39:26 +0000 Subject: [PATCH] feat(devtools): enhance registration process and add git repo name retrieval --- api/deno.json | 2 +- api/env.ts | 14 +++++++ api/local_ipc_client.ts | 84 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 92 insertions(+), 8 deletions(-) diff --git a/api/deno.json b/api/deno.json index e902987..8909ea0 100644 --- a/api/deno.json +++ b/api/deno.json @@ -5,7 +5,7 @@ "@std/streams": "jsr:@std/streams@^1.1.1" }, "name": "@01edu/api", - "version": "0.2.8", + "version": "0.2.9", "license": "MIT", "exports": { "./context": "./context.ts", diff --git a/api/env.ts b/api/env.ts index ffa9ca9..dcaf073 100644 --- a/api/env.ts +++ b/api/env.ts @@ -121,6 +121,20 @@ export const DEVTOOL_URL: string = ENV('DEVTOOL_URL', '') */ export const DEVTOOL_ACCESS_TOKEN: string = ENV('DEVTOOL_ACCESS_TOKEN', '') +/** + * A boolean flag indicating whether the developer tools integration is enabled. + * + * @example + * ```ts + * import { WITH_DEVTOOLS } from '@01edu/api/env'; + * + * if (WITH_DEVTOOLS) { + * // Initialize or enable developer tools integrations + * } + * ``` + */ +export const WITH_DEVTOOLS: boolean = truthy('WITH_DEVTOOLS') + /** * Disable query debug instrumentation when set in the environment. */ diff --git a/api/local_ipc_client.ts b/api/local_ipc_client.ts index 6bf51c1..e408275 100644 --- a/api/local_ipc_client.ts +++ b/api/local_ipc_client.ts @@ -1,10 +1,12 @@ import { TextLineStream } from '@std/streams/text-line-stream' +import { PORT, WITH_DEVTOOLS } from './env.ts' export const defaultSocketPath: string = Deno.build.os === 'windows' ? '\\\\.\\pipe\\01-devtools' : `${Deno.env.get('XDG_RUNTIME_DIR') || '/tmp'}/01-devtools/01-devtools.sock` const encoder = new TextEncoder() +const decoder = new TextDecoder() async function sendCommand( socketPath: string, @@ -28,17 +30,84 @@ async function sendCommand( export let devtoolsPort: number | null = null -export interface RegisterPayload { - projectId: string - name?: string - url: string - sqlEndpoint?: string | null +const getGitRepoName = async () => { + try { + const command = new Deno.Command('git', { + args: ['remote', 'get-url', 'origin'], + }) + const { success, stdout } = await command.output() + if (!success) return null + const url = decoder.decode(stdout).trim() + return url.replace(/\.git$/, '').split(/[/:]/).pop() ?? null + } catch { + // Fail silently + } + return null } -export async function register( - payload: RegisterPayload, +const getDirectoryName = () => + Deno.cwd().replaceAll('\\', '/').split('/').pop() ?? 'project' + +export async function registerToDevtools( socketPath = defaultSocketPath, ): Promise { + if (!WITH_DEVTOOLS) return + + const checkRunning = await new Deno.Command('docker', { + args: ['ps', '-q', '-f', 'name=devtools', '-f', 'status=running'], + stdout: 'piped', + stderr: 'null', + }).output() + + const isRunning = decoder.decode(checkRunning.stdout).trim().length > 0 + + if (!isRunning) { + await new Deno.Command('docker', { + args: ['rm', '-f', 'devtools'], + stdout: 'null', + stderr: 'null', + }).output() + + const socketDir = `${Deno.env.get('XDG_RUNTIME_DIR') ?? '/tmp'}/01-devtools` + + await Deno.mkdir(socketDir, { recursive: true }) + + const { success } = await new Deno.Command('docker', { + args: [ + 'run', + '-d', + '--rm', + '--name', + 'devtools', + '--network', + 'host', + '-e', + 'GEMINI_API_KEY', + '-v', + `${socketDir}:/tmp/01-devtools`, + '-v', + 'devtools-db:/app/db', + 'ghcr.io/01-edu/devtools:latest-dev', + ], + stdout: 'inherit', + stderr: 'inherit', + }).output() + + if (!success) return null + } + + const name = (await getGitRepoName()) ?? getDirectoryName() + const projectId = name.toLowerCase().replace(/[^a-z0-9-_]/g, '') + const url = `localhost:${PORT}` + const sqlEndpoint = `http://${url}/api/sql` + + const payload = { + projectId, + name, + url, + sqlEndpoint, + } + const res = await sendCommand( socketPath, `register/${JSON.stringify(payload)}`, @@ -46,4 +115,5 @@ export async function register( if (!res) return null devtoolsPort = res.port as number + console.info(`DevTools is running on: http://localhost:${devtoolsPort}`) }