feat: fix leaked source to be locally runnable
- Restore full Ink TUI startup chain (cli.tsx entry point) - Create stub .md files for verify skill (Bun text loader hang fix) - Create stub types for filePersistence and SDK modules - Fix Enter key not working (modifiers-napi missing, added try-catch) - Remove overly conservative LOCAL_RECOVERY early return - Add README with setup instructions - Add .env.example template - Add bin/claude-haha entry script and preload.ts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
ANTHROPIC_AUTH_TOKEN=your_token_here
|
||||
ANTHROPIC_BASE_URL=https://api.minimaxi.com/anthropic
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL=MiniMax-M2.7-highspeed
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL=MiniMax-M2.7-highspeed
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL=MiniMax-M2.7-highspeed
|
||||
ANTHROPIC_MODEL=MiniMax-M2.7-highspeed
|
||||
API_TIMEOUT_MS=3000000
|
||||
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
|
||||
DISABLE_TELEMETRY=1
|
||||
@@ -0,0 +1,4 @@
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
node_modules
|
||||
@@ -1,257 +1,158 @@
|
||||
# Claude Code — Leaked Source (2026-03-31)
|
||||
# Claude Code Haha
|
||||
|
||||
> **On March 31, 2026, the full source code of Anthropic's Claude Code CLI was leaked** via a `.map` file exposed in their npm registry.
|
||||
基于 Claude Code 泄露源码修复的**本地可运行版本**,支持接入任意 Anthropic 兼容 API(如 MiniMax、OpenRouter 等)。
|
||||
|
||||
> 原始泄露源码无法直接运行。本仓库修复了启动链路中的多个阻塞问题,使完整的 Ink TUI 交互界面可以在本地工作。
|
||||
|
||||
## 功能
|
||||
|
||||
- 完整的 Ink TUI 交互界面(与官方 Claude Code 一致)
|
||||
- `--print` 无头模式(脚本/CI 场景)
|
||||
- 支持 MCP 服务器、插件、Skills
|
||||
- 支持自定义 API 端点和模型
|
||||
- 降级 Recovery CLI 模式
|
||||
|
||||
---
|
||||
|
||||
## How It Leaked
|
||||
## 快速开始
|
||||
|
||||
[Chaofan Shou (@Fried_rice)](https://x.com/Fried_rice) discovered the leak and posted it publicly:
|
||||
### 1. 安装依赖
|
||||
|
||||
> **"Claude code source code has been leaked via a map file in their npm registry!"**
|
||||
>
|
||||
> — [@Fried_rice, March 31, 2026](https://x.com/Fried_rice/status/2038894956459290963)
|
||||
需要 [Bun](https://bun.sh) >= 1.1 和 Node.js >= 18。
|
||||
|
||||
The source map file in the published npm package contained a reference to the full, unobfuscated TypeScript source, which was downloadable as a zip archive from Anthropic's R2 storage bucket.
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### 2. 配置环境变量
|
||||
|
||||
复制示例文件并填入你的 API Key:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
编辑 `.env`:
|
||||
|
||||
```env
|
||||
# API 认证(二选一)
|
||||
ANTHROPIC_API_KEY=sk-xxx # 标准 API Key(x-api-key 头)
|
||||
ANTHROPIC_AUTH_TOKEN=sk-xxx # Bearer Token(Authorization 头)
|
||||
|
||||
# API 端点(可选,默认 Anthropic 官方)
|
||||
ANTHROPIC_BASE_URL=https://api.minimaxi.com/anthropic
|
||||
|
||||
# 模型配置
|
||||
ANTHROPIC_MODEL=MiniMax-M2.7-highspeed
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL=MiniMax-M2.7-highspeed
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL=MiniMax-M2.7-highspeed
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL=MiniMax-M2.7-highspeed
|
||||
|
||||
# 超时(毫秒)
|
||||
API_TIMEOUT_MS=3000000
|
||||
|
||||
# 禁用遥测和非必要网络请求
|
||||
DISABLE_TELEMETRY=1
|
||||
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
|
||||
```
|
||||
|
||||
### 3. 启动
|
||||
|
||||
```bash
|
||||
# 交互 TUI 模式(完整界面)
|
||||
./bin/claude-haha
|
||||
|
||||
# 无头模式(单次问答)
|
||||
./bin/claude-haha -p "your prompt here"
|
||||
|
||||
# 管道输入
|
||||
echo "explain this code" | ./bin/claude-haha -p
|
||||
|
||||
# 查看所有选项
|
||||
./bin/claude-haha --help
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
## 环境变量说明
|
||||
|
||||
Claude Code is Anthropic's official CLI tool that lets you interact with Claude directly from the terminal to perform software engineering tasks — editing files, running commands, searching codebases, managing git workflows, and more.
|
||||
|
||||
This repository contains the leaked `src/` directory.
|
||||
|
||||
- **Leaked on**: 2026-03-31
|
||||
- **Language**: TypeScript
|
||||
- **Runtime**: Bun
|
||||
- **Terminal UI**: React + [Ink](https://github.com/vadimdemedes/ink) (React for CLI)
|
||||
- **Scale**: ~1,900 files, 512,000+ lines of code
|
||||
| 变量 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `ANTHROPIC_API_KEY` | 二选一 | API Key,通过 `x-api-key` 头发送 |
|
||||
| `ANTHROPIC_AUTH_TOKEN` | 二选一 | Auth Token,通过 `Authorization: Bearer` 头发送 |
|
||||
| `ANTHROPIC_BASE_URL` | 否 | 自定义 API 端点,默认 Anthropic 官方 |
|
||||
| `ANTHROPIC_MODEL` | 否 | 默认模型 |
|
||||
| `ANTHROPIC_DEFAULT_SONNET_MODEL` | 否 | Sonnet 级别模型映射 |
|
||||
| `ANTHROPIC_DEFAULT_HAIKU_MODEL` | 否 | Haiku 级别模型映射 |
|
||||
| `ANTHROPIC_DEFAULT_OPUS_MODEL` | 否 | Opus 级别模型映射 |
|
||||
| `API_TIMEOUT_MS` | 否 | API 请求超时,默认 600000 (10min) |
|
||||
| `DISABLE_TELEMETRY` | 否 | 设为 `1` 禁用遥测 |
|
||||
| `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` | 否 | 设为 `1` 禁用非必要网络请求 |
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
## 降级模式
|
||||
|
||||
如果完整 TUI 出现问题,可以使用简化版 readline 交互模式:
|
||||
|
||||
```bash
|
||||
CLAUDE_CODE_FORCE_RECOVERY_CLI=1 ./bin/claude-haha
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相对于原始泄露源码的修复
|
||||
|
||||
泄露的源码无法直接运行,主要修复了以下问题:
|
||||
|
||||
| 问题 | 根因 | 修复 |
|
||||
|------|------|------|
|
||||
| TUI 不启动 | 入口脚本把无参数启动路由到了 recovery CLI | 恢复走 `cli.tsx` 完整入口 |
|
||||
| 启动卡死 | `verify` skill 导入缺失的 `.md` 文件,Bun text loader 无限挂起 | 创建 stub `.md` 文件 |
|
||||
| `--print` 卡死 | `filePersistence/types.ts` 缺失 | 创建类型桩文件 |
|
||||
| `--print` 卡死 | `ultraplan/prompt.txt` 缺失 | 创建资源桩文件 |
|
||||
| **Enter 键无响应** | `modifiers-napi` native 包缺失,`isModifierPressed()` 抛异常导致 `handleEnter` 中断,`onSubmit` 永远不执行 | 加 try-catch 容错 |
|
||||
| setup 被跳过 | `preload.ts` 自动设置 `LOCAL_RECOVERY=1` 跳过全部初始化 | 移除默认设置 |
|
||||
|
||||
---
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
bin/claude-haha # 入口脚本
|
||||
preload.ts # Bun preload(设置 MACRO 全局变量)
|
||||
.env.example # 环境变量模板
|
||||
src/
|
||||
├── main.tsx # Entrypoint (Commander.js-based CLI parser)
|
||||
├── commands.ts # Command registry
|
||||
├── tools.ts # Tool registry
|
||||
├── Tool.ts # Tool type definitions
|
||||
├── QueryEngine.ts # LLM query engine (core Anthropic API caller)
|
||||
├── context.ts # System/user context collection
|
||||
├── cost-tracker.ts # Token cost tracking
|
||||
│
|
||||
├── commands/ # Slash command implementations (~50)
|
||||
├── tools/ # Agent tool implementations (~40)
|
||||
├── components/ # Ink UI components (~140)
|
||||
├── hooks/ # React hooks
|
||||
├── services/ # External service integrations
|
||||
├── screens/ # Full-screen UIs (Doctor, REPL, Resume)
|
||||
├── types/ # TypeScript type definitions
|
||||
├── utils/ # Utility functions
|
||||
│
|
||||
├── bridge/ # IDE integration bridge (VS Code, JetBrains)
|
||||
├── coordinator/ # Multi-agent coordinator
|
||||
├── plugins/ # Plugin system
|
||||
├── skills/ # Skill system
|
||||
├── keybindings/ # Keybinding configuration
|
||||
├── vim/ # Vim mode
|
||||
├── voice/ # Voice input
|
||||
├── remote/ # Remote sessions
|
||||
├── server/ # Server mode
|
||||
├── memdir/ # Memory directory (persistent memory)
|
||||
├── tasks/ # Task management
|
||||
├── state/ # State management
|
||||
├── migrations/ # Config migrations
|
||||
├── schemas/ # Config schemas (Zod)
|
||||
├── entrypoints/ # Initialization logic
|
||||
├── ink/ # Ink renderer wrapper
|
||||
├── buddy/ # Companion sprite (Easter egg)
|
||||
├── native-ts/ # Native TypeScript utils
|
||||
├── outputStyles/ # Output styling
|
||||
├── query/ # Query pipeline
|
||||
└── upstreamproxy/ # Proxy configuration
|
||||
├── entrypoints/cli.tsx # CLI 主入口
|
||||
├── main.tsx # TUI 主逻辑(Commander.js + React/Ink)
|
||||
├── localRecoveryCli.ts # 降级 Recovery CLI
|
||||
├── setup.ts # 启动初始化
|
||||
├── screens/REPL.tsx # 交互 REPL 界面
|
||||
├── ink/ # Ink 终端渲染引擎
|
||||
├── components/ # UI 组件
|
||||
├── tools/ # Agent 工具(Bash, Edit, Grep 等)
|
||||
├── commands/ # 斜杠命令(/commit, /review 等)
|
||||
├── skills/ # Skill 系统
|
||||
├── services/ # 服务层(API, MCP, OAuth 等)
|
||||
├── hooks/ # React hooks
|
||||
└── utils/ # 工具函数
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Core Architecture
|
||||
## 技术栈
|
||||
|
||||
### 1. Tool System (`src/tools/`)
|
||||
|
||||
Every tool Claude Code can invoke is implemented as a self-contained module. Each tool defines its input schema, permission model, and execution logic.
|
||||
|
||||
| Tool | Description |
|
||||
|---|---|
|
||||
| `BashTool` | Shell command execution |
|
||||
| `FileReadTool` | File reading (images, PDFs, notebooks) |
|
||||
| `FileWriteTool` | File creation / overwrite |
|
||||
| `FileEditTool` | Partial file modification (string replacement) |
|
||||
| `GlobTool` | File pattern matching search |
|
||||
| `GrepTool` | ripgrep-based content search |
|
||||
| `WebFetchTool` | Fetch URL content |
|
||||
| `WebSearchTool` | Web search |
|
||||
| `AgentTool` | Sub-agent spawning |
|
||||
| `SkillTool` | Skill execution |
|
||||
| `MCPTool` | MCP server tool invocation |
|
||||
| `LSPTool` | Language Server Protocol integration |
|
||||
| `NotebookEditTool` | Jupyter notebook editing |
|
||||
| `TaskCreateTool` / `TaskUpdateTool` | Task creation and management |
|
||||
| `SendMessageTool` | Inter-agent messaging |
|
||||
| `TeamCreateTool` / `TeamDeleteTool` | Team agent management |
|
||||
| `EnterPlanModeTool` / `ExitPlanModeTool` | Plan mode toggle |
|
||||
| `EnterWorktreeTool` / `ExitWorktreeTool` | Git worktree isolation |
|
||||
| `ToolSearchTool` | Deferred tool discovery |
|
||||
| `CronCreateTool` | Scheduled trigger creation |
|
||||
| `RemoteTriggerTool` | Remote trigger |
|
||||
| `SleepTool` | Proactive mode wait |
|
||||
| `SyntheticOutputTool` | Structured output generation |
|
||||
|
||||
### 2. Command System (`src/commands/`)
|
||||
|
||||
User-facing slash commands invoked with `/` prefix.
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `/commit` | Create a git commit |
|
||||
| `/review` | Code review |
|
||||
| `/compact` | Context compression |
|
||||
| `/mcp` | MCP server management |
|
||||
| `/config` | Settings management |
|
||||
| `/doctor` | Environment diagnostics |
|
||||
| `/login` / `/logout` | Authentication |
|
||||
| `/memory` | Persistent memory management |
|
||||
| `/skills` | Skill management |
|
||||
| `/tasks` | Task management |
|
||||
| `/vim` | Vim mode toggle |
|
||||
| `/diff` | View changes |
|
||||
| `/cost` | Check usage cost |
|
||||
| `/theme` | Change theme |
|
||||
| `/context` | Context visualization |
|
||||
| `/pr_comments` | View PR comments |
|
||||
| `/resume` | Restore previous session |
|
||||
| `/share` | Share session |
|
||||
| `/desktop` | Desktop app handoff |
|
||||
| `/mobile` | Mobile app handoff |
|
||||
|
||||
### 3. Service Layer (`src/services/`)
|
||||
|
||||
| Service | Description |
|
||||
|---|---|
|
||||
| `api/` | Anthropic API client, file API, bootstrap |
|
||||
| `mcp/` | Model Context Protocol server connection and management |
|
||||
| `oauth/` | OAuth 2.0 authentication flow |
|
||||
| `lsp/` | Language Server Protocol manager |
|
||||
| `analytics/` | GrowthBook-based feature flags and analytics |
|
||||
| `plugins/` | Plugin loader |
|
||||
| `compact/` | Conversation context compression |
|
||||
| `policyLimits/` | Organization policy limits |
|
||||
| `remoteManagedSettings/` | Remote managed settings |
|
||||
| `extractMemories/` | Automatic memory extraction |
|
||||
| `tokenEstimation.ts` | Token count estimation |
|
||||
| `teamMemorySync/` | Team memory synchronization |
|
||||
|
||||
### 4. Bridge System (`src/bridge/`)
|
||||
|
||||
A bidirectional communication layer connecting IDE extensions (VS Code, JetBrains) with the Claude Code CLI.
|
||||
|
||||
- `bridgeMain.ts` — Bridge main loop
|
||||
- `bridgeMessaging.ts` — Message protocol
|
||||
- `bridgePermissionCallbacks.ts` — Permission callbacks
|
||||
- `replBridge.ts` — REPL session bridge
|
||||
- `jwtUtils.ts` — JWT-based authentication
|
||||
- `sessionRunner.ts` — Session execution management
|
||||
|
||||
### 5. Permission System (`src/hooks/toolPermission/`)
|
||||
|
||||
Checks permissions on every tool invocation. Either prompts the user for approval/denial or automatically resolves based on the configured permission mode (`default`, `plan`, `bypassPermissions`, `auto`, etc.).
|
||||
|
||||
### 6. Feature Flags
|
||||
|
||||
Dead code elimination via Bun's `bun:bundle` feature flags:
|
||||
|
||||
```typescript
|
||||
import { feature } from 'bun:bundle'
|
||||
|
||||
// Inactive code is completely stripped at build time
|
||||
const voiceCommand = feature('VOICE_MODE')
|
||||
? require('./commands/voice/index.js').default
|
||||
: null
|
||||
```
|
||||
|
||||
Notable flags: `PROACTIVE`, `KAIROS`, `BRIDGE_MODE`, `DAEMON`, `VOICE_MODE`, `AGENT_TRIGGERS`, `MONITOR_TOOL`
|
||||
|
||||
---
|
||||
|
||||
## Key Files in Detail
|
||||
|
||||
### `QueryEngine.ts` (~46K lines)
|
||||
|
||||
The core engine for LLM API calls. Handles streaming responses, tool-call loops, thinking mode, retry logic, and token counting.
|
||||
|
||||
### `Tool.ts` (~29K lines)
|
||||
|
||||
Defines base types and interfaces for all tools — input schemas, permission models, and progress state types.
|
||||
|
||||
### `commands.ts` (~25K lines)
|
||||
|
||||
Manages registration and execution of all slash commands. Uses conditional imports to load different command sets per environment.
|
||||
|
||||
### `main.tsx`
|
||||
|
||||
Commander.js-based CLI parser + React/Ink renderer initialization. At startup, parallelizes MDM settings, keychain prefetch, and GrowthBook initialization for faster boot.
|
||||
|
||||
---
|
||||
|
||||
## Tech Stack
|
||||
|
||||
| Category | Technology |
|
||||
|---|---|
|
||||
| Runtime | [Bun](https://bun.sh) |
|
||||
| Language | TypeScript (strict) |
|
||||
| Terminal UI | [React](https://react.dev) + [Ink](https://github.com/vadimdemedes/ink) |
|
||||
| CLI Parsing | [Commander.js](https://github.com/tj/commander.js) (extra-typings) |
|
||||
| Schema Validation | [Zod v4](https://zod.dev) |
|
||||
| Code Search | [ripgrep](https://github.com/BurntSushi/ripgrep) (via GrepTool) |
|
||||
| Protocols | [MCP SDK](https://modelcontextprotocol.io), LSP |
|
||||
| API | [Anthropic SDK](https://docs.anthropic.com) |
|
||||
| Telemetry | OpenTelemetry + gRPC |
|
||||
| Feature Flags | GrowthBook |
|
||||
| Auth | OAuth 2.0, JWT, macOS Keychain |
|
||||
|
||||
---
|
||||
|
||||
## Notable Design Patterns
|
||||
|
||||
### Parallel Prefetch
|
||||
|
||||
Startup time is optimized by prefetching MDM settings, keychain reads, and API preconnect in parallel — before heavy module evaluation begins.
|
||||
|
||||
```typescript
|
||||
// main.tsx — fired as side-effects before other imports
|
||||
startMdmRawRead()
|
||||
startKeychainPrefetch()
|
||||
```
|
||||
|
||||
### Lazy Loading
|
||||
|
||||
Heavy modules (OpenTelemetry ~400KB, gRPC ~700KB) are deferred via dynamic `import()` until actually needed.
|
||||
|
||||
### Agent Swarms
|
||||
|
||||
Sub-agents are spawned via `AgentTool`, with `coordinator/` handling multi-agent orchestration. `TeamCreateTool` enables team-level parallel work.
|
||||
|
||||
### Skill System
|
||||
|
||||
Reusable workflows defined in `skills/` and executed through `SkillTool`. Users can add custom skills.
|
||||
|
||||
### Plugin Architecture
|
||||
|
||||
Built-in and third-party plugins are loaded through the `plugins/` subsystem.
|
||||
| 类别 | 技术 |
|
||||
|------|------|
|
||||
| 运行时 | [Bun](https://bun.sh) |
|
||||
| 语言 | TypeScript |
|
||||
| 终端 UI | React + [Ink](https://github.com/vadimdemedes/ink) |
|
||||
| CLI 解析 | Commander.js |
|
||||
| API | Anthropic SDK |
|
||||
| 协议 | MCP, LSP |
|
||||
|
||||
---
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This repository archives source code that was leaked from Anthropic's npm registry on **2026-03-31**. All original source code is the property of [Anthropic](https://www.anthropic.com).
|
||||
本仓库基于 2026-03-31 从 Anthropic npm registry 泄露的 Claude Code 源码。所有原始源码版权归 [Anthropic](https://www.anthropic.com) 所有。仅供学习和研究用途。
|
||||
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
# Force recovery CLI (simple readline REPL, no Ink TUI)
|
||||
if [[ "${CLAUDE_CODE_FORCE_RECOVERY_CLI:-0}" == "1" ]]; then
|
||||
exec bun --env-file=.env ./src/localRecoveryCli.ts "$@"
|
||||
fi
|
||||
|
||||
# Default: full CLI with Ink TUI
|
||||
exec bun --env-file=.env ./src/entrypoints/cli.tsx "$@"
|
||||
@@ -0,0 +1 @@
|
||||
preload = ["./preload.ts"]
|
||||
Generated
+4798
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"name": "claude-code-local",
|
||||
"version": "999.0.0-local",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"claude-haha": "./bin/claude-haha"
|
||||
},
|
||||
"scripts": {
|
||||
"claude-haha": "bun run ./bin/claude-haha",
|
||||
"start": "bun run ./bin/claude-haha"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sandbox-runtime": "^0.0.44",
|
||||
"@anthropic-ai/sdk": "^0.80.0",
|
||||
"@aws-sdk/client-bedrock-runtime": "^3.1020.0",
|
||||
"@commander-js/extra-typings": "^14.0.0",
|
||||
"@growthbook/growthbook": "^1.6.5",
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
"@opentelemetry/api-logs": "^0.214.0",
|
||||
"@opentelemetry/core": "^2.6.1",
|
||||
"@opentelemetry/resources": "^2.6.1",
|
||||
"@opentelemetry/sdk-logs": "^0.214.0",
|
||||
"@opentelemetry/sdk-metrics": "^2.6.1",
|
||||
"@opentelemetry/sdk-trace-base": "^2.6.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.40.0",
|
||||
"ajv": "^8.18.0",
|
||||
"asciichart": "^1.5.25",
|
||||
"auto-bind": "^5.0.1",
|
||||
"axios": "^1.14.0",
|
||||
"bidi-js": "^1.0.3",
|
||||
"chalk": "^5.6.2",
|
||||
"chokidar": "^5.0.0",
|
||||
"cli-boxes": "^4.0.1",
|
||||
"code-excerpt": "^4.0.0",
|
||||
"diff": "^8.0.4",
|
||||
"emoji-regex": "^10.6.0",
|
||||
"env-paths": "^4.0.0",
|
||||
"execa": "^9.6.1",
|
||||
"figures": "^6.1.0",
|
||||
"fuse.js": "^7.1.0",
|
||||
"get-east-asian-width": "^1.5.0",
|
||||
"google-auth-library": "^10.6.2",
|
||||
"highlight.js": "^11.11.1",
|
||||
"https-proxy-agent": "^8.0.0",
|
||||
"ignore": "^7.0.5",
|
||||
"indent-string": "^5.0.0",
|
||||
"ink": "^6.8.0",
|
||||
"jsonc-parser": "^3.3.1",
|
||||
"lodash-es": "^4.17.23",
|
||||
"lru-cache": "^11.2.7",
|
||||
"marked": "^17.0.5",
|
||||
"p-map": "^7.0.4",
|
||||
"picomatch": "^4.0.4",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
"qrcode": "^1.5.4",
|
||||
"react": "^19.2.4",
|
||||
"react-reconciler": "^0.33.0",
|
||||
"semver": "^7.7.4",
|
||||
"shell-quote": "^1.8.3",
|
||||
"signal-exit": "^4.1.0",
|
||||
"stack-utils": "^2.0.6",
|
||||
"strip-ansi": "^7.2.0",
|
||||
"supports-hyperlinks": "^4.4.0",
|
||||
"tree-kill": "^1.2.2",
|
||||
"type-fest": "^5.5.0",
|
||||
"undici": "^7.24.6",
|
||||
"usehooks-ts": "^3.1.1",
|
||||
"vscode-jsonrpc": "^8.2.1",
|
||||
"vscode-languageserver-types": "^3.17.5",
|
||||
"wrap-ansi": "^10.0.0",
|
||||
"ws": "^8.20.0",
|
||||
"xss": "^1.0.15",
|
||||
"yaml": "^2.8.3",
|
||||
"zod": "^4.3.6"
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
const version = process.env.CLAUDE_CODE_LOCAL_VERSION ?? '999.0.0-local';
|
||||
const packageUrl = process.env.CLAUDE_CODE_LOCAL_PACKAGE_URL ?? 'claude-code-local';
|
||||
const buildTime = process.env.CLAUDE_CODE_LOCAL_BUILD_TIME ?? new Date().toISOString();
|
||||
|
||||
process.env.CLAUDE_CODE_LOCAL_SKIP_REMOTE_PREFETCH ??= '1';
|
||||
|
||||
Object.assign(globalThis, {
|
||||
MACRO: {
|
||||
VERSION: version,
|
||||
PACKAGE_URL: packageUrl,
|
||||
NATIVE_PACKAGE_URL: packageUrl,
|
||||
BUILD_TIME: buildTime,
|
||||
FEEDBACK_CHANNEL: 'local',
|
||||
VERSION_CHANGELOG: '',
|
||||
ISSUES_EXPLAINER: '',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
// Local recovery stub for missing generated SDK types.
|
||||
// The leaked source tree does not include this codegen artifact.
|
||||
export {}
|
||||
@@ -0,0 +1,2 @@
|
||||
// Local recovery stub for missing SDK runtime type exports.
|
||||
export {}
|
||||
@@ -0,0 +1,2 @@
|
||||
// Local recovery stub for missing generated SDK settings types.
|
||||
export {}
|
||||
@@ -0,0 +1,2 @@
|
||||
// Local recovery stub for missing SDK tool type exports.
|
||||
export {}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,291 @@
|
||||
import Anthropic from '@anthropic-ai/sdk'
|
||||
import { readFileSync } from 'fs'
|
||||
import { createInterface } from 'readline'
|
||||
|
||||
type OutputFormat = 'text' | 'json'
|
||||
|
||||
function printHelp(): void {
|
||||
process.stdout.write(
|
||||
[
|
||||
'Usage: claude-haha [options] [prompt]',
|
||||
'',
|
||||
'Local recovery mode for this leaked source tree.',
|
||||
'',
|
||||
'Options:',
|
||||
' -h, --help Show help',
|
||||
' -v, --version Show version',
|
||||
' (no args) Start local interactive mode',
|
||||
' -p, --print Send a single prompt and print the result',
|
||||
' --model <model> Override model',
|
||||
' --system-prompt <text> Override system prompt',
|
||||
' --system-prompt-file <file> Read system prompt from file',
|
||||
' --append-system-prompt <text> Append to the system prompt',
|
||||
' --output-format <format> text (default) or json',
|
||||
'',
|
||||
'Environment:',
|
||||
' ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN',
|
||||
' ANTHROPIC_BASE_URL',
|
||||
' ANTHROPIC_MODEL',
|
||||
' API_TIMEOUT_MS',
|
||||
'',
|
||||
].join('\n'),
|
||||
)
|
||||
}
|
||||
|
||||
function printVersion(): void {
|
||||
process.stdout.write('999.0.0-local (Claude Code local recovery)\n')
|
||||
}
|
||||
|
||||
function parseArgs(argv: string[]) {
|
||||
let print = false
|
||||
let model = process.env.ANTHROPIC_MODEL
|
||||
let systemPrompt: string | undefined
|
||||
let appendSystemPrompt: string | undefined
|
||||
let outputFormat: OutputFormat = 'text'
|
||||
const positional: string[] = []
|
||||
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
const arg = argv[i]
|
||||
if (!arg) continue
|
||||
|
||||
if (arg === '-h' || arg === '--help') {
|
||||
return { command: 'help' as const }
|
||||
}
|
||||
if (arg === '-v' || arg === '--version' || arg === '-V') {
|
||||
return { command: 'version' as const }
|
||||
}
|
||||
if (arg === '-p' || arg === '--print') {
|
||||
print = true
|
||||
continue
|
||||
}
|
||||
if (arg === '--bare') {
|
||||
continue
|
||||
}
|
||||
if (arg === '--dangerously-skip-permissions') {
|
||||
continue
|
||||
}
|
||||
if (arg === '--model') {
|
||||
model = argv[++i]
|
||||
continue
|
||||
}
|
||||
if (arg === '--system-prompt') {
|
||||
systemPrompt = argv[++i]
|
||||
continue
|
||||
}
|
||||
if (arg === '--system-prompt-file') {
|
||||
const file = argv[++i]
|
||||
systemPrompt = readFileSync(file!, 'utf8')
|
||||
continue
|
||||
}
|
||||
if (arg === '--append-system-prompt') {
|
||||
appendSystemPrompt = argv[++i]
|
||||
continue
|
||||
}
|
||||
if (arg === '--output-format') {
|
||||
const value = argv[++i]
|
||||
if (value === 'json' || value === 'text') {
|
||||
outputFormat = value
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (arg.startsWith('-')) {
|
||||
continue
|
||||
}
|
||||
positional.push(arg)
|
||||
}
|
||||
|
||||
return {
|
||||
command: 'run' as const,
|
||||
print,
|
||||
model,
|
||||
systemPrompt,
|
||||
appendSystemPrompt,
|
||||
outputFormat,
|
||||
prompt: positional.join(' ').trim(),
|
||||
}
|
||||
}
|
||||
|
||||
async function readPromptFromStdin(): Promise<string> {
|
||||
if (process.stdin.isTTY) return ''
|
||||
const chunks: Buffer[] = []
|
||||
for await (const chunk of process.stdin) {
|
||||
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)))
|
||||
}
|
||||
return Buffer.concat(chunks).toString('utf8').trim()
|
||||
}
|
||||
|
||||
function getSystemPrompt(
|
||||
systemPrompt: string | undefined,
|
||||
appendSystemPrompt: string | undefined,
|
||||
): string | undefined {
|
||||
if (systemPrompt && appendSystemPrompt) {
|
||||
return `${systemPrompt}\n\n${appendSystemPrompt}`
|
||||
}
|
||||
return systemPrompt ?? appendSystemPrompt
|
||||
}
|
||||
|
||||
async function run(): Promise<void> {
|
||||
const parsed = parseArgs(process.argv.slice(2))
|
||||
|
||||
if (parsed.command === 'help') {
|
||||
printHelp()
|
||||
return
|
||||
}
|
||||
if (parsed.command === 'version') {
|
||||
printVersion()
|
||||
return
|
||||
}
|
||||
|
||||
if (!parsed.print) {
|
||||
await runInteractive(parsed)
|
||||
return
|
||||
}
|
||||
|
||||
const prompt = parsed.prompt || (await readPromptFromStdin())
|
||||
if (!prompt) {
|
||||
process.stderr.write('Error: prompt is required\n')
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
const apiKey = process.env.ANTHROPIC_API_KEY
|
||||
const authToken = process.env.ANTHROPIC_AUTH_TOKEN
|
||||
if (!apiKey && !authToken) {
|
||||
process.stderr.write(
|
||||
'Error: set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN\n',
|
||||
)
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
const model =
|
||||
parsed.model ||
|
||||
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL ||
|
||||
process.env.ANTHROPIC_MODEL
|
||||
|
||||
if (!model) {
|
||||
process.stderr.write('Error: model is required\n')
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
const client = new Anthropic({
|
||||
apiKey: apiKey ?? undefined,
|
||||
authToken: authToken ?? undefined,
|
||||
baseURL: process.env.ANTHROPIC_BASE_URL || undefined,
|
||||
timeout: parseInt(process.env.API_TIMEOUT_MS || String(600_000), 10),
|
||||
maxRetries: 0,
|
||||
})
|
||||
|
||||
const response = await client.messages.create({
|
||||
model,
|
||||
max_tokens: 4096,
|
||||
system: getSystemPrompt(parsed.systemPrompt, parsed.appendSystemPrompt),
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
})
|
||||
|
||||
if (parsed.outputFormat === 'json') {
|
||||
process.stdout.write(`${JSON.stringify(response, null, 2)}\n`)
|
||||
return
|
||||
}
|
||||
|
||||
const text = response.content
|
||||
.filter(block => block.type === 'text')
|
||||
.map(block => block.text)
|
||||
.join('\n')
|
||||
|
||||
process.stdout.write(`${text}\n`)
|
||||
}
|
||||
|
||||
async function runInteractive(parsed: {
|
||||
model?: string
|
||||
systemPrompt?: string
|
||||
appendSystemPrompt?: string
|
||||
}): Promise<void> {
|
||||
const apiKey = process.env.ANTHROPIC_API_KEY
|
||||
const authToken = process.env.ANTHROPIC_AUTH_TOKEN
|
||||
if (!apiKey && !authToken) {
|
||||
process.stderr.write(
|
||||
'Error: set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN\n',
|
||||
)
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
const model =
|
||||
parsed.model ||
|
||||
process.env.ANTHROPIC_DEFAULT_SONNET_MODEL ||
|
||||
process.env.ANTHROPIC_MODEL
|
||||
|
||||
if (!model) {
|
||||
process.stderr.write('Error: model is required\n')
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
const client = new Anthropic({
|
||||
apiKey: apiKey ?? undefined,
|
||||
authToken: authToken ?? undefined,
|
||||
baseURL: process.env.ANTHROPIC_BASE_URL || undefined,
|
||||
timeout: parseInt(process.env.API_TIMEOUT_MS || String(600_000), 10),
|
||||
maxRetries: 0,
|
||||
})
|
||||
|
||||
const system = getSystemPrompt(parsed.systemPrompt, parsed.appendSystemPrompt)
|
||||
const messages: Array<{ role: 'user' | 'assistant'; content: string }> = []
|
||||
const rl = createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
prompt: 'you> ',
|
||||
})
|
||||
|
||||
process.stdout.write(
|
||||
`Claude Haha local interactive mode\nmodel: ${model}\ncommands: /exit, /clear\n\n`,
|
||||
)
|
||||
rl.prompt()
|
||||
|
||||
for await (const line of rl) {
|
||||
const input = line.trim()
|
||||
if (!input) {
|
||||
rl.prompt()
|
||||
continue
|
||||
}
|
||||
if (input === '/exit' || input === '/quit') {
|
||||
rl.close()
|
||||
break
|
||||
}
|
||||
if (input === '/clear') {
|
||||
messages.length = 0
|
||||
process.stdout.write('history cleared\n')
|
||||
rl.prompt()
|
||||
continue
|
||||
}
|
||||
|
||||
messages.push({ role: 'user', content: input })
|
||||
try {
|
||||
const response = await client.messages.create({
|
||||
model,
|
||||
max_tokens: 4096,
|
||||
system,
|
||||
messages,
|
||||
})
|
||||
const text = response.content
|
||||
.filter(block => block.type === 'text')
|
||||
.map(block => block.text)
|
||||
.join('\n')
|
||||
process.stdout.write(`claude> ${text}\n\n`)
|
||||
messages.push({ role: 'assistant', content: text })
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : String(error)
|
||||
process.stderr.write(`error: ${message}\n`)
|
||||
}
|
||||
rl.prompt()
|
||||
}
|
||||
}
|
||||
|
||||
void run().catch(error => {
|
||||
const message = error instanceof Error ? error.stack || error.message : String(error)
|
||||
process.stderr.write(`${message}\n`)
|
||||
process.exitCode = 1
|
||||
})
|
||||
+13
-7
File diff suppressed because one or more lines are too long
@@ -165,6 +165,10 @@ function computeChecksum(
|
||||
* getSettings() to avoid circular dependencies during settings loading.
|
||||
*/
|
||||
export function isPolicyLimitsEligible(): boolean {
|
||||
if (process.env.CLAUDE_CODE_LOCAL_SKIP_REMOTE_PREFETCH === '1') {
|
||||
return false
|
||||
}
|
||||
|
||||
// 3p provider users should not hit the policy limits endpoint
|
||||
if (getAPIProvider() !== 'firstParty') {
|
||||
return false
|
||||
|
||||
@@ -49,6 +49,10 @@ export function resetSyncCache(): void {
|
||||
export function isRemoteManagedSettingsEligible(): boolean {
|
||||
if (cached !== undefined) return cached
|
||||
|
||||
if (process.env.CLAUDE_CODE_LOCAL_SKIP_REMOTE_PREFETCH === '1') {
|
||||
return (cached = setEligibility(false))
|
||||
}
|
||||
|
||||
// 3p provider users should not hit the settings endpoint
|
||||
if (getAPIProvider() !== 'firstParty') {
|
||||
return (cached = setEligibility(false))
|
||||
|
||||
@@ -159,6 +159,16 @@ export async function setup(
|
||||
|
||||
// IMPORTANT: setCwd() must be called before any other code that depends on the cwd
|
||||
setCwd(cwd)
|
||||
setOriginalCwd(cwd)
|
||||
setProjectRoot(cwd)
|
||||
|
||||
// Local recovery mode: when CLAUDE_CODE_LOCAL_RECOVERY=1 is explicitly set,
|
||||
// trim startup to minimum. Otherwise run full setup for the Ink TUI.
|
||||
if (process.env.CLAUDE_CODE_LOCAL_RECOVERY === '1') {
|
||||
process.stderr.write('[local-recovery] setup early return\n')
|
||||
profileCheckpoint('setup_local_recovery_early_return')
|
||||
return
|
||||
}
|
||||
|
||||
// Capture hooks configuration snapshot to avoid hidden hook modifications.
|
||||
// IMPORTANT: Must be called AFTER setCwd() so hooks are loaded from the correct directory
|
||||
|
||||
+13
-34
@@ -1,16 +1,5 @@
|
||||
import { feature } from 'bun:bundle'
|
||||
import { shouldAutoEnableClaudeInChrome } from 'src/utils/claudeInChrome/setup.js'
|
||||
import { registerBatchSkill } from './batch.js'
|
||||
import { registerClaudeInChromeSkill } from './claudeInChrome.js'
|
||||
import { registerDebugSkill } from './debug.js'
|
||||
import { registerKeybindingsSkill } from './keybindings.js'
|
||||
import { registerLoremIpsumSkill } from './loremIpsum.js'
|
||||
import { registerRememberSkill } from './remember.js'
|
||||
import { registerSimplifySkill } from './simplify.js'
|
||||
import { registerSkillifySkill } from './skillify.js'
|
||||
import { registerStuckSkill } from './stuck.js'
|
||||
import { registerUpdateConfigSkill } from './updateConfig.js'
|
||||
import { registerVerifySkill } from './verify.js'
|
||||
|
||||
/**
|
||||
* Initialize all bundled skills.
|
||||
@@ -22,58 +11,48 @@ import { registerVerifySkill } from './verify.js'
|
||||
* 3. Import and call that function here
|
||||
*/
|
||||
export function initBundledSkills(): void {
|
||||
registerUpdateConfigSkill()
|
||||
registerKeybindingsSkill()
|
||||
registerVerifySkill()
|
||||
registerDebugSkill()
|
||||
registerLoremIpsumSkill()
|
||||
registerSkillifySkill()
|
||||
registerRememberSkill()
|
||||
registerSimplifySkill()
|
||||
registerBatchSkill()
|
||||
registerStuckSkill()
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
require('./updateConfig.js').registerUpdateConfigSkill()
|
||||
require('./keybindings.js').registerKeybindingsSkill()
|
||||
require('./verify.js').registerVerifySkill()
|
||||
require('./debug.js').registerDebugSkill()
|
||||
require('./loremIpsum.js').registerLoremIpsumSkill()
|
||||
require('./skillify.js').registerSkillifySkill()
|
||||
require('./remember.js').registerRememberSkill()
|
||||
require('./simplify.js').registerSimplifySkill()
|
||||
require('./batch.js').registerBatchSkill()
|
||||
require('./stuck.js').registerStuckSkill()
|
||||
if (feature('KAIROS') || feature('KAIROS_DREAM')) {
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
const { registerDreamSkill } = require('./dream.js')
|
||||
/* eslint-enable @typescript-eslint/no-require-imports */
|
||||
registerDreamSkill()
|
||||
}
|
||||
if (feature('REVIEW_ARTIFACT')) {
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
const { registerHunterSkill } = require('./hunter.js')
|
||||
/* eslint-enable @typescript-eslint/no-require-imports */
|
||||
registerHunterSkill()
|
||||
}
|
||||
if (feature('AGENT_TRIGGERS')) {
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
const { registerLoopSkill } = require('./loop.js')
|
||||
/* eslint-enable @typescript-eslint/no-require-imports */
|
||||
// /loop's isEnabled delegates to isKairosCronEnabled() — same lazy
|
||||
// per-invocation pattern as the cron tools. Registered unconditionally;
|
||||
// the skill's own isEnabled callback decides visibility.
|
||||
registerLoopSkill()
|
||||
}
|
||||
if (feature('AGENT_TRIGGERS_REMOTE')) {
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
const {
|
||||
registerScheduleRemoteAgentsSkill,
|
||||
} = require('./scheduleRemoteAgents.js')
|
||||
/* eslint-enable @typescript-eslint/no-require-imports */
|
||||
registerScheduleRemoteAgentsSkill()
|
||||
}
|
||||
if (feature('BUILDING_CLAUDE_APPS')) {
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
const { registerClaudeApiSkill } = require('./claudeApi.js')
|
||||
/* eslint-enable @typescript-eslint/no-require-imports */
|
||||
registerClaudeApiSkill()
|
||||
}
|
||||
if (shouldAutoEnableClaudeInChrome()) {
|
||||
registerClaudeInChromeSkill()
|
||||
require('./claudeInChrome.js').registerClaudeInChromeSkill()
|
||||
}
|
||||
if (feature('RUN_SKILL_GENERATOR')) {
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
const { registerRunSkillGeneratorSkill } = require('./runSkillGenerator.js')
|
||||
/* eslint-enable @typescript-eslint/no-require-imports */
|
||||
registerRunSkillGeneratorSkill()
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-require-imports */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
name: verify
|
||||
description: Verify a code change does what it should by running the app.
|
||||
---
|
||||
|
||||
Verify the code change works as expected.
|
||||
@@ -0,0 +1 @@
|
||||
# CLI verification example
|
||||
@@ -0,0 +1 @@
|
||||
# Server verification example
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react'
|
||||
|
||||
export function TungstenLiveMonitor(): React.JSX.Element | null {
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { z } from 'zod/v4'
|
||||
|
||||
const inputSchema = z.object({}).passthrough()
|
||||
|
||||
export const TungstenTool = {
|
||||
name: 'tungsten',
|
||||
aliases: [],
|
||||
maxResultSizeChars: 0,
|
||||
inputSchema,
|
||||
async description() {
|
||||
return 'Unavailable in this local recovery build.'
|
||||
},
|
||||
async prompt() {
|
||||
return 'TungstenTool is unavailable in this local recovery build.'
|
||||
},
|
||||
async call() {
|
||||
return {
|
||||
data: {
|
||||
success: false,
|
||||
error: 'TungstenTool is unavailable in this local recovery build.',
|
||||
},
|
||||
}
|
||||
},
|
||||
isConcurrencySafe() {
|
||||
return true
|
||||
},
|
||||
isEnabled() {
|
||||
return false
|
||||
},
|
||||
isReadOnly() {
|
||||
return true
|
||||
},
|
||||
async checkPermissions() {
|
||||
return {
|
||||
behavior: 'deny' as const,
|
||||
message: 'TungstenTool is unavailable in this local recovery build.',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export function clearSessionsWithTungstenUsage(): void {}
|
||||
|
||||
export function resetInitializationState(): void {}
|
||||
@@ -0,0 +1 @@
|
||||
export const WORKFLOW_TOOL_NAME = 'workflow'
|
||||
@@ -0,0 +1,20 @@
|
||||
export type ConnectorTextBlock = {
|
||||
type: 'connector_text';
|
||||
text?: string;
|
||||
};
|
||||
|
||||
export type ConnectorTextDelta = {
|
||||
type: 'connector_text_delta';
|
||||
text?: string;
|
||||
};
|
||||
|
||||
export function isConnectorTextBlock(
|
||||
value: unknown,
|
||||
): value is ConnectorTextBlock {
|
||||
return (
|
||||
typeof value === 'object' &&
|
||||
value !== null &&
|
||||
'type' in value &&
|
||||
(value as { type?: unknown }).type === 'connector_text'
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Local recovery stub for missing filePersistence types
|
||||
|
||||
export const DEFAULT_UPLOAD_CONCURRENCY = 5
|
||||
export const FILE_COUNT_LIMIT = 100
|
||||
export const OUTPUTS_SUBDIR = 'outputs'
|
||||
|
||||
export interface FailedPersistence {
|
||||
filePath: string
|
||||
error: string
|
||||
}
|
||||
|
||||
export interface PersistedFile {
|
||||
filePath: string
|
||||
fileId?: string
|
||||
}
|
||||
|
||||
export interface FilesPersistedEventData {
|
||||
persisted: PersistedFile[]
|
||||
failed: FailedPersistence[]
|
||||
}
|
||||
|
||||
export type TurnStartTime = number
|
||||
@@ -28,9 +28,13 @@ export function isModifierPressed(modifier: ModifierKey): boolean {
|
||||
if (process.platform !== 'darwin') {
|
||||
return false
|
||||
}
|
||||
// Dynamic import to avoid loading native module at top level
|
||||
const { isModifierPressed: nativeIsModifierPressed } =
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
require('modifiers-napi') as { isModifierPressed: (m: string) => boolean }
|
||||
return nativeIsModifierPressed(modifier)
|
||||
try {
|
||||
// Dynamic import to avoid loading native module at top level
|
||||
const { isModifierPressed: nativeIsModifierPressed } =
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
require('modifiers-napi') as { isModifierPressed: (m: string) => boolean }
|
||||
return nativeIsModifierPressed(modifier)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
You are a planning assistant.
|
||||
@@ -0,0 +1,24 @@
|
||||
export type PermissionMode =
|
||||
| 'ask'
|
||||
| 'skip_all_permission_checks'
|
||||
| 'follow_a_plan';
|
||||
|
||||
export type Logger = {
|
||||
silly?: (...args: unknown[]) => void;
|
||||
debug?: (...args: unknown[]) => void;
|
||||
info?: (...args: unknown[]) => void;
|
||||
warn?: (...args: unknown[]) => void;
|
||||
error?: (...args: unknown[]) => void;
|
||||
};
|
||||
|
||||
export type ClaudeForChromeContext = Record<string, unknown>;
|
||||
|
||||
export const BROWSER_TOOLS: Array<{ name: string }> = [];
|
||||
|
||||
export function createClaudeForChromeMcpServer(
|
||||
_context: ClaudeForChromeContext,
|
||||
) {
|
||||
return {
|
||||
async connect(_transport: unknown): Promise<void> {},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export type SyntaxTheme = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export class ColorDiff {
|
||||
format(input: string): string {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
export class ColorFile {
|
||||
format(input: string): string {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
export function getSyntaxTheme(themeName: string): SyntaxTheme {
|
||||
return { name: themeName };
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowJs": true,
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@ant/claude-for-chrome-mcp": [
|
||||
"./stubs/ant-claude-for-chrome-mcp.ts"
|
||||
],
|
||||
"color-diff-napi": [
|
||||
"./stubs/color-diff-napi.ts"
|
||||
],
|
||||
"src/*": [
|
||||
"./src/*"
|
||||
]
|
||||
},
|
||||
"types": [
|
||||
"bun-types"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user