lynkr 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +12 -0
- package/CLAUDE.md +39 -0
- package/LICENSE +21 -0
- package/README.md +417 -0
- package/bin/cli.js +3 -0
- package/index.js +3 -0
- package/package.json +54 -0
- package/src/api/middleware/logging.js +37 -0
- package/src/api/middleware/session.js +55 -0
- package/src/api/router.js +80 -0
- package/src/cache/prompt.js +183 -0
- package/src/clients/databricks.js +72 -0
- package/src/config/index.js +301 -0
- package/src/db/index.js +192 -0
- package/src/diff/comments.js +153 -0
- package/src/edits/index.js +171 -0
- package/src/indexer/index.js +1610 -0
- package/src/indexer/navigation/index.js +32 -0
- package/src/indexer/navigation/providers/treeSitter.js +36 -0
- package/src/indexer/parser.js +324 -0
- package/src/logger/index.js +27 -0
- package/src/mcp/client.js +194 -0
- package/src/mcp/index.js +34 -0
- package/src/mcp/permissions.js +69 -0
- package/src/mcp/registry.js +225 -0
- package/src/mcp/sandbox.js +238 -0
- package/src/metrics/index.js +38 -0
- package/src/orchestrator/index.js +1492 -0
- package/src/policy/index.js +212 -0
- package/src/policy/web-fallback.js +33 -0
- package/src/server.js +73 -0
- package/src/sessions/index.js +15 -0
- package/src/sessions/record.js +31 -0
- package/src/sessions/store.js +179 -0
- package/src/tasks/store.js +349 -0
- package/src/tests/coverage.js +173 -0
- package/src/tests/index.js +171 -0
- package/src/tests/store.js +213 -0
- package/src/tools/edits.js +94 -0
- package/src/tools/execution.js +169 -0
- package/src/tools/git.js +1346 -0
- package/src/tools/index.js +258 -0
- package/src/tools/indexer.js +360 -0
- package/src/tools/mcp-remote.js +81 -0
- package/src/tools/mcp.js +116 -0
- package/src/tools/process.js +151 -0
- package/src/tools/stubs.js +55 -0
- package/src/tools/tasks.js +260 -0
- package/src/tools/tests.js +132 -0
- package/src/tools/web.js +286 -0
- package/src/tools/workspace.js +173 -0
- package/src/workspace/index.js +95 -0
package/.eslintrc.cjs
ADDED
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!-- Generated by claude-code indexer -->
|
|
2
|
+
# CLAUDE.md
|
|
3
|
+
|
|
4
|
+
- After invoking `web_search`, wait for the tool result and let the assistant finish summarizing before sending any new user prompts.
|
|
5
|
+
- When the user asks for news or search results, respond with the summary already generated in the assistant’s next turn; do not restart the conversation unless asked.
|
|
6
|
+
- Avoid repeating warmup or onboarding messages once the user has made their real request.
|
|
7
|
+
|
|
8
|
+
# Project Overview
|
|
9
|
+
|
|
10
|
+
- Workspace root: `/Users/vishalveera.reddy/claude-code`
|
|
11
|
+
- Indexed at: 2025-11-23T23:22:56.258Z
|
|
12
|
+
- Files indexed: 52
|
|
13
|
+
|
|
14
|
+
## Language Mix
|
|
15
|
+
|
|
16
|
+
- javascript: 44 files (84.62%)
|
|
17
|
+
- json: 3 files (5.77%)
|
|
18
|
+
- yaml: 1 files (1.92%)
|
|
19
|
+
- shell: 1 files (1.92%)
|
|
20
|
+
|
|
21
|
+
## Framework Signals
|
|
22
|
+
|
|
23
|
+
- **node** (1 signals)
|
|
24
|
+
- package.json detected (package.json)
|
|
25
|
+
- **express** (1 signals)
|
|
26
|
+
- Express dependency detected (package.json)
|
|
27
|
+
|
|
28
|
+
## Style Guide Insights
|
|
29
|
+
|
|
30
|
+
- eslint: .eslintrc.cjs (ESLint configuration)
|
|
31
|
+
|
|
32
|
+
## Top Workspace Dependencies
|
|
33
|
+
|
|
34
|
+
- ( (refs: 13)
|
|
35
|
+
|
|
36
|
+
## Re-index Guidance
|
|
37
|
+
|
|
38
|
+
Run `workspace_index_rebuild` to refresh this document after making large changes.
|
|
39
|
+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Vishal Veera Reddy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# Lynkr
|
|
2
|
+
|
|
3
|
+
> Drop-in HTTP proxy that lets Claude Code CLI talk to non-Anthropic backends, manage local tools, and compose Model Context Protocol (MCP) servers with prompt caching, repo intelligence, and Git-aware automation.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Overview](#overview)
|
|
8
|
+
2. [Core Capabilities](#core-capabilities)
|
|
9
|
+
- [Repo Intelligence & Navigation](#repo-intelligence--navigation)
|
|
10
|
+
- [Git Workflow Enhancements](#git-workflow-enhancements)
|
|
11
|
+
- [Diff & Change Management](#diff--change-management)
|
|
12
|
+
- [Execution & Tooling](#execution--tooling)
|
|
13
|
+
- [Workflow & Collaboration](#workflow--collaboration)
|
|
14
|
+
- [UX, Monitoring, and Logs](#ux-monitoring-and-logs)
|
|
15
|
+
3. [Architecture](#architecture)
|
|
16
|
+
4. [Getting Started](#getting-started)
|
|
17
|
+
5. [Configuration Reference](#configuration-reference)
|
|
18
|
+
6. [Runtime Operations](#runtime-operations)
|
|
19
|
+
- [Launching the Proxy](#launching-the-proxy)
|
|
20
|
+
- [Connecting Claude Code CLI](#connecting-claude-code-cli)
|
|
21
|
+
- [Using Built-in Workspace Tools](#using-built-in-workspace-tools)
|
|
22
|
+
- [Working with Prompt Caching](#working-with-prompt-caching)
|
|
23
|
+
- [Integrating MCP Servers](#integrating-mcp-servers)
|
|
24
|
+
7. [Manual Test Matrix](#manual-test-matrix)
|
|
25
|
+
8. [Troubleshooting](#troubleshooting)
|
|
26
|
+
9. [Roadmap & Known Gaps](#roadmap--known-gaps)
|
|
27
|
+
10. [FAQ](#faq)
|
|
28
|
+
11. [License](#license)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Overview
|
|
33
|
+
|
|
34
|
+
This repository contains a Node.js service that emulates the Anthropic Claude Code backend so that the Claude Code CLI (or any compatible client) can operate against alternative model providers and custom tooling.
|
|
35
|
+
|
|
36
|
+
Key highlights:
|
|
37
|
+
|
|
38
|
+
- **Claude provider adapters** – Works with Databricks (default) and Azure-hosted Anthropic endpoints; requests are normalized to each provider while returning Claude-flavored responses.
|
|
39
|
+
- **Workspace awareness** – Local repo indexing, `CLAUDE.md` summaries, language-aware navigation, and Git helpers mirror core Claude Code workflows.
|
|
40
|
+
- **Model Context Protocol (MCP) orchestration** – Automatically discovers MCP manifests, launches JSON-RPC 2.0 servers, and re-exposes their tools inside the proxy.
|
|
41
|
+
- **Prompt caching** – Re-uses repeated prompts to reduce latency and token consumption, matching Claude’s own cache semantics.
|
|
42
|
+
- **Policy enforcement** – Environment-driven guardrails control Git operations, test requirements, web fetch fallbacks, and sandboxing rules.
|
|
43
|
+
|
|
44
|
+
The result is a self-hosted alternative that stays close to Anthropic’s ergonomics while remaining hackable for experimentation.
|
|
45
|
+
|
|
46
|
+
> **Compatibility note:** Claude models hosted on Databricks work out of the box. Set `MODEL_PROVIDER=azure-anthropic` (and related credentials) to target the Azure-hosted Anthropic `/anthropic/v1/messages` endpoint. Additional providers will require future adapters.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Core Capabilities
|
|
51
|
+
|
|
52
|
+
### Repo Intelligence & Navigation
|
|
53
|
+
|
|
54
|
+
- Fast indexer builds a lightweight SQLite catalog of files, symbols, references, and framework hints.
|
|
55
|
+
- `CLAUDE.md` summary highlights language mix, frameworks, lint configs, and dependency signals.
|
|
56
|
+
- Symbol search and reference lookups return definition sites and cross-file usage for supported languages (TypeScript/JavaScript/Python via Tree-sitter parsers) with heuristic fallbacks for others.
|
|
57
|
+
- Automatic invalidation ensures removed files disappear from search results after `workspace_index_rebuild`.
|
|
58
|
+
|
|
59
|
+
### Git Workflow Enhancements
|
|
60
|
+
|
|
61
|
+
- Git status, diff, stage, commit, push, and pull tooling via `src/tools/git.js`.
|
|
62
|
+
- Policy flags such as `POLICY_GIT_ALLOW_PUSH` and `POLICY_GIT_REQUIRE_TESTS` enforce push restrictions or test gating.
|
|
63
|
+
- Diff review endpoints summarise changes and highlight risks, feeding the AI review surface.
|
|
64
|
+
- Release note generator composes summarized change logs for downstream publishing.
|
|
65
|
+
|
|
66
|
+
### Diff & Change Management
|
|
67
|
+
|
|
68
|
+
- Unified diff summaries with optional AI review (`workspace_diff_review`).
|
|
69
|
+
- Release note synthesis from Git history.
|
|
70
|
+
- Test harness integrates with git policies to ensure guarding before commit/push events.
|
|
71
|
+
- (Planned) Per-file threaded reviews and automated risk estimation (see [Roadmap](#roadmap--known-gaps)).
|
|
72
|
+
|
|
73
|
+
### Execution & Tooling
|
|
74
|
+
|
|
75
|
+
- Tool execution pipeline sandboxes or runs tools in the host workspace based on policy.
|
|
76
|
+
- MCP sandbox orchestration (Docker runtime by default) optionally isolates external tools with mount and permission controls.
|
|
77
|
+
- Automated testing harness exposes `workspace_test_run`, `workspace_test_history`, and `workspace_test_summary`.
|
|
78
|
+
- Prompt caching reduces repeated token usage for iterative conversations.
|
|
79
|
+
|
|
80
|
+
### Workflow & Collaboration
|
|
81
|
+
|
|
82
|
+
- Lightweight task tracker (`workspace_task_*` tools) persists TODO items in SQLite.
|
|
83
|
+
- Session database (`data/sessions.db`) stores conversational transcripts for auditing.
|
|
84
|
+
- Policy web fallback fetches limited remote data when explicitly permitted.
|
|
85
|
+
|
|
86
|
+
### UX, Monitoring, and Logs
|
|
87
|
+
|
|
88
|
+
- Pino-based structured logs with timestamps and severity.
|
|
89
|
+
- Request/response logging for Databricks interactions (visible in stdout).
|
|
90
|
+
- Session appenders log every user, assistant, and tool turn for reproducibility.
|
|
91
|
+
- Metrics directory ready for future Prometheus/StatsD integration.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Architecture
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
┌────────────────────┐ ┌───────────────────────┐
|
|
99
|
+
│ Claude Code CLI │──HTTP│ Claude Code Proxy │
|
|
100
|
+
│ (or Claude client) │ │ (Express API gateway) │
|
|
101
|
+
└────────────────────┘ └──────────┬────────────┘
|
|
102
|
+
│
|
|
103
|
+
┌───────────────────────────────┼─────────────────────────────┐
|
|
104
|
+
│ │ │
|
|
105
|
+
┌───────▼───────┐ ┌───────▼────────┐ ┌──────▼───────┐
|
|
106
|
+
│ Orchestrator │ │ Prompt Cache │ │ Session Store│
|
|
107
|
+
│ (agent loop) │ │ (LRU + TTL) │ │ (SQLite) │
|
|
108
|
+
└───────┬───────┘ └───────┬────────┘ └──────┬───────┘
|
|
109
|
+
│ │ │
|
|
110
|
+
┌───────▼────────────────────────────┐ │ ┌────────────────────────▼──────┐
|
|
111
|
+
│ Tool Registry & Policy Engine │ │ │ Indexer / Repo Intelligence │
|
|
112
|
+
│ (workspace, git, diff, MCP tools) │ │ │ (SQLite catalog + CLAUDE.md) │
|
|
113
|
+
└───────┬────────────────────────────┘ │ └────────────────────────┬──────┘
|
|
114
|
+
│ │ │
|
|
115
|
+
┌───────▼────────┐ ┌─────────────────────────────┐ ┌──────▼──────────┐
|
|
116
|
+
│ MCP Registry │ │ Provider Adapters │ │ Sandbox Runtime │
|
|
117
|
+
│ (manifest -> │────────RPC────│ (Databricks / Azure Anthropic│──────┐ │ (Docker, etc.) │
|
|
118
|
+
│ JSON-RPC client│ │ + future backends) │ │ └────────────────┘
|
|
119
|
+
└────────────────┘ └───────────┬──────────────────┘ │
|
|
120
|
+
│ │
|
|
121
|
+
┌───────────▼───────────┐ │
|
|
122
|
+
│ Databricks Serving │─────────────┘
|
|
123
|
+
│ Endpoint (REST) │
|
|
124
|
+
└───────────────────────┘
|
|
125
|
+
│
|
|
126
|
+
┌───────────▼───────────┐
|
|
127
|
+
│ Azure Anthropic │
|
|
128
|
+
│ `/anthropic/v1/messages`│
|
|
129
|
+
└───────────────────────┘
|
|
130
|
+
|
|
131
|
+
┌─────────▼─────────┐
|
|
132
|
+
│ External MCP tools │
|
|
133
|
+
│ (GitHub, Jira, etc)│
|
|
134
|
+
└────────────────────┘
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- **`src/api/router.js`** – Express routes that accept Claude-compatible `/v1/messages` requests.
|
|
138
|
+
- **`src/orchestrator/index.js`** – Agent loop handling model invocation, tool execution, prompt caching, and policy enforcement.
|
|
139
|
+
- **`src/cache/prompt.js`** – LRU cache implementation with SHA-256 keying and TTL eviction.
|
|
140
|
+
- **`src/mcp/*`** – Manifest discovery, JSON-RPC 2.0 client, and dynamic tool registration for MCP servers.
|
|
141
|
+
- **`src/tools/*`** – Built-in workspace, git, diff, testing, task, and MCP bridging tools.
|
|
142
|
+
- **`src/indexer/index.js`** – File crawler and metadata extractor that persists into SQLite and regenerates `CLAUDE.md`.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Getting Started
|
|
147
|
+
|
|
148
|
+
### Prerequisites
|
|
149
|
+
|
|
150
|
+
- **Node.js 18+** (required for the global `fetch` API).
|
|
151
|
+
- **npm** (bundled with Node).
|
|
152
|
+
- **Databricks account** with a Claude-compatible serving endpoint (e.g., `databricks-claude-sonnet-4-5`).
|
|
153
|
+
- Optional: **Docker** for MCP sandboxing and tool isolation.
|
|
154
|
+
- Optional: **Claude Code CLI** (latest release). Configure it to target the proxy URL instead of api.anthropic.com.
|
|
155
|
+
|
|
156
|
+
### Installation
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
git clone https://github.com/vishalveerareddy123/Lynkr.git
|
|
160
|
+
cd Lynkr
|
|
161
|
+
npm install
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Populate an `.env` file (or export environment variables) before starting:
|
|
165
|
+
|
|
166
|
+
```env
|
|
167
|
+
MODEL_PROVIDER=databricks
|
|
168
|
+
DATABRICKS_API_BASE=https://<your-workspace>.cloud.databricks.com
|
|
169
|
+
DATABRICKS_API_KEY=<personal-access-token>
|
|
170
|
+
PORT=8080
|
|
171
|
+
WORKSPACE_ROOT=/path/to/your/repo
|
|
172
|
+
PROMPT_CACHE_ENABLED=true
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
You can copy `.env.example` if you maintain one, or rely on shell exports.
|
|
176
|
+
|
|
177
|
+
#### Selecting a model provider
|
|
178
|
+
|
|
179
|
+
Set `MODEL_PROVIDER` to select the upstream endpoint:
|
|
180
|
+
|
|
181
|
+
- `MODEL_PROVIDER=databricks` (default) – expects `DATABRICKS_API_BASE`, `DATABRICKS_API_KEY`, and optionally `DATABRICKS_ENDPOINT_PATH`.
|
|
182
|
+
- `MODEL_PROVIDER=azure-anthropic` – routes requests to Azure’s `/anthropic/v1/messages` endpoint and uses the headers Azure expects.
|
|
183
|
+
|
|
184
|
+
For Azure-hosted Anthropic, supply the Azure-specific credentials:
|
|
185
|
+
|
|
186
|
+
```env
|
|
187
|
+
MODEL_PROVIDER=azure-anthropic
|
|
188
|
+
AZURE_ANTHROPIC_ENDPOINT=https://<resource-name>.services.ai.azure.com/anthropic/v1/messages
|
|
189
|
+
AZURE_ANTHROPIC_API_KEY=<azure-api-key>
|
|
190
|
+
AZURE_ANTHROPIC_VERSION=2023-06-01
|
|
191
|
+
PORT=8080
|
|
192
|
+
WORKSPACE_ROOT=/path/to/your/repo
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Configuration Reference
|
|
198
|
+
|
|
199
|
+
| Variable | Description | Default |
|
|
200
|
+
|----------|-------------|---------|
|
|
201
|
+
| `PORT` | HTTP port for the proxy server. | `8080` |
|
|
202
|
+
| `WORKSPACE_ROOT` | Filesystem path exposed to workspace tools and indexer. | `process.cwd()` |
|
|
203
|
+
| `MODEL_PROVIDER` | Selects the model backend (`databricks`, `azure-anthropic`). | `databricks` |
|
|
204
|
+
| `MODEL_DEFAULT` | Overrides the default model/deployment name sent to the provider. | Provider-specific default |
|
|
205
|
+
| `DATABRICKS_API_BASE` | Base URL of your Databricks workspace (required when `MODEL_PROVIDER=databricks`). | – |
|
|
206
|
+
| `DATABRICKS_API_KEY` | Databricks PAT used for the serving endpoint (required for Databricks). | – |
|
|
207
|
+
| `DATABRICKS_ENDPOINT_PATH` | Optional override for the Databricks serving endpoint path. | `/serving-endpoints/databricks-claude-sonnet-4-5/invocations` |
|
|
208
|
+
| `AZURE_ANTHROPIC_ENDPOINT` | Full HTTPS endpoint for Azure-hosted Anthropic `/anthropic/v1/messages` (required when `MODEL_PROVIDER=azure-anthropic`). | – |
|
|
209
|
+
| `AZURE_ANTHROPIC_API_KEY` | API key supplied via the `x-api-key` header for Azure Anthropic. | – |
|
|
210
|
+
| `AZURE_ANTHROPIC_VERSION` | Anthropic API version header for Azure Anthropic calls. | `2023-06-01` |
|
|
211
|
+
| `PROMPT_CACHE_ENABLED` | Toggle the prompt cache system. | `true` |
|
|
212
|
+
| `PROMPT_CACHE_TTL_MS` | Milliseconds before cached prompts expire. | `300000` (5 minutes) |
|
|
213
|
+
| `PROMPT_CACHE_MAX_ENTRIES` | Maximum number of cached prompts retained. | `64` |
|
|
214
|
+
| `POLICY_MAX_STEPS` | Max agent loop iterations before timeout. | `8` |
|
|
215
|
+
| `POLICY_GIT_ALLOW_PUSH` | Allow/disallow `workspace_git_push`. | `false` |
|
|
216
|
+
| `POLICY_GIT_REQUIRE_TESTS` | Enforce passing tests before `workspace_git_commit`. | `false` |
|
|
217
|
+
| `POLICY_GIT_TEST_COMMAND` | Custom test command invoked by policies. | `null` |
|
|
218
|
+
| `WEB_SEARCH_ENDPOINT` | URL for policy-driven web fetch fallback. | `http://localhost:8888/search` |
|
|
219
|
+
| `WEB_SEARCH_ALLOWED_HOSTS` | Comma-separated allowlist for `web_fetch`. | `null` |
|
|
220
|
+
| `MCP_SERVER_MANIFEST` | Single manifest file for MCP server. | `null` |
|
|
221
|
+
| `MCP_MANIFEST_DIRS` | Semicolon-separated directories scanned for manifests. | `~/.claude/mcp` |
|
|
222
|
+
| `MCP_SANDBOX_ENABLED` | Enable container sandbox for MCP tools (requires `MCP_SANDBOX_IMAGE`). | `true` |
|
|
223
|
+
| `MCP_SANDBOX_IMAGE` | Docker/OCI image name used for sandboxing. | `null` |
|
|
224
|
+
| `WORKSPACE_TEST_COMMAND` | Default CLI used by `workspace_test_run`. | `null` |
|
|
225
|
+
| `WORKSPACE_TEST_TIMEOUT_MS` | Test harness timeout. | `600000` |
|
|
226
|
+
| `WORKSPACE_TEST_COVERAGE_FILES` | Comma-separated coverage summary files. | `coverage/coverage-summary.json` |
|
|
227
|
+
|
|
228
|
+
See `src/config/index.js` for the full configuration matrix, including sandbox mounts, permissions, and MCP networking policies.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Runtime Operations
|
|
233
|
+
|
|
234
|
+
### Launching the Proxy
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# Development: auto-restarts on file changes (requires nodemon)
|
|
238
|
+
npm run dev
|
|
239
|
+
|
|
240
|
+
# Production
|
|
241
|
+
npm start
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Logs stream to stdout. The server listens on `PORT` and exposes `/v1/messages` in the Anthropic-compatible shape.
|
|
245
|
+
|
|
246
|
+
### Connecting Claude Code CLI
|
|
247
|
+
|
|
248
|
+
1. Install or upgrade Claude Code CLI.
|
|
249
|
+
2. Export the proxy endpoint:
|
|
250
|
+
```bash
|
|
251
|
+
export ANTHROPIC_BASE_URL=http://localhost:8080
|
|
252
|
+
export ANTHROPIC_API_KEY=dummy # not used, but Anthropic CLI requires it
|
|
253
|
+
```
|
|
254
|
+
3. Launch `claude` CLI within `WORKSPACE_ROOT`.
|
|
255
|
+
4. Invoke commands as normal; the CLI will route requests through the proxy.
|
|
256
|
+
|
|
257
|
+
### Using Built-in Workspace Tools
|
|
258
|
+
|
|
259
|
+
You can call tools programmatically via HTTP:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
curl http://localhost:8080/v1/messages \
|
|
263
|
+
-H 'Content-Type: application/json' \
|
|
264
|
+
-H 'x-session-id: manual-test' \
|
|
265
|
+
-d '{
|
|
266
|
+
"model": "claude-proxy",
|
|
267
|
+
"messages": [{ "role": "user", "content": "Rebuild the workspace index." }],
|
|
268
|
+
"tools": [{
|
|
269
|
+
"name": "workspace_index_rebuild",
|
|
270
|
+
"type": "function",
|
|
271
|
+
"description": "Rebuild the repo index and project summary",
|
|
272
|
+
"input_schema": { "type": "object" }
|
|
273
|
+
}],
|
|
274
|
+
"tool_choice": {
|
|
275
|
+
"type": "function",
|
|
276
|
+
"function": { "name": "workspace_index_rebuild" }
|
|
277
|
+
}
|
|
278
|
+
}'
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Tool responses appear in the assistant content block with structured JSON.
|
|
282
|
+
|
|
283
|
+
### Working with Prompt Caching
|
|
284
|
+
|
|
285
|
+
- Set `PROMPT_CACHE_ENABLED=true` (default) to activate the cache.
|
|
286
|
+
- The cache retains up to `PROMPT_CACHE_MAX_ENTRIES` entries for `PROMPT_CACHE_TTL_MS` milliseconds.
|
|
287
|
+
- A cache hit skips the Databricks call; response metadata populates `cache_read_input_tokens`.
|
|
288
|
+
- Cache misses record `cache_creation_input_tokens`, indicating a fresh prompt was cached.
|
|
289
|
+
- Cache entries are invalidated automatically when they age out; no manual maintenance required.
|
|
290
|
+
- Disable caching temporarily by exporting `PROMPT_CACHE_ENABLED=false` and restarting the server.
|
|
291
|
+
|
|
292
|
+
### Integrating MCP Servers
|
|
293
|
+
|
|
294
|
+
1. Place MCP manifest JSON files under `~/.claude/mcp` or configure `MCP_MANIFEST_DIRS`.
|
|
295
|
+
2. Each manifest should define the server command, arguments, and capabilities per the MCP spec.
|
|
296
|
+
3. Restart the proxy; manifests are loaded at boot. Registered tools appear with names `mcp_<server>_<tool>`.
|
|
297
|
+
4. Invoke tools via `workspace_mcp_call` or indirectly when the assistant selects them.
|
|
298
|
+
5. Sandbox settings (`MCP_SANDBOX_*`) control Docker runtime, mounts, environment passthrough, and permission prompts.
|
|
299
|
+
|
|
300
|
+
### Running with Docker
|
|
301
|
+
|
|
302
|
+
A `Dockerfile` and `docker-compose.yml` are included for reproducible deployments.
|
|
303
|
+
|
|
304
|
+
#### Build & run with Docker Compose
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
cp .env.example .env # populate with Databricks/Azure credentials, workspace path, etc.
|
|
308
|
+
docker compose up --build
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
The compose file exposes:
|
|
312
|
+
|
|
313
|
+
- Proxy HTTP API on `8080`
|
|
314
|
+
- Optional SearxNG instance on `8888` (started automatically when `WEB_SEARCH_ENDPOINT` is the default)
|
|
315
|
+
|
|
316
|
+
Workspace files are mounted into the container (`./:/workspace`), and `./data` is persisted for SQLite state.
|
|
317
|
+
|
|
318
|
+
#### Manual Docker build
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
docker build -t claude-code-proxy .
|
|
322
|
+
docker run --rm -p 8080:8080 -p 8888:8888 \
|
|
323
|
+
-v "$(pwd)":/workspace \
|
|
324
|
+
-v "$(pwd)/data":/app/data \
|
|
325
|
+
--env-file .env \
|
|
326
|
+
claude-code-proxy
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Adjust port and volume mappings to suit your environment. Ensure the container has access to the target workspace and required credentials.
|
|
330
|
+
|
|
331
|
+
### Provider-specific behaviour
|
|
332
|
+
|
|
333
|
+
- **Databricks** – Mirrors Anthropic’s hosted behaviour. Automatic policy web fallbacks (`needsWebFallback`) can trigger an extra `web_fetch`, and the upstream service executes dynamic pages on your behalf.
|
|
334
|
+
- **Azure Anthropic** – Requests are normalised to Azure’s payload shape. The proxy disables automatic `web_fetch` fallbacks to avoid duplicate tool executions; instead, the assistant surfaces a diagnostic message and you can trigger the tool manually if required.
|
|
335
|
+
- In both cases, `web_search` and `web_fetch` run locally. They do not execute JavaScript, so pages that render data client-side (Google Finance, etc.) will return scaffolding only. Prefer JSON/CSV quote APIs (e.g. Yahoo chart API) when you need live financial data.
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Manual Test Matrix
|
|
340
|
+
|
|
341
|
+
| Area | Scenario | Steps | Expected Outcome |
|
|
342
|
+
|------|----------|-------|------------------|
|
|
343
|
+
| **Indexing & Repo Intelligence** | Rebuild index | 1. `workspace_index_rebuild` 2. Inspect `CLAUDE.md` 3. Run `workspace_symbol_search` | CLAUDE.md and symbol catalog reflect current repo state. |
|
|
344
|
+
| | Remove file & reindex | 1. Delete a tracked file 2. Rebuild index 3. Search for removed symbol | Symbol search returns no hits; CLAUDE.md drops the file from language counts. |
|
|
345
|
+
| **Language Navigation** | Cross-file definition | 1. Choose TS symbol defined/imported across files 2. Search for symbol 3. Get references | Definition points to source file; references list usages in other files only. |
|
|
346
|
+
| | Unsupported language fallback | 1. Use Ruby file with unique method 2. Symbol search and references | Heuristic matches return without crashing. |
|
|
347
|
+
| **Project Summary** | After tests | 1. Run `workspace_index_rebuild` 2. Call `project_summary` | Summary includes latest test stats and style hints (e.g., ESLint). |
|
|
348
|
+
| | Missing coverage files | 1. Move coverage JSON 2. Call `project_summary` | Response notes missing coverage gracefully. |
|
|
349
|
+
| **Task Tracker** | CRUD flow | 1. `workspace_task_create` 2. `workspace_tasks_list` 3. `workspace_task_update` 4. `workspace_task_set_status` 5. `workspace_task_delete` | Tasks persist across calls; deletion removes entry. |
|
|
350
|
+
| **Git Guards** | Push policy | 1. `POLICY_GIT_ALLOW_PUSH=false` 2. `workspace_git_push` | Request denied with policy message. |
|
|
351
|
+
| | Require tests before commit | 1. `POLICY_GIT_REQUIRE_TESTS=true` 2. Attempt commit without running tests | Commit blocked until tests executed. |
|
|
352
|
+
| **Prompt Cache** | Cache hit | 1. Send identical prompt twice 2. Check logs | Second response logs cache hit; response usage shows `cache_read_input_tokens`. |
|
|
353
|
+
| **MCP** | Manifest discovery | 1. Add manifest 2. Restart proxy 3. Call `workspace_mcp_call` | MCP tools execute via JSON-RPC bridge. |
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Troubleshooting
|
|
358
|
+
|
|
359
|
+
- **`path must be a non-empty string` errors** – Tool calls like `fs_read` require explicit paths. Verify the CLI sent a valid `path` argument.
|
|
360
|
+
- **Agent loop exceeding limits** – Increase `POLICY_MAX_STEPS` or fix misbehaving tool that loops.
|
|
361
|
+
- **`spawn npm test ENOENT`** – Configure `WORKSPACE_TEST_COMMAND` or ensure `npm test` exists in the workspace.
|
|
362
|
+
- **MCP server not discovered** – Confirm manifests live inside `MCP_MANIFEST_DIRS` and contain executable commands. Check logs for discovery errors.
|
|
363
|
+
- **Prompt cache not activating** – Ensure `PROMPT_CACHE_ENABLED=true`. Cache only stores tool-free completions; tool use requests bypass caching by design.
|
|
364
|
+
- **Claude CLI prompts for missing tools** – Verify `tools` array in the client request lists the functions you expect. The proxy only exposes registered handlers.
|
|
365
|
+
- **Dynamic finance pages return stale data** – `web_fetch` fetches static HTML only. Use an API endpoint (e.g. Yahoo Finance chart JSON) or the Databricks-hosted tooling if you need rendered values from heavily scripted pages.
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Roadmap & Known Gaps
|
|
370
|
+
|
|
371
|
+
- **Per-file diff comments & conversation threading** – Planned to mirror Claude’s review UX.
|
|
372
|
+
- **Automated risk assessment tied to diffs** – Future enhancement leveraging test outcomes and static analysis.
|
|
373
|
+
- **Expanded language-server fidelity** – Currently Tree-sitter-based; deeper AST integration or LSP bridging is a future goal.
|
|
374
|
+
- **Claude Skills parity** – Skills are not reproduced; designing a safe, declarative skill layer is an open area.
|
|
375
|
+
- **Coverage dashboards & historical trends** – Test summary tracks latest runs but no long-term history yet.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## FAQ
|
|
380
|
+
|
|
381
|
+
**Q: Is this an exact drop-in replacement for Anthropic’s backend?**
|
|
382
|
+
A: No. It mimics key Claude Code CLI behaviors but is intentionally extensible; certain premium features (Claude Skills, hosted sandboxes) are out of scope.
|
|
383
|
+
|
|
384
|
+
**Q: How does the proxy compare with Anthropic’s hosted backend?**
|
|
385
|
+
A: Functionally they overlap on core workflows (chat, tool calls, repo ops), but differ in scope:
|
|
386
|
+
|
|
387
|
+
| Capability | Anthropic Hosted Backend | Claude Code Proxy |
|
|
388
|
+
|------------|-------------------------|-------------------|
|
|
389
|
+
| Claude models | Anthropic-operated Sonnet/Opus | Adapters for Databricks (default) and Azure Anthropic |
|
|
390
|
+
| Prompt cache | Managed, opaque | Local LRU cache with configurable TTL/size |
|
|
391
|
+
| Git & workspace tools | Anthropic-managed hooks | Local Node handlers (`src/tools/`) with policy gate |
|
|
392
|
+
| Web search/fetch | Hosted browsing agent, JS-capable | Local HTTP fetch (no JS) plus optional policy fallback |
|
|
393
|
+
| MCP orchestration | Anthropic-managed sandbox | Local MCP discovery, optional Docker sandbox |
|
|
394
|
+
| Secure sandboxes | Anthropic-provided remote sandboxes | Optional Docker runtime; full access if disabled |
|
|
395
|
+
| Claude Skills / workflows | Available in hosted product | Not implemented (future roadmap) |
|
|
396
|
+
| Support & SLAs | Anthropic-run service | Self-hosted; you own uptime, auth, logging |
|
|
397
|
+
| Cost & scaling | Usage-billed API | Whatever infra you deploy (Node + dependencies) |
|
|
398
|
+
|
|
399
|
+
The proxy is ideal when you need local control, custom tooling, or non-Anthropic model endpoints. If you require fully managed browsing, secure sandboxes, or enterprise SLA, stick with the hosted backend.
|
|
400
|
+
|
|
401
|
+
**Q: Does prompt caching work like Anthropic’s cache?**
|
|
402
|
+
A: Functionally similar. Identical messages (model, messages, tools, sampling params) reuse cached responses until TTL expires. Tool-invoking turns skip caching.
|
|
403
|
+
|
|
404
|
+
**Q: Can I connect multiple MCP servers?**
|
|
405
|
+
A: Yes. Place multiple manifests in `MCP_MANIFEST_DIRS`. Each server is launched and its tools are namespaced.
|
|
406
|
+
|
|
407
|
+
**Q: How do I change the workspace root?**
|
|
408
|
+
A: Set `WORKSPACE_ROOT` before starting the proxy. The indexer and filesystem tools operate relative to that path.
|
|
409
|
+
|
|
410
|
+
**Q: Where are session transcripts stored?**
|
|
411
|
+
A: In SQLite at `data/sessions.db` (configurable via `SESSION_DB_PATH`).
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## License
|
|
416
|
+
|
|
417
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
package/bin/cli.js
ADDED
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lynkr",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Self-hosted Claude Code proxy with Databricks and Azure Anthropic adapters, workspace tooling, and MCP integration.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"lynkr": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node index.js",
|
|
11
|
+
"dev": "nodemon index.js",
|
|
12
|
+
"lint": "eslint src index.js",
|
|
13
|
+
"test": "echo \"No automated tests configured\" && exit 0"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"claude",
|
|
17
|
+
"anthropic",
|
|
18
|
+
"proxy",
|
|
19
|
+
"databricks",
|
|
20
|
+
"azure",
|
|
21
|
+
"mcp"
|
|
22
|
+
],
|
|
23
|
+
"author": "Vishal Veera Reddy",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/vishalveerareddy123/Lynkr.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/vishalveerareddy123/Lynkr/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/vishalveerareddy123/Lynkr#readme",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18.0.0"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"better-sqlite3": "^9.4.0",
|
|
38
|
+
"diff": "^5.2.0",
|
|
39
|
+
"dotenv": "^16.4.5",
|
|
40
|
+
"express": "^5.1.0",
|
|
41
|
+
"fast-glob": "^3.3.2",
|
|
42
|
+
"pino": "^8.17.2",
|
|
43
|
+
"pino-http": "^8.6.0",
|
|
44
|
+
"tree-sitter": "^0.20.1",
|
|
45
|
+
"tree-sitter-javascript": "^0.20.3",
|
|
46
|
+
"tree-sitter-python": "^0.20.1",
|
|
47
|
+
"tree-sitter-typescript": "^0.20.3"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"eslint": "^8.57.0",
|
|
51
|
+
"nodemon": "^3.1.0",
|
|
52
|
+
"pino-pretty": "^10.2.0"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const pinoHttp = require("pino-http");
|
|
2
|
+
const logger = require("../../logger");
|
|
3
|
+
|
|
4
|
+
function maskHeaders(headers = {}) {
|
|
5
|
+
const clone = { ...headers };
|
|
6
|
+
if (typeof clone["x-api-key"] === "string") {
|
|
7
|
+
clone["x-api-key"] = "***redacted***";
|
|
8
|
+
}
|
|
9
|
+
if (typeof clone["x-anthropic-api-key"] === "string") {
|
|
10
|
+
clone["x-anthropic-api-key"] = "***redacted***";
|
|
11
|
+
}
|
|
12
|
+
return clone;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const loggingMiddleware = pinoHttp({
|
|
16
|
+
logger,
|
|
17
|
+
customProps: (req) => ({
|
|
18
|
+
sessionId: req.sessionId ?? null,
|
|
19
|
+
}),
|
|
20
|
+
customLogLevel: (req, res, err) => {
|
|
21
|
+
if (err || res.statusCode >= 500) return "error";
|
|
22
|
+
if (res.statusCode >= 400) return "warn";
|
|
23
|
+
return "info";
|
|
24
|
+
},
|
|
25
|
+
wrapSerializers: true,
|
|
26
|
+
serializers: {
|
|
27
|
+
req(req) {
|
|
28
|
+
return {
|
|
29
|
+
method: req.method,
|
|
30
|
+
url: req.url,
|
|
31
|
+
headers: maskHeaders(req.headers),
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
module.exports = loggingMiddleware;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const crypto = require("crypto");
|
|
2
|
+
const { getOrCreateSession } = require("../../sessions/store");
|
|
3
|
+
|
|
4
|
+
const PRIMARY_HEADER = "x-session-id";
|
|
5
|
+
const FALLBACK_HEADERS = [
|
|
6
|
+
"x-claude-session-id",
|
|
7
|
+
"x-claude-session",
|
|
8
|
+
"x-claude-conversation-id",
|
|
9
|
+
"anthropic-session-id",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
function normaliseSessionId(value) {
|
|
13
|
+
if (typeof value !== "string") return null;
|
|
14
|
+
const trimmed = value.trim();
|
|
15
|
+
return trimmed.length ? trimmed : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function extractSessionId(req) {
|
|
19
|
+
const primary = normaliseSessionId(req.headers[PRIMARY_HEADER]);
|
|
20
|
+
if (primary) return primary;
|
|
21
|
+
|
|
22
|
+
for (const header of FALLBACK_HEADERS) {
|
|
23
|
+
const candidate = normaliseSessionId(req.headers[header]);
|
|
24
|
+
if (candidate) return candidate;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const body = req.body ?? {};
|
|
28
|
+
const bodyId =
|
|
29
|
+
normaliseSessionId(body.session_id) ??
|
|
30
|
+
normaliseSessionId(body.sessionId) ??
|
|
31
|
+
normaliseSessionId(body.conversation_id);
|
|
32
|
+
if (bodyId) return bodyId;
|
|
33
|
+
|
|
34
|
+
const generated = crypto.randomUUID();
|
|
35
|
+
req.generatedSessionId = true;
|
|
36
|
+
return generated;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function sessionMiddleware(req, res, next) {
|
|
40
|
+
try {
|
|
41
|
+
const sessionId = extractSessionId(req);
|
|
42
|
+
req.sessionId = sessionId;
|
|
43
|
+
|
|
44
|
+
const session = getOrCreateSession(sessionId);
|
|
45
|
+
req.session = session;
|
|
46
|
+
return next();
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return next(err);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
sessionMiddleware,
|
|
54
|
+
SESSION_HEADER: PRIMARY_HEADER,
|
|
55
|
+
};
|