diff --git a/.github/workflows/desktop-packaging.yml b/.github/workflows/desktop-packaging.yml index 371973a6a..dc2279a6c 100644 --- a/.github/workflows/desktop-packaging.yml +++ b/.github/workflows/desktop-packaging.yml @@ -7,11 +7,12 @@ on: - gitnexus-desktop/** workflow_dispatch: -permissions: {} +permissions: + contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: false + cancel-in-progress: true jobs: package: @@ -75,4 +76,4 @@ jobs: name: ${{ matrix.artifact_name }} path: ${{ matrix.artifact_paths }} if-no-files-found: error - retention-days: 14 \ No newline at end of file + retention-days: 14 diff --git a/CLAUDE.md b/CLAUDE.md index 6e15782b9..04150725d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,104 +51,4 @@ If always-on instructions grow, load deep conventions via conditional reads (e.g ## GitNexus rules -See the ` -# GitNexus — Code Intelligence - -This project is indexed by GitNexus as **gitnexus** (18208 symbols, 25369 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. - -> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. - -## Always Do - -- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user. -- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows. -- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits. -- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance. -- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`. - -## When Debugging - -1. `gitnexus_query({query: ""})` — find execution flows related to the issue -2. `gitnexus_context({name: ""})` — see all callers, callees, and process participation -3. `READ gitnexus://repo/gitnexus/process/{processName}` — trace the full execution flow step by step -4. For regressions: `gitnexus_detect_changes({scope: "compare", base_ref: "main"})` — see what your branch changed - -## When Refactoring - -- **Renaming**: MUST use `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` first. Review the preview — graph edits are safe, text_search edits need manual review. Then run with `dry_run: false`. -- **Extracting/Splitting**: MUST run `gitnexus_context({name: "target"})` to see all incoming/outgoing refs, then `gitnexus_impact({target: "target", direction: "upstream"})` to find all external callers before moving code. -- After any refactor: run `gitnexus_detect_changes({scope: "all"})` to verify only expected files changed. - -## Never Do - -- NEVER edit a function, class, or method without first running `gitnexus_impact` on it. -- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis. -- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph. -- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope. - -## Tools Quick Reference - -| Tool | When to use | Command | -|------|-------------|---------| -| `query` | Find code by concept | `gitnexus_query({query: "auth validation"})` | -| `context` | 360-degree view of one symbol | `gitnexus_context({name: "validateUser"})` | -| `impact` | Blast radius before editing | `gitnexus_impact({target: "X", direction: "upstream"})` | -| `detect_changes` | Pre-commit scope check | `gitnexus_detect_changes({scope: "staged"})` | -| `rename` | Safe multi-file rename | `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` | -| `cypher` | Custom graph queries | `gitnexus_cypher({query: "MATCH ..."})` | - -## Impact Risk Levels - -| Depth | Meaning | Action | -|-------|---------|--------| -| d=1 | WILL BREAK — direct callers/importers | MUST update these | -| d=2 | LIKELY AFFECTED — indirect deps | Should test | -| d=3 | MAY NEED TESTING — transitive | Test if critical path | - -## Resources - -| Resource | Use for | -|----------|---------| -| `gitnexus://repo/gitnexus/context` | Codebase overview, check index freshness | -| `gitnexus://repo/gitnexus/clusters` | All functional areas | -| `gitnexus://repo/gitnexus/processes` | All execution flows | -| `gitnexus://repo/gitnexus/process/{name}` | Step-by-step execution trace | - -## Self-Check Before Finishing - -Before completing any code modification task, verify: -1. `gitnexus_impact` was run for all modified symbols -2. No HIGH/CRITICAL risk warnings were ignored -3. `gitnexus_detect_changes()` confirms changes match expected scope -4. All d=1 (WILL BREAK) dependents were updated - -## Keeping the Index Fresh - -After committing code changes, the GitNexus index becomes stale. Re-run analyze to update it: - -```bash -npx gitnexus analyze -``` - -If the index previously included embeddings, preserve them by adding `--embeddings`: - -```bash -npx gitnexus analyze --embeddings -``` - -To check whether embeddings exist, inspect `.gitnexus/meta.json` — the `stats.embeddings` field shows the count (0 means no embeddings). **Running analyze without `--embeddings` will delete any previously generated embeddings.** - -> Claude Code users: A PostToolUse hook handles this automatically after `git commit` and `git merge`. - -## CLI - -| Task | Read this skill file | -|------|---------------------| -| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` | -| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` | -| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` | -| Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` | -| Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` | -| Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` | - -` block in **[AGENTS.md](AGENTS.md)** for the canonical MCP tools, impact analysis rules, and index instructions. +See the canonical `gitnexus:start` … `gitnexus:end` block in [AGENTS.md](AGENTS.md). diff --git a/gitnexus-desktop/src/126312502.png b/gitnexus-desktop/src/126312502.png deleted file mode 100644 index c338812a9..000000000 Binary files a/gitnexus-desktop/src/126312502.png and /dev/null differ diff --git a/gitnexus-desktop/src/main/main.ts b/gitnexus-desktop/src/main/main.ts index d7325d9a7..08637b469 100644 --- a/gitnexus-desktop/src/main/main.ts +++ b/gitnexus-desktop/src/main/main.ts @@ -430,7 +430,20 @@ const sendStaticResponse = (assetPath: string | null, response: ServerResponse): const handlePackagedWebRequest = (request: IncomingMessage, response: ServerResponse): void => { const requestUrl = request.url ?? '/'; - const requestedPath = decodeURIComponent(new URL(requestUrl, 'http://127.0.0.1').pathname); + let requestedPath: string; + + try { + requestedPath = decodeURIComponent(new URL(requestUrl, 'http://127.0.0.1').pathname); + } catch (error) { + if (error instanceof URIError) { + response.writeHead(400, { 'Content-Type': 'text/plain; charset=utf-8' }); + response.end('Bad request'); + return; + } + + throw error; + } + sendStaticResponse(normalizeStaticPath(GITNEXUS_WEB_PACKAGED_DIR, requestedPath), response); }; @@ -611,7 +624,7 @@ const loadShellRenderer = async (window: BrowserWindow): Promise => { return; } - const rendererEntry = path.join(__dirname, '../renderer/src/renderer/index.html'); + const rendererEntry = path.join(__dirname, '../renderer/index.html'); console.info(`[gitnexus-desktop] Loading shell renderer file: ${rendererEntry}`); await window.loadFile(rendererEntry); }; diff --git a/gitnexus-desktop/src/renderer/src/App.tsx b/gitnexus-desktop/src/renderer/src/App.tsx deleted file mode 100644 index e30af9a0b..000000000 --- a/gitnexus-desktop/src/renderer/src/App.tsx +++ /dev/null @@ -1,356 +0,0 @@ -import { useEffect, useState } from 'react'; - -type DesktopShellState = { - appName: string; - isAlwaysOnTop: boolean; - isMaximized: boolean; - platform: string; - titleBarHeight: number; -}; - -type DesktopApi = { - appName: string; - close: () => Promise; - getShellState: () => Promise; - minimize: () => Promise; - onWindowStateChanged: (callback: (state: DesktopShellState) => void) => () => void; - platform: string; - titleBarHeight: number; - toggleAlwaysOnTop: () => Promise; - toggleMaximize: () => Promise; -}; - -const defaultDesktopState: DesktopShellState = { - appName: 'GitNexus Desktop', - isAlwaysOnTop: false, - isMaximized: false, - platform: 'win32', - titleBarHeight: 38, -}; - -const fallbackDesktopApi: DesktopApi = { - appName: defaultDesktopState.appName, - close: async () => {}, - getShellState: async () => defaultDesktopState, - minimize: async () => defaultDesktopState, - onWindowStateChanged: () => () => {}, - platform: defaultDesktopState.platform, - titleBarHeight: defaultDesktopState.titleBarHeight, - toggleAlwaysOnTop: async () => defaultDesktopState, - toggleMaximize: async () => defaultDesktopState, -}; - -const desktopApi = - (window as Window & { gitnexusDesktop?: DesktopApi }).gitnexusDesktop ?? fallbackDesktopApi; - -const styles = ` - :root { - color-scheme: dark; - } - - .desktop-shell { - --titlebar-height: 38px; - height: 100vh; - display: grid; - grid-template-rows: var(--titlebar-height) 1fr; - background: #0d0d0d; - color: #f4f4f5; - overflow: hidden; - } - - .desktop-shell__titlebar { - display: grid; - grid-template-columns: minmax(144px, 1fr) auto minmax(144px, 1fr); - align-items: center; - gap: 12px; - height: var(--titlebar-height); - padding: 0 10px; - background: #0d0d0d; - border-bottom: 1px solid rgba(255, 255, 255, 0.06); - -webkit-app-region: drag; - user-select: none; - } - - .desktop-shell__side { - display: flex; - align-items: center; - min-width: 144px; - min-height: 100%; - } - - .desktop-shell__side--end { - justify-content: flex-end; - } - - .desktop-shell__title { - justify-self: center; - font-family: 'Segoe UI Variable', 'Segoe UI', 'SF Pro Text', system-ui, sans-serif; - font-size: 12px; - font-weight: 600; - letter-spacing: 0.06em; - color: rgba(244, 244, 245, 0.9); - white-space: nowrap; - } - - .desktop-shell__spacer { - min-width: 118px; - min-height: 1px; - } - - .desktop-shell__content { - background: #0d0d0d; - } - - .desktop-shell__content::after { - content: ''; - display: block; - width: 100%; - height: 100%; - background: #0d0d0d; - } - - .window-controls, - .traffic-lights { - display: flex; - align-items: center; - gap: 0; - -webkit-app-region: no-drag; - } - - .window-control { - width: 46px; - height: calc(var(--titlebar-height) - 8px); - border: 0; - border-radius: 8px; - background: transparent; - color: rgba(244, 244, 245, 0.88); - display: inline-flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: background-color 120ms ease, color 120ms ease; - } - - .window-control:hover { - background: rgba(255, 255, 255, 0.08); - } - - .window-control--close:hover { - background: #c42b1c; - color: #ffffff; - } - - .window-control svg { - width: 10px; - height: 10px; - stroke: currentColor; - stroke-width: 1.2; - fill: none; - vector-effect: non-scaling-stroke; - } - - .traffic-lights { - gap: 8px; - } - - .traffic-light { - width: 12px; - height: 12px; - padding: 0; - border: 0; - border-radius: 999px; - cursor: pointer; - transition: filter 120ms ease, transform 120ms ease; - -webkit-app-region: no-drag; - } - - .traffic-light:hover { - filter: brightness(1.04); - } - - .traffic-light--close { - background: #ff5f57; - } - - .traffic-light--minimize { - background: #febc2e; - } - - .traffic-light--maximize { - background: #28c840; - } - - @media (max-width: 720px) { - .desktop-shell__titlebar { - grid-template-columns: minmax(116px, 1fr) auto minmax(116px, 1fr); - gap: 8px; - padding: 0 8px; - } - - .desktop-shell__side { - min-width: 116px; - } - - .window-control { - width: 42px; - } - } -`; - -function MinimizeIcon() { - return ( - - ); -} - -function MaximizeIcon({ isMaximized }: { isMaximized: boolean }) { - if (isMaximized) { - return ( - - ); - } - - return ( - - ); -} - -function CloseIcon() { - return ( - - ); -} - -export default function App() { - const [shellState, setShellState] = useState({ - ...defaultDesktopState, - appName: desktopApi.appName, - platform: desktopApi.platform, - titleBarHeight: desktopApi.titleBarHeight, - }); - - useEffect(() => { - let cancelled = false; - - void desktopApi.getShellState().then((state) => { - if (!cancelled && state) { - setShellState(state); - } - }); - - const unsubscribe = desktopApi.onWindowStateChanged((state) => { - if (!cancelled) { - setShellState(state); - } - }); - - return () => { - cancelled = true; - unsubscribe(); - }; - }, []); - - const isMac = shellState.platform === 'darwin'; - const handleMinimize = async (): Promise => { - const nextState = await desktopApi.minimize(); - - if (nextState) { - setShellState(nextState); - } - }; - - const handleToggleMaximize = async (): Promise => { - const nextState = await desktopApi.toggleMaximize(); - - if (nextState) { - setShellState(nextState); - } - }; - - const handleClose = async (): Promise => { - await desktopApi.close(); - }; - - return ( - <> - -
-
-
- {isMac ? ( -
-
- ) : ( - - -
{shellState.appName}
- -
- {isMac ? ( - -
- -
-
- - ); -} diff --git a/gitnexus-desktop/src/renderer/src/styles.css b/gitnexus-desktop/src/renderer/src/styles.css deleted file mode 100644 index 73a906450..000000000 --- a/gitnexus-desktop/src/renderer/src/styles.css +++ /dev/null @@ -1,22 +0,0 @@ -html, -body, -#root { - margin: 0; - min-height: 100%; -} - -body { - min-height: 100vh; - font-family: 'Segoe UI', sans-serif; - background: #101114; - color: #f5f7fb; -} - -.app-shell { - min-height: 100vh; - display: grid; - place-items: center; - font-size: 2rem; - font-weight: 600; - letter-spacing: 0.04em; -}