@phi-code-admin/phi-code 0.65.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.
@@ -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
- // Always offer to add a provider via select menu
468
- const providerOptions = [
469
- "Skip (continue with current providers)",
470
- ...providers.map(p => {
471
- const status = p.available ? "✅" : "⬜";
472
- const tag = p.local ? " (local)" : "";
473
- return `${status} ${p.name}${tag}`;
474
- }),
475
- ];
476
- const addProvider = await ctx.ui.select("Add or change a provider?", providerOptions);
477
-
478
- const choiceIdx = providerOptions.indexOf(addProvider ?? "");
479
- if (choiceIdx > 0) { // 0 = Skip
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.", "info");
487
- return;
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 — ask for API key
492
- ctx.ui.notify(`\n🔑 **${chosen.name}**`, "info");
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
- if (!apiKey || apiKey.trim().length < 5) {
500
- ctx.ui.notify("❌ Invalid API key. Skipped.", "error");
501
- } else {
502
- // Save to models.json
503
- let modelsConfig: any = { providers: {} };
504
- try {
505
- const existing = await readFile(modelsJsonPath, "utf-8");
506
- modelsConfig = JSON.parse(existing);
507
- } catch { /* new file */ }
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
- const masked = apiKey.trim().substring(0, 6) + "..." + apiKey.trim().slice(-4);
532
- ctx.ui.notify(`✅ **${chosen.name}** saved (${masked})`, "info");
533
- ctx.ui.notify(` ${chosen.models.length} models configured in \`models.json\``, "info");
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);
@@ -503,6 +503,7 @@ export default function orchestratorExtension(pi: ExtensionAPI) {
503
503
 
504
504
  /**
505
505
  * Load routing config and build phase queue with model assignments + agent definitions.
506
+ * Each phase now reads outputs from previous phases and writes structured outputs.
506
507
  */
507
508
  function buildPhases(description: string): OrchestratorPhase[] {
508
509
  const routingPath = join(homedir(), ".phi", "agent", "routing.json");
@@ -525,31 +526,195 @@ export default function orchestratorExtension(pi: ExtensionAPI) {
525
526
  const test = getModel("test");
526
527
  const review = getModel("review");
527
528
 
529
+ const ts = timestamp();
530
+
528
531
  return [
529
532
  {
530
533
  key: "explore", label: "🔍 Phase 1 — EXPLORE", model: explore.preferred, fallback: explore.fallback,
531
534
  agent: loadAgentDef("explore"),
532
- instruction: `Analyze the project requirements and existing codebase. Identify what exists, what's needed, and any constraints.\n\n**Project:** ${description}\n\nList files, read key ones, check dependencies. Return a structured summary.`,
535
+ instruction: `You are the EXPLORE agent. Analyze the project requirements and existing codebase.
536
+
537
+ **Project Request:** ${description}
538
+
539
+ **Your tasks:**
540
+ 1. List all existing files and read key ones
541
+ 2. Identify tech stack, patterns, and constraints
542
+ 3. Create a STRUCTURED PROJECT BRIEF in \`.phi/plans/brief-${ts}.md\`:
543
+ - Context: what exists now
544
+ - Objective: what needs to be built
545
+ - Requirements: specific features needed
546
+ - Tech decisions: frameworks, patterns to use
547
+ - Constraints: what to NOT break
548
+
549
+ **Step 4:** Write your findings to \`.phi/plans/explore-${ts}.md\`
550
+
551
+ **Format for the project brief:**
552
+ \`\`\`markdown
553
+ ## Project Brief
554
+
555
+ ### Context
556
+ [Analyze what the user is asking for]
557
+
558
+ ### Objective
559
+ [Clear, specific goal]
560
+
561
+ ### Requirements
562
+ [Bullet list of what must be built]
563
+
564
+ ### Tech Decisions
565
+ [Frameworks, patterns, architecture choices]
566
+
567
+ ### Constraints
568
+ - Production-quality code, no placeholders
569
+ - Every function fully implemented
570
+ - Follow existing patterns if codebase exists
571
+ - [Any other specific constraints]
572
+ \`\`\``,
533
573
  },
534
574
  {
535
575
  key: "plan", label: "📐 Phase 2 — PLAN", model: plan.preferred, fallback: plan.fallback,
536
576
  agent: loadAgentDef("plan"),
537
- instruction: `Design the architecture for this project. Define file structure, tech choices, and implementation approach.\n\n**Project:** ${description}\n\nBe specific: list every file to create with its purpose.`,
577
+ instruction: `You are the PLAN agent. Design the architecture and create a detailed task list.
578
+
579
+ **Project Request:** ${description}
580
+
581
+ **Step 1:** Read \`.phi/plans/brief-*.md\` (created by the explore phase)
582
+ **Step 2:** Read \`.phi/plans/explore-*.md\` to understand the codebase analysis
583
+ **Step 3:** Design the architecture based on findings
584
+ **Step 4:** Create a DETAILED TODO LIST in \`.phi/plans/todo-${ts}.md\`:
585
+ For each task:
586
+ - Task number and title
587
+ - Agent assignment (code/test)
588
+ - Files to create/modify
589
+ - Specific implementation details
590
+ - Dependencies on other tasks
591
+
592
+ **Format for the todo list:**
593
+ \`\`\`markdown
594
+ # TODO: Project Tasks
595
+
596
+ ## Task 1: [Task Title] [agent-type]
597
+ - [ ] Specific implementation details
598
+ - [ ] Files to create: path/to/file.ext
599
+ - [ ] Expected behavior
600
+ - Dependencies: None
601
+
602
+ ## Task 2: [Task Title] [agent-type]
603
+ - [ ] Implementation details
604
+ - Dependencies: Task 1
605
+ \`\`\``,
538
606
  },
539
607
  {
540
608
  key: "code", label: "💻 Phase 3 — CODE", model: code.preferred, fallback: code.fallback,
541
609
  agent: loadAgentDef("code"),
542
- instruction: `Implement the COMPLETE project. Create ALL files with production-quality code.\n\n**Project:** ${description}\n\n**Rules:**\n- Create every file needed\n- No placeholders, no TODOs, no stubs\n- Every function must be fully implemented\n- Follow the architecture from the previous planning phase`,
610
+ instruction: `You are the CODE agent. Implement the complete project.
611
+
612
+ **Project Request:** ${description}
613
+
614
+ **Step 1:** Read \`.phi/plans/brief-*.md\` for project context
615
+ **Step 2:** Read \`.phi/plans/todo-*.md\` to get your task list
616
+ **Step 3:** Implement EVERY task from the todo list, in order
617
+ **Step 4:** Write a progress report to \`.phi/plans/progress-${ts}.md\`
618
+
619
+ **Rules:**
620
+ - Create every file listed in the plan
621
+ - No placeholders, no TODOs, no stubs
622
+ - Every function must be fully implemented
623
+ - Follow the architecture from the plan
624
+ - Check off tasks in your progress report as you complete them
625
+
626
+ **Progress report format:**
627
+ \`\`\`markdown
628
+ # Progress Report
629
+
630
+ ## Completed Tasks
631
+ - [x] Task 1: Description - DONE
632
+ - [x] Task 2: Description - DONE
633
+
634
+ ## Files Created
635
+ - path/to/file1.ext - Purpose
636
+ - path/to/file2.ext - Purpose
637
+
638
+ ## Implementation Notes
639
+ [Any important decisions or changes made]
640
+ \`\`\``,
543
641
  },
544
642
  {
545
643
  key: "test", label: "🧪 Phase 4 — TEST", model: test.preferred, fallback: test.fallback,
546
644
  agent: loadAgentDef("test"),
547
- instruction: `Test the implementation. Run the code, check for errors, verify it works.\n\n**Project:** ${description}\n\nFix any errors you find. Ensure the project runs correctly.`,
645
+ instruction: `You are the TEST agent. Verify the implementation.
646
+
647
+ **Project Request:** ${description}
648
+
649
+ **Step 1:** Read \`.phi/plans/todo-*.md\` to know what was planned
650
+ **Step 2:** Read \`.phi/plans/progress-*.md\` to see what was done
651
+ **Step 3:** Run the code, check for errors, test key features
652
+ **Step 4:** Fix any errors you find
653
+ **Step 5:** Write test results to \`.phi/plans/test-${ts}.md\`
654
+
655
+ **Test report format:**
656
+ \`\`\`markdown
657
+ # Test Report
658
+
659
+ ## Tests Executed
660
+ - [ ] Feature 1: Description - PASS/FAIL
661
+ - [ ] Feature 2: Description - PASS/FAIL
662
+
663
+ ## Errors Found & Fixed
664
+ - Error: Description
665
+ - Fix: What was done
666
+
667
+ ## Manual Testing
668
+ - Tested: What was manually verified
669
+ - Result: Pass/Fail with details
670
+
671
+ ## Final Status
672
+ ✅ All tests pass / ❌ Issues remain
673
+ \`\`\``,
548
674
  },
549
675
  {
550
676
  key: "review", label: "🔍 Phase 5 — REVIEW", model: review.preferred, fallback: review.fallback,
551
677
  agent: loadAgentDef("review"),
552
- instruction: `Review the code quality, security, and performance. Fix any issues.\n\n**Project:** ${description}\n\nCheck: error handling, edge cases, code style, documentation.`,
678
+ instruction: `You are the REVIEW agent. Final quality review.
679
+
680
+ **Project Request:** ${description}
681
+
682
+ **Step 1:** Read all \`.phi/plans/*.md\` files
683
+ **Step 2:** Review code quality, security, performance
684
+ **Step 3:** Fix any issues found
685
+ **Step 4:** Write final report to \`.phi/plans/review-${ts}.md\`
686
+
687
+ **Review checklist:**
688
+ - Code quality: naming, structure, readability
689
+ - Security: input validation, error handling
690
+ - Performance: efficiency, resource usage
691
+ - Documentation: comments, README if needed
692
+ - Completeness: all requirements met
693
+
694
+ **Final report format:**
695
+ \`\`\`markdown
696
+ # Final Review
697
+
698
+ ## Code Quality ✅/❌
699
+ - Structure: Good/Needs work
700
+ - Naming: Clear/Unclear
701
+ - Comments: Adequate/Missing
702
+
703
+ ## Security ✅/❌
704
+ - Input validation: Present/Missing
705
+ - Error handling: Robust/Weak
706
+
707
+ ## Performance ✅/❌
708
+ - Efficiency: Good/Could improve
709
+ - Resource usage: Optimal/Excessive
710
+
711
+ ## Completeness ✅/❌
712
+ - All requirements met: Yes/No
713
+ - All files created: Yes/No
714
+
715
+ ## Final Verdict
716
+ ✅ Project ready for production / ❌ Issues need resolution
717
+ \`\`\``,
553
718
  },
554
719
  ];
555
720
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phi-code-admin/phi-code",
3
- "version": "0.65.0",
3
+ "version": "0.66.1",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {