xling 0.0.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +276 -1
- package/dist/base-BWvHbkly.js +69 -0
- package/dist/base-BWvHbkly.js.map +1 -0
- package/dist/base-BXJVsMwL.d.ts +45 -0
- package/dist/base-BXJVsMwL.d.ts.map +1 -0
- package/dist/base-DdIJJBHV.js +34 -0
- package/dist/base-DdIJJBHV.js.map +1 -0
- package/dist/base-EQ6uvBQs.d.ts +43 -0
- package/dist/base-EQ6uvBQs.d.ts.map +1 -0
- package/dist/claude-BsdlWM7z.js +31 -0
- package/dist/claude-BsdlWM7z.js.map +1 -0
- package/dist/claude-D7KdpYHQ.js +209 -0
- package/dist/claude-D7KdpYHQ.js.map +1 -0
- package/dist/claudeDefault-pd-Kyu6o.js +19 -0
- package/dist/claudeDefault-pd-Kyu6o.js.map +1 -0
- package/dist/codex-Crifr9cw.js +32 -0
- package/dist/codex-Crifr9cw.js.map +1 -0
- package/dist/codex-UJ2PYHA6.js +85 -0
- package/dist/codex-UJ2PYHA6.js.map +1 -0
- package/dist/commands/settings/get.d.ts +24 -0
- package/dist/commands/settings/get.d.ts.map +1 -0
- package/dist/commands/settings/get.js +118 -0
- package/dist/commands/settings/get.js.map +1 -0
- package/dist/commands/settings/inspect.d.ts +19 -0
- package/dist/commands/settings/inspect.d.ts.map +1 -0
- package/dist/commands/settings/inspect.js +88 -0
- package/dist/commands/settings/inspect.js.map +1 -0
- package/dist/commands/settings/list.d.ts +25 -0
- package/dist/commands/settings/list.d.ts.map +1 -0
- package/dist/commands/settings/list.js +147 -0
- package/dist/commands/settings/list.js.map +1 -0
- package/dist/commands/settings/set.d.ts +22 -0
- package/dist/commands/settings/set.d.ts.map +1 -0
- package/dist/commands/settings/set.js +83 -0
- package/dist/commands/settings/set.js.map +1 -0
- package/dist/commands/settings/switch.d.ts +27 -0
- package/dist/commands/settings/switch.d.ts.map +1 -0
- package/dist/commands/settings/switch.js +164 -0
- package/dist/commands/settings/switch.js.map +1 -0
- package/dist/commands/x/index.d.ts +25 -0
- package/dist/commands/x/index.d.ts.map +1 -0
- package/dist/commands/x/index.js +130 -0
- package/dist/commands/x/index.js.map +1 -0
- package/dist/dispatcher-BUU7wUgm.js +94 -0
- package/dist/dispatcher-BUU7wUgm.js.map +1 -0
- package/dist/dispatcher-Co94YvDc.js +76 -0
- package/dist/dispatcher-Co94YvDc.js.map +1 -0
- package/dist/domain/interfaces.d.ts +3 -0
- package/dist/domain/interfaces.js +1 -0
- package/dist/domain/types.d.ts +2 -0
- package/dist/domain/types.js +1 -0
- package/dist/domain/validators.d.ts +82 -0
- package/dist/domain/validators.d.ts.map +1 -0
- package/dist/domain/validators.js +58 -0
- package/dist/domain/validators.js.map +1 -0
- package/dist/editor-D4qoje1V.js +32 -0
- package/dist/editor-D4qoje1V.js.map +1 -0
- package/dist/errors-CAZ5k5YT.js +89 -0
- package/dist/errors-CAZ5k5YT.js.map +1 -0
- package/dist/format-Cqecj3RS.js +229 -0
- package/dist/format-Cqecj3RS.js.map +1 -0
- package/dist/fsStore-BPnFUGta.js +122 -0
- package/dist/fsStore-BPnFUGta.js.map +1 -0
- package/dist/gemini-Qo5146d_.js +52 -0
- package/dist/gemini-Qo5146d_.js.map +1 -0
- package/dist/interfaces-DRNAGN0l.d.ts +75 -0
- package/dist/interfaces-DRNAGN0l.d.ts.map +1 -0
- package/dist/run.d.ts +1 -0
- package/dist/run.js +15 -0
- package/dist/run.js.map +1 -0
- package/dist/runner-BE7zZq1g.js +89 -0
- package/dist/runner-BE7zZq1g.js.map +1 -0
- package/dist/services/launch/adapters/base.d.ts +4 -0
- package/dist/services/launch/adapters/base.js +4 -0
- package/dist/services/launch/adapters/claude.d.ts +25 -0
- package/dist/services/launch/adapters/claude.d.ts.map +1 -0
- package/dist/services/launch/adapters/claude.js +5 -0
- package/dist/services/launch/adapters/codex.d.ts +26 -0
- package/dist/services/launch/adapters/codex.d.ts.map +1 -0
- package/dist/services/launch/adapters/codex.js +5 -0
- package/dist/services/launch/dispatcher.d.ts +44 -0
- package/dist/services/launch/dispatcher.d.ts.map +1 -0
- package/dist/services/launch/dispatcher.js +8 -0
- package/dist/services/settings/adapters/base.d.ts +4 -0
- package/dist/services/settings/adapters/base.js +5 -0
- package/dist/services/settings/adapters/claude.d.ts +43 -0
- package/dist/services/settings/adapters/claude.d.ts.map +1 -0
- package/dist/services/settings/adapters/claude.js +9 -0
- package/dist/services/settings/adapters/codex.d.ts +45 -0
- package/dist/services/settings/adapters/codex.d.ts.map +1 -0
- package/dist/services/settings/adapters/codex.js +6 -0
- package/dist/services/settings/adapters/gemini.d.ts +32 -0
- package/dist/services/settings/adapters/gemini.d.ts.map +1 -0
- package/dist/services/settings/adapters/gemini.js +6 -0
- package/dist/services/settings/dispatcher.d.ts +36 -0
- package/dist/services/settings/dispatcher.d.ts.map +1 -0
- package/dist/services/settings/dispatcher.js +12 -0
- package/dist/services/settings/fsStore.d.ts +46 -0
- package/dist/services/settings/fsStore.d.ts.map +1 -0
- package/dist/services/settings/fsStore.js +4 -0
- package/dist/services/settings/templates/claudeDefault.d.ts +20 -0
- package/dist/services/settings/templates/claudeDefault.d.ts.map +1 -0
- package/dist/services/settings/templates/claudeDefault.js +3 -0
- package/dist/types--0tjriPy.d.ts +104 -0
- package/dist/types--0tjriPy.d.ts.map +1 -0
- package/dist/utils/editor.d.ts +6 -0
- package/dist/utils/editor.d.ts.map +1 -0
- package/dist/utils/editor.js +4 -0
- package/dist/utils/errors.d.ts +61 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +3 -0
- package/dist/utils/format.d.ts +20 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +3 -0
- package/dist/utils/logger.d.ts +32 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +46 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/runner.d.ts +36 -0
- package/dist/utils/runner.d.ts.map +1 -0
- package/dist/utils/runner.js +3 -0
- package/package.json +66 -6
package/README.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# xling
|
|
2
|
+
|
|
3
|
+
Unified CLI for managing AI tool settings across Claude Code, Codex, and Gemini CLI.
|
|
4
|
+
|
|
1
5
|
## What's in a Name? The Story of `xling`
|
|
2
6
|
|
|
3
7
|
The name `xling` was carefully chosen to represent the project's philosophy, blending modern tech symbolism with a rich, dual-meaning core.
|
|
@@ -16,4 +20,275 @@ At the heart of the name is `ling`, a concept with two harmonious faces rooted i
|
|
|
16
20
|
1. **令 (lìng)**: This means "command" or "order." It represents the tool's heritage as a command-line interface—unwavering, precise, and powerful.
|
|
17
21
|
2. **灵 (líng)**: This translates to "intelligence," "spirit," or "agility." It embodies the AI engine that gives `xling` its smarts, allowing it to understand natural language, anticipate intent, and perform complex tasks with a touch of magic.
|
|
18
22
|
|
|
19
|
-
Together, `xling` is more than just a tool; it's an intelligent partner that amplifies your ability to command your digital world.
|
|
23
|
+
Together, `xling` is more than just a tool; it's an intelligent partner that amplifies your ability to command your digital world.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **Unified Interface**: Manage settings for multiple AI CLI tools with a single command
|
|
28
|
+
- **Quick Launcher**: Just type `xling x` to start Claude Code instantly with yolo mode
|
|
29
|
+
- **Multiple Scopes**: Support for user, project, local, and system-level configurations
|
|
30
|
+
- **Profile Switching**: Switch between different configuration profiles (Codex)
|
|
31
|
+
- **Dry Run Mode**: Preview changes before applying them
|
|
32
|
+
- **JSON Output**: Machine-readable output for scripting
|
|
33
|
+
- **Type Safe**: Built with TypeScript for reliability
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Install dependencies
|
|
39
|
+
bun install
|
|
40
|
+
|
|
41
|
+
# Build the project
|
|
42
|
+
bun run build
|
|
43
|
+
|
|
44
|
+
# Link globally (optional)
|
|
45
|
+
npm link
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
### Quick Start - The `x` Command
|
|
51
|
+
|
|
52
|
+
The fastest way to start your AI tools! Just type `xling x` to launch Claude Code with yolo mode.
|
|
53
|
+
|
|
54
|
+
**Claude Code is launched by default** - the ultimate convenience!
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# 🚀 Fastest way - Start Claude Code instantly
|
|
58
|
+
xling x
|
|
59
|
+
|
|
60
|
+
# Continue last conversation/session
|
|
61
|
+
xling x -c
|
|
62
|
+
|
|
63
|
+
# Resume from conversation/session list
|
|
64
|
+
xling x -r
|
|
65
|
+
|
|
66
|
+
# Pass arguments to Claude
|
|
67
|
+
xling x -- chat "Hello, how are you?"
|
|
68
|
+
|
|
69
|
+
# Start without yolo mode
|
|
70
|
+
xling x --no-yolo
|
|
71
|
+
|
|
72
|
+
# Start Codex instead
|
|
73
|
+
xling x --tool codex
|
|
74
|
+
# or use the short flag
|
|
75
|
+
xling x -t codex
|
|
76
|
+
|
|
77
|
+
# Continue last Codex session
|
|
78
|
+
xling x -t codex -c
|
|
79
|
+
|
|
80
|
+
# Start Codex in a specific directory
|
|
81
|
+
xling x -t codex -C /path/to/project
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Resume Options:**
|
|
85
|
+
- `-c` or `--continue`: Continue the last conversation/session
|
|
86
|
+
- Claude Code: `claude -c`
|
|
87
|
+
- Codex: `codex resume --last`
|
|
88
|
+
- `-r` or `--resume`: Show a list to choose from
|
|
89
|
+
- Claude Code: `claude -r`
|
|
90
|
+
- Codex: `codex resume`
|
|
91
|
+
|
|
92
|
+
**Yolo mode flags:**
|
|
93
|
+
- Claude Code: `--dangerously-skip-permissions`
|
|
94
|
+
- Codex: `--dangerously-bypass-approvals-and-sandbox`
|
|
95
|
+
|
|
96
|
+
### List Settings
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# List all settings for Claude Code (user scope)
|
|
100
|
+
xling settings:list --tool claude --scope user
|
|
101
|
+
|
|
102
|
+
# List Codex settings in table format
|
|
103
|
+
xling settings:list --tool codex --table
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
> Claude-specific: `settings:list --tool claude` now enumerates every
|
|
107
|
+
> `settings*.json` file (for example `settings.hxi.json`) in the selected scope
|
|
108
|
+
> so you can quickly discover switchable variants.
|
|
109
|
+
>
|
|
110
|
+
> Codex-specific: `settings:list --tool codex` surfaces only the `model_providers`
|
|
111
|
+
> block from `~/.codex/config.toml`, helping you audit provider names, base URLs,
|
|
112
|
+
> and env key bindings at a glance.
|
|
113
|
+
|
|
114
|
+
`settings:list` 默认输出 YAML 风格的简洁概览;如需表格/JSON,请加 `--table` 或
|
|
115
|
+
`--json`。其余命令仍以 JSON 为默认输出,可通过 `--no-json` 获取文本格式。
|
|
116
|
+
|
|
117
|
+
### Get Settings File
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Show Claude user settings (plain text default)
|
|
121
|
+
xling settings:get --tool claude --scope user
|
|
122
|
+
|
|
123
|
+
# Inspect a Claude variant (settings.hxi.json)
|
|
124
|
+
xling settings:get hxi --tool claude --scope user
|
|
125
|
+
|
|
126
|
+
# Show Codex config (plain text)
|
|
127
|
+
xling settings:get --tool codex
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Edit Settings (Claude)
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Create/edit settings.hxi.json in VS Code (default)
|
|
134
|
+
xling settings:set --tool claude --scope user --name hxi
|
|
135
|
+
|
|
136
|
+
# Open default settings in Cursor
|
|
137
|
+
xling settings:set --tool claude --scope project --name default --ide cursor --no-json
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`settings:set` 现专注于整文件编辑:传 `--name`(默认 `default`)即可创建/打开
|
|
141
|
+
`settings.<name>.json`,并使用 `--ide` 指定编辑器(默认 VS Code 的 `code`)。
|
|
142
|
+
|
|
143
|
+
> Note: 所有 `settings:*` 命令仅依赖 `--tool`、`--scope`、`--name` 等 flag;不再提供
|
|
144
|
+
> `developerShortcuts.runCommand` 这类键级参数。
|
|
145
|
+
|
|
146
|
+
### Switch Profiles or Claude Variants
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Switch to a different profile
|
|
150
|
+
xling settings:switch oss --tool codex
|
|
151
|
+
|
|
152
|
+
# Activate settings.hxi.json for Claude user scope
|
|
153
|
+
xling settings:switch hxi --tool claude --scope user
|
|
154
|
+
|
|
155
|
+
# Apply without prompt (Claude)
|
|
156
|
+
xling settings:switch hxi --tool claude --scope user --force
|
|
157
|
+
|
|
158
|
+
# Force and keep a .bak backup
|
|
159
|
+
xling settings:switch hxi --tool claude --scope user --force --backup
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Claude switches现在默认进行交互式 diff 预览:命令会先打印彩色统一 diff,
|
|
163
|
+
然后提示 `overwrite / backup / cancel`。若要非交互执行,使用 `--force`,并可
|
|
164
|
+
通过 `--backup` 强制保留 `.bak`。Codex 保持原行为,直接切换 profile。
|
|
165
|
+
|
|
166
|
+
### Inspect Configuration
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# View configuration file information
|
|
170
|
+
xling settings:inspect --tool claude --scope user
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Supported Tools
|
|
174
|
+
|
|
175
|
+
### Claude Code
|
|
176
|
+
|
|
177
|
+
- **Scopes**: user, project, local
|
|
178
|
+
- **Config Files**:
|
|
179
|
+
- User: `~/.claude/settings.json`
|
|
180
|
+
- Project: `.claude/settings.json`
|
|
181
|
+
- Local: `.claude/settings.local.json`
|
|
182
|
+
|
|
183
|
+
### Codex
|
|
184
|
+
|
|
185
|
+
- **Scopes**: user
|
|
186
|
+
- **Config Files**:
|
|
187
|
+
- User: `~/.codex/config.toml`
|
|
188
|
+
- **Features**: Profile switching
|
|
189
|
+
|
|
190
|
+
### Gemini CLI
|
|
191
|
+
|
|
192
|
+
- **Scopes**: user, project, system
|
|
193
|
+
- **Config Files**:
|
|
194
|
+
- User: `~/.gemini/settings.json`
|
|
195
|
+
- Project: `.gemini/settings.json`
|
|
196
|
+
- System: Platform-dependent
|
|
197
|
+
|
|
198
|
+
## Architecture
|
|
199
|
+
|
|
200
|
+
The project follows SOLID principles:
|
|
201
|
+
|
|
202
|
+
- **Single Responsibility**: Each adapter handles one tool
|
|
203
|
+
- **Open/Closed**: Easy to add new tools without modifying existing code
|
|
204
|
+
- **Liskov Substitution**: All adapters implement the same interface
|
|
205
|
+
- **Interface Segregation**: Clean, focused interfaces
|
|
206
|
+
- **Dependency Inversion**: Commands depend on abstractions, not implementations
|
|
207
|
+
|
|
208
|
+
### Directory Structure
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
xling/
|
|
212
|
+
├── bin/
|
|
213
|
+
│ └── run.js # CLI entry point
|
|
214
|
+
├── src/
|
|
215
|
+
│ ├── commands/ # oclif commands
|
|
216
|
+
│ │ └── settings/
|
|
217
|
+
│ ├── domain/ # Types and interfaces
|
|
218
|
+
│ ├── services/ # Business logic
|
|
219
|
+
│ │ └── settings/
|
|
220
|
+
│ │ ├── adapters/ # Tool adapters
|
|
221
|
+
│ │ ├── fsStore.ts # File system operations
|
|
222
|
+
│ │ └── dispatcher.ts
|
|
223
|
+
│ └── utils/ # Utilities
|
|
224
|
+
└── test/ # Tests and fixtures
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Development
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Install dependencies
|
|
231
|
+
bun install
|
|
232
|
+
|
|
233
|
+
# Build (using tsdown)
|
|
234
|
+
bun run build
|
|
235
|
+
|
|
236
|
+
# Watch mode (tsdown --watch)
|
|
237
|
+
bun run dev
|
|
238
|
+
|
|
239
|
+
# Code quality
|
|
240
|
+
bun run lint # Lint with oxlint
|
|
241
|
+
bun run lint:fix # Auto-fix lint issues
|
|
242
|
+
bun run format # Format with oxfmt
|
|
243
|
+
bun run format:check # Check formatting
|
|
244
|
+
bun run typecheck # Type check with tsc
|
|
245
|
+
|
|
246
|
+
# Run tests
|
|
247
|
+
bun test
|
|
248
|
+
bun test:watch
|
|
249
|
+
bun test:coverage
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Toolchain
|
|
253
|
+
|
|
254
|
+
**Build System**
|
|
255
|
+
|
|
256
|
+
This project uses [tsdown](https://tsdown.vercel.app/) for fast TypeScript compilation and bundling:
|
|
257
|
+
|
|
258
|
+
- **Fast builds**: Powered by rolldown (Rust-based bundler)
|
|
259
|
+
- **ESM output**: Generates `.js` files for modern Node.js
|
|
260
|
+
- **Type definitions**: Automatically generates `.d.ts` files
|
|
261
|
+
- **Source maps**: Includes source maps for debugging
|
|
262
|
+
- **Tree shaking**: Optimized bundle size
|
|
263
|
+
|
|
264
|
+
**Code Quality**
|
|
265
|
+
|
|
266
|
+
- **Linting**: [oxlint](https://oxc.rs/) - Rust-based linter, 50-100x faster than ESLint
|
|
267
|
+
- **Formatting**: [oxfmt](https://oxc.rs/) - Fast formatter compatible with Prettier config
|
|
268
|
+
- **Type Checking**: TypeScript compiler for strict type safety
|
|
269
|
+
|
|
270
|
+
## Testing
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
# Run all tests
|
|
274
|
+
bun test
|
|
275
|
+
|
|
276
|
+
# Run with coverage
|
|
277
|
+
bun test:coverage
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Contributing
|
|
281
|
+
|
|
282
|
+
1. Fork the repository
|
|
283
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
284
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
285
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
286
|
+
5. Open a Pull Request
|
|
287
|
+
|
|
288
|
+
## License
|
|
289
|
+
|
|
290
|
+
Apache-2.0
|
|
291
|
+
|
|
292
|
+
## Author
|
|
293
|
+
|
|
294
|
+
Kingsword <kingsword09@gmail.com>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { a as InvalidScopeError } from "./errors-CAZ5k5YT.js";
|
|
2
|
+
import { a as readJSON, c as writeJSON, i as getFileInfo, r as fileExists } from "./fsStore-BPnFUGta.js";
|
|
3
|
+
|
|
4
|
+
//#region src/services/settings/adapters/base.ts
|
|
5
|
+
/**
|
|
6
|
+
* 抽象基类
|
|
7
|
+
*/
|
|
8
|
+
var BaseAdapter = class {
|
|
9
|
+
/**
|
|
10
|
+
* 列出所有配置
|
|
11
|
+
*/
|
|
12
|
+
async list(scope) {
|
|
13
|
+
if (!this.validateScope(scope)) throw new InvalidScopeError(scope);
|
|
14
|
+
const path = this.resolvePath(scope);
|
|
15
|
+
return {
|
|
16
|
+
type: "entries",
|
|
17
|
+
entries: this.readConfig(path),
|
|
18
|
+
filePath: path
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 默认 switchProfile 会抛出,子类可覆盖
|
|
23
|
+
*/
|
|
24
|
+
async switchProfile(_scope, _profile, _options) {
|
|
25
|
+
throw new Error(`Tool ${this.toolId} does not support profile switching`);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 检查配置文件
|
|
29
|
+
*/
|
|
30
|
+
async inspect(scope) {
|
|
31
|
+
if (!this.validateScope(scope)) throw new InvalidScopeError(scope);
|
|
32
|
+
const path = this.resolvePath(scope);
|
|
33
|
+
if (!fileExists(path)) return {
|
|
34
|
+
path,
|
|
35
|
+
exists: false
|
|
36
|
+
};
|
|
37
|
+
const fileInfo = getFileInfo(path);
|
|
38
|
+
const config = this.readConfig(path);
|
|
39
|
+
return {
|
|
40
|
+
path,
|
|
41
|
+
exists: true,
|
|
42
|
+
content: JSON.stringify(config, null, 2),
|
|
43
|
+
size: fileInfo?.size,
|
|
44
|
+
lastModified: fileInfo?.lastModified
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 默认 edit 会抛出,子类可覆盖
|
|
49
|
+
*/
|
|
50
|
+
async edit(scope, _options) {
|
|
51
|
+
throw new Error(`Tool ${this.toolId} does not support edit for ${scope}`);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 读取配置文件(子类可覆盖)
|
|
55
|
+
*/
|
|
56
|
+
readConfig(path) {
|
|
57
|
+
return readJSON(path);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 写入配置文件(子类可覆盖)
|
|
61
|
+
*/
|
|
62
|
+
writeConfig(path, data, backup = true) {
|
|
63
|
+
writeJSON(path, data, backup);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
export { BaseAdapter as t };
|
|
69
|
+
//# sourceMappingURL=base-BWvHbkly.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-BWvHbkly.js","names":["fsStore.fileExists","fsStore.getFileInfo","fsStore.readJSON"],"sources":["../src/services/settings/adapters/base.ts"],"sourcesContent":["/**\n * 适配器抽象基类\n * 实现通用逻辑,减少重复代码(DRY 原则)\n */\n\nimport type { SettingsAdapter } from \"@/domain/interfaces.ts\";\nimport type {\n ToolId,\n Scope,\n InspectResult,\n SettingsListData,\n SettingsResult,\n EditOptions,\n SwitchOptions,\n} from \"@/domain/types.ts\";\nimport { InvalidScopeError } from \"@/utils/errors.ts\";\nimport * as fsStore from \"@/services/settings/fsStore.ts\";\n\n/**\n * 抽象基类\n */\nexport abstract class BaseAdapter implements SettingsAdapter {\n abstract readonly toolId: ToolId;\n\n /**\n * 子类必须实现的方法\n */\n abstract resolvePath(scope: Scope): string;\n abstract validateScope(scope: Scope): boolean;\n\n /**\n * 列出所有配置\n */\n async list(scope: Scope): Promise<SettingsListData> {\n if (!this.validateScope(scope)) {\n throw new InvalidScopeError(scope);\n }\n\n const path = this.resolvePath(scope);\n const config = this.readConfig(path);\n\n return {\n type: \"entries\",\n entries: config,\n filePath: path,\n };\n }\n\n /**\n * 默认 switchProfile 会抛出,子类可覆盖\n */\n async switchProfile(\n _scope: Scope,\n _profile: string,\n _options?: SwitchOptions,\n ): Promise<SettingsResult> {\n throw new Error(`Tool ${this.toolId} does not support profile switching`);\n }\n\n /**\n * 检查配置文件\n */\n async inspect(scope: Scope): Promise<InspectResult> {\n if (!this.validateScope(scope)) {\n throw new InvalidScopeError(scope);\n }\n\n const path = this.resolvePath(scope);\n const exists = fsStore.fileExists(path);\n\n if (!exists) {\n return {\n path,\n exists: false,\n };\n }\n\n const fileInfo = fsStore.getFileInfo(path);\n const config = this.readConfig(path);\n\n return {\n path,\n exists: true,\n content: JSON.stringify(config, null, 2),\n size: fileInfo?.size,\n lastModified: fileInfo?.lastModified,\n };\n }\n\n /**\n * 默认 edit 会抛出,子类可覆盖\n */\n async edit(scope: Scope, _options: EditOptions): Promise<SettingsResult> {\n throw new Error(`Tool ${this.toolId} does not support edit for ${scope}`);\n }\n\n /**\n * 读取配置文件(子类可覆盖)\n */\n protected readConfig(path: string): Record<string, unknown> {\n return fsStore.readJSON(path);\n }\n\n /**\n * 写入配置文件(子类可覆盖)\n */\n protected writeConfig(\n path: string,\n data: Record<string, unknown>,\n backup = true,\n ): void {\n fsStore.writeJSON(path, data, backup);\n }\n}\n"],"mappings":";;;;;;;AAqBA,IAAsB,cAAtB,MAA6D;;;;CAY3D,MAAM,KAAK,OAAyC;AAClD,MAAI,CAAC,KAAK,cAAc,MAAM,CAC5B,OAAM,IAAI,kBAAkB,MAAM;EAGpC,MAAM,OAAO,KAAK,YAAY,MAAM;AAGpC,SAAO;GACL,MAAM;GACN,SAJa,KAAK,WAAW,KAAK;GAKlC,UAAU;GACX;;;;;CAMH,MAAM,cACJ,QACA,UACA,UACyB;AACzB,QAAM,IAAI,MAAM,QAAQ,KAAK,OAAO,qCAAqC;;;;;CAM3E,MAAM,QAAQ,OAAsC;AAClD,MAAI,CAAC,KAAK,cAAc,MAAM,CAC5B,OAAM,IAAI,kBAAkB,MAAM;EAGpC,MAAM,OAAO,KAAK,YAAY,MAAM;AAGpC,MAAI,CAFWA,WAAmB,KAAK,CAGrC,QAAO;GACL;GACA,QAAQ;GACT;EAGH,MAAM,WAAWC,YAAoB,KAAK;EAC1C,MAAM,SAAS,KAAK,WAAW,KAAK;AAEpC,SAAO;GACL;GACA,QAAQ;GACR,SAAS,KAAK,UAAU,QAAQ,MAAM,EAAE;GACxC,MAAM,UAAU;GAChB,cAAc,UAAU;GACzB;;;;;CAMH,MAAM,KAAK,OAAc,UAAgD;AACvE,QAAM,IAAI,MAAM,QAAQ,KAAK,OAAO,6BAA6B,QAAQ;;;;;CAM3E,AAAU,WAAW,MAAuC;AAC1D,SAAOC,SAAiB,KAAK;;;;;CAM/B,AAAU,YACR,MACA,MACA,SAAS,MACH;AACN,YAAkB,MAAM,MAAM,OAAO"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { m as ToolId, r as LaunchCommandSpec } from "./types--0tjriPy.js";
|
|
2
|
+
import { t as LaunchAdapter } from "./interfaces-DRNAGN0l.js";
|
|
3
|
+
|
|
4
|
+
//#region src/services/launch/adapters/base.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 抽象基类
|
|
8
|
+
* 体现 SOLID 原则:
|
|
9
|
+
* - SRP: 只负责命令规范构建
|
|
10
|
+
* - Template Method: 定义算法骨架,子类实现具体步骤
|
|
11
|
+
* - DRY: 复用 validateAvailability 和 getVersion 实现
|
|
12
|
+
*/
|
|
13
|
+
declare abstract class BaseLaunchAdapter implements LaunchAdapter {
|
|
14
|
+
/**
|
|
15
|
+
* 工具标识符(子类必须实现)
|
|
16
|
+
*/
|
|
17
|
+
abstract readonly toolId: ToolId;
|
|
18
|
+
/**
|
|
19
|
+
* 可执行文件名称(子类必须实现)
|
|
20
|
+
*/
|
|
21
|
+
abstract readonly executable: string;
|
|
22
|
+
/**
|
|
23
|
+
* 构建启动命令配置(子类必须实现)
|
|
24
|
+
* @param payload Launch 请求参数
|
|
25
|
+
* @returns 命令规范
|
|
26
|
+
*/
|
|
27
|
+
abstract buildCommandSpec(payload: {
|
|
28
|
+
yolo?: boolean;
|
|
29
|
+
resume?: boolean;
|
|
30
|
+
continue?: boolean;
|
|
31
|
+
}): LaunchCommandSpec;
|
|
32
|
+
/**
|
|
33
|
+
* 默认实现:检查可执行文件是否存在
|
|
34
|
+
* 子类可以覆盖此方法以提供自定义验证逻辑
|
|
35
|
+
*/
|
|
36
|
+
validateAvailability(): Promise<boolean>;
|
|
37
|
+
/**
|
|
38
|
+
* 默认版本检查实现
|
|
39
|
+
* 子类可以覆盖此方法以使用不同的版本参数
|
|
40
|
+
*/
|
|
41
|
+
getVersion(): Promise<string>;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { BaseLaunchAdapter as t };
|
|
45
|
+
//# sourceMappingURL=base-BXJVsMwL.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-BXJVsMwL.d.ts","names":[],"sources":["../src/services/launch/adapters/base.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;uBAgBsB,iBAAA,YAA6B;;;;4BAIvB;;;;;;;;;;;;;;MAgBtB;;;;;0BAM0B;;;;;gBAQV"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { n as getExecutableVersion, t as checkExecutable } from "./runner-BE7zZq1g.js";
|
|
2
|
+
|
|
3
|
+
//#region src/services/launch/adapters/base.ts
|
|
4
|
+
/**
|
|
5
|
+
* 抽象基类
|
|
6
|
+
* 体现 SOLID 原则:
|
|
7
|
+
* - SRP: 只负责命令规范构建
|
|
8
|
+
* - Template Method: 定义算法骨架,子类实现具体步骤
|
|
9
|
+
* - DRY: 复用 validateAvailability 和 getVersion 实现
|
|
10
|
+
*/
|
|
11
|
+
var BaseLaunchAdapter = class {
|
|
12
|
+
/**
|
|
13
|
+
* 默认实现:检查可执行文件是否存在
|
|
14
|
+
* 子类可以覆盖此方法以提供自定义验证逻辑
|
|
15
|
+
*/
|
|
16
|
+
async validateAvailability() {
|
|
17
|
+
return checkExecutable(this.executable);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 默认版本检查实现
|
|
21
|
+
* 子类可以覆盖此方法以使用不同的版本参数
|
|
22
|
+
*/
|
|
23
|
+
async getVersion() {
|
|
24
|
+
try {
|
|
25
|
+
return await getExecutableVersion(this.executable);
|
|
26
|
+
} catch {
|
|
27
|
+
return "unknown";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { BaseLaunchAdapter as t };
|
|
34
|
+
//# sourceMappingURL=base-DdIJJBHV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-DdIJJBHV.js","names":[],"sources":["../src/services/launch/adapters/base.ts"],"sourcesContent":["/**\n * Launch 适配器抽象基类\n * 实现通用逻辑,减少重复代码(DRY 原则)\n */\n\nimport type { LaunchAdapter } from \"@/domain/interfaces.ts\";\nimport type { ToolId, LaunchCommandSpec } from \"@/domain/types.ts\";\nimport { checkExecutable, getExecutableVersion } from \"@/utils/runner.ts\";\n\n/**\n * 抽象基类\n * 体现 SOLID 原则:\n * - SRP: 只负责命令规范构建\n * - Template Method: 定义算法骨架,子类实现具体步骤\n * - DRY: 复用 validateAvailability 和 getVersion 实现\n */\nexport abstract class BaseLaunchAdapter implements LaunchAdapter {\n /**\n * 工具标识符(子类必须实现)\n */\n abstract readonly toolId: ToolId;\n\n /**\n * 可执行文件名称(子类必须实现)\n */\n abstract readonly executable: string;\n\n /**\n * 构建启动命令配置(子类必须实现)\n * @param payload Launch 请求参数\n * @returns 命令规范\n */\n abstract buildCommandSpec(payload: {\n yolo?: boolean;\n resume?: boolean;\n continue?: boolean;\n }): LaunchCommandSpec;\n\n /**\n * 默认实现:检查可执行文件是否存在\n * 子类可以覆盖此方法以提供自定义验证逻辑\n */\n async validateAvailability(): Promise<boolean> {\n return checkExecutable(this.executable);\n }\n\n /**\n * 默认版本检查实现\n * 子类可以覆盖此方法以使用不同的版本参数\n */\n async getVersion(): Promise<string> {\n try {\n return await getExecutableVersion(this.executable);\n } catch {\n return \"unknown\";\n }\n }\n}\n"],"mappings":";;;;;;;;;;AAgBA,IAAsB,oBAAtB,MAAiE;;;;;CA0B/D,MAAM,uBAAyC;AAC7C,SAAO,gBAAgB,KAAK,WAAW;;;;;;CAOzC,MAAM,aAA8B;AAClC,MAAI;AACF,UAAO,MAAM,qBAAqB,KAAK,WAAW;UAC5C;AACN,UAAO"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { f as SettingsResult, m as ToolId, n as InspectResult, p as SwitchOptions, s as Scope, t as EditOptions, u as SettingsListData } from "./types--0tjriPy.js";
|
|
2
|
+
import { n as SettingsAdapter } from "./interfaces-DRNAGN0l.js";
|
|
3
|
+
|
|
4
|
+
//#region src/services/settings/adapters/base.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 抽象基类
|
|
8
|
+
*/
|
|
9
|
+
declare abstract class BaseAdapter implements SettingsAdapter {
|
|
10
|
+
abstract readonly toolId: ToolId;
|
|
11
|
+
/**
|
|
12
|
+
* 子类必须实现的方法
|
|
13
|
+
*/
|
|
14
|
+
abstract resolvePath(scope: Scope): string;
|
|
15
|
+
abstract validateScope(scope: Scope): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* 列出所有配置
|
|
18
|
+
*/
|
|
19
|
+
list(scope: Scope): Promise<SettingsListData>;
|
|
20
|
+
/**
|
|
21
|
+
* 默认 switchProfile 会抛出,子类可覆盖
|
|
22
|
+
*/
|
|
23
|
+
switchProfile(_scope: Scope, _profile: string, _options?: SwitchOptions): Promise<SettingsResult>;
|
|
24
|
+
/**
|
|
25
|
+
* 检查配置文件
|
|
26
|
+
*/
|
|
27
|
+
inspect(scope: Scope): Promise<InspectResult>;
|
|
28
|
+
/**
|
|
29
|
+
* 默认 edit 会抛出,子类可覆盖
|
|
30
|
+
*/
|
|
31
|
+
edit(scope: Scope, _options: EditOptions): Promise<SettingsResult>;
|
|
32
|
+
/**
|
|
33
|
+
* 读取配置文件(子类可覆盖)
|
|
34
|
+
*/
|
|
35
|
+
protected readConfig(path: string): Record<string, unknown>;
|
|
36
|
+
/**
|
|
37
|
+
* 写入配置文件(子类可覆盖)
|
|
38
|
+
*/
|
|
39
|
+
protected writeConfig(path: string, data: Record<string, unknown>, backup?: boolean): void;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { BaseAdapter as t };
|
|
43
|
+
//# sourceMappingURL=base-EQ6uvBQs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-EQ6uvBQs.d.ts","names":[],"sources":["../src/services/settings/adapters/base.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAiCoC,uBAZd,WAAA,YAAuB,eAYT,CAAA;EAAR,kBAAA,MAAA,EAXA,MAWA;EAmBhB;;;EAGP,SAAA,WAAA,CAAA,KAAA,EA5ByB,KA4BzB,CAAA,EAAA,MAAA;EAOkB,SAAA,aAAA,CAAA,KAAA,EAlCS,KAkCT,CAAA,EAAA,OAAA;EAAgB;;;EA8BF,IAAA,CAAA,KAAA,EA3DjB,KA2DiB,CAAA,EA3DT,OA2DS,CA3DD,gBA2DC,CAAA;EAAsB;;;EAgBjD,aAAA,CAAA,MAAA,EAxDE,KAwDF,EAAA,QAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAtDK,aAsDL,CAAA,EArDL,OAqDK,CArDG,cAqDH,CAAA;EAvFmC;;;iBAyCtB,QAAQ,QAAQ;;;;cA8BnB,iBAAiB,cAAc,QAAQ;;;;sCAOrB;;;;4CAS5B"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { t as BaseLaunchAdapter } from "./base-DdIJJBHV.js";
|
|
2
|
+
|
|
3
|
+
//#region src/services/launch/adapters/claude.ts
|
|
4
|
+
/**
|
|
5
|
+
* Claude Code Launch 适配器
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Claude Code 启动适配器
|
|
9
|
+
*
|
|
10
|
+
* Yolo 模式: --dangerously-skip-permissions
|
|
11
|
+
* Resume 模式: -r (显示对话列表选择)
|
|
12
|
+
* Continue 模式: -c (继续最后一个对话)
|
|
13
|
+
*/
|
|
14
|
+
var ClaudeLaunchAdapter = class extends BaseLaunchAdapter {
|
|
15
|
+
toolId = "claude";
|
|
16
|
+
executable = "claude";
|
|
17
|
+
buildCommandSpec(payload) {
|
|
18
|
+
const baseArgs = [];
|
|
19
|
+
if (payload.continue) baseArgs.push("-c");
|
|
20
|
+
else if (payload.resume) baseArgs.push("-r");
|
|
21
|
+
return {
|
|
22
|
+
executable: this.executable,
|
|
23
|
+
baseArgs,
|
|
24
|
+
yoloArgs: payload.yolo ? ["--dangerously-skip-permissions"] : void 0
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { ClaudeLaunchAdapter as t };
|
|
31
|
+
//# sourceMappingURL=claude-BsdlWM7z.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-BsdlWM7z.js","names":["baseArgs: string[]"],"sources":["../src/services/launch/adapters/claude.ts"],"sourcesContent":["/**\n * Claude Code Launch 适配器\n */\n\nimport { BaseLaunchAdapter } from \"./base.ts\";\nimport type { LaunchCommandSpec } from \"@/domain/types.ts\";\n\n/**\n * Claude Code 启动适配器\n *\n * Yolo 模式: --dangerously-skip-permissions\n * Resume 模式: -r (显示对话列表选择)\n * Continue 模式: -c (继续最后一个对话)\n */\nexport class ClaudeLaunchAdapter extends BaseLaunchAdapter {\n readonly toolId = \"claude\" as const;\n readonly executable = \"claude\";\n\n buildCommandSpec(payload: {\n yolo?: boolean;\n resume?: boolean;\n continue?: boolean;\n }): LaunchCommandSpec {\n const baseArgs: string[] = [];\n\n // Resume 和 Continue 是互斥的\n if (payload.continue) {\n baseArgs.push(\"-c\");\n } else if (payload.resume) {\n baseArgs.push(\"-r\");\n }\n\n return {\n executable: this.executable,\n baseArgs,\n yoloArgs: payload.yolo ? [\"--dangerously-skip-permissions\"] : undefined,\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,IAAa,sBAAb,cAAyC,kBAAkB;CACzD,AAAS,SAAS;CAClB,AAAS,aAAa;CAEtB,iBAAiB,SAIK;EACpB,MAAMA,WAAqB,EAAE;AAG7B,MAAI,QAAQ,SACV,UAAS,KAAK,KAAK;WACV,QAAQ,OACjB,UAAS,KAAK,KAAK;AAGrB,SAAO;GACL,YAAY,KAAK;GACjB;GACA,UAAU,QAAQ,OAAO,CAAC,iCAAiC,GAAG;GAC/D"}
|