{"id":28547809,"url":"https://github.com/ydb-platform/monaco-ghost","last_synced_at":"2026-01-27T11:12:32.149Z","repository":{"id":275463706,"uuid":"897830122","full_name":"ydb-platform/monaco-ghost","owner":"ydb-platform","description":null,"archived":false,"fork":false,"pushed_at":"2025-12-03T07:39:40.000Z","size":1645,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-12-06T09:19:36.592Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ydb-platform.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-12-03T10:10:01.000Z","updated_at":"2025-12-03T07:39:30.000Z","dependencies_parsed_at":"2025-04-01T08:33:25.096Z","dependency_job_id":"88a6ddfe-d030-409b-b7cc-b4e4756faa67","html_url":"https://github.com/ydb-platform/monaco-ghost","commit_stats":null,"previous_names":["ydb-platform/monaco-ghost"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/ydb-platform/monaco-ghost","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ydb-platform%2Fmonaco-ghost","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ydb-platform%2Fmonaco-ghost/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ydb-platform%2Fmonaco-ghost/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ydb-platform%2Fmonaco-ghost/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ydb-platform","download_url":"https://codeload.github.com/ydb-platform/monaco-ghost/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ydb-platform%2Fmonaco-ghost/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28812371,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T07:41:26.337Z","status":"ssl_error","status_checked_at":"2026-01-27T07:41:08.776Z","response_time":168,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-10T01:07:48.488Z","updated_at":"2026-01-27T11:12:32.143Z","avatar_url":"https://github.com/ydb-platform.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @ydb-platform/monaco-ghost\n\n\u003cdiv align=\"center\"\u003e\n\n[![CI](https://github.com/ydb-platform/monaco-ghost/actions/workflows/ci.yml/badge.svg)](https://github.com/ydb-platform/monaco-ghost/actions/workflows/ci.yml)\n[![npm version](https://badge.fury.io/js/%40ydb-platform%2Fmonaco-ghost.svg)](https://www.npmjs.com/package/@ydb-platform/monaco-ghost)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)\n\n🚀 A lightweight adapter for integrating completion services with Monaco Editor's inline completion system.\n\n[Installation](#-installation) •\n[Quick Start](#-quick-start) •\n[Documentation](#-documentation) •\n[Contributing](#-contributing)\n\n\u003c/div\u003e\n\n---\n\n## ✨ Features at a Glance\n\n- 👻 **Ghost Text Display** - Inline suggestions with keyboard navigation\n- ⚡ **High Performance** - Debouncing, caching, and optimized for large files\n- 🎯 **Type Safety** - Comprehensive TypeScript support\n- 🎨 **Theme Support** - Dark and light themes with customization options\n- 📊 **Event System** - Rich analytics and error tracking\n- 🧩 **React Integration** - Pre-built components and hooks\n\n## 📦 Installation\n\n```bash\nnpm install @ydb-platform/monaco-ghost monaco-editor\n```\n\n## 🚀 Quick Start\n\nThe library provides multiple ways to integrate with React applications. Here are the main approaches:\n\n### React Integration with Hook\n\n\u003cdetails\u003e\n\u003csummary\u003eReact Integration with Hook - Recommended for most use cases\u003c/summary\u003e\n\n```typescript\nimport React, { useCallback } from 'react';\nimport MonacoEditor from 'react-monaco-editor';\nimport * as monaco from 'monaco-editor';\nimport { useMonacoGhost } from '@ydb-platform/monaco-ghost';\n\nfunction MyCustomEditor() {\n  // Java-specific API implementation\n  const javaApi = {\n    getCodeAssistSuggestions: async () =\u003e ({\n      Suggests: [{ Text: 'System.out.println(\"Hello, World!\");' }],\n      RequestId: 'demo-request',\n    }),\n  };\n\n  // Java-specific configuration\n  const javaConfig = {\n    debounceTime: 200,\n    suggestionCache: {\n      enabled: true,\n    },\n  };\n\n  const eventHandlers = {\n    onCompletionAccept: text =\u003e console.log('Accepted:', text),\n    onCompletionDecline: (text, reason, otherSuggestions) =\u003e\n      console.log('Declined:', text, reason, otherSuggestions),\n    onCompletionIgnore: (text, otherSuggestions) =\u003e console.log('Ignored:', text, otherSuggestions),\n    onCompletionError: error =\u003e console.error('Error:', error),\n  };\n\n  const { register } = useMonacoGhost({\n    api: javaApi,\n    eventHandlers,\n    config: javaConfig,\n  });\n\n  const editorDidMount = useCallback(\n    (editor: monaco.editor.IStandaloneCodeEditor) =\u003e {\n      register(editor);\n    },\n    [register]\n  );\n\n  const options = {\n    selectOnLineNumbers: true,\n    minimap: { enabled: false },\n    automaticLayout: true,\n    fontSize: 14,\n    lineNumbers: 'on',\n    scrollBeyondLastLine: false,\n    roundedSelection: false,\n    padding: { top: 10 },\n  };\n\n  return (\n    \u003cMonacoEditor\n      height=\"600\"\n      width=\"800\"\n      language=\"java\"\n      theme=\"vs-dark\" // or \"vs-light\"\n      value=\"// Your Java code here\"\n      options={options}\n      editorDidMount={editorDidMount}\n    /\u003e\n  );\n}\n```\n\n\u003c/details\u003e\n\n### Direct Instance Creation\n\n\u003cdetails\u003e\n\u003csummary\u003eAlternative: Direct Instance Creation - For advanced use cases requiring fine-grained control\u003c/summary\u003e\n\nFor more control over the ghost instance lifecycle, you can use `createMonacoGhostInstance` instead of the hook:\n\n```typescript\nimport React from 'react';\nimport MonacoEditor from 'react-monaco-editor';\nimport * as monaco from 'monaco-editor';\nimport { createMonacoGhostInstance } from '@ydb-platform/monaco-ghost';\n\nfunction MyCustomEditor() {\n  const [monacoGhostInstance, setMonacoGhostInstance] =\n    React.useState\u003cReturnType\u003ctypeof createMonacoGhostInstance\u003e\u003e();\n\n  // Configuration and helpers\n  const monacoGhostConfig = {\n    api: {\n      getCodeAssistSuggestions: async () =\u003e ({\n        Suggests: [{ Text: 'System.out.println(\"Hello, World!\");' }],\n        RequestId: 'demo-request',\n      }),\n    },\n    eventHandlers: {\n      onCompletionAccept: text =\u003e console.log('Accepted:', text),\n      onCompletionDecline: (text, reason, otherSuggestions) =\u003e\n        console.log('Declined:', text, reason, otherSuggestions),\n      onCompletionIgnore: (text, otherSuggestions) =\u003e\n        console.log('Ignored:', text, otherSuggestions),\n      onCompletionError: error =\u003e console.error('Error:', error),\n    },\n    config: {\n      language: 'java',\n      debounceTime: 200,\n      suggestionCache: {\n        enabled: true,\n      },\n    },\n  };\n\n  // Initialize ghost instance when enabled\n  React.useEffect(() =\u003e {\n    if (monacoGhostInstance \u0026\u0026 isCodeAssistEnabled) {\n      monacoGhostInstance.register(monacoGhostConfig);\n    }\n\n    return () =\u003e {\n      monacoGhostInstance?.unregister();\n    };\n  }, [isCodeAssistEnabled, monacoGhostConfig, monacoGhostInstance]);\n\n  const editorDidMount = (editor: monaco.editor.IStandaloneCodeEditor) =\u003e {\n    setMonacoGhostInstance(createMonacoGhostInstance(editor));\n  };\n\n  return (\n    \u003cMonacoEditor\n      width=\"800\"\n      height=\"600\"\n      language=\"java\"\n      theme=\"vs-dark\"\n      value=\"// Your Java code here\"\n      options={{\n        selectOnLineNumbers: true,\n        minimap: { enabled: false },\n        automaticLayout: true,\n      }}\n      editorDidMount={editorDidMount}\n    /\u003e\n  );\n}\n```\n\nThis approach gives you more control over when the ghost instance is created and destroyed, and allows for more complex initialization logic if needed.\n\n\u003c/details\u003e\n\n### Pre-built editor component \n\n\u003cdetails\u003e\n\u003csummary\u003eUsing the pre-built editor component - Simplest way to get started\u003c/summary\u003e\n\n```typescript\n// Using the pre-built editor component\nimport { MonacoEditor } from '@ydb-platform/monaco-ghost';\n\nfunction MyApp() {\n  // SQL-specific API implementation\n  const sqlApi = {\n    getCodeAssistSuggestions: async () =\u003e ({\n      Suggests: [{ Text: 'SELECT * FROM users;' }],\n      RequestId: 'demo-request',\n    }),\n  };\n\n  // SQL-specific configuration\n  const sqlConfig = {\n    debounceTime: 200,\n    suggestionCache: {\n      enabled: true,\n    },\n  };\n\n  return (\n    \u003cMonacoEditor\n      initialValue=\"-- Your SQL code here\"\n      language=\"sql\"\n      theme=\"vs-dark\" // or \"vs-light\"\n      api={sqlApi}\n      config={sqlConfig}\n      onCompletionAccept={text =\u003e console.log('Accepted:', text)}\n      onCompletionDecline={(text, reason, otherSuggestions) =\u003e\n        console.log('Declined:', text, reason, otherSuggestions)\n      }\n      onCompletionIgnore={(text, otherSuggestions) =\u003e\n        console.log('Ignored:', text, otherSuggestions)\n      }\n      onCompletionError={error =\u003e console.error('Error:', error)}\n      editorOptions={{\n        minimap: { enabled: false },\n        fontSize: 14,\n      }}\n    /\u003e\n  );\n}\n```\n\n\u003c/details\u003e\n\n### Vanilla JavaScript\n\n\u003cdetails\u003e\n\u003csummary\u003eView Vanilla JavaScript implementation\u003c/summary\u003e\n\n```typescript\nimport * as monaco from 'monaco-editor';\nimport {\n  createCodeCompletionService,\n  registerCompletionCommands,\n} from '@ydb-platform/monaco-ghost';\n\n// Create language-specific API implementation\nconst sqlApi = {\n  getCodeAssistSuggestions: async data =\u003e {\n    // Call your completion service\n    // Return suggestions in the expected format\n    return {\n      Suggests: [{ Text: 'SELECT * FROM users;' }],\n      RequestId: 'request-id',\n    };\n  },\n};\n\n// Configure the adapter with language-specific settings\nconst sqlConfig = {\n  debounceTime: 200,\n  suggestionCache: {\n    enabled: true,\n  },\n};\n\n// Create provider for SQL\nconst sqlCompletionProvider = createCodeCompletionService(sqlApi, sqlConfig);\n\n// Subscribe to completion events with type safety\nsqlCompletionProvider.events.on('completion:accept', data =\u003e {\n  console.log('Completion accepted:', data.acceptedText);\n});\n\nsqlCompletionProvider.events.on('completion:decline', data =\u003e {\n  console.log(\n    'Completion declined:',\n    data.suggestionText,\n    'reason:',\n    data.reason,\n    'other suggestions:',\n    data.otherSuggestions\n  );\n});\n\nsqlCompletionProvider.events.on('completion:ignore', data =\u003e {\n  console.log(\n    'Completion ignored:',\n    data.suggestionText,\n    'other suggestions:',\n    data.otherSuggestions\n  );\n});\n\nsqlCompletionProvider.events.on('completion:error', error =\u003e {\n  console.error('Completion error:', error);\n});\n\n// Register with Monaco for SQL\nmonaco.languages.registerInlineCompletionsProvider(['sql'], sqlCompletionProvider);\n\n// Register commands (assuming you have an editor instance)\nregisterCompletionCommands(monaco, sqlCompletionProvider, editor);\n```\n\n\u003c/details\u003e\n\n## 📚 Documentation\n\n### 🎮 Keyboard Shortcuts\n\n| Key      | Action                       |\n| -------- | ---------------------------- |\n| `Tab`    | Accept current suggestion    |\n| `Escape` | Decline current suggestion   |\n| `Alt+]`  | Cycle to next suggestion     |\n| `Alt+[`  | Cycle to previous suggestion |\n\n### ⚙️ Configuration\n\n```typescript\ninterface CodeCompletionConfig {\n  // Required when using hooks\n  language?: string; // The language this configuration applies to (e.g., 'sql', 'java')\n\n  // Performance settings\n  debounceTime?: number; // Time in ms to debounce API calls (default: 200)\n\n  // Cache settings\n  suggestionCache?: {\n    enabled?: boolean; // Whether to enable suggestion caching (default: true)\n  };\n}\n```\n\n### 🔌 API Interface\n\n\u003cdetails\u003e\n\u003csummary\u003eView API Interface details\u003c/summary\u003e\n\n```typescript\ninterface ICodeCompletionAPI {\n  getCodeAssistSuggestions(data: PromptFile[]): Promise\u003cSuggestions\u003e;\n}\n\nexport interface PromptPosition {\n  lineNumber: number;\n  column: number;\n}\n\nexport interface PromptFragment {\n  text: string;\n  start: PromptPosition;\n  end: PromptPosition;\n}\n\nexport interface PromptFile {\n  path: string;\n  fragments: PromptFragment[];\n  cursorPosition: PromptPosition;\n}\n\nexport interface Suggestions {\n  items: string[];\n  requestId?: string;\n}\n\n```\n\u003c/details\u003e\n\n### 📊 Events\n\n\u003cdetails\u003e\n\u003csummary\u003eView Events documentation\u003c/summary\u003e\n\nThe completion service emits four types of events with rich data:\n\n#### 1. Acceptance Events\n\n```typescript\ninterface CompletionAcceptEvent {\n  requestId: string;\n  acceptedText: string;\n}\n\ncompletionProvider.events.on('completion:accept', (data: CompletionAcceptEvent) =\u003e {\n  console.log('Accepted:', data.acceptedText);\n});\n```\n\n#### 2. Decline Events\n\n```typescript\ninterface CompletionDeclineEvent {\n  requestId: string;\n  suggestionText: string;\n  reason: string;\n  hitCount: number;\n  otherSuggestions: string[];\n}\n\ncompletionProvider.events.on('completion:decline', (data: CompletionDeclineEvent) =\u003e {\n  console.log('Declined:', data.suggestionText, 'reason:', data.reason);\n  console.log('Other suggestions:', data.otherSuggestions);\n  console.log('Times shown:', data.hitCount);\n});\n```\n\n#### 3. Ignore Events\n\n```typescript\ninterface CompletionIgnoreEvent {\n  requestId: string;\n  suggestionText: string;\n  otherSuggestions: string[];\n}\n\ncompletionProvider.events.on('completion:ignore', (data: CompletionIgnoreEvent) =\u003e {\n  console.log('Ignored:', data.suggestionText);\n  console.log('Other suggestions:', data.otherSuggestions);\n});\n```\n\n#### 4. Error Events\n\n```typescript\ncompletionProvider.events.on('completion:error', (error: Error) =\u003e {\n  console.error('Completion error:', error);\n});\n```\n\n\u003c/details\u003e\n\n## 🛠️ Development\n\n### Setup\n\n```bash\n# Install dependencies\nnpm install\n\n# Start Storybook for development\nnpm run storybook\n\n# Run tests\nnpm run test\n\n# Run tests with coverage\nnpm run test:coverage\n```\n\n### Build System\n\nThe package uses a hybrid build system:\n\n- **TypeScript (tsc)** for type checking and declaration files\n- **esbuild** for fast, optimized builds\n\nOutput Formats:\n\n- **CommonJS**: `dist/cjs/index.js`\n- **ES Modules**: `dist/esm/index.js`\n- **TypeScript Declarations**: `dist/types/index.d.ts`\n\n\u003cdetails\u003e\n\u003csummary\u003eView Build Commands\u003c/summary\u003e\n\n```bash\n# Type checking only\nnpm run type-check\n\n# Build type declarations\nnpm run build:types\n\n# Build CommonJS version\nnpm run build:cjs\n\n# Build ES Modules version\nnpm run build:esm\n\n# Full build (all formats)\nnpm run build\n```\n\n\u003c/details\u003e\n\n## 👥 Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n\u003cdetails\u003e\n\u003csummary\u003eView Development Guidelines\u003c/summary\u003e\n\n### Development Guidelines\n\n#### 1. Code Context\n\n- Handle text limits appropriately\n- Maintain cursor position accuracy\n- Consider edge cases\n- Support partial text acceptance\n\n#### 2. Error Handling\n\n- Wrap API calls in try-catch blocks\n- Fail gracefully on errors\n- Log issues without breaking editor\n- Emit error events for monitoring\n\n#### 3. Performance\n\n- Use debouncing for API calls\n- Implement efficient caching\n- Track suggestion hit counts\n- Clean up resources properly\n\n#### 4. Testing\n\n- Add tests for new features\n- Maintain backward compatibility\n- Test edge cases\n- Verify event handling\n\u003c/details\u003e\n\n## 📄 License\n\nApache-2.0 - see [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fydb-platform%2Fmonaco-ghost","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fydb-platform%2Fmonaco-ghost","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fydb-platform%2Fmonaco-ghost/lists"}