archbyte 0.2.7 → 0.2.9
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 +2 -2
- package/dist/cli/setup.js +85 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ archbyte login
|
|
|
14
14
|
# Configure your AI provider (BYOK)
|
|
15
15
|
archbyte init
|
|
16
16
|
|
|
17
|
-
#
|
|
17
|
+
# Using Claude Code / Codex? Install the MCP server too:
|
|
18
18
|
archbyte mcp install
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -22,7 +22,7 @@ Your API keys stay on your machine. ArchByte never stores or transmits your prov
|
|
|
22
22
|
|
|
23
23
|
### Setup with Claude Code
|
|
24
24
|
|
|
25
|
-
**Option A: MCP
|
|
25
|
+
**Option A: MCP** — use ArchByte tools directly in Claude Code. You still need to sign in and configure a provider first:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
28
|
archbyte mcp install
|
package/dist/cli/setup.js
CHANGED
|
@@ -11,7 +11,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
11
11
|
const __dirname = path.dirname(__filename);
|
|
12
12
|
const PROVIDERS = [
|
|
13
13
|
{ name: "anthropic", label: "Anthropic", hint: "Claude Sonnet / Opus" },
|
|
14
|
-
{ name: "openai", label: "OpenAI", hint: "
|
|
14
|
+
{ name: "openai", label: "OpenAI", hint: "GPT-5.2 / o4-mini" },
|
|
15
15
|
{ name: "google", label: "Google", hint: "Gemini Flash / Pro" },
|
|
16
16
|
];
|
|
17
17
|
const PROVIDER_MODELS = {
|
|
@@ -22,10 +22,9 @@ const PROVIDER_MODELS = {
|
|
|
22
22
|
{ id: "claude-opus-4-6", label: "Claude Opus 4.6", hint: "Most capable" },
|
|
23
23
|
],
|
|
24
24
|
openai: [
|
|
25
|
-
{ id: "", label: "Default (recommended)", hint: "
|
|
26
|
-
{ id: "gpt-5.2
|
|
27
|
-
{ id: "
|
|
28
|
-
{ id: "o3", label: "o3", hint: "Reasoning model" },
|
|
25
|
+
{ id: "", label: "Default (recommended)", hint: "GPT-5.2 for all agents" },
|
|
26
|
+
{ id: "gpt-5.2", label: "GPT-5.2", hint: "Latest flagship model" },
|
|
27
|
+
{ id: "o4-mini", label: "o4-mini", hint: "Fast reasoning model" },
|
|
29
28
|
],
|
|
30
29
|
google: [
|
|
31
30
|
{ id: "", label: "Default (recommended)", hint: "Flash for fast agents, Pro for connections" },
|
|
@@ -93,10 +92,47 @@ function askHidden(prompt) {
|
|
|
93
92
|
stdin.on("data", onData);
|
|
94
93
|
});
|
|
95
94
|
}
|
|
96
|
-
|
|
95
|
+
function askText(prompt) {
|
|
96
|
+
return new Promise((resolve) => {
|
|
97
|
+
process.stdout.write(prompt);
|
|
98
|
+
const stdin = process.stdin;
|
|
99
|
+
const wasRaw = stdin.isRaw;
|
|
100
|
+
stdin.setRawMode(true);
|
|
101
|
+
stdin.resume();
|
|
102
|
+
stdin.setEncoding("utf8");
|
|
103
|
+
let input = "";
|
|
104
|
+
const onData = (data) => {
|
|
105
|
+
for (const ch of data) {
|
|
106
|
+
if (ch === "\n" || ch === "\r" || ch === "\u0004") {
|
|
107
|
+
stdin.setRawMode(wasRaw ?? false);
|
|
108
|
+
stdin.pause();
|
|
109
|
+
stdin.removeListener("data", onData);
|
|
110
|
+
process.stdout.write("\n");
|
|
111
|
+
resolve(input);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
else if (ch === "\u0003") {
|
|
115
|
+
process.stdout.write("\n");
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
else if (ch === "\u007F" || ch === "\b") {
|
|
119
|
+
if (input.length > 0) {
|
|
120
|
+
input = input.slice(0, -1);
|
|
121
|
+
process.stdout.write("\b \b");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
input += ch;
|
|
126
|
+
process.stdout.write(ch);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
stdin.on("data", onData);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async function validateProviderSilent(providerName, apiKey, model) {
|
|
97
134
|
try {
|
|
98
135
|
const provider = createProvider({ provider: providerName, apiKey });
|
|
99
|
-
const model = resolveModel(providerName, "fast");
|
|
100
136
|
await provider.chat({
|
|
101
137
|
model,
|
|
102
138
|
system: "Reply with 'ok'.",
|
|
@@ -105,7 +141,11 @@ async function validateProviderSilent(providerName, apiKey) {
|
|
|
105
141
|
});
|
|
106
142
|
return true;
|
|
107
143
|
}
|
|
108
|
-
catch {
|
|
144
|
+
catch (err) {
|
|
145
|
+
if (process.env.ARCHBYTE_DEBUG) {
|
|
146
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
147
|
+
console.log(chalk.red(`\n Validation error: ${msg}`));
|
|
148
|
+
}
|
|
109
149
|
return false;
|
|
110
150
|
}
|
|
111
151
|
}
|
|
@@ -132,26 +172,7 @@ export async function handleSetup() {
|
|
|
132
172
|
if (hasClaude || hasCodex) {
|
|
133
173
|
const tools = [hasClaude && "Claude Code", hasCodex && "Codex CLI"].filter(Boolean).join(" and ");
|
|
134
174
|
console.log(chalk.cyan(` Detected ${tools} on this machine.`));
|
|
135
|
-
console.log(chalk.white(`
|
|
136
|
-
console.log(chalk.white(` Your AI tool already provides the model, so you skip the BYOK step.`));
|
|
137
|
-
console.log();
|
|
138
|
-
console.log(chalk.white(` Run: `) + chalk.bold.cyan(`archbyte mcp install`));
|
|
139
|
-
console.log();
|
|
140
|
-
const continueIdx = await select("Continue with BYOK setup anyway?", [
|
|
141
|
-
`Skip ${chalk.gray("(use MCP instead, recommended)")}`,
|
|
142
|
-
`Continue ${chalk.gray("(set up your own API key)")}`,
|
|
143
|
-
]);
|
|
144
|
-
if (continueIdx === 0) {
|
|
145
|
-
console.log();
|
|
146
|
-
console.log(chalk.gray(" Run `archbyte mcp install` to configure MCP for your AI tool."));
|
|
147
|
-
console.log();
|
|
148
|
-
console.log(chalk.gray(" Then open your AI tool and try:"));
|
|
149
|
-
console.log(chalk.cyan(' "Analyze the architecture of this project"'));
|
|
150
|
-
console.log(chalk.cyan(' "Export the architecture as a Mermaid diagram"'));
|
|
151
|
-
console.log(chalk.cyan(' "Show me the architecture stats"'));
|
|
152
|
-
console.log();
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
175
|
+
console.log(chalk.white(` After setup, run `) + chalk.bold.cyan(`archbyte mcp install`) + chalk.white(` to use ArchByte from your AI tool.`));
|
|
155
176
|
console.log();
|
|
156
177
|
}
|
|
157
178
|
const config = loadConfig();
|
|
@@ -182,7 +203,8 @@ export async function handleSetup() {
|
|
|
182
203
|
for (const p of configured) {
|
|
183
204
|
const active = p === config.provider ? chalk.green(" (active)") : "";
|
|
184
205
|
const model = profiles[p].model ? chalk.gray(` model: ${profiles[p].model}`) : "";
|
|
185
|
-
|
|
206
|
+
const email = profiles[p].email ? chalk.gray(` (${profiles[p].email})`) : "";
|
|
207
|
+
console.log(chalk.gray(` ${p}: ${maskKey(profiles[p].apiKey)}${email}${model}${active}`));
|
|
186
208
|
}
|
|
187
209
|
console.log();
|
|
188
210
|
}
|
|
@@ -232,6 +254,30 @@ export async function handleSetup() {
|
|
|
232
254
|
if (!profiles[provider])
|
|
233
255
|
profiles[provider] = { apiKey: "" };
|
|
234
256
|
profiles[provider].apiKey = apiKey;
|
|
257
|
+
// Step 2b: Email for this provider account (optional)
|
|
258
|
+
const existingEmail = profiles[provider].email;
|
|
259
|
+
if (existingEmail) {
|
|
260
|
+
console.log(chalk.gray(`\n Account email: ${existingEmail}`));
|
|
261
|
+
const emailIdx = await select(" Update email?", [
|
|
262
|
+
`Keep existing ${chalk.gray("(" + existingEmail + ")")}`,
|
|
263
|
+
"Enter new email",
|
|
264
|
+
"Skip",
|
|
265
|
+
]);
|
|
266
|
+
if (emailIdx === 1) {
|
|
267
|
+
const newEmail = await askText(chalk.bold(" Email: "));
|
|
268
|
+
if (newEmail) {
|
|
269
|
+
profiles[provider].email = newEmail;
|
|
270
|
+
console.log(chalk.green(` ✓ Email: ${newEmail}`));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
const email = await askText(chalk.bold(` ${selected.label} account email ${chalk.gray("(optional, Enter to skip)")}: `));
|
|
276
|
+
if (email) {
|
|
277
|
+
profiles[provider].email = email;
|
|
278
|
+
console.log(chalk.green(` ✓ Email: ${email}`));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
235
281
|
// Step 3: Model selection
|
|
236
282
|
const models = PROVIDER_MODELS[provider];
|
|
237
283
|
if (models) {
|
|
@@ -251,9 +297,11 @@ export async function handleSetup() {
|
|
|
251
297
|
}
|
|
252
298
|
}
|
|
253
299
|
config.profiles = profiles;
|
|
300
|
+
// Validate with the model the user actually chose
|
|
301
|
+
const validationModel = profiles[provider].model ?? resolveModel(provider, "fast");
|
|
254
302
|
// Validate provider with spinner
|
|
255
|
-
const s = spinner(
|
|
256
|
-
let isValid = await validateProviderSilent(provider, apiKey);
|
|
303
|
+
const s = spinner(`Validating credentials with ${validationModel}`);
|
|
304
|
+
let isValid = await validateProviderSilent(provider, apiKey, validationModel);
|
|
257
305
|
s.stop(isValid ? "valid" : "invalid", isValid ? "green" : "red");
|
|
258
306
|
// Retry loop on failure
|
|
259
307
|
if (!isValid) {
|
|
@@ -267,8 +315,8 @@ export async function handleSetup() {
|
|
|
267
315
|
profiles[provider].apiKey = newKey;
|
|
268
316
|
console.log(chalk.green(` ✓ API key: ${maskKey(newKey)}`));
|
|
269
317
|
}
|
|
270
|
-
const s2 = spinner(
|
|
271
|
-
isValid = await validateProviderSilent(provider, profiles[provider].apiKey);
|
|
318
|
+
const s2 = spinner(`Validating credentials with ${validationModel}`);
|
|
319
|
+
isValid = await validateProviderSilent(provider, profiles[provider].apiKey, validationModel);
|
|
272
320
|
s2.stop(isValid ? "valid" : "invalid", isValid ? "green" : "red");
|
|
273
321
|
}
|
|
274
322
|
if (!isValid) {
|
|
@@ -319,6 +367,10 @@ export async function handleSetup() {
|
|
|
319
367
|
console.log();
|
|
320
368
|
console.log(chalk.bold(" Next: ") + chalk.cyan("archbyte run") + chalk.bold(" to analyze your codebase."));
|
|
321
369
|
console.log(chalk.gray(" Run from your project root, or use ") + chalk.cyan("archbyte run -d /path/to/project"));
|
|
370
|
+
if (hasClaude || hasCodex) {
|
|
371
|
+
console.log();
|
|
372
|
+
console.log(chalk.bold(" MCP: ") + chalk.cyan("archbyte mcp install") + chalk.bold(" to use ArchByte from your AI tool."));
|
|
373
|
+
}
|
|
322
374
|
console.log();
|
|
323
375
|
}
|
|
324
376
|
function writeArchbyteReadme(archbyteDir) {
|