@phi-code-admin/phi-code 0.66.0 → 0.66.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/extensions/phi/init.ts +88 -57
- package/package.json +1 -1
package/extensions/phi/init.ts
CHANGED
|
@@ -464,76 +464,107 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
464
464
|
|
|
465
465
|
// No warning needed — the wizard itself handles configuration
|
|
466
466
|
|
|
467
|
-
//
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
467
|
+
// Provider configuration loop — add as many providers as needed
|
|
468
|
+
let addingProviders = true;
|
|
469
|
+
while (addingProviders) {
|
|
470
|
+
const providerOptions = [
|
|
471
|
+
"Done — continue with current providers",
|
|
472
|
+
...providers.map(p => {
|
|
473
|
+
const status = p.available ? "✅" : "⬜";
|
|
474
|
+
const tag = p.local ? " (local)" : "";
|
|
475
|
+
const modelCount = p.available ? ` (${p.models.length} models)` : "";
|
|
476
|
+
return `${status} ${p.name}${tag}${modelCount}`;
|
|
477
|
+
}),
|
|
478
|
+
];
|
|
479
|
+
const addProvider = await ctx.ui.select("Configure a provider (add multiple!):", providerOptions);
|
|
480
|
+
|
|
481
|
+
const choiceIdx = providerOptions.indexOf(addProvider ?? "");
|
|
482
|
+
if (choiceIdx <= 0) { // 0 = Done, or cancelled
|
|
483
|
+
addingProviders = false;
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
|
|
480
487
|
const chosen = providers[choiceIdx - 1];
|
|
481
488
|
|
|
482
489
|
if (chosen.local) {
|
|
483
490
|
const port = chosen.name === "Ollama" ? 11434 : 1234;
|
|
484
491
|
if (!chosen.available) {
|
|
485
492
|
ctx.ui.notify(`\n💡 **${chosen.name}** — make sure it's running on port ${port}.`, "info");
|
|
486
|
-
ctx.ui.notify("Then restart phi and run `/phi-init` again
|
|
487
|
-
|
|
493
|
+
ctx.ui.notify("Then restart phi and run `/phi-init` again.\n", "info");
|
|
494
|
+
} else {
|
|
495
|
+
ctx.ui.notify(`\n✅ **${chosen.name}** is running with ${chosen.models.length} model(s).\n`, "info");
|
|
488
496
|
}
|
|
489
|
-
ctx.ui.notify(`\n✅ **${chosen.name}** is running with ${chosen.models.length} model(s).`, "info");
|
|
490
497
|
} else {
|
|
491
|
-
// Cloud provider —
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
const apiKey = await ctx.ui.input(
|
|
495
|
-
`Enter your ${chosen.name} API key`,
|
|
496
|
-
"Paste your key here"
|
|
498
|
+
// Cloud provider — choose auth method
|
|
499
|
+
const supportsOAuth = ["openai", "anthropic", "google"].includes(
|
|
500
|
+
chosen.name.toLowerCase().split(" ")[0]
|
|
497
501
|
);
|
|
498
502
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
const providerId = chosen.name.toLowerCase().replace(/\s+/g, "-");
|
|
510
|
-
modelsConfig.providers[providerId] = {
|
|
511
|
-
baseUrl: chosen.baseUrl,
|
|
512
|
-
api: "openai-completions",
|
|
513
|
-
apiKey: apiKey.trim(),
|
|
514
|
-
models: await Promise.all(chosen.models.map(async (id: string) => {
|
|
515
|
-
const spec = await getModelSpec(id);
|
|
516
|
-
return {
|
|
517
|
-
id,
|
|
518
|
-
name: id,
|
|
519
|
-
reasoning: spec.reasoning,
|
|
520
|
-
input: ["text"],
|
|
521
|
-
contextWindow: spec.contextWindow,
|
|
522
|
-
maxTokens: spec.maxTokens,
|
|
523
|
-
};
|
|
524
|
-
})),
|
|
525
|
-
};
|
|
526
|
-
|
|
527
|
-
await writeFile(modelsJsonPath, JSON.stringify(modelsConfig, null, 2), "utf-8");
|
|
528
|
-
process.env[chosen.envVar] = apiKey.trim();
|
|
529
|
-
chosen.available = true;
|
|
503
|
+
let authMethod = "api-key";
|
|
504
|
+
if (supportsOAuth) {
|
|
505
|
+
const authChoice = await ctx.ui.select(
|
|
506
|
+
`How to authenticate with ${chosen.name}?`,
|
|
507
|
+
["API Key (paste your key)", "OAuth (browser login via /login)"]
|
|
508
|
+
);
|
|
509
|
+
if (authChoice?.includes("OAuth")) {
|
|
510
|
+
authMethod = "oauth";
|
|
511
|
+
}
|
|
512
|
+
}
|
|
530
513
|
|
|
531
|
-
|
|
532
|
-
ctx.ui.notify(
|
|
533
|
-
ctx.ui.notify(
|
|
514
|
+
if (authMethod === "oauth") {
|
|
515
|
+
ctx.ui.notify(`\n🔐 **${chosen.name}** — Use \`/login\` after setup to authenticate via OAuth.`, "info");
|
|
516
|
+
ctx.ui.notify("OAuth opens a browser window for secure login.\n", "info");
|
|
517
|
+
// Mark as available for model assignment (auth will be done via /login)
|
|
518
|
+
chosen.available = true;
|
|
519
|
+
} else {
|
|
520
|
+
// API Key method
|
|
521
|
+
ctx.ui.notify(`\n🔑 **${chosen.name}**`, "info");
|
|
522
|
+
|
|
523
|
+
const apiKey = await ctx.ui.input(
|
|
524
|
+
`Enter your ${chosen.name} API key`,
|
|
525
|
+
"Paste your key here"
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
if (!apiKey || apiKey.trim().length < 5) {
|
|
529
|
+
ctx.ui.notify("❌ Invalid API key. Skipped.\n", "error");
|
|
530
|
+
} else {
|
|
531
|
+
// Save to models.json (merges with existing)
|
|
532
|
+
let modelsConfig: any = { providers: {} };
|
|
533
|
+
try {
|
|
534
|
+
const existing = await readFile(modelsJsonPath, "utf-8");
|
|
535
|
+
modelsConfig = JSON.parse(existing);
|
|
536
|
+
if (!modelsConfig.providers) modelsConfig.providers = {};
|
|
537
|
+
} catch { /* new file */ }
|
|
538
|
+
|
|
539
|
+
const providerId = chosen.name.toLowerCase().replace(/\s+/g, "-");
|
|
540
|
+
modelsConfig.providers[providerId] = {
|
|
541
|
+
baseUrl: chosen.baseUrl,
|
|
542
|
+
api: "openai-completions",
|
|
543
|
+
apiKey: apiKey.trim(),
|
|
544
|
+
models: await Promise.all(chosen.models.map(async (id: string) => {
|
|
545
|
+
const spec = await getModelSpec(id);
|
|
546
|
+
return {
|
|
547
|
+
id,
|
|
548
|
+
name: id,
|
|
549
|
+
reasoning: spec.reasoning,
|
|
550
|
+
input: ["text"],
|
|
551
|
+
contextWindow: spec.contextWindow,
|
|
552
|
+
maxTokens: spec.maxTokens,
|
|
553
|
+
};
|
|
554
|
+
})),
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
await writeFile(modelsJsonPath, JSON.stringify(modelsConfig, null, 2), "utf-8");
|
|
558
|
+
process.env[chosen.envVar] = apiKey.trim();
|
|
559
|
+
chosen.available = true;
|
|
560
|
+
|
|
561
|
+
const masked = apiKey.trim().substring(0, 6) + "..." + apiKey.trim().slice(-4);
|
|
562
|
+
ctx.ui.notify(`✅ **${chosen.name}** configured (${masked})`, "info");
|
|
563
|
+
ctx.ui.notify(` ${chosen.models.length} models added to \`models.json\`\n`, "info");
|
|
564
|
+
}
|
|
534
565
|
}
|
|
535
566
|
}
|
|
536
|
-
}
|
|
567
|
+
} // end while (addingProviders)
|
|
537
568
|
|
|
538
569
|
// Re-check available after potential additions
|
|
539
570
|
available = providers.filter(p => p.available);
|