mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-19 00:03:33 +00:00
fix(desktop): correct packaged shell assets
This commit is contained in:
parent
21fb1b9a0c
commit
c5238debf6
6 changed files with 20 additions and 484 deletions
7
.github/workflows/desktop-packaging.yml
vendored
7
.github/workflows/desktop-packaging.yml
vendored
|
|
@ -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
|
||||
retention-days: 14
|
||||
|
|
|
|||
102
CLAUDE.md
102
CLAUDE.md
|
|
@ -51,104 +51,4 @@ If always-on instructions grow, load deep conventions via conditional reads (e.g
|
|||
|
||||
## GitNexus rules
|
||||
|
||||
See the `<!-- gitnexus:start -->
|
||||
# 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: "<error or symptom>"})` — find execution flows related to the issue
|
||||
2. `gitnexus_context({name: "<suspect function>"})` — 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` |
|
||||
|
||||
<!-- gitnexus:end -->` 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).
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 5.7 KiB |
|
|
@ -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<void> => {
|
|||
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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<void>;
|
||||
getShellState: () => Promise<DesktopShellState>;
|
||||
minimize: () => Promise<DesktopShellState | null>;
|
||||
onWindowStateChanged: (callback: (state: DesktopShellState) => void) => () => void;
|
||||
platform: string;
|
||||
titleBarHeight: number;
|
||||
toggleAlwaysOnTop: () => Promise<DesktopShellState | null>;
|
||||
toggleMaximize: () => Promise<DesktopShellState | null>;
|
||||
};
|
||||
|
||||
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 (
|
||||
<svg viewBox="0 0 10 10" aria-hidden="true">
|
||||
<path d="M2 5h6" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function MaximizeIcon({ isMaximized }: { isMaximized: boolean }) {
|
||||
if (isMaximized) {
|
||||
return (
|
||||
<svg viewBox="0 0 10 10" aria-hidden="true">
|
||||
<path d="M2.25 3.25h4.5v4.5h-4.5z" />
|
||||
<path d="M3.25 2.25h4.5v4.5" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<svg viewBox="0 0 10 10" aria-hidden="true">
|
||||
<path d="M2.25 2.25h5.5v5.5h-5.5z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function CloseIcon() {
|
||||
return (
|
||||
<svg viewBox="0 0 10 10" aria-hidden="true">
|
||||
<path d="M2 2l6 6" />
|
||||
<path d="M8 2L2 8" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const [shellState, setShellState] = useState<DesktopShellState>({
|
||||
...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<void> => {
|
||||
const nextState = await desktopApi.minimize();
|
||||
|
||||
if (nextState) {
|
||||
setShellState(nextState);
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggleMaximize = async (): Promise<void> => {
|
||||
const nextState = await desktopApi.toggleMaximize();
|
||||
|
||||
if (nextState) {
|
||||
setShellState(nextState);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = async (): Promise<void> => {
|
||||
await desktopApi.close();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{styles}</style>
|
||||
<div className="desktop-shell">
|
||||
<header className="desktop-shell__titlebar">
|
||||
<div className="desktop-shell__side">
|
||||
{isMac ? (
|
||||
<div className="traffic-lights" aria-label="Window controls">
|
||||
<button
|
||||
type="button"
|
||||
className="traffic-light traffic-light--close"
|
||||
aria-label="Close window"
|
||||
onClick={handleClose}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="traffic-light traffic-light--minimize"
|
||||
aria-label="Minimize window"
|
||||
onClick={handleMinimize}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="traffic-light traffic-light--maximize"
|
||||
aria-label={shellState.isMaximized ? 'Restore window' : 'Maximize window'}
|
||||
onClick={handleToggleMaximize}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="desktop-shell__spacer" aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="desktop-shell__title">{shellState.appName}</div>
|
||||
|
||||
<div className="desktop-shell__side desktop-shell__side--end">
|
||||
{isMac ? (
|
||||
<div className="desktop-shell__spacer" aria-hidden="true" />
|
||||
) : (
|
||||
<div className="window-controls" aria-label="Window controls">
|
||||
<button
|
||||
type="button"
|
||||
className="window-control"
|
||||
aria-label="Minimize window"
|
||||
onClick={handleMinimize}
|
||||
>
|
||||
<MinimizeIcon />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="window-control"
|
||||
aria-label={shellState.isMaximized ? 'Restore window' : 'Maximize window'}
|
||||
onClick={handleToggleMaximize}
|
||||
>
|
||||
<MaximizeIcon isMaximized={shellState.isMaximized} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="window-control window-control--close"
|
||||
aria-label="Close window"
|
||||
onClick={handleClose}
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main className="desktop-shell__content" aria-hidden="true" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue