@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.
- package/extensions/phi/init.ts +88 -57
- package/extensions/phi/orchestrator.ts +170 -5
- 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);
|
|
@@ -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.
|
|
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: `
|
|
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: `
|
|
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: `
|
|
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: `
|
|
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
|
}
|