gencode-ai 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -90
- package/dist/agent/agent.d.ts +1 -1
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +8 -2
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/types.d.ts +9 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/cli/components/AllModelsSelector.d.ts +11 -0
- package/dist/cli/components/AllModelsSelector.d.ts.map +1 -0
- package/dist/cli/components/AllModelsSelector.js +153 -0
- package/dist/cli/components/AllModelsSelector.js.map +1 -0
- package/dist/cli/components/App.d.ts.map +1 -1
- package/dist/cli/components/App.js +59 -25
- package/dist/cli/components/App.js.map +1 -1
- package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
- package/dist/cli/components/CommandSuggestions.js +1 -0
- package/dist/cli/components/CommandSuggestions.js.map +1 -1
- package/dist/cli/components/Messages.d.ts +15 -1
- package/dist/cli/components/Messages.d.ts.map +1 -1
- package/dist/cli/components/Messages.js +41 -15
- package/dist/cli/components/Messages.js.map +1 -1
- package/dist/cli/components/ModelSelector.d.ts +7 -7
- package/dist/cli/components/ModelSelector.d.ts.map +1 -1
- package/dist/cli/components/ModelSelector.js +116 -33
- package/dist/cli/components/ModelSelector.js.map +1 -1
- package/dist/cli/components/ProviderManager.d.ts +8 -0
- package/dist/cli/components/ProviderManager.d.ts.map +1 -0
- package/dist/cli/components/ProviderManager.js +280 -0
- package/dist/cli/components/ProviderManager.js.map +1 -0
- package/dist/cli/components/markdown.d.ts +9 -0
- package/dist/cli/components/markdown.d.ts.map +1 -0
- package/dist/cli/components/markdown.js +129 -0
- package/dist/cli/components/markdown.js.map +1 -0
- package/dist/cli/components/theme.d.ts +5 -0
- package/dist/cli/components/theme.d.ts.map +1 -1
- package/dist/cli/components/theme.js +7 -0
- package/dist/cli/components/theme.js.map +1 -1
- package/dist/cli/index.js +19 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +3 -2
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +2 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/providers-config.d.ts +28 -0
- package/dist/config/providers-config.d.ts.map +1 -0
- package/dist/config/providers-config.js +79 -0
- package/dist/config/providers-config.js.map +1 -0
- package/dist/config/types.d.ts +31 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +1 -0
- package/dist/config/types.js.map +1 -1
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +14 -3
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/index.d.ts +5 -3
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +13 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/registry.d.ts +66 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +158 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/search/brave.d.ts +14 -0
- package/dist/providers/search/brave.d.ts.map +1 -0
- package/dist/providers/search/brave.js +87 -0
- package/dist/providers/search/brave.js.map +1 -0
- package/dist/providers/search/exa.d.ts +12 -0
- package/dist/providers/search/exa.d.ts.map +1 -0
- package/dist/providers/search/exa.js +158 -0
- package/dist/providers/search/exa.js.map +1 -0
- package/dist/providers/search/index.d.ts +31 -0
- package/dist/providers/search/index.d.ts.map +1 -0
- package/dist/providers/search/index.js +75 -0
- package/dist/providers/search/index.js.map +1 -0
- package/dist/providers/search/serper.d.ts +14 -0
- package/dist/providers/search/serper.d.ts.map +1 -0
- package/dist/providers/search/serper.js +87 -0
- package/dist/providers/search/serper.js.map +1 -0
- package/dist/providers/search/types.d.ts +21 -0
- package/dist/providers/search/types.d.ts.map +1 -0
- package/dist/providers/search/types.js +5 -0
- package/dist/providers/search/types.js.map +1 -0
- package/dist/providers/store.d.ts +104 -0
- package/dist/providers/store.d.ts.map +1 -0
- package/dist/providers/store.js +171 -0
- package/dist/providers/store.js.map +1 -0
- package/dist/providers/types.d.ts +7 -1
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/vertex-ai.d.ts +33 -0
- package/dist/providers/vertex-ai.d.ts.map +1 -0
- package/dist/providers/vertex-ai.js +407 -0
- package/dist/providers/vertex-ai.js.map +1 -0
- package/dist/tools/builtin/webfetch.d.ts +20 -0
- package/dist/tools/builtin/webfetch.d.ts.map +1 -0
- package/dist/tools/builtin/webfetch.js +231 -0
- package/dist/tools/builtin/webfetch.js.map +1 -0
- package/dist/tools/builtin/websearch.d.ts +17 -0
- package/dist/tools/builtin/websearch.d.ts.map +1 -0
- package/dist/tools/builtin/websearch.js +101 -0
- package/dist/tools/builtin/websearch.js.map +1 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +24 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/types.d.ts +19 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js +8 -0
- package/dist/tools/types.js.map +1 -1
- package/dist/tools/utils/ssrf.d.ts +18 -0
- package/dist/tools/utils/ssrf.d.ts.map +1 -0
- package/dist/tools/utils/ssrf.js +70 -0
- package/dist/tools/utils/ssrf.js.map +1 -0
- package/docs/README.md +5 -4
- package/docs/proposals/0001-web-fetch-tool.md +32 -2
- package/docs/proposals/0002-web-search-tool.md +59 -2
- package/docs/proposals/0041-configuration-system.md +556 -0
- package/docs/proposals/README.md +3 -2
- package/docs/providers.md +220 -0
- package/package.json +7 -2
- package/src/agent/agent.ts +9 -2
- package/src/agent/types.ts +9 -1
- package/src/cli/components/App.tsx +72 -23
- package/src/cli/components/CommandSuggestions.tsx +1 -0
- package/src/cli/components/Messages.tsx +117 -29
- package/src/cli/components/ModelSelector.tsx +169 -52
- package/src/cli/components/ProviderManager.tsx +534 -0
- package/src/cli/components/markdown.ts +157 -0
- package/src/cli/components/theme.ts +7 -0
- package/src/cli/index.tsx +22 -7
- package/src/config/index.ts +3 -2
- package/src/config/providers-config.ts +85 -0
- package/src/config/types.ts +35 -1
- package/src/providers/gemini.ts +20 -4
- package/src/providers/index.ts +18 -3
- package/src/providers/registry.ts +198 -0
- package/src/providers/search/brave.ts +132 -0
- package/src/providers/search/exa.ts +217 -0
- package/src/providers/search/index.ts +79 -0
- package/src/providers/search/serper.ts +133 -0
- package/src/providers/search/types.ts +24 -0
- package/src/providers/store.ts +216 -0
- package/src/providers/types.ts +9 -1
- package/src/providers/vertex-ai.ts +594 -0
- package/src/tools/builtin/webfetch.ts +264 -0
- package/src/tools/builtin/websearch.ts +117 -0
- package/src/tools/index.ts +24 -2
- package/src/tools/types.ts +20 -0
- package/src/tools/utils/ssrf.ts +79 -0
- package/CLAUDE.md +0 -70
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
# Proposal: Configuration System
|
|
2
|
+
|
|
3
|
+
- **Proposal ID**: 0041
|
|
4
|
+
- **Author**: gencode team
|
|
5
|
+
- **Status**: Draft
|
|
6
|
+
- **Created**: 2026-01-15
|
|
7
|
+
- **Updated**: 2026-01-15
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Implement a comprehensive configuration system for gencode, supporting multi-level configuration loading (user and project level), environment variable handling, permission management, and configuration merging. This design draws from both Claude Code's `~/.claude/` directory structure and OpenCode's configuration patterns.
|
|
12
|
+
|
|
13
|
+
## Motivation
|
|
14
|
+
|
|
15
|
+
A robust configuration system is essential for:
|
|
16
|
+
|
|
17
|
+
1. **Personalization**: Users need to customize behavior, model selection, and permissions
|
|
18
|
+
2. **Project-specific settings**: Different projects may require different configurations
|
|
19
|
+
3. **Team collaboration**: Shared project settings can be version controlled
|
|
20
|
+
4. **Security**: Sensitive local settings should be gitignored while shared settings remain portable
|
|
21
|
+
5. **Provider flexibility**: gencode's multi-provider architecture needs clean configuration for API keys and provider selection
|
|
22
|
+
|
|
23
|
+
## Claude Code Reference
|
|
24
|
+
|
|
25
|
+
### Configuration File Hierarchy
|
|
26
|
+
|
|
27
|
+
Claude Code uses a layered configuration system with the following priority (high to low):
|
|
28
|
+
|
|
29
|
+
| Level | Location | Purpose | Git Tracked |
|
|
30
|
+
|-------|----------|---------|-------------|
|
|
31
|
+
| 1 | `~/.claude.json` | Legacy main config | No |
|
|
32
|
+
| 2 | `~/.claude/settings.json` | User global settings | No |
|
|
33
|
+
| 3 | `~/.claude/settings.local.json` | User local settings | No |
|
|
34
|
+
| 4 | `.claude/settings.json` | Project shared settings | Yes |
|
|
35
|
+
| 5 | `.claude/settings.local.json` | Project personal settings | No (gitignored) |
|
|
36
|
+
| 6 | `.mcp.json` | Project MCP servers | Yes |
|
|
37
|
+
|
|
38
|
+
### Environment Variables
|
|
39
|
+
|
|
40
|
+
Claude Code supports extensive environment variables:
|
|
41
|
+
|
|
42
|
+
**Authentication & API:**
|
|
43
|
+
- `ANTHROPIC_API_KEY` - Primary API key
|
|
44
|
+
- `ANTHROPIC_AUTH_TOKEN` - Alternative token
|
|
45
|
+
- `ANTHROPIC_BASE_URL` - Custom API endpoint
|
|
46
|
+
- `ANTHROPIC_MODEL` - Default model selection
|
|
47
|
+
- `ANTHROPIC_SMALL_FAST_MODEL` - Fast model for quick operations
|
|
48
|
+
|
|
49
|
+
**Cloud Providers:**
|
|
50
|
+
- `CLAUDE_CODE_USE_BEDROCK` - Enable AWS Bedrock
|
|
51
|
+
- `CLAUDE_CODE_USE_VERTEX` - Enable Google Vertex AI
|
|
52
|
+
- `CLAUDE_CODE_SKIP_BEDROCK_AUTH` - Bypass AWS auth
|
|
53
|
+
- `CLAUDE_CODE_SKIP_VERTEX_AUTH` - Bypass Vertex auth
|
|
54
|
+
|
|
55
|
+
**Operational:**
|
|
56
|
+
- `CLAUDE_CODE_MAX_OUTPUT_TOKENS` - Token limit
|
|
57
|
+
- `CLAUDE_CODE_ACTION` - Permission mode (acceptEdits, plan, bypassPermissions)
|
|
58
|
+
- `FORCE_CODE_TERMINAL` - Force CLI mode
|
|
59
|
+
|
|
60
|
+
**Debugging:**
|
|
61
|
+
- `DEBUG` - Verbose logging
|
|
62
|
+
- `DISABLE_ERROR_REPORTING` - No error submission
|
|
63
|
+
- `DISABLE_TELEMETRY` - No usage tracking
|
|
64
|
+
|
|
65
|
+
### settings.json Structure
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"projects": {
|
|
70
|
+
"/path/to/project": {
|
|
71
|
+
"mcpServers": { },
|
|
72
|
+
"allowedTools": [ ]
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"permissions": {
|
|
76
|
+
"allow": ["Bash(npm:*)", "Read(/path/**)"],
|
|
77
|
+
"deny": ["Read(./.env)"]
|
|
78
|
+
},
|
|
79
|
+
"model": "claude-opus-4-5-20251101",
|
|
80
|
+
"spinnerTipsEnabled": false,
|
|
81
|
+
"attribution": {
|
|
82
|
+
"commits": true,
|
|
83
|
+
"pullRequests": true
|
|
84
|
+
},
|
|
85
|
+
"mcpServers": { },
|
|
86
|
+
"enableAllProjectMcpServers": true
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Tool Permission Patterns
|
|
91
|
+
|
|
92
|
+
- `Bash(git log:*)` - Git commands
|
|
93
|
+
- `Bash(npm run:*)` - NPM scripts
|
|
94
|
+
- `Read(/path/**)` - File patterns with globs
|
|
95
|
+
- `WebFetch(domain:github.com)` - Domain restrictions
|
|
96
|
+
- Tool names: `Task`, `Glob`, `Grep`, `LS`, `Edit`, `MultiEdit`, `Write`, `WebSearch`
|
|
97
|
+
|
|
98
|
+
## OpenCode Reference
|
|
99
|
+
|
|
100
|
+
OpenCode provides additional patterns worth adopting:
|
|
101
|
+
|
|
102
|
+
### Configuration Loading Order (Low → High Priority)
|
|
103
|
+
|
|
104
|
+
1. Remote config (`.well-known/opencode`)
|
|
105
|
+
2. Global config (`~/.config/opencode/opencode.json`)
|
|
106
|
+
3. `OPENCODE_CONFIG` env var file
|
|
107
|
+
4. Project config (`opencode.json`)
|
|
108
|
+
5. `OPENCODE_CONFIG_CONTENT` inline JSON
|
|
109
|
+
|
|
110
|
+
### Key Features
|
|
111
|
+
|
|
112
|
+
- **JSON/JSONC support**: Comments and trailing commas allowed
|
|
113
|
+
- **Environment variable substitution**: `{env:VARIABLE_NAME}` syntax
|
|
114
|
+
- **File content inclusion**: `{file:path/to/file}` syntax
|
|
115
|
+
- **Deep merge**: Arrays concatenate rather than replace
|
|
116
|
+
- **Zod schema validation**: Runtime type checking
|
|
117
|
+
|
|
118
|
+
## Detailed Design
|
|
119
|
+
|
|
120
|
+
### Directory Structure
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
~/.gencode/ # User-level configuration
|
|
124
|
+
├── settings.json # Main user config
|
|
125
|
+
├── settings.local.json # User local overrides (gitignored pattern)
|
|
126
|
+
├── GENCODE.md # User context (like CLAUDE.md)
|
|
127
|
+
├── commands/ # Custom slash commands
|
|
128
|
+
├── skills/ # Custom skills
|
|
129
|
+
├── agents/ # Custom subagents
|
|
130
|
+
├── plugins/ # Plugin management
|
|
131
|
+
│ ├── marketplaces.json
|
|
132
|
+
│ └── installed.json
|
|
133
|
+
├── hooks/ # Event hooks
|
|
134
|
+
└── sessions/ # Session data
|
|
135
|
+
|
|
136
|
+
./gencode.json # Project config (like opencode.json)
|
|
137
|
+
./.gencode/ # Project directory
|
|
138
|
+
├── settings.local.json # Project local overrides (gitignored)
|
|
139
|
+
├── GENCODE.md # Project context
|
|
140
|
+
├── rules/ # Path-scoped rules
|
|
141
|
+
└── skills/ # Project-specific skills
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Configuration Priority (High → Low)
|
|
145
|
+
|
|
146
|
+
1. **Environment variables** (`GENCODE_*`, provider API keys)
|
|
147
|
+
2. **CLI arguments** (`--model`, `--provider`)
|
|
148
|
+
3. **Project local** (`./.gencode/settings.local.json`)
|
|
149
|
+
4. **Project shared** (`./gencode.json`)
|
|
150
|
+
5. **User local** (`~/.gencode/settings.local.json`)
|
|
151
|
+
6. **User global** (`~/.gencode/settings.json`)
|
|
152
|
+
7. **Defaults**
|
|
153
|
+
|
|
154
|
+
### API Design
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// src/config/types.ts
|
|
158
|
+
interface GencodeConfig {
|
|
159
|
+
// Provider configuration
|
|
160
|
+
provider?: 'anthropic' | 'openai' | 'gemini' | 'bedrock' | 'vertex';
|
|
161
|
+
model?: string;
|
|
162
|
+
|
|
163
|
+
// Permission system
|
|
164
|
+
permissions?: {
|
|
165
|
+
allow?: string[]; // e.g., ["Bash(npm:*)", "Read(**/src/**)"]
|
|
166
|
+
deny?: string[]; // e.g., ["Read(.env)", "Bash(rm -rf:*)"]
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Environment variables to inject
|
|
170
|
+
env?: Record<string, string>;
|
|
171
|
+
|
|
172
|
+
// Hook definitions
|
|
173
|
+
hooks?: {
|
|
174
|
+
preToolUse?: HookConfig[];
|
|
175
|
+
postToolUse?: HookConfig[];
|
|
176
|
+
notification?: HookConfig[];
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// MCP server configuration
|
|
180
|
+
mcpServers?: Record<string, McpServerConfig>;
|
|
181
|
+
|
|
182
|
+
// Plugin enablement
|
|
183
|
+
enabledPlugins?: string[];
|
|
184
|
+
|
|
185
|
+
// UI preferences
|
|
186
|
+
theme?: 'dark' | 'light' | 'auto';
|
|
187
|
+
spinnerTipsEnabled?: boolean;
|
|
188
|
+
|
|
189
|
+
// Attribution settings
|
|
190
|
+
attribution?: {
|
|
191
|
+
commits?: boolean;
|
|
192
|
+
pullRequests?: boolean;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
interface HookConfig {
|
|
197
|
+
tool?: string;
|
|
198
|
+
command: string;
|
|
199
|
+
timeout?: number;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
interface McpServerConfig {
|
|
203
|
+
command: string;
|
|
204
|
+
args?: string[];
|
|
205
|
+
env?: Record<string, string>;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// src/config/loader.ts
|
|
209
|
+
interface ConfigLoader {
|
|
210
|
+
load(): Promise<GencodeConfig>;
|
|
211
|
+
getUserConfig(): Promise<GencodeConfig>;
|
|
212
|
+
getProjectConfig(): Promise<GencodeConfig>;
|
|
213
|
+
getEffectiveConfig(): Promise<GencodeConfig>;
|
|
214
|
+
watch(callback: (config: GencodeConfig) => void): void;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/config/env.ts
|
|
218
|
+
interface EnvHandler {
|
|
219
|
+
getProviderFromEnv(): string | undefined;
|
|
220
|
+
getModelFromEnv(): string | undefined;
|
|
221
|
+
getApiKey(provider: string): string | undefined;
|
|
222
|
+
substituteEnvVars(value: string): string;
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Environment Variables
|
|
227
|
+
|
|
228
|
+
**Provider Selection:**
|
|
229
|
+
- `GENCODE_PROVIDER` - Provider name (anthropic, openai, gemini, bedrock, vertex)
|
|
230
|
+
- `GENCODE_MODEL` - Model ID
|
|
231
|
+
- `GENCODE_CONFIG` - Custom config file path
|
|
232
|
+
|
|
233
|
+
**Provider API Keys (Auto-detect):**
|
|
234
|
+
- `ANTHROPIC_API_KEY`
|
|
235
|
+
- `OPENAI_API_KEY`
|
|
236
|
+
- `GOOGLE_API_KEY`
|
|
237
|
+
- `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` (for Bedrock)
|
|
238
|
+
|
|
239
|
+
**Operational:**
|
|
240
|
+
- `GENCODE_MAX_OUTPUT_TOKENS` - Token limit
|
|
241
|
+
- `GENCODE_DISABLE_TELEMETRY` - Disable tracking
|
|
242
|
+
- `GENCODE_DEBUG` - Debug mode
|
|
243
|
+
- `HTTP_PROXY` / `HTTPS_PROXY` - Network proxy
|
|
244
|
+
|
|
245
|
+
### settings.json Schema
|
|
246
|
+
|
|
247
|
+
```json
|
|
248
|
+
{
|
|
249
|
+
"$schema": "https://gencode.dev/settings.schema.json",
|
|
250
|
+
"provider": "anthropic",
|
|
251
|
+
"model": "claude-sonnet-4",
|
|
252
|
+
"permissions": {
|
|
253
|
+
"allow": ["Bash(npm:*)", "Read(**/src/**)"],
|
|
254
|
+
"deny": ["Read(.env)", "Bash(rm -rf:*)"]
|
|
255
|
+
},
|
|
256
|
+
"env": {
|
|
257
|
+
"CUSTOM_VAR": "value",
|
|
258
|
+
"API_URL": "{env:BASE_API_URL}/v1"
|
|
259
|
+
},
|
|
260
|
+
"hooks": {
|
|
261
|
+
"postToolUse": [
|
|
262
|
+
{ "tool": "Write", "command": "make fmt" }
|
|
263
|
+
]
|
|
264
|
+
},
|
|
265
|
+
"mcpServers": {
|
|
266
|
+
"memory": {
|
|
267
|
+
"command": "npx",
|
|
268
|
+
"args": ["@modelcontextprotocol/server-memory"]
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
"enabledPlugins": ["git@official", "jira@community"],
|
|
272
|
+
"theme": "dark",
|
|
273
|
+
"spinnerTipsEnabled": true,
|
|
274
|
+
"attribution": {
|
|
275
|
+
"commits": true,
|
|
276
|
+
"pullRequests": true
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Implementation Approach
|
|
282
|
+
|
|
283
|
+
#### Phase 1: Core Config Loading
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
// src/config/loader.ts
|
|
287
|
+
import { parse as parseJsonc } from 'jsonc-parser';
|
|
288
|
+
import { findUp } from 'find-up';
|
|
289
|
+
import { z } from 'zod';
|
|
290
|
+
|
|
291
|
+
const ConfigSchema = z.object({
|
|
292
|
+
provider: z.enum(['anthropic', 'openai', 'gemini', 'bedrock', 'vertex']).optional(),
|
|
293
|
+
model: z.string().optional(),
|
|
294
|
+
permissions: z.object({
|
|
295
|
+
allow: z.array(z.string()).optional(),
|
|
296
|
+
deny: z.array(z.string()).optional(),
|
|
297
|
+
}).optional(),
|
|
298
|
+
// ... rest of schema
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
export class ConfigLoader {
|
|
302
|
+
private userConfigDir = path.join(os.homedir(), '.gencode');
|
|
303
|
+
|
|
304
|
+
async load(): Promise<GencodeConfig> {
|
|
305
|
+
const configs = await Promise.all([
|
|
306
|
+
this.loadDefaults(),
|
|
307
|
+
this.loadUserGlobal(),
|
|
308
|
+
this.loadUserLocal(),
|
|
309
|
+
this.loadProjectShared(),
|
|
310
|
+
this.loadProjectLocal(),
|
|
311
|
+
]);
|
|
312
|
+
|
|
313
|
+
return this.deepMerge(...configs);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private async loadFile(filePath: string): Promise<Partial<GencodeConfig>> {
|
|
317
|
+
try {
|
|
318
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
319
|
+
const parsed = parseJsonc(content); // Supports comments
|
|
320
|
+
return ConfigSchema.partial().parse(parsed);
|
|
321
|
+
} catch {
|
|
322
|
+
return {};
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private deepMerge(...configs: Partial<GencodeConfig>[]): GencodeConfig {
|
|
327
|
+
// Arrays concatenate, objects merge recursively
|
|
328
|
+
return configs.reduce((acc, config) => {
|
|
329
|
+
return mergeWith(acc, config, (objValue, srcValue) => {
|
|
330
|
+
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
|
|
331
|
+
return [...objValue, ...srcValue]; // Concatenate arrays
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
}, {} as GencodeConfig);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
#### Phase 2: Environment Variable Handling
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// src/config/env.ts
|
|
343
|
+
export class EnvHandler {
|
|
344
|
+
private readonly providerKeyMap: Record<string, string> = {
|
|
345
|
+
anthropic: 'ANTHROPIC_API_KEY',
|
|
346
|
+
openai: 'OPENAI_API_KEY',
|
|
347
|
+
gemini: 'GOOGLE_API_KEY',
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
getProviderFromEnv(): string | undefined {
|
|
351
|
+
return process.env.GENCODE_PROVIDER;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
getApiKey(provider: string): string | undefined {
|
|
355
|
+
const envKey = this.providerKeyMap[provider];
|
|
356
|
+
return envKey ? process.env[envKey] : undefined;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Substitute {env:VAR} patterns
|
|
360
|
+
substituteEnvVars(value: string): string {
|
|
361
|
+
return value.replace(/\{env:(\w+)\}/g, (_, varName) => {
|
|
362
|
+
return process.env[varName] || '';
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
autoDetectProvider(): string | undefined {
|
|
367
|
+
for (const [provider, key] of Object.entries(this.providerKeyMap)) {
|
|
368
|
+
if (process.env[key]) {
|
|
369
|
+
return provider;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
#### Phase 3: Permission Matching
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
// src/config/permissions.ts
|
|
381
|
+
import { minimatch } from 'minimatch';
|
|
382
|
+
|
|
383
|
+
export class PermissionMatcher {
|
|
384
|
+
constructor(private config: GencodeConfig) {}
|
|
385
|
+
|
|
386
|
+
isAllowed(tool: string, args: string): boolean {
|
|
387
|
+
const permission = `${tool}(${args})`;
|
|
388
|
+
|
|
389
|
+
// Check deny list first
|
|
390
|
+
for (const pattern of this.config.permissions?.deny || []) {
|
|
391
|
+
if (this.matchPermission(permission, pattern)) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Check allow list
|
|
397
|
+
for (const pattern of this.config.permissions?.allow || []) {
|
|
398
|
+
if (this.matchPermission(permission, pattern)) {
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return false; // Default deny
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
private matchPermission(permission: string, pattern: string): boolean {
|
|
407
|
+
// Parse pattern: Tool(arg:pattern)
|
|
408
|
+
const match = pattern.match(/^(\w+)\((.+)\)$/);
|
|
409
|
+
if (!match) return false;
|
|
410
|
+
|
|
411
|
+
const [, toolPattern, argPattern] = match;
|
|
412
|
+
const [tool, arg] = permission.match(/^(\w+)\((.+)\)$/)?.slice(1) || [];
|
|
413
|
+
|
|
414
|
+
if (toolPattern !== tool && toolPattern !== '*') return false;
|
|
415
|
+
return minimatch(arg, argPattern);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### File Changes
|
|
421
|
+
|
|
422
|
+
| File | Action | Description |
|
|
423
|
+
|------|--------|-------------|
|
|
424
|
+
| `src/config/types.ts` | Create | Configuration type definitions |
|
|
425
|
+
| `src/config/loader.ts` | Create | Multi-level config loading |
|
|
426
|
+
| `src/config/env.ts` | Create | Environment variable handling |
|
|
427
|
+
| `src/config/permissions.ts` | Create | Permission pattern matching |
|
|
428
|
+
| `src/config/index.ts` | Create | Public API exports |
|
|
429
|
+
| `src/agent/agent.ts` | Modify | Integrate config system |
|
|
430
|
+
| `src/cli/index.ts` | Modify | Add --config CLI flag |
|
|
431
|
+
| `schemas/settings.schema.json` | Create | JSON Schema for validation |
|
|
432
|
+
|
|
433
|
+
## User Experience
|
|
434
|
+
|
|
435
|
+
### First-time Setup
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
# gencode auto-detects provider from API keys
|
|
439
|
+
$ export OPENAI_API_KEY=sk-...
|
|
440
|
+
$ gencode
|
|
441
|
+
# Uses OpenAI automatically
|
|
442
|
+
|
|
443
|
+
# Or specify explicitly
|
|
444
|
+
$ export GENCODE_PROVIDER=anthropic
|
|
445
|
+
$ export ANTHROPIC_API_KEY=sk-ant-...
|
|
446
|
+
$ gencode
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Project Configuration
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
# Initialize project config
|
|
453
|
+
$ gencode init
|
|
454
|
+
# Creates ./gencode.json with sensible defaults
|
|
455
|
+
|
|
456
|
+
# View effective configuration
|
|
457
|
+
$ gencode config
|
|
458
|
+
# Shows merged configuration from all sources
|
|
459
|
+
|
|
460
|
+
# Set project-specific model
|
|
461
|
+
$ gencode config set model claude-sonnet-4
|
|
462
|
+
# Updates ./gencode.json
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Permission Management
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
# View current permissions
|
|
469
|
+
$ gencode /permissions
|
|
470
|
+
|
|
471
|
+
# Allow npm commands for this project
|
|
472
|
+
$ gencode config allow "Bash(npm:*)"
|
|
473
|
+
|
|
474
|
+
# Deny reading .env files
|
|
475
|
+
$ gencode config deny "Read(.env)"
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## Alternatives Considered
|
|
479
|
+
|
|
480
|
+
### Single Config File
|
|
481
|
+
|
|
482
|
+
A single `~/.gencoderc` file would be simpler but lacks:
|
|
483
|
+
- Project-specific overrides
|
|
484
|
+
- Team-shareable settings
|
|
485
|
+
- Local-only sensitive settings
|
|
486
|
+
|
|
487
|
+
### YAML Configuration
|
|
488
|
+
|
|
489
|
+
YAML is more readable but:
|
|
490
|
+
- JSON has better tooling support
|
|
491
|
+
- JSONC provides comments without complexity
|
|
492
|
+
- Matches Claude Code and OpenCode patterns
|
|
493
|
+
|
|
494
|
+
### No Environment Variable Substitution
|
|
495
|
+
|
|
496
|
+
Simpler implementation but:
|
|
497
|
+
- Forces duplication of values
|
|
498
|
+
- Makes CI/CD integration harder
|
|
499
|
+
- Loses flexibility for sensitive values
|
|
500
|
+
|
|
501
|
+
## Security Considerations
|
|
502
|
+
|
|
503
|
+
1. **API Key Handling**: Never log or expose API keys; load from environment only
|
|
504
|
+
2. **Local Settings**: `settings.local.json` files should be gitignored
|
|
505
|
+
3. **Permission Defaults**: Default to deny; require explicit allow
|
|
506
|
+
4. **File Permissions**: Config files should be user-readable only (0600)
|
|
507
|
+
5. **Command Injection**: Validate hook commands; sanitize environment variable substitution
|
|
508
|
+
|
|
509
|
+
## Testing Strategy
|
|
510
|
+
|
|
511
|
+
1. **Unit Tests**:
|
|
512
|
+
- Config loading from multiple sources
|
|
513
|
+
- Deep merge behavior (especially arrays)
|
|
514
|
+
- Environment variable substitution
|
|
515
|
+
- Permission pattern matching
|
|
516
|
+
|
|
517
|
+
2. **Integration Tests**:
|
|
518
|
+
- Full config resolution with mock file system
|
|
519
|
+
- CLI flag override behavior
|
|
520
|
+
- Provider auto-detection
|
|
521
|
+
|
|
522
|
+
3. **E2E Tests**:
|
|
523
|
+
- `gencode config` commands
|
|
524
|
+
- Permission enforcement during tool execution
|
|
525
|
+
|
|
526
|
+
## Migration Path
|
|
527
|
+
|
|
528
|
+
1. **From mycode**: Migrate `~/.mycode/` to `~/.gencode/`
|
|
529
|
+
2. **Version Detection**: Check for legacy config locations and prompt migration
|
|
530
|
+
3. **Backward Compatibility**: Support reading old config format for one major version
|
|
531
|
+
|
|
532
|
+
## Dependencies
|
|
533
|
+
|
|
534
|
+
- [find-up](https://www.npmjs.com/package/find-up) - Directory traversal
|
|
535
|
+
- [jsonc-parser](https://www.npmjs.com/package/jsonc-parser) - JSON with comments
|
|
536
|
+
- [minimatch](https://www.npmjs.com/package/minimatch) - Glob pattern matching
|
|
537
|
+
- [zod](https://www.npmjs.com/package/zod) - Schema validation (already used)
|
|
538
|
+
- [lodash.mergewith](https://www.npmjs.com/package/lodash.mergewith) - Deep merge
|
|
539
|
+
|
|
540
|
+
## Related Proposals
|
|
541
|
+
|
|
542
|
+
| Proposal | Relationship |
|
|
543
|
+
|----------|--------------|
|
|
544
|
+
| [0006 Memory System](./0006-memory-system.md) | GENCODE.md is stored in config directories |
|
|
545
|
+
| [0009 Hooks System](./0009-hooks-system.md) | Hook definitions stored in settings.json |
|
|
546
|
+
| [0022 Plugin System](./0022-plugin-system.md) | Plugin enablement configured in settings |
|
|
547
|
+
| [0023 Permission Enhancements](./0023-permission-enhancements.md) | Permission patterns defined in settings |
|
|
548
|
+
|
|
549
|
+
## References
|
|
550
|
+
|
|
551
|
+
- [Claude Code Settings - Official Docs](https://code.claude.com/docs/en/settings)
|
|
552
|
+
- [Claude Code Configuration Guide | ClaudeLog](https://claudelog.com/configuration/)
|
|
553
|
+
- [Claude Code CLI Environment Variables](https://gist.github.com/unkn0wncode/f87295d055dd0f0e8082358a0b5cc467)
|
|
554
|
+
- [settings.json in Claude Code Guide](https://www.eesel.ai/blog/settings-json-claude-code)
|
|
555
|
+
- [OpenCode Config Docs](https://opencode.ai/docs/config/)
|
|
556
|
+
- [OpenCode Configuration System | DeepWiki](https://deepwiki.com/sst/opencode/3-configuration-system)
|
package/docs/proposals/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# gencode Enhancement Proposals
|
|
2
2
|
|
|
3
|
-
This directory contains enhancement proposals for the
|
|
3
|
+
This directory contains enhancement proposals for the gencode project. Each proposal describes a feature inspired by Claude Code that we plan to implement.
|
|
4
4
|
|
|
5
5
|
## Proposal Process
|
|
6
6
|
|
|
@@ -28,6 +28,7 @@ This directory contains enhancement proposals for the mycode project. Each propo
|
|
|
28
28
|
| [0010](./0010-mcp-integration.md) | MCP Integration | Draft |
|
|
29
29
|
| [0011](./0011-custom-commands.md) | Custom Commands | Draft |
|
|
30
30
|
| [0012](./0012-ask-user-question.md) | AskUserQuestion Tool | Draft |
|
|
31
|
+
| [0041](./0041-configuration-system.md) | Configuration System | Draft |
|
|
31
32
|
|
|
32
33
|
### P2 Priority - Enhanced Features
|
|
33
34
|
|