read config file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
## Tech Stack
|
||||
|
||||
- This is a Tauri v2 app.
|
||||
- Always use pnpm to install dependencies.
|
||||
- Use TypeScript for frontend code. Do not use any type.
|
||||
- Must use @tanstack/react-query for data fetching, mutations, and asynchronous tasks. All query and mutation should be defined in the `lib/query.ts` file by default.
|
||||
- Use React Router for navigation.
|
||||
- Use React Hook Form for form handling.
|
||||
- Use shadcn/ui and tailwindcss(v4) for styling
|
||||
|
||||
## React code principles
|
||||
|
||||
- Use functional components and hooks.
|
||||
- Do not use export default to export components.
|
||||
- Carefully design whether to put the react query/mutation logic in the component file or in the `lib/query.ts` file.
|
||||
- Carefully design whether to put the form handling logic in the component file or in the `lib/form.ts` file.
|
||||
- Do not separate components into smaller files unless I told you to do so.
|
||||
|
||||
## Code architecture guide
|
||||
|
||||
- You should write Tauri commands in the `src-tauri/src/commands.rs` file with a well designed command name.
|
||||
|
||||
## Use exa by Default
|
||||
Always use exa when I need code generation, library installation, setup or configuration steps, or library/API documentation. This means you should automatically use the exa MCP tools get library docs without me having to explicitly ask.
|
||||
@@ -0,0 +1,23 @@
|
||||
CC config is a configuration file manager for Claude Code.
|
||||
|
||||
|
||||
## Claude Code configuration files definition
|
||||
|
||||
- **User settings** are defined in `~/.claude/settings.json` and apply to all projects.
|
||||
- **Project settings** are saved in your project directory:
|
||||
- `.claude/settings.json` for settings that are checked into source control and shared with your team
|
||||
- `.claude/settings.local.json` for settings that are not checked in, useful for personal preferences and experimentation. Claude Code will configure git to ignore `.claude/settings.local.json` when it is created.
|
||||
- For enterprise deployments of Claude Code, we also support **enterprise managed policy settings**. These take precedence over user and project settings. System administrators can deploy policies to:
|
||||
- macOS: `/Library/Application Support/ClaudeCode/managed-settings.json`
|
||||
- Linux and WSL: `/etc/claude-code/managed-settings.json`
|
||||
- Windows: `C:\ProgramData\ClaudeCode\managed-settings.json`
|
||||
- Enterprise deployments can also configure **managed MCP servers** that override user-configured servers. See [Enterprise MCP configuration](https://docs.claude.com/en/docs/claude-code/mcp#enterprise-mcp-configuration):
|
||||
- macOS: `/Library/Application Support/ClaudeCode/managed-mcp.json`
|
||||
- Linux and WSL: `/etc/claude-code/managed-mcp.json`
|
||||
- Windows: `C:\ProgramData\ClaudeCode\managed-mcp.json`
|
||||
|
||||
|
||||
In this phase, only do the follwing tasks:
|
||||
|
||||
- Implement the Tauri commands and react-query/mutation that read and write the configuration files.
|
||||
- A minimal UI that allows you to view and edit the configuration files.
|
||||
@@ -0,0 +1,7 @@
|
||||
# Tauri + React + Typescript
|
||||
|
||||
This template should help get you started developing with Tauri, React and Typescript in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
|
||||
@@ -0,0 +1,251 @@
|
||||
Claude Code offers a variety of settings to configure its behavior to meet your needs. You can configure Claude Code by running the `/config` command when using the interactive REPL, which opens a tabbed Settings interface where you can view status information and modify configuration options.
|
||||
|
||||
## Settings files
|
||||
|
||||
The `settings.json` file is our official mechanism for configuring Claude Code through hierarchical settings:
|
||||
- **User settings** are defined in `~/.claude/settings.json` and apply to all projects.
|
||||
- **Project settings** are saved in your project directory:
|
||||
- `.claude/settings.json` for settings that are checked into source control and shared with your team
|
||||
- `.claude/settings.local.json` for settings that are not checked in, useful for personal preferences and experimentation. Claude Code will configure git to ignore `.claude/settings.local.json` when it is created.
|
||||
- For enterprise deployments of Claude Code, we also support **enterprise managed policy settings**. These take precedence over user and project settings. System administrators can deploy policies to:
|
||||
- macOS: `/Library/Application Support/ClaudeCode/managed-settings.json`
|
||||
- Linux and WSL: `/etc/claude-code/managed-settings.json`
|
||||
- Windows: `C:\ProgramData\ClaudeCode\managed-settings.json`
|
||||
- Enterprise deployments can also configure **managed MCP servers** that override user-configured servers. See [Enterprise MCP configuration](https://docs.claude.com/en/docs/claude-code/mcp#enterprise-mcp-configuration):
|
||||
- macOS: `/Library/Application Support/ClaudeCode/managed-mcp.json`
|
||||
- Linux and WSL: `/etc/claude-code/managed-mcp.json`
|
||||
- Windows: `C:\ProgramData\ClaudeCode\managed-mcp.json`
|
||||
|
||||
Example settings.json
|
||||
|
||||
```
|
||||
{
|
||||
|
||||
"permissions": {
|
||||
|
||||
"allow": [
|
||||
|
||||
"Bash(npm run lint)",
|
||||
|
||||
"Bash(npm run test:*)",
|
||||
|
||||
"Read(~/.zshrc)"
|
||||
|
||||
],
|
||||
|
||||
"deny": [
|
||||
|
||||
"Bash(curl:*)",
|
||||
|
||||
"Read(./.env)",
|
||||
|
||||
"Read(./.env.*)",
|
||||
|
||||
"Read(./secrets/**)"
|
||||
|
||||
]
|
||||
|
||||
},
|
||||
|
||||
"env": {
|
||||
|
||||
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
|
||||
|
||||
"OTEL_METRICS_EXPORTER": "otlp"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Available settings
|
||||
|
||||
`settings.json` supports a number of options:
|
||||
|
||||
| Key | Description | Example |
|
||||
| --- | --- | --- |
|
||||
| `apiKeyHelper` | Custom script, to be executed in `/bin/sh`, to generate an auth value. This value will be sent as `X-Api-Key` and `Authorization: Bearer` headers for model requests | `/bin/generate_temp_api_key.sh` |
|
||||
| `cleanupPeriodDays` | How long to locally retain chat transcripts based on last activity date (default: 30 days) | `20` |
|
||||
| `env` | Environment variables that will be applied to every session | `{"FOO": "bar"}` |
|
||||
| `includeCoAuthoredBy` | Whether to include the `co-authored-by Claude` byline in git commits and pull requests (default: `true`) | `false` |
|
||||
| `permissions` | See table below for structure of permissions. | |
|
||||
| `hooks` | Configure custom commands to run before or after tool executions. See [hooks documentation](https://docs.claude.com/en/docs/claude-code/hooks) | `{"PreToolUse": {"Bash": "echo 'Running command...'"}}` |
|
||||
| `disableAllHooks` | Disable all [hooks](https://docs.claude.com/en/docs/claude-code/hooks) | `true` |
|
||||
| `model` | Override the default model to use for Claude Code | `"claude-sonnet-4-5-20250929"` |
|
||||
| `statusLine` | Configure a custom status line to display context. See [statusLine documentation](https://docs.claude.com/en/docs/claude-code/statusline) | `{"type": "command", "command": "~/.claude/statusline.sh"}` |
|
||||
| `outputStyle` | Configure an output style to adjust the system prompt. See [output styles documentation](https://docs.claude.com/en/docs/claude-code/output-styles) | `"Explanatory"` |
|
||||
| `forceLoginMethod` | Use `claudeai` to restrict login to Claude.ai accounts, `console` to restrict login to Claude Console (API usage billing) accounts | `claudeai` |
|
||||
| `forceLoginOrgUUID` | Specify the UUID of an organization to automatically select it during login, bypassing the organization selection step. Requires `forceLoginMethod` to be set | `"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"` |
|
||||
| `enableAllProjectMcpServers` | Automatically approve all MCP servers defined in project `.mcp.json` files | `true` |
|
||||
| `enabledMcpjsonServers` | List of specific MCP servers from `.mcp.json` files to approve | `["memory", "github"]` |
|
||||
| `disabledMcpjsonServers` | List of specific MCP servers from `.mcp.json` files to reject | `["filesystem"]` |
|
||||
| `useEnterpriseMcpConfigOnly` | When set in managed-settings.json, restricts MCP servers to only those defined in managed-mcp.json. See [Enterprise MCP configuration](https://docs.claude.com/en/docs/claude-code/mcp#enterprise-mcp-configuration) | `true` |
|
||||
| `awsAuthRefresh` | Custom script that modifies the `.aws` directory (see [advanced credential configuration](https://docs.claude.com/en/docs/claude-code/amazon-bedrock#advanced-credential-configuration)) | `aws sso login --profile myprofile` |
|
||||
| `awsCredentialExport` | Custom script that outputs JSON with AWS credentials (see [advanced credential configuration](https://docs.claude.com/en/docs/claude-code/amazon-bedrock#advanced-credential-configuration)) | `/bin/generate_aws_grant.sh` |
|
||||
|
||||
| Keys | Description | Example |
|
||||
| --- | --- | --- |
|
||||
| `allow` | Array of [permission rules](https://docs.claude.com/en/docs/claude-code/iam#configuring-permissions) to allow tool use. **Note:** Bash rules use prefix matching, not regex | `[ "Bash(git diff:*)" ]` |
|
||||
| `ask` | Array of [permission rules](https://docs.claude.com/en/docs/claude-code/iam#configuring-permissions) to ask for confirmation upon tool use. | `[ "Bash(git push:*)" ]` |
|
||||
| `deny` | Array of [permission rules](https://docs.claude.com/en/docs/claude-code/iam#configuring-permissions) to deny tool use. Use this to also exclude sensitive files from Claude Code access. **Note:** Bash patterns are prefix matches and can be bypassed (see [Bash permission limitations](https://docs.claude.com/en/docs/claude-code/iam#tool-specific-permission-rules)) | `[ "WebFetch", "Bash(curl:*)", "Read(./.env)", "Read(./secrets/**)" ]` |
|
||||
| `additionalDirectories` | Additional [working directories](https://docs.claude.com/en/docs/claude-code/iam#working-directories) that Claude has access to | `[ "../docs/" ]` |
|
||||
| `defaultMode` | Default [permission mode](https://docs.claude.com/en/docs/claude-code/iam#permission-modes) when opening Claude Code | `"acceptEdits"` |
|
||||
| `disableBypassPermissionsMode` | Set to `"disable"` to prevent `bypassPermissions` mode from being activated. See [managed policy settings](https://docs.claude.com/en/docs/claude-code/iam#enterprise-managed-policy-settings) | `"disable"` |
|
||||
|
||||
### Settings precedence
|
||||
|
||||
Settings are applied in order of precedence (highest to lowest):
|
||||
1. **Enterprise managed policies** (`managed-settings.json`)
|
||||
- Deployed by IT/DevOps
|
||||
- Cannot be overridden
|
||||
2. **Command line arguments**
|
||||
- Temporary overrides for a specific session
|
||||
3. **Local project settings** (`.claude/settings.local.json`)
|
||||
- Personal project-specific settings
|
||||
4. **Shared project settings** (`.claude/settings.json`)
|
||||
- Team-shared project settings in source control
|
||||
5. **User settings** (`~/.claude/settings.json`)
|
||||
- Personal global settings
|
||||
This hierarchy ensures that enterprise security policies are always enforced while still allowing teams and individuals to customize their experience.
|
||||
|
||||
### Key points about the configuration system
|
||||
|
||||
- **Memory files (CLAUDE.md)**: Contain instructions and context that Claude loads at startup
|
||||
- **Settings files (JSON)**: Configure permissions, environment variables, and tool behavior
|
||||
- **Slash commands**: Custom commands that can be invoked during a session with `/command-name`
|
||||
- **MCP servers**: Extend Claude Code with additional tools and integrations
|
||||
- **Precedence**: Higher-level configurations (Enterprise) override lower-level ones (User/Project)
|
||||
- **Inheritance**: Settings are merged, with more specific settings adding to or overriding broader ones
|
||||
|
||||
### System prompt availability
|
||||
|
||||
Unlike for claude.ai, we do not publish Claude Code’s internal system prompt on this website. Use CLAUDE.md files or `--append-system-prompt` to add custom instructions to Claude Code’s behavior.
|
||||
|
||||
### Excluding sensitive files
|
||||
|
||||
To prevent Claude Code from accessing files containing sensitive information (e.g., API keys, secrets, environment files), use the `permissions.deny` setting in your `.claude/settings.json` file:
|
||||
|
||||
```
|
||||
{
|
||||
|
||||
"permissions": {
|
||||
|
||||
"deny": [
|
||||
|
||||
"Read(./.env)",
|
||||
|
||||
"Read(./.env.*)",
|
||||
|
||||
"Read(./secrets/**)",
|
||||
|
||||
"Read(./config/credentials.json)",
|
||||
|
||||
"Read(./build)"
|
||||
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This replaces the deprecated `ignorePatterns` configuration. Files matching these patterns will be completely invisible to Claude Code, preventing any accidental exposure of sensitive data.
|
||||
|
||||
## Subagent configuration
|
||||
|
||||
Claude Code supports custom AI subagents that can be configured at both user and project levels. These subagents are stored as Markdown files with YAML frontmatter:
|
||||
- **User subagents**: `~/.claude/agents/` - Available across all your projects
|
||||
- **Project subagents**: `.claude/agents/` - Specific to your project and can be shared with your team
|
||||
Subagent files define specialized AI assistants with custom prompts and tool permissions. Learn more about creating and using subagents in the [subagents documentation](https://docs.claude.com/en/docs/claude-code/sub-agents).
|
||||
|
||||
## Environment variables
|
||||
|
||||
Claude Code supports the following environment variables to control its behavior:
|
||||
|
||||
All environment variables can also be configured in [`settings.json`](https://docs.claude.com/en/docs/claude-code/#available-settings). This is useful as a way to automatically set environment variables for each session, or to roll out a set of environment variables for your whole team or organization.
|
||||
|
||||
| Variable | Purpose |
|
||||
| --- | --- |
|
||||
| `ANTHROPIC_API_KEY` | API key sent as `X-Api-Key` header, typically for the Claude SDK (for interactive usage, run `/login`) |
|
||||
| `ANTHROPIC_AUTH_TOKEN` | Custom value for the `Authorization` header (the value you set here will be prefixed with `Bearer `) |
|
||||
| `ANTHROPIC_CUSTOM_HEADERS` | Custom headers you want to add to the request (in `Name: Value` format) |
|
||||
| `ANTHROPIC_DEFAULT_HAIKU_MODEL` | See [Model configuration](https://docs.claude.com/en/docs/claude-code/model-config#environment-variables) |
|
||||
| `ANTHROPIC_DEFAULT_OPUS_MODEL` | See [Model configuration](https://docs.claude.com/en/docs/claude-code/model-config#environment-variables) |
|
||||
| `ANTHROPIC_DEFAULT_SONNET_MODEL` | See [Model configuration](https://docs.claude.com/en/docs/claude-code/model-config#environment-variables) |
|
||||
| `ANTHROPIC_MODEL` | Name of the model setting to use (see [Model Configuration](https://docs.claude.com/en/docs/claude-code/model-config#environment-variables)) |
|
||||
| `ANTHROPIC_SMALL_FAST_MODEL` | \[DEPRECATED\] Name of [Haiku-class model for background tasks](https://docs.claude.com/en/docs/claude-code/costs) |
|
||||
| `ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION` | Override AWS region for the Haiku-class model when using Bedrock |
|
||||
| `AWS_BEARER_TOKEN_BEDROCK` | Bedrock API key for authentication (see [Bedrock API keys](https://aws.amazon.com/blogs/machine-learning/accelerate-ai-development-with-amazon-bedrock-api-keys/)) |
|
||||
| `BASH_DEFAULT_TIMEOUT_MS` | Default timeout for long-running bash commands |
|
||||
| `BASH_MAX_OUTPUT_LENGTH` | Maximum number of characters in bash outputs before they are middle-truncated |
|
||||
| `BASH_MAX_TIMEOUT_MS` | Maximum timeout the model can set for long-running bash commands |
|
||||
| `CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR` | Return to the original working directory after each Bash command |
|
||||
| `CLAUDE_CODE_API_KEY_HELPER_TTL_MS` | Interval in milliseconds at which credentials should be refreshed (when using `apiKeyHelper`) |
|
||||
| `CLAUDE_CODE_CLIENT_CERT` | Path to client certificate file for mTLS authentication |
|
||||
| `CLAUDE_CODE_CLIENT_KEY_PASSPHRASE` | Passphrase for encrypted CLAUDE\_CODE\_CLIENT\_KEY (optional) |
|
||||
| `CLAUDE_CODE_CLIENT_KEY` | Path to client private key file for mTLS authentication |
|
||||
| `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` | Equivalent of setting `DISABLE_AUTOUPDATER`, `DISABLE_BUG_COMMAND`, `DISABLE_ERROR_REPORTING`, and `DISABLE_TELEMETRY` |
|
||||
| `CLAUDE_CODE_DISABLE_TERMINAL_TITLE` | Set to `1` to disable automatic terminal title updates based on conversation context |
|
||||
| `CLAUDE_CODE_IDE_SKIP_AUTO_INSTALL` | Skip auto-installation of IDE extensions |
|
||||
| `CLAUDE_CODE_MAX_OUTPUT_TOKENS` | Set the maximum number of output tokens for most requests |
|
||||
| `CLAUDE_CODE_SKIP_BEDROCK_AUTH` | Skip AWS authentication for Bedrock (e.g. when using an LLM gateway) |
|
||||
| `CLAUDE_CODE_SKIP_VERTEX_AUTH` | Skip Google authentication for Vertex (e.g. when using an LLM gateway) |
|
||||
| `CLAUDE_CODE_SUBAGENT_MODEL` | See [Model configuration](https://docs.claude.com/en/docs/claude-code/model-config) |
|
||||
| `CLAUDE_CODE_USE_BEDROCK` | Use [Bedrock](https://docs.claude.com/en/docs/claude-code/amazon-bedrock) |
|
||||
| `CLAUDE_CODE_USE_VERTEX` | Use [Vertex](https://docs.claude.com/en/docs/claude-code/google-vertex-ai) |
|
||||
| `DISABLE_AUTOUPDATER` | Set to `1` to disable automatic updates. This takes precedence over the `autoUpdates` configuration setting. |
|
||||
| `DISABLE_BUG_COMMAND` | Set to `1` to disable the `/bug` command |
|
||||
| `DISABLE_COST_WARNINGS` | Set to `1` to disable cost warning messages |
|
||||
| `DISABLE_ERROR_REPORTING` | Set to `1` to opt out of Sentry error reporting |
|
||||
| `DISABLE_NON_ESSENTIAL_MODEL_CALLS` | Set to `1` to disable model calls for non-critical paths like flavor text |
|
||||
| `DISABLE_TELEMETRY` | Set to `1` to opt out of Statsig telemetry (note that Statsig events do not include user data like code, file paths, or bash commands) |
|
||||
| `HTTP_PROXY` | Specify HTTP proxy server for network connections |
|
||||
| `HTTPS_PROXY` | Specify HTTPS proxy server for network connections |
|
||||
| `MAX_MCP_OUTPUT_TOKENS` | Maximum number of tokens allowed in MCP tool responses. Claude Code displays a warning when output exceeds 10,000 tokens (default: 25000) |
|
||||
| `MAX_THINKING_TOKENS` | Enable [extended thinking](https://docs.claude.com/en/docs/build-with-claude/extended-thinking) and set the token budget for the thinking process. Extended thinking improves performance on complex reasoning and coding tasks but impacts [prompt caching efficiency](https://docs.claude.com/en/docs/build-with-claude/prompt-caching#caching-with-thinking-blocks). Disabled by default. |
|
||||
| `MCP_TIMEOUT` | Timeout in milliseconds for MCP server startup |
|
||||
| `MCP_TOOL_TIMEOUT` | Timeout in milliseconds for MCP tool execution |
|
||||
| `NO_PROXY` | List of domains and IPs to which requests will be directly issued, bypassing proxy |
|
||||
| `SLASH_COMMAND_TOOL_CHAR_BUDGET` | Maximum number of characters for slash command metadata shown to [SlashCommand tool](https://docs.claude.com/en/docs/claude-code/slash-commands#slashcommand-tool) (default: 15000) |
|
||||
| `USE_BUILTIN_RIPGREP` | Set to `0` to use system-installed `rg` intead of `rg` included with Claude Code |
|
||||
| `VERTEX_REGION_CLAUDE_3_5_HAIKU` | Override region for Claude 3.5 Haiku when using Vertex AI |
|
||||
| `VERTEX_REGION_CLAUDE_3_5_SONNET` | Override region for Claude Sonnet 3.5 when using Vertex AI |
|
||||
| `VERTEX_REGION_CLAUDE_3_7_SONNET` | Override region for Claude 3.7 Sonnet when using Vertex AI |
|
||||
| `VERTEX_REGION_CLAUDE_4_0_OPUS` | Override region for Claude 4.0 Opus when using Vertex AI |
|
||||
| `VERTEX_REGION_CLAUDE_4_0_SONNET` | Override region for Claude 4.0 Sonnet when using Vertex AI |
|
||||
| `VERTEX_REGION_CLAUDE_4_1_OPUS` | Override region for Claude 4.1 Opus when using Vertex AI |
|
||||
|
||||
## Tools available to Claude
|
||||
|
||||
Claude Code has access to a set of powerful tools that help it understand and modify your codebase:
|
||||
|
||||
| Tool | Description | Permission Required |
|
||||
| --- | --- | --- |
|
||||
| **Bash** | Executes shell commands in your environment | Yes |
|
||||
| **Edit** | Makes targeted edits to specific files | Yes |
|
||||
| **Glob** | Finds files based on pattern matching | No |
|
||||
| **Grep** | Searches for patterns in file contents | No |
|
||||
| **MultiEdit** | Performs multiple edits on a single file atomically | Yes |
|
||||
| **NotebookEdit** | Modifies Jupyter notebook cells | Yes |
|
||||
| **NotebookRead** | Reads and displays Jupyter notebook contents | No |
|
||||
| **Read** | Reads the contents of files | No |
|
||||
| **SlashCommand** | Runs a [custom slash command](https://docs.claude.com/en/docs/claude-code/slash-commands#slashcommand-tool) | Yes |
|
||||
| **Task** | Runs a sub-agent to handle complex, multi-step tasks | No |
|
||||
| **TodoWrite** | Creates and manages structured task lists | No |
|
||||
| **WebFetch** | Fetches content from a specified URL | Yes |
|
||||
| **WebSearch** | Performs web searches with domain filtering | Yes |
|
||||
| **Write** | Creates or overwrites files | Yes |
|
||||
|
||||
Permission rules can be configured using `/allowed-tools` or in [permission settings](https://docs.claude.com/en/docs/claude-code/settings#available-settings). Also see [Tool-specific permission rules](https://docs.claude.com/en/docs/claude-code/iam#tool-specific-permission-rules).
|
||||
|
||||
### Extending tools with hooks
|
||||
|
||||
You can run custom commands before or after any tool executes using [Claude Code hooks](https://docs.claude.com/en/docs/claude-code/hooks-guide).For example, you could automatically run a Python formatter after Claude modifies Python files, or prevent modifications to production configuration files by blocking Write operations to certain paths.
|
||||
|
||||
## See also
|
||||
|
||||
- [Identity and Access Management](https://docs.claude.com/en/docs/claude-code/iam#configuring-permissions) - Learn about Claude Code’s permission system
|
||||
- [IAM and access control](https://docs.claude.com/en/docs/claude-code/iam#enterprise-managed-policy-settings) - Enterprise policy management
|
||||
- [Troubleshooting](https://docs.claude.com/en/docs/claude-code/troubleshooting#auto-updater-issues) - Solutions for common configuration issues
|
||||
|
||||
[Analytics](https://docs.claude.com/en/docs/claude-code/analytics) [Visual Studio Code](https://docs.claude.com/en/docs/claude-code/vs-code)
|
||||
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tauri + React + Typescript</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "cc-config",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@tanstack/react-query": "^5.90.2",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-opener": "^2",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-hook-form": "^7.64.0",
|
||||
"react-router-dom": "^7.9.3",
|
||||
"zod": "^4.1.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/vite": "^4.1.14",
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@types/react": "^19.1.8",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"@vitejs/plugin-react": "^4.6.0",
|
||||
"tailwindcss": "^4.1.14",
|
||||
"typescript": "~5.8.3",
|
||||
"vite": "^7.0.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<svg width="206" height="231" viewBox="0 0 206 231" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M143.143 84C143.143 96.1503 133.293 106 121.143 106C108.992 106 99.1426 96.1503 99.1426 84C99.1426 71.8497 108.992 62 121.143 62C133.293 62 143.143 71.8497 143.143 84Z" fill="#FFC131"/>
|
||||
<ellipse cx="84.1426" cy="147" rx="22" ry="22" transform="rotate(180 84.1426 147)" fill="#24C8DB"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M166.738 154.548C157.86 160.286 148.023 164.269 137.757 166.341C139.858 160.282 141 153.774 141 147C141 144.543 140.85 142.121 140.558 139.743C144.975 138.204 149.215 136.139 153.183 133.575C162.73 127.404 170.292 118.608 174.961 108.244C179.63 97.8797 181.207 86.3876 179.502 75.1487C177.798 63.9098 172.884 53.4021 165.352 44.8883C157.82 36.3744 147.99 30.2165 137.042 27.1546C126.095 24.0926 114.496 24.2568 103.64 27.6274C92.7839 30.998 83.1319 37.4317 75.8437 46.1553C74.9102 47.2727 74.0206 48.4216 73.176 49.5993C61.9292 50.8488 51.0363 54.0318 40.9629 58.9556C44.2417 48.4586 49.5653 38.6591 56.679 30.1442C67.0505 17.7298 80.7861 8.57426 96.2354 3.77762C111.685 -1.01901 128.19 -1.25267 143.769 3.10474C159.348 7.46215 173.337 16.2252 184.056 28.3411C194.775 40.457 201.767 55.4101 204.193 71.404C206.619 87.3978 204.374 103.752 197.73 118.501C191.086 133.25 180.324 145.767 166.738 154.548ZM41.9631 74.275L62.5557 76.8042C63.0459 72.813 63.9401 68.9018 65.2138 65.1274C57.0465 67.0016 49.2088 70.087 41.9631 74.275Z" fill="#FFC131"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.4045 76.4519C47.3493 70.6709 57.2677 66.6712 67.6171 64.6132C65.2774 70.9669 64 77.8343 64 85.0001C64 87.1434 64.1143 89.26 64.3371 91.3442C60.0093 92.8732 55.8533 94.9092 51.9599 97.4256C42.4128 103.596 34.8505 112.392 30.1816 122.756C25.5126 133.12 23.9357 144.612 25.6403 155.851C27.3449 167.09 32.2584 177.598 39.7906 186.112C47.3227 194.626 57.153 200.784 68.1003 203.846C79.0476 206.907 90.6462 206.743 101.502 203.373C112.359 200.002 122.011 193.568 129.299 184.845C130.237 183.722 131.131 182.567 131.979 181.383C143.235 180.114 154.132 176.91 164.205 171.962C160.929 182.49 155.596 192.319 148.464 200.856C138.092 213.27 124.357 222.426 108.907 227.222C93.458 232.019 76.9524 232.253 61.3736 227.895C45.7948 223.538 31.8055 214.775 21.0867 202.659C10.3679 190.543 3.37557 175.59 0.949823 159.596C-1.47592 143.602 0.768139 127.248 7.41237 112.499C14.0566 97.7497 24.8183 85.2327 38.4045 76.4519ZM163.062 156.711L163.062 156.711C162.954 156.773 162.846 156.835 162.738 156.897C162.846 156.835 162.954 156.773 163.062 156.711Z" fill="#24C8DB"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,7 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Generated by Tauri
|
||||
# will have schema files for capabilities auto-completion
|
||||
/gen/schemas
|
||||
@@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "cc-config"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
# The `_lib` suffix may seem redundant but it is necessary
|
||||
# to make the lib name unique and wouldn't conflict with the bin name.
|
||||
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
|
||||
name = "cc_config_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "2", features = [] }
|
||||
tauri-plugin-opener = "2"
|
||||
tauri-plugin-fs = "2"
|
||||
tauri-plugin-store = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
dirs = "5"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"opener:default"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 974 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 903 B |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,143 @@
|
||||
use serde_json::Value;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||
pub struct ConfigFile {
|
||||
pub path: String,
|
||||
pub content: Value,
|
||||
pub exists: bool,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn read_config_file(config_type: String) -> Result<ConfigFile, String> {
|
||||
let home_dir = dirs::home_dir().ok_or("Could not find home directory")?;
|
||||
|
||||
let path = match config_type.as_str() {
|
||||
"user" => home_dir.join(".claude/settings.json"),
|
||||
"project" => std::env::current_dir()
|
||||
.unwrap()
|
||||
.join(".claude/settings.json"),
|
||||
"project_local" => std::env::current_dir()
|
||||
.unwrap()
|
||||
.join(".claude/settings.local.json"),
|
||||
"enterprise_macos" => PathBuf::from("/Library/Application Support/ClaudeCode/managed-settings.json"),
|
||||
"enterprise_linux" => PathBuf::from("/etc/claude-code/managed-settings.json"),
|
||||
"enterprise_windows" => PathBuf::from("C:\\ProgramData\\ClaudeCode\\managed-settings.json"),
|
||||
"mcp_macos" => PathBuf::from("/Library/Application Support/ClaudeCode/managed-mcp.json"),
|
||||
"mcp_linux" => PathBuf::from("/etc/claude-code/managed-mcp.json"),
|
||||
"mcp_windows" => PathBuf::from("C:\\ProgramData\\ClaudeCode\\managed-mcp.json"),
|
||||
_ => return Err("Invalid configuration type".to_string()),
|
||||
};
|
||||
|
||||
let path_str = path.to_string_lossy().to_string();
|
||||
|
||||
if path.exists() {
|
||||
let content = std::fs::read_to_string(&path)
|
||||
.map_err(|e| format!("Failed to read file: {}", e))?;
|
||||
|
||||
let json_content: Value = serde_json::from_str(&content)
|
||||
.map_err(|e| format!("Failed to parse JSON: {}", e))?;
|
||||
|
||||
Ok(ConfigFile {
|
||||
path: path_str,
|
||||
content: json_content,
|
||||
exists: true,
|
||||
})
|
||||
} else {
|
||||
Ok(ConfigFile {
|
||||
path: path_str,
|
||||
content: Value::Object(serde_json::Map::new()),
|
||||
exists: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn write_config_file(config_type: String, content: Value) -> Result<(), String> {
|
||||
let home_dir = dirs::home_dir().ok_or("Could not find home directory")?;
|
||||
|
||||
let path = match config_type.as_str() {
|
||||
"user" => home_dir.join(".claude/settings.json"),
|
||||
"project" => {
|
||||
let project_path = std::env::current_dir().unwrap().join(".claude");
|
||||
std::fs::create_dir_all(&project_path)
|
||||
.map_err(|e| format!("Failed to create .claude directory: {}", e))?;
|
||||
project_path.join("settings.json")
|
||||
},
|
||||
"project_local" => {
|
||||
let project_path = std::env::current_dir().unwrap().join(".claude");
|
||||
std::fs::create_dir_all(&project_path)
|
||||
.map_err(|e| format!("Failed to create .claude directory: {}", e))?;
|
||||
project_path.join("settings.local.json")
|
||||
},
|
||||
_ => return Err("Cannot write to enterprise configuration files".to_string()),
|
||||
};
|
||||
|
||||
let json_content = serde_json::to_string_pretty(&content)
|
||||
.map_err(|e| format!("Failed to serialize JSON: {}", e))?;
|
||||
|
||||
std::fs::write(&path, json_content)
|
||||
.map_err(|e| format!("Failed to write file: {}", e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_config_files() -> Result<Vec<String>, String> {
|
||||
let mut configs = vec![];
|
||||
|
||||
// User settings
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
let user_settings = home.join(".claude/settings.json");
|
||||
if user_settings.exists() {
|
||||
configs.push("user".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Project settings
|
||||
let current_dir = std::env::current_dir().unwrap();
|
||||
let project_settings = current_dir.join(".claude/settings.json");
|
||||
if project_settings.exists() {
|
||||
configs.push("project".to_string());
|
||||
}
|
||||
|
||||
let project_local_settings = current_dir.join(".claude/settings.local.json");
|
||||
if project_local_settings.exists() {
|
||||
configs.push("project_local".to_string());
|
||||
}
|
||||
|
||||
// Enterprise settings (read-only)
|
||||
if cfg!(target_os = "macos") {
|
||||
let enterprise_path = PathBuf::from("/Library/Application Support/ClaudeCode/managed-settings.json");
|
||||
if enterprise_path.exists() {
|
||||
configs.push("enterprise_macos".to_string());
|
||||
}
|
||||
|
||||
let mcp_path = PathBuf::from("/Library/Application Support/ClaudeCode/managed-mcp.json");
|
||||
if mcp_path.exists() {
|
||||
configs.push("mcp_macos".to_string());
|
||||
}
|
||||
} else if cfg!(target_os = "linux") {
|
||||
let enterprise_path = PathBuf::from("/etc/claude-code/managed-settings.json");
|
||||
if enterprise_path.exists() {
|
||||
configs.push("enterprise_linux".to_string());
|
||||
}
|
||||
|
||||
let mcp_path = PathBuf::from("/etc/claude-code/managed-mcp.json");
|
||||
if mcp_path.exists() {
|
||||
configs.push("mcp_linux".to_string());
|
||||
}
|
||||
} else if cfg!(target_os = "windows") {
|
||||
let enterprise_path = PathBuf::from("C:\\ProgramData\\ClaudeCode\\managed-settings.json");
|
||||
if enterprise_path.exists() {
|
||||
configs.push("enterprise_windows".to_string());
|
||||
}
|
||||
|
||||
let mcp_path = PathBuf::from("C:\\ProgramData\\ClaudeCode\\managed-mcp.json");
|
||||
if mcp_path.exists() {
|
||||
configs.push("mcp_windows".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(configs)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
mod commands;
|
||||
|
||||
use commands::*;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_fs::init())
|
||||
.plugin(tauri_plugin_store::Builder::default().build())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
read_config_file,
|
||||
write_config_file,
|
||||
list_config_files
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
cc_config_lib::run()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "cc-config",
|
||||
"version": "0.1.0",
|
||||
"identifier": "org.randynamic.ccconfig",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"devUrl": "http://localhost:1420",
|
||||
"beforeBuildCommand": "pnpm build",
|
||||
"frontendDist": "../dist"
|
||||
},
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"title": "cc-config",
|
||||
"width": 800,
|
||||
"height": 600
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
.logo.vite:hover {
|
||||
filter: drop-shadow(0 0 2em #747bff);
|
||||
}
|
||||
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafb);
|
||||
}
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
color: #0f0f0f;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0;
|
||||
padding-top: 10vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: 0.75s;
|
||||
}
|
||||
|
||||
.logo.tauri:hover {
|
||||
filter: drop-shadow(0 0 2em #24c8db);
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
color: #0f0f0f;
|
||||
background-color: #ffffff;
|
||||
transition: border-color 0.25s;
|
||||
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #396cd8;
|
||||
}
|
||||
button:active {
|
||||
border-color: #396cd8;
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#greet-input {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
color: #f6f6f6;
|
||||
background-color: #2f2f2f;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #24c8db;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
color: #ffffff;
|
||||
background-color: #0f0f0f98;
|
||||
}
|
||||
button:active {
|
||||
background-color: #0f0f0f69;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
import { useState } from "react";
|
||||
import { useConfigFiles, useConfigFile, useWriteConfigFile, type ConfigType, type ConfigFile } from "./lib/query";
|
||||
import "./App.css";
|
||||
|
||||
function App() {
|
||||
const [selectedConfig, setSelectedConfig] = useState<ConfigType | "">("");
|
||||
const [jsonContent, setJsonContent] = useState<string>("");
|
||||
|
||||
const { data: configFiles, isLoading: configsLoading } = useConfigFiles();
|
||||
const { data: configFile, isLoading: configLoading } = useConfigFile(selectedConfig as ConfigType);
|
||||
const writeConfigMutation = useWriteConfigFile();
|
||||
|
||||
const handleLoadConfig = () => {
|
||||
if (configFile && configFile.content) {
|
||||
setJsonContent(JSON.stringify(configFile.content, null, 2));
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveConfig = () => {
|
||||
if (!selectedConfig) return;
|
||||
|
||||
try {
|
||||
const parsedContent = JSON.parse(jsonContent);
|
||||
writeConfigMutation.mutate({
|
||||
configType: selectedConfig,
|
||||
content: parsedContent,
|
||||
});
|
||||
} catch (error) {
|
||||
alert("Invalid JSON format. Please fix the errors and try again.");
|
||||
}
|
||||
};
|
||||
|
||||
const getConfigDisplayName = (configType: ConfigType) => {
|
||||
const displayNames: Record<ConfigType, string> = {
|
||||
user: "User Settings (~/.claude/settings.json)",
|
||||
project: "Project Settings (.claude/settings.json)",
|
||||
project_local: "Project Local Settings (.claude/settings.local.json)",
|
||||
enterprise_macos: "Enterprise Settings (macOS)",
|
||||
enterprise_linux: "Enterprise Settings (Linux)",
|
||||
enterprise_windows: "Enterprise Settings (Windows)",
|
||||
mcp_macos: "Managed MCP Servers (macOS)",
|
||||
mcp_linux: "Managed MCP Servers (Linux)",
|
||||
mcp_windows: "Managed MCP Servers (Windows)",
|
||||
};
|
||||
return displayNames[configType];
|
||||
};
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-gray-50 p-8">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<h1 className="text-3xl font-bold text-gray-900 mb-8">
|
||||
Claude Code Configuration Manager
|
||||
</h1>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{/* Configuration Files List */}
|
||||
<div className="bg-white rounded-lg shadow p-6">
|
||||
<h2 className="text-xl font-semibold text-gray-800 mb-4">
|
||||
Configuration Files
|
||||
</h2>
|
||||
|
||||
{configsLoading ? (
|
||||
<p className="text-gray-600">Loading configuration files...</p>
|
||||
) : configFiles && configFiles.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
{configFiles.map((configType) => (
|
||||
<div
|
||||
key={configType}
|
||||
className={`p-3 border rounded cursor-pointer transition-colors ${
|
||||
selectedConfig === configType
|
||||
? "border-blue-500 bg-blue-50"
|
||||
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setSelectedConfig(configType)}
|
||||
>
|
||||
<div className="font-medium text-gray-900">
|
||||
{getConfigDisplayName(configType)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-gray-600">
|
||||
No configuration files found. Create one by selecting a type below.
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className="mt-6 pt-6 border-t border-gray-200">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-3">
|
||||
Create New Configuration
|
||||
</h3>
|
||||
<div className="space-y-2">
|
||||
<button
|
||||
onClick={() => setSelectedConfig("user")}
|
||||
className="w-full text-left p-3 border border-gray-200 rounded hover:bg-gray-50"
|
||||
>
|
||||
<div className="font-medium">User Settings</div>
|
||||
<div className="text-sm text-gray-600">
|
||||
Applies to all projects
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setSelectedConfig("project")}
|
||||
className="w-full text-left p-3 border border-gray-200 rounded hover:bg-gray-50"
|
||||
>
|
||||
<div className="font-medium">Project Settings</div>
|
||||
<div className="text-sm text-gray-600">
|
||||
Shared with your team
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setSelectedConfig("project_local")}
|
||||
className="w-full text-left p-3 border border-gray-200 rounded hover:bg-gray-50"
|
||||
>
|
||||
<div className="font-medium">Project Local Settings</div>
|
||||
<div className="text-sm text-gray-600">
|
||||
Personal preferences
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Configuration Editor */}
|
||||
<div className="bg-white rounded-lg shadow p-6">
|
||||
<h2 className="text-xl font-semibold text-gray-800 mb-4">
|
||||
Configuration Editor
|
||||
</h2>
|
||||
|
||||
{selectedConfig ? (
|
||||
<div>
|
||||
<div className="mb-4 p-3 bg-gray-100 rounded">
|
||||
<div className="font-medium text-gray-900">
|
||||
{getConfigDisplayName(selectedConfig)}
|
||||
</div>
|
||||
{configFile && (
|
||||
<div className="text-sm text-gray-600 mt-1">
|
||||
Path: {configFile.path}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{configLoading ? (
|
||||
<p className="text-gray-600">Loading configuration...</p>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={handleLoadConfig}
|
||||
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
||||
>
|
||||
Load Content
|
||||
</button>
|
||||
<button
|
||||
onClick={handleSaveConfig}
|
||||
disabled={writeConfigMutation.isPending}
|
||||
className="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700 disabled:opacity-50"
|
||||
>
|
||||
{writeConfigMutation.isPending ? "Saving..." : "Save"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
value={jsonContent}
|
||||
onChange={(e) => setJsonContent(e.target.value)}
|
||||
className="w-full h-96 p-4 border border-gray-300 rounded font-mono text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="Configuration content in JSON format..."
|
||||
spellCheck={false}
|
||||
/>
|
||||
|
||||
{writeConfigMutation.error && (
|
||||
<div className="p-3 bg-red-100 border border-red-400 text-red-700 rounded">
|
||||
Error: {writeConfigMutation.error.message}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{writeConfigMutation.isSuccess && (
|
||||
<div className="p-3 bg-green-100 border border-green-400 text-green-700 rounded">
|
||||
Configuration saved successfully!
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-12 text-gray-600">
|
||||
Select a configuration file to edit
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,47 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
export type ConfigType =
|
||||
| "user"
|
||||
| "project"
|
||||
| "project_local"
|
||||
| "enterprise_macos"
|
||||
| "enterprise_linux"
|
||||
| "enterprise_windows"
|
||||
| "mcp_macos"
|
||||
| "mcp_linux"
|
||||
| "mcp_windows";
|
||||
|
||||
export interface ConfigFile {
|
||||
path: string;
|
||||
content: unknown;
|
||||
exists: boolean;
|
||||
}
|
||||
|
||||
export const useConfigFiles = () => {
|
||||
return useQuery({
|
||||
queryKey: ["config-files"],
|
||||
queryFn: () => invoke<ConfigType[]>("list_config_files"),
|
||||
});
|
||||
};
|
||||
|
||||
export const useConfigFile = (configType: ConfigType) => {
|
||||
return useQuery({
|
||||
queryKey: ["config-file", configType],
|
||||
queryFn: () => invoke<ConfigFile>("read_config_file", { configType }),
|
||||
enabled: !!configType,
|
||||
});
|
||||
};
|
||||
|
||||
export const useWriteConfigFile = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: ({ configType, content }: { configType: ConfigType; content: unknown }) =>
|
||||
invoke<void>("write_config_file", { configType, content }),
|
||||
onSuccess: (_, variables) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["config-file", variables.configType] });
|
||||
queryClient.invalidateQueries({ queryKey: ["config-files"] });
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import App from "./App";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<App />
|
||||
</QueryClientProvider>
|
||||
</React.StrictMode>,
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
|
||||
// @ts-expect-error process is a nodejs global
|
||||
const host = process.env.TAURI_DEV_HOST;
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig(async () => ({
|
||||
plugins: [react(), tailwindcss()],
|
||||
|
||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||
//
|
||||
// 1. prevent Vite from obscuring rust errors
|
||||
clearScreen: false,
|
||||
// 2. tauri expects a fixed port, fail if that port is not available
|
||||
server: {
|
||||
port: 1420,
|
||||
strictPort: true,
|
||||
host: host || false,
|
||||
hmr: host
|
||||
? {
|
||||
protocol: "ws",
|
||||
host,
|
||||
port: 1421,
|
||||
}
|
||||
: undefined,
|
||||
watch: {
|
||||
// 3. tell Vite to ignore watching `src-tauri`
|
||||
ignored: ["**/src-tauri/**"],
|
||||
},
|
||||
},
|
||||
}));
|
||||