@cdoing/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cdoing/permissions.json +8 -0
- package/dist/callbacks.d.ts +17 -0
- package/dist/callbacks.d.ts.map +1 -0
- package/dist/callbacks.js +265 -0
- package/dist/callbacks.js.map +1 -0
- package/dist/chat.d.ts +27 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +57 -0
- package/dist/chat.js.map +1 -0
- package/dist/commands.d.ts +22 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +452 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +84 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +427 -0
- package/dist/config.js.map +1 -0
- package/dist/help.d.ts +9 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +167 -0
- package/dist/help.js.map +1 -0
- package/dist/history.d.ts +51 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +207 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +220 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth.d.ts +13 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +182 -0
- package/dist/oauth.js.map +1 -0
- package/dist/review.d.ts +26 -0
- package/dist/review.d.ts.map +1 -0
- package/dist/review.js +198 -0
- package/dist/review.js.map +1 -0
- package/dist/serve.d.ts +23 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +293 -0
- package/dist/serve.js.map +1 -0
- package/dist/tools.d.ts +14 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +57 -0
- package/dist/tools.js.map +1 -0
- package/dist/ui/App.d.ts +24 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +321 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/MessageList.d.ts +14 -0
- package/dist/ui/MessageList.d.ts.map +1 -0
- package/dist/ui/MessageList.js +147 -0
- package/dist/ui/MessageList.js.map +1 -0
- package/dist/ui/SessionBrowser.d.ts +18 -0
- package/dist/ui/SessionBrowser.d.ts.map +1 -0
- package/dist/ui/SessionBrowser.js +149 -0
- package/dist/ui/SessionBrowser.js.map +1 -0
- package/dist/ui/SetupWizard.d.ts +23 -0
- package/dist/ui/SetupWizard.d.ts.map +1 -0
- package/dist/ui/SetupWizard.js +402 -0
- package/dist/ui/SetupWizard.js.map +1 -0
- package/dist/ui/Spinner.d.ts +15 -0
- package/dist/ui/Spinner.d.ts.map +1 -0
- package/dist/ui/Spinner.js +111 -0
- package/dist/ui/Spinner.js.map +1 -0
- package/dist/ui/StatusBar.d.ts +16 -0
- package/dist/ui/StatusBar.d.ts.map +1 -0
- package/dist/ui/StatusBar.js +56 -0
- package/dist/ui/StatusBar.js.map +1 -0
- package/dist/ui/UserInput.d.ts +13 -0
- package/dist/ui/UserInput.d.ts.map +1 -0
- package/dist/ui/UserInput.js +872 -0
- package/dist/ui/UserInput.js.map +1 -0
- package/dist/ui/hooks/helpers.d.ts +55 -0
- package/dist/ui/hooks/helpers.d.ts.map +1 -0
- package/dist/ui/hooks/helpers.js +304 -0
- package/dist/ui/hooks/helpers.js.map +1 -0
- package/dist/ui/hooks/useAgent.d.ts +60 -0
- package/dist/ui/hooks/useAgent.d.ts.map +1 -0
- package/dist/ui/hooks/useAgent.js +213 -0
- package/dist/ui/hooks/useAgent.js.map +1 -0
- package/dist/ui/hooks/useChat.d.ts +74 -0
- package/dist/ui/hooks/useChat.d.ts.map +1 -0
- package/dist/ui/hooks/useChat.js +819 -0
- package/dist/ui/hooks/useChat.js.map +1 -0
- package/dist/ui/theme.d.ts +73 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +214 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/types.d.ts +37 -0
- package/dist/ui/types.d.ts.map +1 -0
- package/dist/ui/types.js +3 -0
- package/dist/ui/types.js.map +1 -0
- package/package.json +33 -0
- package/src/callbacks.ts +294 -0
- package/src/chat.ts +72 -0
- package/src/commands.ts +425 -0
- package/src/config.ts +462 -0
- package/src/help.ts +182 -0
- package/src/history.ts +205 -0
- package/src/index.ts +248 -0
- package/src/oauth.ts +164 -0
- package/src/review.ts +233 -0
- package/src/serve.ts +290 -0
- package/src/tools.ts +104 -0
- package/src/ui/App.tsx +426 -0
- package/src/ui/MessageList.tsx +222 -0
- package/src/ui/SessionBrowser.tsx +161 -0
- package/src/ui/SetupWizard.tsx +412 -0
- package/src/ui/Spinner.tsx +103 -0
- package/src/ui/StatusBar.tsx +106 -0
- package/src/ui/UserInput.tsx +954 -0
- package/src/ui/hooks/helpers.ts +271 -0
- package/src/ui/hooks/useAgent.ts +270 -0
- package/src/ui/hooks/useChat.ts +943 -0
- package/src/ui/theme.ts +326 -0
- package/src/ui/types.ts +41 -0
- package/tsconfig.json +18 -0
package/src/commands.ts
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Subcommand Handlers
|
|
3
|
+
*
|
|
4
|
+
* Handlers for: cdoing config, cdoing init, cdoing doctor
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import * as os from "os";
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
import figlet from "figlet";
|
|
12
|
+
import { loadConfig, saveConfig, getStoredConfigDisplay, updateStoredConfig } from "./config";
|
|
13
|
+
import { getApiKeyEnvVar } from "@cdoing/ai";
|
|
14
|
+
|
|
15
|
+
const CONFIG_DIR = path.join(os.homedir(), ".cdoing");
|
|
16
|
+
const PROJECT_CONFIG_DIR = ".cdoing";
|
|
17
|
+
const PROJECT_CONFIG_FILE = "config.md";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Handle `cdoing config <action> [key] [value]`
|
|
21
|
+
*/
|
|
22
|
+
export function handleConfigCommand(action: string, key?: string, value?: string): void {
|
|
23
|
+
switch (action) {
|
|
24
|
+
case "list":
|
|
25
|
+
console.log();
|
|
26
|
+
console.log(chalk.hex("#4FC3F7").bold(" ⚙️ Stored Config"));
|
|
27
|
+
console.log(chalk.hex("#78909C")(" ─────────────────────────────────────"));
|
|
28
|
+
for (const line of getStoredConfigDisplay()) {
|
|
29
|
+
console.log(chalk.hex("#B0BEC5")(` ${line}`));
|
|
30
|
+
}
|
|
31
|
+
console.log();
|
|
32
|
+
break;
|
|
33
|
+
|
|
34
|
+
case "get":
|
|
35
|
+
if (!key) {
|
|
36
|
+
console.log(chalk.hex("#EF5350")("\n ❌ Usage: cdoing config get <key>"));
|
|
37
|
+
console.log(chalk.hex("#78909C")(" Keys: provider, model, mode, api-key, base-url\n"));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const config = loadConfig();
|
|
41
|
+
let val: string | undefined;
|
|
42
|
+
switch (key) {
|
|
43
|
+
case "provider": val = config.provider; break;
|
|
44
|
+
case "model": val = config.model; break;
|
|
45
|
+
case "mode": val = config.mode; break;
|
|
46
|
+
case "base-url": val = config.baseUrl; break;
|
|
47
|
+
case "api-key":
|
|
48
|
+
const provider = config.provider || "anthropic";
|
|
49
|
+
val = config.apiKeys?.[provider];
|
|
50
|
+
if (val) val = val.slice(0, 8) + "..." + val.slice(-4);
|
|
51
|
+
break;
|
|
52
|
+
default:
|
|
53
|
+
console.log(chalk.hex("#EF5350")(`\n ❌ Unknown key: ${key}\n`));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
console.log(val ? chalk.hex("#81C784")(val) : chalk.hex("#78909C")("(not set)"));
|
|
57
|
+
break;
|
|
58
|
+
|
|
59
|
+
case "set":
|
|
60
|
+
if (!key || value === undefined) {
|
|
61
|
+
console.log(chalk.hex("#EF5350")("\n ❌ Usage: cdoing config set <key> <value>"));
|
|
62
|
+
console.log(chalk.hex("#78909C")(" Keys: provider, model, mode, api-key, base-url\n"));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const result = updateStoredConfig(key, value);
|
|
66
|
+
if (result.success) {
|
|
67
|
+
const display = key === "api-key" ? value.slice(0, 8) + "..." : value;
|
|
68
|
+
console.log();
|
|
69
|
+
console.log(chalk.hex("#81C784")(" ✓ Saved: ") + chalk.hex("#4FC3F7")(key) + chalk.hex("#78909C")(" = ") + chalk.hex("#FFFFFF")(display));
|
|
70
|
+
console.log();
|
|
71
|
+
} else {
|
|
72
|
+
console.log(chalk.hex("#EF5350")(`\n ❌ ${result.error}\n`));
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
|
|
76
|
+
default:
|
|
77
|
+
console.log(chalk.hex("#EF5350")(`\n ❌ Unknown action: ${action}`));
|
|
78
|
+
console.log(chalk.hex("#78909C")(" Usage: cdoing config <list|get|set> [key] [value]\n"));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Handle `cdoing init` - create .cdoing/ directory and config.md template
|
|
84
|
+
*/
|
|
85
|
+
export function handleInit(): void {
|
|
86
|
+
const cwd = process.cwd();
|
|
87
|
+
const configDir = path.join(cwd, PROJECT_CONFIG_DIR);
|
|
88
|
+
const configFile = path.join(configDir, PROJECT_CONFIG_FILE);
|
|
89
|
+
|
|
90
|
+
if (fs.existsSync(configFile)) {
|
|
91
|
+
console.log();
|
|
92
|
+
console.log(chalk.hex("#FFB74D")(" ⚠️ Project already initialized"));
|
|
93
|
+
console.log(chalk.hex("#90A4AE")(" .cdoing/config.md exists"));
|
|
94
|
+
console.log();
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!fs.existsSync(configDir)) {
|
|
99
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const template = `# Project Configuration
|
|
103
|
+
|
|
104
|
+
This file configures cdoing for this project.
|
|
105
|
+
|
|
106
|
+
## Instructions
|
|
107
|
+
|
|
108
|
+
Add project-specific instructions here. The agent will follow these guidelines.
|
|
109
|
+
|
|
110
|
+
\`\`\`
|
|
111
|
+
- Use TypeScript for all new code
|
|
112
|
+
- Follow existing code patterns
|
|
113
|
+
- Write tests for new features
|
|
114
|
+
\`\`\`
|
|
115
|
+
|
|
116
|
+
## Context
|
|
117
|
+
|
|
118
|
+
Describe your project here:
|
|
119
|
+
- What does this project do?
|
|
120
|
+
- What technologies does it use?
|
|
121
|
+
- Any special conventions?
|
|
122
|
+
|
|
123
|
+
## Files to Ignore
|
|
124
|
+
|
|
125
|
+
Files the agent should not modify:
|
|
126
|
+
- node_modules/
|
|
127
|
+
- dist/
|
|
128
|
+
- .env
|
|
129
|
+
|
|
130
|
+
## Preferred Tools
|
|
131
|
+
|
|
132
|
+
- Use npm for package management
|
|
133
|
+
- Use vitest for testing
|
|
134
|
+
`;
|
|
135
|
+
|
|
136
|
+
fs.writeFileSync(configFile, template, "utf-8");
|
|
137
|
+
console.log();
|
|
138
|
+
console.log(chalk.hex("#6BCB77")(figlet.textSync("Init!", { font: "Small" })));
|
|
139
|
+
console.log(chalk.hex("#81C784")(" ✨ Project initialized!"));
|
|
140
|
+
console.log(chalk.hex("#90A4AE")(" Created: ") + chalk.hex("#4FC3F7")(".cdoing/config.md"));
|
|
141
|
+
console.log();
|
|
142
|
+
console.log(chalk.hex("#78909C")(" Edit this file to customize agent behavior for your project."));
|
|
143
|
+
console.log();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ── Shell completion scripts ──────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
const ZSH_COMPLETION = `#compdef cdoing
|
|
149
|
+
# Zsh completion for cdoing — install with: cdoing completions zsh > ~/.zsh/completions/_cdoing
|
|
150
|
+
# Then add to ~/.zshrc: fpath=(~/.zsh/completions $fpath) && autoload -Uz compinit && compinit
|
|
151
|
+
|
|
152
|
+
_cdoing() {
|
|
153
|
+
local context state line
|
|
154
|
+
typeset -A opt_args
|
|
155
|
+
|
|
156
|
+
_arguments -C \\
|
|
157
|
+
'(-m --model)'{-m,--model}'[Model to use]:model:->models' \\
|
|
158
|
+
'(-p --provider)'{-p,--provider}'[AI provider]:provider:(anthropic openai google ollama custom)' \\
|
|
159
|
+
'--base-url[Base URL for custom providers]:url:' \\
|
|
160
|
+
'--api-key[API key]:key:' \\
|
|
161
|
+
'--mode[Permission mode]:mode:(ask auto-edit auto)' \\
|
|
162
|
+
'(-d --dir)'{-d,--dir}'[Working directory]:directory:_directories' \\
|
|
163
|
+
'--login[Login with Claude via OAuth]' \\
|
|
164
|
+
'--logout[Clear stored OAuth tokens]' \\
|
|
165
|
+
'--print[Print output only]' \\
|
|
166
|
+
'(-r --resume)'{-r,--resume}'[Resume conversation by ID]:id:' \\
|
|
167
|
+
'(-c --continue)'{-c,--continue}'[Continue most recent conversation]' \\
|
|
168
|
+
'--max-turns[Maximum agent turns]:turns:' \\
|
|
169
|
+
'--output-format[Output format]:format:(text json stream-json)' \\
|
|
170
|
+
'--verbose[Enable verbose logging]' \\
|
|
171
|
+
'--system-prompt[Custom system prompt]:prompt:' \\
|
|
172
|
+
'--allowed-tools[Comma-separated allowed tools]:tools:' \\
|
|
173
|
+
'--disallowed-tools[Comma-separated disallowed tools]:tools:' \\
|
|
174
|
+
'(-h --help)'{-h,--help}'[Show help]' \\
|
|
175
|
+
'(-V --version)'{-V,--version}'[Show version]' \\
|
|
176
|
+
'1: :->subcmd' \\
|
|
177
|
+
'*:: :->args'
|
|
178
|
+
|
|
179
|
+
case $state in
|
|
180
|
+
subcmd)
|
|
181
|
+
local -a cmds
|
|
182
|
+
cmds=(
|
|
183
|
+
'config:Manage configuration'
|
|
184
|
+
'init:Initialize project with .cdoing/config.md'
|
|
185
|
+
'doctor:Diagnose setup and configuration'
|
|
186
|
+
'completions:Generate shell completion script'
|
|
187
|
+
)
|
|
188
|
+
_describe 'subcommand' cmds
|
|
189
|
+
;;
|
|
190
|
+
models)
|
|
191
|
+
local -a models
|
|
192
|
+
models=(
|
|
193
|
+
'claude-sonnet-4-6:Anthropic Sonnet 4.6'
|
|
194
|
+
'claude-opus-4-6:Anthropic Opus 4.6'
|
|
195
|
+
'claude-haiku-4-5:Anthropic Haiku 4.5'
|
|
196
|
+
'gpt-4o:OpenAI GPT-4o'
|
|
197
|
+
'gpt-4o-mini:OpenAI GPT-4o Mini'
|
|
198
|
+
'o3-mini:OpenAI o3 Mini'
|
|
199
|
+
'gemini-2.0-flash:Google Gemini 2.0 Flash'
|
|
200
|
+
'gemini-1.5-pro:Google Gemini 1.5 Pro'
|
|
201
|
+
'llama3.1:Ollama LLaMA 3.1'
|
|
202
|
+
'mistral:Ollama Mistral'
|
|
203
|
+
'codellama:Ollama CodeLlama'
|
|
204
|
+
)
|
|
205
|
+
_describe 'model' models
|
|
206
|
+
;;
|
|
207
|
+
args)
|
|
208
|
+
case $words[1] in
|
|
209
|
+
config)
|
|
210
|
+
_arguments \\
|
|
211
|
+
'1:action:(get set list)' \\
|
|
212
|
+
'2:key:(provider model mode api-key base-url)' \\
|
|
213
|
+
'3:value:'
|
|
214
|
+
;;
|
|
215
|
+
completions)
|
|
216
|
+
_arguments '1:shell:(zsh bash)'
|
|
217
|
+
;;
|
|
218
|
+
esac
|
|
219
|
+
;;
|
|
220
|
+
esac
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
_cdoing "$@"
|
|
224
|
+
`;
|
|
225
|
+
|
|
226
|
+
const BASH_COMPLETION = `# Bash completion for cdoing — install with: cdoing completions bash > ~/.bash_completion.d/cdoing
|
|
227
|
+
# Then add to ~/.bashrc: source ~/.bash_completion.d/cdoing
|
|
228
|
+
|
|
229
|
+
_cdoing_completion() {
|
|
230
|
+
local cur prev words cword
|
|
231
|
+
_init_completion 2>/dev/null || {
|
|
232
|
+
COMPREPLY=()
|
|
233
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
234
|
+
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
local subcommands="config init doctor completions"
|
|
238
|
+
local flags="--model --provider --base-url --api-key --mode --dir --login --logout --print --resume --continue --max-turns --output-format --verbose --system-prompt --allowed-tools --disallowed-tools --help --version"
|
|
239
|
+
local models="claude-sonnet-4-6 claude-opus-4-6 claude-haiku-4-5 gpt-4o gpt-4o-mini o3-mini gemini-2.0-flash gemini-1.5-pro llama3.1 mistral codellama"
|
|
240
|
+
|
|
241
|
+
case "\${prev}" in
|
|
242
|
+
--model|-m)
|
|
243
|
+
COMPREPLY=( \$(compgen -W "\${models}" -- "\${cur}") )
|
|
244
|
+
return ;;
|
|
245
|
+
--provider|-p)
|
|
246
|
+
COMPREPLY=( \$(compgen -W "anthropic openai google ollama custom" -- "\${cur}") )
|
|
247
|
+
return ;;
|
|
248
|
+
--mode)
|
|
249
|
+
COMPREPLY=( \$(compgen -W "ask auto-edit auto" -- "\${cur}") )
|
|
250
|
+
return ;;
|
|
251
|
+
--output-format)
|
|
252
|
+
COMPREPLY=( \$(compgen -W "text json stream-json" -- "\${cur}") )
|
|
253
|
+
return ;;
|
|
254
|
+
--dir|-d)
|
|
255
|
+
COMPREPLY=( \$(compgen -d -- "\${cur}") )
|
|
256
|
+
return ;;
|
|
257
|
+
config)
|
|
258
|
+
COMPREPLY=( \$(compgen -W "get set list" -- "\${cur}") )
|
|
259
|
+
return ;;
|
|
260
|
+
get|set)
|
|
261
|
+
COMPREPLY=( \$(compgen -W "provider model mode api-key base-url" -- "\${cur}") )
|
|
262
|
+
return ;;
|
|
263
|
+
completions)
|
|
264
|
+
COMPREPLY=( \$(compgen -W "zsh bash" -- "\${cur}") )
|
|
265
|
+
return ;;
|
|
266
|
+
esac
|
|
267
|
+
|
|
268
|
+
if [[ "\${cur}" == -* ]]; then
|
|
269
|
+
COMPREPLY=( \$(compgen -W "\${flags}" -- "\${cur}") )
|
|
270
|
+
return
|
|
271
|
+
fi
|
|
272
|
+
|
|
273
|
+
if [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
274
|
+
COMPREPLY=( \$(compgen -W "\${subcommands}" -- "\${cur}") )
|
|
275
|
+
return
|
|
276
|
+
fi
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
complete -F _cdoing_completion cdoing
|
|
280
|
+
`;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Handle `cdoing completions <shell>` - print shell completion script
|
|
284
|
+
*/
|
|
285
|
+
export function handleCompletions(shell: string): void {
|
|
286
|
+
const s = (shell || "").toLowerCase();
|
|
287
|
+
|
|
288
|
+
if (s === "zsh") {
|
|
289
|
+
process.stdout.write(ZSH_COMPLETION);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (s === "bash") {
|
|
294
|
+
process.stdout.write(BASH_COMPLETION);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// No shell arg — print install instructions
|
|
299
|
+
console.log();
|
|
300
|
+
console.log(chalk.hex("#4FC3F7").bold(" 🐚 Shell Completions"));
|
|
301
|
+
console.log(chalk.hex("#78909C")(" ─────────────────────────────────────"));
|
|
302
|
+
console.log();
|
|
303
|
+
console.log(chalk.hex("#B0BEC5")(" Usage: cdoing completions <shell>"));
|
|
304
|
+
console.log(chalk.hex("#78909C")(" Shells: zsh bash"));
|
|
305
|
+
console.log();
|
|
306
|
+
console.log(chalk.hex("#FFB74D").bold(" Zsh:"));
|
|
307
|
+
console.log(chalk.hex("#90A4AE")(" mkdir -p ~/.zsh/completions"));
|
|
308
|
+
console.log(chalk.hex("#81C784")(" cdoing completions zsh > ~/.zsh/completions/_cdoing"));
|
|
309
|
+
console.log(chalk.hex("#90A4AE")(" # Add to ~/.zshrc if not already present:"));
|
|
310
|
+
console.log(chalk.hex("#90A4AE")(' echo \'fpath=(~/.zsh/completions $fpath)\' >> ~/.zshrc'));
|
|
311
|
+
console.log(chalk.hex("#90A4AE")(' echo "autoload -Uz compinit && compinit" >> ~/.zshrc'));
|
|
312
|
+
console.log(chalk.hex("#90A4AE")(" source ~/.zshrc"));
|
|
313
|
+
console.log();
|
|
314
|
+
console.log(chalk.hex("#FFB74D").bold(" Bash:"));
|
|
315
|
+
console.log(chalk.hex("#90A4AE")(" mkdir -p ~/.bash_completion.d"));
|
|
316
|
+
console.log(chalk.hex("#81C784")(" cdoing completions bash > ~/.bash_completion.d/cdoing"));
|
|
317
|
+
console.log(chalk.hex("#90A4AE")(' echo "source ~/.bash_completion.d/cdoing" >> ~/.bashrc'));
|
|
318
|
+
console.log(chalk.hex("#90A4AE")(" source ~/.bashrc"));
|
|
319
|
+
console.log();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Handle `cdoing doctor` - diagnose setup and configuration issues
|
|
324
|
+
*/
|
|
325
|
+
export function handleDoctor(): void {
|
|
326
|
+
console.log();
|
|
327
|
+
console.log(chalk.hex("#4FC3F7").bold(" 🏥 System Diagnostics"));
|
|
328
|
+
console.log(chalk.hex("#78909C")(" ─────────────────────────────────────"));
|
|
329
|
+
console.log();
|
|
330
|
+
|
|
331
|
+
let issues = 0;
|
|
332
|
+
let passed = 0;
|
|
333
|
+
|
|
334
|
+
const ok = (msg: string) => {
|
|
335
|
+
passed++;
|
|
336
|
+
console.log(chalk.hex("#81C784")(" ✓ ") + chalk.hex("#B0BEC5")(msg));
|
|
337
|
+
};
|
|
338
|
+
const skip = (msg: string) => {
|
|
339
|
+
console.log(chalk.hex("#78909C")(" ○ ") + chalk.hex("#78909C")(msg));
|
|
340
|
+
};
|
|
341
|
+
const fail = (msg: string) => {
|
|
342
|
+
issues++;
|
|
343
|
+
console.log(chalk.hex("#EF5350")(" ✗ ") + chalk.hex("#FFCDD2")(msg));
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// Check global config directory
|
|
347
|
+
if (fs.existsSync(CONFIG_DIR)) {
|
|
348
|
+
ok("Global config: ~/.cdoing/");
|
|
349
|
+
} else {
|
|
350
|
+
skip("Global config: not created yet");
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Check API keys
|
|
354
|
+
const config = loadConfig();
|
|
355
|
+
const providers = ["anthropic", "openai", "google"];
|
|
356
|
+
const providerIcons: Record<string, string> = {
|
|
357
|
+
anthropic: "🤖",
|
|
358
|
+
openai: "🧠",
|
|
359
|
+
google: "🌐",
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
for (const provider of providers) {
|
|
363
|
+
const envVar = getApiKeyEnvVar(provider);
|
|
364
|
+
const hasEnv = !!process.env[envVar];
|
|
365
|
+
const hasStored = !!config.apiKeys?.[provider];
|
|
366
|
+
const icon = providerIcons[provider] || "🔑";
|
|
367
|
+
|
|
368
|
+
if (hasEnv) {
|
|
369
|
+
ok(`${icon} ${provider}: API key in ${envVar}`);
|
|
370
|
+
} else if (hasStored) {
|
|
371
|
+
ok(`${icon} ${provider}: API key in config`);
|
|
372
|
+
} else {
|
|
373
|
+
skip(`${icon} ${provider}: no API key configured`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Check project config
|
|
378
|
+
const projectConfig = path.join(process.cwd(), PROJECT_CONFIG_DIR, PROJECT_CONFIG_FILE);
|
|
379
|
+
if (fs.existsSync(projectConfig)) {
|
|
380
|
+
ok("📁 Project config: .cdoing/config.md");
|
|
381
|
+
} else {
|
|
382
|
+
skip("📁 Project config: not initialized (run: cdoing init)");
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Check hooks
|
|
386
|
+
const globalHooks = path.join(CONFIG_DIR, "hooks.json");
|
|
387
|
+
const projectHooks = path.join(process.cwd(), PROJECT_CONFIG_DIR, "hooks.json");
|
|
388
|
+
|
|
389
|
+
if (fs.existsSync(globalHooks)) {
|
|
390
|
+
ok("🪝 Global hooks: ~/.cdoing/hooks.json");
|
|
391
|
+
}
|
|
392
|
+
if (fs.existsSync(projectHooks)) {
|
|
393
|
+
ok("🪝 Project hooks: .cdoing/hooks.json");
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Check permissions
|
|
397
|
+
const globalPerms = path.join(CONFIG_DIR, "permissions.json");
|
|
398
|
+
const projectPerms = path.join(process.cwd(), PROJECT_CONFIG_DIR, "permissions.json");
|
|
399
|
+
|
|
400
|
+
if (fs.existsSync(globalPerms)) {
|
|
401
|
+
ok("🔐 Global permissions: ~/.cdoing/permissions.json");
|
|
402
|
+
}
|
|
403
|
+
if (fs.existsSync(projectPerms)) {
|
|
404
|
+
ok("🔐 Project permissions: .cdoing/permissions.json");
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Check Node.js version
|
|
408
|
+
const nodeVersion = process.version;
|
|
409
|
+
const major = parseInt(nodeVersion.slice(1).split(".")[0], 10);
|
|
410
|
+
if (major >= 18) {
|
|
411
|
+
ok(`📦 Node.js: ${nodeVersion}`);
|
|
412
|
+
} else {
|
|
413
|
+
fail(`📦 Node.js: ${nodeVersion} (requires 18+)`);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Summary
|
|
417
|
+
console.log();
|
|
418
|
+
console.log(chalk.hex("#78909C")(" ─────────────────────────────────────"));
|
|
419
|
+
if (issues === 0) {
|
|
420
|
+
console.log(chalk.hex("#81C784").bold(` ✨ All ${passed} checks passed!`));
|
|
421
|
+
} else {
|
|
422
|
+
console.log(chalk.hex("#FFB74D")(` ⚠️ ${passed} passed, ${issues} issue(s) found`));
|
|
423
|
+
}
|
|
424
|
+
console.log();
|
|
425
|
+
}
|