From fc6007e70b517293f61ff12bccd75bcd8e3cda32 Mon Sep 17 00:00:00 2001 From: ChamHerry <51915924+ChamHerry@users.noreply.github.com> Date: Sat, 23 May 2026 13:14:24 +0800 Subject: [PATCH 1/5] feat(i18n): make web and CLI language-aware (#1748) --- .gitignore | 4 +- docs/code-indexing/cobol/README.md | 100 --- docs/code-indexing/cobol/copy-expansion.md | 157 ---- docs/code-indexing/cobol/deep-indexing.md | 312 -------- docs/code-indexing/cobol/file-detection.md | 126 --- docs/code-indexing/cobol/graph-model.md | 193 ----- docs/code-indexing/cobol/performance.md | 261 ------- docs/code-indexing/cobol/regex-extraction.md | 206 ----- docs/guides/microservices-grpc.md | 300 -------- docs/guides/microservices-thrift.md | 185 ----- ...-feat-cobol-full-language-coverage-plan.md | 326 -------- .../plans/2026-04-02-pr626-high-fixes.md | 725 ------------------ .../2026-04-02-pr626-high-fixes-design.md | 175 ----- gitnexus-web/e2e/language-switching.spec.ts | 71 ++ gitnexus-web/package-lock.json | 102 ++- gitnexus-web/package.json | 3 + gitnexus-web/src/App.tsx | 31 +- .../src/components/AnalyzeOnboarding.tsx | 10 +- .../src/components/AnalyzeProgress.tsx | 31 +- .../src/components/CodeReferencesPanel.tsx | 49 +- gitnexus-web/src/components/DropZone.tsx | 34 +- .../src/components/EmbeddingStatus.tsx | 20 +- gitnexus-web/src/components/FileTreePanel.tsx | 58 +- gitnexus-web/src/components/GraphCanvas.tsx | 24 +- gitnexus-web/src/components/Header.tsx | 41 +- gitnexus-web/src/components/HelpPanel.tsx | 201 +++-- .../src/components/LanguageSwitcher.tsx | 43 ++ .../src/components/LoadingOverlay.tsx | 17 +- .../src/components/MarkdownRenderer.tsx | 12 +- .../src/components/MermaidDiagram.tsx | 16 +- .../src/components/OnboardingGuide.tsx | 44 +- .../src/components/ProcessFlowModal.tsx | 28 +- .../src/components/ProcessesPanel.tsx | 54 +- gitnexus-web/src/components/QueryFAB.tsx | 52 +- gitnexus-web/src/components/RepoAnalyzer.tsx | 59 +- gitnexus-web/src/components/RepoLanding.tsx | 33 +- gitnexus-web/src/components/RightPanel.tsx | 47 +- gitnexus-web/src/components/SettingsPanel.tsx | 178 +++-- gitnexus-web/src/components/StatusBar.tsx | 15 +- gitnexus-web/src/components/ToolCallCard.tsx | 37 +- .../src/components/WebGPUFallbackDialog.tsx | 43 +- .../settings/ProviderConfigCard.tsx | 9 +- gitnexus-web/src/hooks/useAppState.tsx | 34 +- gitnexus-web/src/i18n/error-messages.ts | 27 + gitnexus-web/src/i18n/index.ts | 70 ++ gitnexus-web/src/i18n/languages.ts | 42 + gitnexus-web/src/i18n/progress.ts | 31 + gitnexus-web/src/i18n/resources.ts | 20 + gitnexus-web/src/locales/en/chat.json | 36 + gitnexus-web/src/locales/en/common.json | 85 ++ gitnexus-web/src/locales/en/errors.json | 19 + gitnexus-web/src/locales/en/graph.json | 174 +++++ gitnexus-web/src/locales/en/header.json | 16 + gitnexus-web/src/locales/en/help.json | 96 +++ gitnexus-web/src/locales/en/onboarding.json | 67 ++ gitnexus-web/src/locales/en/settings.json | 93 +++ gitnexus-web/src/locales/zh-CN/chat.json | 36 + gitnexus-web/src/locales/zh-CN/common.json | 85 ++ gitnexus-web/src/locales/zh-CN/errors.json | 19 + gitnexus-web/src/locales/zh-CN/graph.json | 174 +++++ gitnexus-web/src/locales/zh-CN/header.json | 16 + gitnexus-web/src/locales/zh-CN/help.json | 96 +++ .../src/locales/zh-CN/onboarding.json | 67 ++ gitnexus-web/src/locales/zh-CN/settings.json | 93 +++ gitnexus-web/src/main.tsx | 1 + gitnexus-web/test/setup.ts | 33 + .../test/unit/embedding-auto-start.test.ts | 25 + gitnexus-web/test/unit/i18n.test.tsx | 98 +++ .../test/unit/test-setup-storage.test.ts | 13 + gitnexus/src/cli/clean.ts | 64 +- gitnexus/src/cli/cli-message.ts | 29 + gitnexus/src/cli/detect-changes-format.ts | 86 +++ gitnexus/src/cli/doctor.ts | 93 ++- gitnexus/src/cli/eval-server.ts | 39 +- gitnexus/src/cli/help-i18n.ts | 222 ++++++ gitnexus/src/cli/i18n/en.ts | 245 ++++++ gitnexus/src/cli/i18n/index.ts | 57 ++ gitnexus/src/cli/i18n/resources.ts | 7 + gitnexus/src/cli/i18n/zh-CN.ts | 228 ++++++ gitnexus/src/cli/index.ts | 24 +- gitnexus/src/cli/list.ts | 25 +- gitnexus/src/cli/remove.ts | 23 +- gitnexus/src/cli/serve.ts | 27 +- gitnexus/src/cli/status.ts | 21 +- gitnexus/src/cli/tool.ts | 51 +- gitnexus/test/unit/cli-i18n.test.ts | 49 ++ gitnexus/test/unit/cli-index-help.test.ts | 183 ++++- gitnexus/test/unit/cli-message.test.ts | 14 +- gitnexus/test/unit/doctor-format.test.ts | 21 + gitnexus/test/unit/eval-formatters.test.ts | 30 +- gitnexus/test/unit/tool-direct-cli.test.ts | 24 + 91 files changed, 3787 insertions(+), 3773 deletions(-) delete mode 100644 docs/code-indexing/cobol/README.md delete mode 100644 docs/code-indexing/cobol/copy-expansion.md delete mode 100644 docs/code-indexing/cobol/deep-indexing.md delete mode 100644 docs/code-indexing/cobol/file-detection.md delete mode 100644 docs/code-indexing/cobol/graph-model.md delete mode 100644 docs/code-indexing/cobol/performance.md delete mode 100644 docs/code-indexing/cobol/regex-extraction.md delete mode 100644 docs/guides/microservices-grpc.md delete mode 100644 docs/guides/microservices-thrift.md delete mode 100644 docs/plans/2026-03-26-feat-cobol-full-language-coverage-plan.md delete mode 100644 docs/superpowers/plans/2026-04-02-pr626-high-fixes.md delete mode 100644 docs/superpowers/specs/2026-04-02-pr626-high-fixes-design.md create mode 100644 gitnexus-web/e2e/language-switching.spec.ts create mode 100644 gitnexus-web/src/components/LanguageSwitcher.tsx create mode 100644 gitnexus-web/src/i18n/error-messages.ts create mode 100644 gitnexus-web/src/i18n/index.ts create mode 100644 gitnexus-web/src/i18n/languages.ts create mode 100644 gitnexus-web/src/i18n/progress.ts create mode 100644 gitnexus-web/src/i18n/resources.ts create mode 100644 gitnexus-web/src/locales/en/chat.json create mode 100644 gitnexus-web/src/locales/en/common.json create mode 100644 gitnexus-web/src/locales/en/errors.json create mode 100644 gitnexus-web/src/locales/en/graph.json create mode 100644 gitnexus-web/src/locales/en/header.json create mode 100644 gitnexus-web/src/locales/en/help.json create mode 100644 gitnexus-web/src/locales/en/onboarding.json create mode 100644 gitnexus-web/src/locales/en/settings.json create mode 100644 gitnexus-web/src/locales/zh-CN/chat.json create mode 100644 gitnexus-web/src/locales/zh-CN/common.json create mode 100644 gitnexus-web/src/locales/zh-CN/errors.json create mode 100644 gitnexus-web/src/locales/zh-CN/graph.json create mode 100644 gitnexus-web/src/locales/zh-CN/header.json create mode 100644 gitnexus-web/src/locales/zh-CN/help.json create mode 100644 gitnexus-web/src/locales/zh-CN/onboarding.json create mode 100644 gitnexus-web/src/locales/zh-CN/settings.json create mode 100644 gitnexus-web/test/unit/embedding-auto-start.test.ts create mode 100644 gitnexus-web/test/unit/i18n.test.tsx create mode 100644 gitnexus-web/test/unit/test-setup-storage.test.ts create mode 100644 gitnexus/src/cli/detect-changes-format.ts create mode 100644 gitnexus/src/cli/help-i18n.ts create mode 100644 gitnexus/src/cli/i18n/en.ts create mode 100644 gitnexus/src/cli/i18n/index.ts create mode 100644 gitnexus/src/cli/i18n/resources.ts create mode 100644 gitnexus/src/cli/i18n/zh-CN.ts create mode 100644 gitnexus/test/unit/cli-i18n.test.ts create mode 100644 gitnexus/test/unit/doctor-format.test.ts diff --git a/.gitignore b/.gitignore index 2c370d2d0..9ca3d0d09 100644 --- a/.gitignore +++ b/.gitignore @@ -68,8 +68,8 @@ gitnexus-web/test-results/ eval/.coverage eval/.hypothesis/ -# Design docs (local only) -docs/plans/ +# Local docs +docs/ gitnexus/test/fixtures/mini-repo/*.md gitnexus/test/fixtures/mini-repo/.claude diff --git a/docs/code-indexing/cobol/README.md b/docs/code-indexing/cobol/README.md deleted file mode 100644 index c96eb4626..000000000 --- a/docs/code-indexing/cobol/README.md +++ /dev/null @@ -1,100 +0,0 @@ -# COBOL Code Indexing - -GitNexus indexes COBOL codebases using a **regex-only extraction** strategy, bypassing tree-sitter entirely. This document explains why, how the pipeline works, and links to detailed sub-documents. - -## Why Regex-Only? - -The tree-sitter-cobol grammar (v0.0.1) has three critical limitations that make it unusable for production indexing: - -| Issue | Impact | Severity | -|-------|--------|----------| -| External scanner hangs on ~5% of files | No timeout mechanism exists for the C scanner; the process blocks indefinitely | **Blocking** | -| Only ~15% of paragraph headers detected | Most procedure-division paragraphs are invisible to the grammar | High | -| Patch markers in cols 1-6 cause parse errors | Enterprise COBOL uses non-standard sequence area content (e.g., `mzADD`, `estero`, `#FIX`) | High | - -Because the external scanner hang cannot be interrupted (there is no `setTimeoutMicros` equivalent for tree-sitter), using tree-sitter-cobol would hang the indexing pipeline on a non-trivial fraction of real-world files. - -The regex-only approach provides: - -- **Speed**: ~1ms per file average extraction time -- **Reliability**: zero hangs, zero crashes across 13,000+ files -- **Coverage**: captures all critical symbols -- program name, paragraphs, sections, CALL, PERFORM, COPY, data items (01-77, 88-level), file declarations, FD entries, EXEC SQL/CICS blocks, ENTRY points, and MOVE statements - -## Architecture - -```mermaid -flowchart TD - A[Repository Scan] --> B{File Detection} - B -->|Extension match| C[COBOL file] - B -->|GITNEXUS_COBOL_DIRS match| C - B -->|No match| Z[Skip] - - C --> D{Copybook?} - D -->|Yes| E[Add to Copybook Map] - D -->|No| F[Source Program] - - E --> G[COPY Expansion Engine] - F --> G - - G -->|Inline copybook content| H[Expanded Source] - H --> I[Patch Marker Cleanup] - I --> J[Regex State Machine] - - J --> K[Extracted Symbols] - K --> L[Graph Model Builder] - L --> M[Knowledge Graph] - - subgraph "Per-Chunk Processing" - G - H - I - J - K - L - end - - subgraph "Post-Processing" - M --> N[Community Detection] - M --> O[Process Detection] - M --> P[Contract Detection] - end - - style J fill:#e8f5e9,stroke:#2e7d32 - style G fill:#e3f2fd,stroke:#1565c0 -``` - -## COBOL vs Tree-Sitter Languages - -| Feature | COBOL (Regex) | Tree-Sitter Languages | -|---------|--------------|----------------------| -| Parser | Single-pass regex state machine | tree-sitter grammar + queries | -| Speed | ~1ms/file | ~5ms/file | -| AST available | No | Yes | -| COPY expansion | Yes (pre-processing step) | N/A | -| Deep indexing | Data items, SQL, CICS, FD, ENTRY | Type annotations, generics, etc. | -| Call extraction | PERFORM (intra-file) + CALL (cross-program) | AST-based call site detection | -| Import extraction | COPY statements | `import`/`require`/`use`/`#include` | -| Coverage | All critical symbols | Language-dependent query coverage | -| Failure mode | Never hangs | External scanner can hang (COBOL only) | - -## Sub-Documents - -| Document | Description | -|----------|-------------| -| [File Detection](./file-detection.md) | Extension mapping, `GITNEXUS_COBOL_DIRS`, copybook classification | -| [COPY Expansion](./copy-expansion.md) | Copybook inlining, REPLACING transformations, cycle detection | -| [Regex Extraction](./regex-extraction.md) | State machine, regex patterns, line processing | -| [Deep Indexing](./deep-indexing.md) | Data items, EXEC SQL/CICS, file declarations, FD, ENTRY, MOVE | -| [Graph Model](./graph-model.md) | COBOL-specific node types, edge types, full annotated example | -| [Performance](./performance.md) | Benchmarks, worker pool tuning, caps, troubleshooting | - -## Key Source Files - -| File | Purpose | -|------|---------| -| `gitnexus/src/core/ingestion/cobol-preprocessor.ts` | Patch marker cleanup + regex extraction engine | -| `gitnexus/src/core/ingestion/cobol-copy-expander.ts` | COPY statement expansion with REPLACING | -| `gitnexus/src/core/ingestion/utils.ts` | `getLanguageFromPath`, `getLanguageFromFilename` | -| `gitnexus/src/core/ingestion/pipeline.ts` | `isCobolCopybook`, `expandCobolCopies`, `detectCrossProgamContracts` | -| `gitnexus/src/core/ingestion/workers/parse-worker.ts` | `processCobolRegexOnly` -- graph model builder | -| `gitnexus/src/core/ingestion/workers/worker-pool.ts` | Configurable sub-batch size for COBOL | diff --git a/docs/code-indexing/cobol/copy-expansion.md b/docs/code-indexing/cobol/copy-expansion.md deleted file mode 100644 index 7c6aaa2a3..000000000 --- a/docs/code-indexing/cobol/copy-expansion.md +++ /dev/null @@ -1,157 +0,0 @@ -# COBOL COPY Expansion - -The COPY statement is COBOL's include mechanism -- analogous to `#include` in C or `import` in modern languages. GitNexus expands COPY statements **before** regex extraction so that symbols defined inside copybooks (data items, paragraphs, etc.) are visible in the program's extracted graph. - -## Supported Syntax - -### Basic COPY - -```cobol -COPY CPSESP. -COPY "WORKGRID.CPY". -``` - -Inlines the content of the named copybook, replacing the COPY line(s). - -### COPY with REPLACING - -```cobol -COPY CPSESP REPLACING "ANAZI-KEY" BY "LK-KEY". -COPY CPSESP REPLACING LEADING "ESP-" BY "LK-ESP-" - LEADING "KPSESPL" BY "LK-KPSESPL". -COPY LINKAGE REPLACING TRAILING "-IN" BY "-OUT". -``` - -Three REPLACING types are supported: - -| Type | Syntax | Behavior | Example | -| ------------ | ------------------------------------ | --------------------------------------- | -------------------------------- | -| **EXACT** | `REPLACING "OLD" BY "NEW"` | Replace exact identifier matches | `ANAZI-KEY` becomes `LK-KEY` | -| **LEADING** | `REPLACING LEADING "PFX-" BY "NEW-"` | Replace prefix on all COBOL identifiers | `ESP-NAME` becomes `LK-ESP-NAME` | -| **TRAILING** | `REPLACING TRAILING "-IN" BY "-OUT"` | Replace suffix on all COBOL identifiers | `DATA-IN` becomes `DATA-OUT` | - -Multiple REPLACING clauses can appear in a single COPY statement. They are applied in order to each COBOL identifier in the copybook content. - -### Multi-Line COPY - -COPY statements can span multiple lines (standard COBOL continuation rules apply): - -```cobol - COPY CPSESP REPLACING - - LEADING "ESP-" BY "LK-ESP-" - - LEADING "KPSESPL" BY "LK-KPSESPL". -``` - -Continuation lines (indicator `-` in column 7) are merged before COPY statement scanning. - -## Expansion Flow - -```mermaid -sequenceDiagram - participant Pipeline - participant Expander as COPY Expander - participant Resolver - participant Reader - - Pipeline->>Pipeline: Identify all COBOL files - Pipeline->>Pipeline: Classify copybooks vs programs - Pipeline->>Reader: Read all copybook content upfront - Reader-->>Pipeline: Copybook content map (name -> content) - - loop For each source file in chunk - Pipeline->>Expander: expandCopies(content, filePath, resolveFile, readFile) - Expander->>Expander: Merge continuation lines - Expander->>Expander: Detect COPY statements via regex - - loop For each COPY statement (reverse order) - Expander->>Resolver: resolveFile(copyTarget) - Resolver-->>Expander: Copybook key or null - - alt Resolved successfully - Expander->>Reader: readFile(resolvedKey) - Reader-->>Expander: Copybook content - - Expander->>Expander: Apply REPLACING transformations - Expander->>Expander: Recurse for nested COPYs (depth + 1) - Expander->>Expander: Splice expanded content into output - else Not resolved - Expander->>Expander: Keep original COPY line - end - end - - Expander-->>Pipeline: Expanded content + resolution metadata - Pipeline->>Pipeline: Replace file content with expanded content - end -``` - -The return type `CopyExpansionResult` contains `expandedContent` and `copyResolutions`. The `expansionDepth` field has been removed from the return type (it was unused by callers). - -COPY statement line numbers in `CopyResolution` are 1-based (consistent with the preprocessor's line numbering). The splice operation that replaces COPY lines with expanded content adjusts for 0-based array indexing internally. - -## Cycle Detection - -Circular COPY references (e.g., copybook A includes copybook B which includes copybook A) are detected and handled: - -1. Each expansion chain maintains a `visited` set of resolved copybook paths -2. If a copybook path is already in the visited set, the expansion is skipped -3. A `warnedCircular` set (internal to `expandCopies()`, not a parameter) deduplicates warning messages within a single file expansion - -Known circular copybooks in PROJECT-NAME: `ANAZI`, `ANDIP`, `QDIPE` (self-referential includes). - -## Max Depth - -Nested COPY expansion is limited to **10 levels** (`DEFAULT_MAX_DEPTH`). If a COPY chain exceeds this depth, a warning is logged and the remaining COPY statements are left unexpanded. - -## Max Total Expansions - -A breadth amplification guard caps the total number of COPY expansions across all branches within a single file to **500** (`MAX_TOTAL_EXPANSIONS`). This prevents exponential blowup from diamond-shaped COPY graphs where N copybooks each include N other copybooks. Once the limit is reached, further COPY statements in that file are left unexpanded and a single warning is logged. - -## REPLACING Application Detail - -The REPLACING engine works by scanning all COBOL identifiers (matching `\b[A-Z][A-Z0-9-]*\b`) in the copybook content and applying each replacement rule: - -``` -Original copybook content: - 05 ESP-NAME PIC X(30). - 05 ESP-CODE PIC X(10). - 05 KPSESPL-FLAG PIC X(01). - -After REPLACING LEADING "ESP-" BY "LK-ESP-" LEADING "KPSESPL" BY "LK-KPSESPL": - 05 LK-ESP-NAME PIC X(30). - 05 LK-ESP-CODE PIC X(10). - 05 LK-KPSESPL-FLAG PIC X(01). -``` - -For LEADING replacements, the engine checks if each identifier starts with the `from` prefix (case-insensitive) and replaces only the prefix portion, preserving the rest of the identifier. - -For TRAILING replacements, the same logic applies to suffixes. - -For EXACT replacements, only identifiers that match the `from` value exactly (case-insensitive) are replaced. - -## Copybook Resolution - -The resolver tries multiple strategies to match a COPY target name to a copybook file: - -1. **Exact match**: `COPY CPSESP` resolves to copybook named `CPSESP` -2. **Strip extension**: `COPY WORKGRID.CPY` strips `.CPY` and resolves to `WORKGRID` -3. **Add extension**: `COPY CPSESP` tries `CPSESP.CPY` and `CPSESP.COPY` - -If no match is found, the COPY statement is left in place (unexpanded) and a resolution record with `resolvedPath: null` is created. - -## Pipeline Integration - -The expansion runs **per chunk**, after file content is read but before dispatch to worker threads: - -1. All copybook files are read upfront (they are typically small, collectively under 100MB) -2. Per chunk, the copybook map is merged with chunk content (in case a chunk contains copybooks) -3. Only programs (not copybooks themselves) undergo expansion -4. The expanded content replaces the original content in-place before worker dispatch - -## Inline Comment Handling - -The copy expander's `stripInlineComment()` helper is quote-aware: pipe characters (`|`) inside single- or double-quoted strings are preserved. This matches the same quote-aware logic used by the preprocessor. - -## Source Files - -- `gitnexus/src/core/ingestion/cobol-copy-expander.ts` -- `expandCopies()`, `parseReplacingClause()`, `applyReplacing()` -- `gitnexus/src/core/ingestion/pipeline.ts` -- `expandCobolCopies()`, copybook map construction, chunk integration diff --git a/docs/code-indexing/cobol/deep-indexing.md b/docs/code-indexing/cobol/deep-indexing.md deleted file mode 100644 index f28376782..000000000 --- a/docs/code-indexing/cobol/deep-indexing.md +++ /dev/null @@ -1,312 +0,0 @@ -# COBOL Deep Indexing - -Beyond basic symbol extraction (program name, paragraphs, CALL, PERFORM, COPY), GitNexus performs deep indexing of COBOL-specific constructs: data items, EXEC SQL/CICS blocks, file declarations, FD entries, ENTRY points, and MOVE statements. - -## Data Items - -### Level Numbers - -| Level Range | Meaning | Graph Node Type | -|-------------|---------|-----------------| -| 01 | Record (group item) | `Record` | -| 02-49 | Elementary/group items | `Property` | -| 66 | RENAMES | `Property` | -| 77 | Independent item | `Property` | -| 88 | Condition name | `Const` | - -FILLER items are skipped (no useful name for the graph). - -### Clauses Parsed - -The `parseDataItemClauses()` function extracts these clauses from the trailing text of a data item declaration: - -| Clause | Pattern | Example | -|--------|---------|---------| -| `PIC` / `PICTURE` | `\bPIC(?:TURE)?\s+(?:IS\s+)?(\S+)` | `PIC X(30)`, `PICTURE IS 9(5)V99` | -| `USAGE` | `\bUSAGE\s+(?:IS\s+)?(COMP\|BINARY\|...)` | `USAGE IS COMP-3`, `BINARY` | -| `REDEFINES` | `\bREDEFINES\s+([A-Z][A-Z0-9-]+)` | `REDEFINES WK-DATE-NUM` | -| `OCCURS` | `\bOCCURS\s+(\d+)` | `OCCURS 12 TIMES` | - -Standalone COMP variants (without the `USAGE` keyword) are also detected: `COMP`, `COMP-1` through `COMP-6`, `COMP-X`, `BINARY`, `PACKED-DECIMAL`. - -### Data Hierarchy - -Data items form a hierarchical structure based on level numbers. The extractor uses a **stack algorithm**: - -``` -Processing order: - 01 WK-RECORD -> push {01, WK-RECORD} -> parent: Module - 05 WK-NAME -> push {05, WK-NAME} -> parent: WK-RECORD (01 < 05) - 10 WK-FIRST -> push {10, WK-FIRST} -> parent: WK-NAME (05 < 10) - 10 WK-LAST -> pop WK-FIRST, push -> parent: WK-NAME (05 < 10) - 05 WK-CODE -> pop WK-LAST, WK-NAME -> parent: WK-RECORD (01 < 05) - 88 WK-ACTIVE -> (88 handled separately) -> parent: WK-CODE -``` - -The stack maintains items where each entry's level is strictly less than the next. When a new item arrives with a level <= the top of stack, items are popped until the stack top has a smaller level. A `CONTAINS` edge is created from the stack top to the new item. - -For 88-level condition names, the parent is the immediately preceding non-88 data item (found by scanning backwards). - -### Annotated Example - -```cobol - 01 WK-EMPLOYEE. - 05 WK-EMP-ID PIC 9(6). - 05 WK-EMP-NAME PIC X(30). - 05 WK-EMP-STATUS PIC X(01). - 88 WK-ACTIVE VALUE "A". - 88 WK-INACTIVE VALUE "I". - 05 WK-SALARY PIC 9(7)V99 COMP-3. - 05 WK-DEPT PIC X(04) OCCURS 3 TIMES. -``` - -Produces: -- `Record` node: `WK-EMPLOYEE` (level 01, section: working-storage) -- `Property` nodes: `WK-EMP-ID`, `WK-EMP-NAME`, `WK-EMP-STATUS`, `WK-SALARY`, `WK-DEPT` -- `Const` nodes: `WK-ACTIVE` (values: `A`), `WK-INACTIVE` (values: `I`) -- `CONTAINS` edges: `WK-EMPLOYEE -> WK-EMP-ID`, `WK-EMPLOYEE -> WK-EMP-NAME`, etc. -- `CONTAINS` edges: `WK-EMP-STATUS -> WK-ACTIVE`, `WK-EMP-STATUS -> WK-INACTIVE` - -### Data Item Cap - -A maximum of **500 data items per file** (`MAX_DATA_ITEMS_PER_FILE`) are processed. Some COBOL programs (especially after COPY expansion) can have 10,000+ data items, which would cause graph bloat and push the V8 relationship Map past its 16.7M entry limit across thousands of files. - -The cap applies after extraction: the first 500 items in source order are kept. Since 01-level records appear first, critical top-level structure is preserved. - -## EXEC SQL - -EXEC SQL blocks are accumulated across lines between `EXEC SQL` and `END-EXEC`, then parsed as a unit. - -### Operation Classification - -The first SQL keyword determines the operation: - -| First Keyword | Operation | -|---------------|-----------| -| `SELECT` | SELECT | -| `INSERT` | INSERT | -| `UPDATE` | UPDATE | -| `DELETE` | DELETE | -| `DECLARE` | DECLARE | -| `OPEN` | OPEN | -| `CLOSE` | CLOSE | -| `FETCH` | FETCH | -| *(anything else)* | OTHER | - -### Table Extraction - -Tables are extracted from SQL clauses: - -| Clause Pattern | Example | -|----------------|---------| -| `FROM
Analysis complete
+{t('repoAnalyzer.complete')}
{repoName}
Loading graph...
+{t('repoAnalyzer.loadingGraph')}
); } @@ -153,6 +163,7 @@ export interface RepoAnalyzerProps { } export const RepoAnalyzer = ({ variant, onComplete, onCancel }: RepoAnalyzerProps) => { + const { t } = useTranslation(['common', 'errors', 'onboarding']); const inputId = useId(); const folderInputRef = useRef- Supports GitLab.com and self-hosted GitLab instances. -
+{t('onboarding:repoAnalyzer.gitlabSupported')}
- Indexed {formatRelativeTime(repo.indexedAt)} + {t('onboarding:landing.indexed', { time: formatRelativeTime(repo.indexedAt, t) })}
)} @@ -64,17 +67,18 @@ function RepoCard({ repo, onClick }: { repo: BackendRepo; onClick: () => void })- Select an indexed repository to explore, or analyze a new one. + {t('landing.description')}
@@ -128,7 +134,7 @@ export const RepoLanding = ({ repos, onSelectRepo, onAnalyzeComplete }: RepoLand- Public & private repos · Cloned locally by the server · No data leaves - your machine + {t('landing.footer')}
); diff --git a/gitnexus-web/src/components/RightPanel.tsx b/gitnexus-web/src/components/RightPanel.tsx index 3e063a168..193d2c1e6 100644 --- a/gitnexus-web/src/components/RightPanel.tsx +++ b/gitnexus-web/src/components/RightPanel.tsx @@ -16,7 +16,9 @@ import { ToolCallCard } from './ToolCallCard'; import { isProviderConfigured } from '../core/llm/settings-service'; import { MarkdownRenderer } from './MarkdownRenderer'; import { ProcessesPanel } from './ProcessesPanel'; +import { useTranslation } from 'react-i18next'; export const RightPanel = () => { + const { t } = useTranslation(['chat', 'common']); const { isRightPanelOpen, setRightPanelOpen, @@ -202,10 +204,10 @@ export const RightPanel = () => { }; const chatSuggestions = [ - 'Explain the project architecture', - 'What does this project do?', - 'Show me the most important files', - 'Find all API handlers', + t('chat:suggestions.architecture'), + t('chat:suggestions.whatDoes'), + t('chat:suggestions.importantFiles'), + t('chat:suggestions.apiHandlers'), ]; if (!isRightPanelOpen) return null; @@ -225,7 +227,7 @@ export const RightPanel = () => { }`} >- I can help you understand the architecture, find functions, or explain - connections. + {t('chat:empty.description')}
Type a model ID or press Enter
-e.g. openai/gpt-4o
+{t('customModelHint')}
+{t('customModelExample')}
No models match "{searchTerm}"
-Press Enter to use as custom ID
+{t('noModelsMatch', { searchTerm })}
+{t('pressEnterCustom')}
Configure your LLM provider
+{t('settings:subtitle')}
- Run gitnexus serve to
- start the local server
-
{t('settings:runServeHint')}
- Leave empty to use the default OpenAI API. Set a custom URL for proxies or - compatible APIs. + {t('settings:providers.openai.baseUrlHint')}
- Configure your Azure OpenAI service in the{' '} + {t('settings:azureHint')}{' '} - Azure Portal + {t('settings:azurePortal')}
- 📋 Quick Start: Install Ollama from{' '} + {t('settings:providers.ollama.quickStart')}{' '} + {t('settings:providers.ollama.installFrom')}{' '} ollama.ai - , then run: + {t('settings:providers.ollama.thenRun')}
ollama serve
@@ -697,7 +708,7 @@ export const SettingsPanel = ({
- Default port is 11434.
+ {t('settings:defaultPort')}{' '}
+ 11434.
-
+
{ollamaError && !isCheckingOllama && (
@@ -750,11 +764,11 @@ export const SettingsPanel = ({
ollama: { ...prev.ollama!, model: e.target.value },
}))
}
- placeholder="e.g., llama3.2, mistral, codellama"
+ placeholder={t('settings:providers.ollama.modelPlaceholder')}
className="w-full rounded-xl border border-border-subtle bg-elevated px-4 py-3 font-mono text-sm text-text-primary transition-all outline-none placeholder:text-text-muted focus:border-accent focus:ring-2 focus:ring-accent/20"
/>
- Pull a model with{' '}
+ {t('settings:pullModel')}{' '}
ollama pull llama3.2
@@ -767,10 +781,10 @@ export const SettingsPanel = ({
title="OpenRouter"
apiKey={{
value: settings.openrouter?.apiKey ?? '',
- placeholder: 'Enter your OpenRouter API key',
- helperText: 'Get your API key from',
+ placeholder: t('settings:providers.openrouter.apiKeyPlaceholder'),
+ helperText: t('settings:providers.openrouter.helperText'),
helperLink: 'https://openrouter.ai/keys',
- helperLinkLabel: 'OpenRouter Keys',
+ helperLinkLabel: t('settings:providers.openrouter.helperLinkLabel'),
isVisible: !!showApiKey['openrouter'],
onChange: (value) =>
setSettings((prev) => ({
@@ -781,7 +795,9 @@ export const SettingsPanel = ({
}}
>
-
+
@@ -795,14 +811,14 @@ export const SettingsPanel = ({
onLoadModels={loadOpenRouterModels}
/>
- Browse all models at{' '}
+ {t('settings:browseModels')}{' '}
- OpenRouter Models
+ {t('settings:openRouterModels')}
@@ -815,10 +831,10 @@ export const SettingsPanel = ({
title="MiniMax"
apiKey={{
value: settings.minimax?.apiKey ?? '',
- placeholder: 'Enter your MiniMax API key',
- helperText: 'Get your API key from',
+ placeholder: t('settings:providers.minimax.apiKeyPlaceholder'),
+ helperText: t('settings:providers.minimax.helperText'),
helperLink: 'https://platform.minimax.io',
- helperLinkLabel: 'MiniMax Platform',
+ helperLinkLabel: t('settings:providers.minimax.helperLinkLabel'),
isVisible: !!showApiKey['minimax'],
onChange: (value) =>
setSettings((prev) => ({
@@ -829,13 +845,13 @@ export const SettingsPanel = ({
}}
model={{
value: settings.minimax?.model ?? 'MiniMax-M2.5',
- placeholder: 'e.g., MiniMax-M2.5, MiniMax-M2.5-highspeed',
+ placeholder: t('settings:providers.minimax.modelPlaceholder'),
onChange: (value) =>
setSettings((prev) => ({
...prev,
minimax: { ...prev.minimax!, model: value },
})),
- helperText: 'Available: MiniMax-M2.5 (default), MiniMax-M2.5-highspeed (faster)',
+ helperText: t('settings:providers.minimax.helperModel'),
}}
/>
)}
@@ -846,7 +862,7 @@ export const SettingsPanel = ({
- Get your API key from{' '}
+ {t('settings:providers.openai.helperText')}{' '}
- Z.AI Platform
+ {t('settings:zaiPlatform')}
-
+
-
+
-
- Coding API (default). Use https://api.z.ai/api/paas/v4 for the general API.
-
+ {t('settings:glmCodingApi')}
)}
@@ -934,10 +952,10 @@ export const SettingsPanel = ({
🔒
{formattedArgs}
@@ -160,12 +163,12 @@ export const ToolCallCard = ({ toolCall, defaultExpanded = false }: ToolCallCard
{toolCall.result && (
- Result
+ {t('graph:toolCall.result')}
{toolCall.result.length > 3000
- ? toolCall.result.slice(0, 3000) + '\n\n... (truncated)'
+ ? toolCall.result.slice(0, 3000) + '\n\n' + t('common:progress.truncated')
: toolCall.result}
@@ -176,7 +179,7 @@ export const ToolCallCard = ({ toolCall, defaultExpanded = false }: ToolCallCard
{toolCall.status === 'running' && !toolCall.result && (
- Executing...
+ {t('common:progress.executing')}
)}
diff --git a/gitnexus-web/src/components/WebGPUFallbackDialog.tsx b/gitnexus-web/src/components/WebGPUFallbackDialog.tsx
index 91c0a16f5..5b607ac1b 100644
--- a/gitnexus-web/src/components/WebGPUFallbackDialog.tsx
+++ b/gitnexus-web/src/components/WebGPUFallbackDialog.tsx
@@ -1,5 +1,6 @@
import { useState, useEffect } from 'react';
import { X, Snail, Rocket, SkipForward } from '@/lib/lucide-icons';
+import { useTranslation } from 'react-i18next';
interface WebGPUFallbackDialogProps {
isOpen: boolean;
@@ -20,6 +21,7 @@ export const WebGPUFallbackDialog = ({
onSkip,
nodeCount,
}: WebGPUFallbackDialogProps) => {
+ const { t } = useTranslation('graph');
const [isAnimating, setIsAnimating] = useState(true);
const [isVisible, setIsVisible] = useState(false);
@@ -69,10 +71,10 @@ export const WebGPUFallbackDialog = ({
🤔
- Your browser doesn't support GPU acceleration -
+{t('embedding.fallback.subtitle')}
- Couldn't create embeddings with WebGPU, so semantic search (Graph RAG) won't be as - smart. The graph still works fine though! + {t('embedding.fallback.description')}
- Your options: + + {t('embedding.fallback.options')} +
💡 Tip: Try Chrome or Edge for WebGPU support
+{t('embedding.fallback.tip')}
+ Compatible via OpenAI API format. The deepseek-reasoner model uses thinking mode and + requires round-tripping reasoning content. +
+