@phi-code-admin/phi-code 0.96.1 → 0.97.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.
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * Setup Wizard Extension (/setup) - Refonte UX du wizard de configuration.
3
3
  *
4
- * Per Q8 strategy B: nouvelle commande /setup qui remplace /phi-init
5
- * (gardé en alias rétrocompat dans init.ts). UX:
4
+ * Per Q8 strategy B: nouvelle commande /setup qui remplace /phi-init.
5
+ * Depuis 0.97.0 c'est LE seul wizard : /phi-init (init.ts) importe
6
+ * runSetupWizard d'ici au lieu d'entretenir sa propre copie, et le catalogue
7
+ * de providers vit dans providers/catalog.ts (partagé avec /benchmark). UX:
6
8
  * - Panneau de statut persistant via setWidget (providers + assignments)
7
9
  * - Fuzzy search via ctx.ui.select (matching builtin Phi/upstream)
8
10
  * - Ping API immédiat à la saisie de clé (validation 401/200)
@@ -25,39 +27,25 @@ import { join } from "node:path";
25
27
  import { ApiKeyStore, type ExtensionAPI, type ExtensionUIContext, getApiKeyStore, getConfigWatcher } from "phi-code";
26
28
  import {
27
29
  ALIBABA_ENV_VAR,
28
- ALIBABA_MODELS,
29
30
  ALIBABA_PROVIDERS,
30
31
  ALIBABA_RATE_LIMITS,
31
32
  buildAlibabaProviderConfig,
32
33
  pingAlibaba,
33
34
  validateAlibabaApiKey,
34
35
  } from "./providers/alibaba.js";
36
+ import { getProviderCatalog, type ProviderCatalogEntry } from "./providers/catalog.js";
35
37
  import { fetchLiveModels, pingProvider, toPersistedModel } from "./providers/live-models.js";
36
38
  import {
37
39
  buildOpenCodeGoAnthropicProviderConfig,
38
40
  buildOpenCodeGoProviderConfig,
39
41
  getOpenCodeGoModels,
40
42
  OPENCODE_GO_AUTH_URL,
41
- OPENCODE_GO_ENV_VAR,
42
43
  pingOpenCodeGo,
43
44
  validateOpenCodeGoApiKey,
44
45
  } from "./providers/opencode-go.js";
45
46
 
46
47
  // ─── Types ───────────────────────────────────────────────────────────────
47
48
 
48
- interface ProviderEntry {
49
- id: string;
50
- displayName: string;
51
- envVar: string;
52
- baseUrl: string;
53
- api: string;
54
- staticModels: string[];
55
- supportsOAuth?: boolean;
56
- local?: boolean;
57
- probeUrl?: string;
58
- docUrl?: string;
59
- }
60
-
61
49
  interface RouteAssignment {
62
50
  preferred: string;
63
51
  fallback: string;
@@ -77,7 +65,7 @@ interface RoutingConfigOut {
77
65
  default: { model: string; agent: string | null };
78
66
  }
79
67
 
80
- const ORCHESTRATION_ROLES = [
68
+ export const ORCHESTRATION_ROLES = [
81
69
  {
82
70
  key: "explore",
83
71
  label: "Explore",
@@ -117,106 +105,11 @@ const ORCHESTRATION_ROLES = [
117
105
 
118
106
  const DEBUG_KEYWORDS = ["fix", "bug", "error", "debug", "crash", "broken", "failing", "issue", "troubleshoot"];
119
107
 
120
- // ─── Provider catalog ────────────────────────────────────────────────────
121
-
122
- function getProviderCatalog(): ProviderEntry[] {
123
- return [
124
- {
125
- id: "alibaba-codingplan",
126
- displayName: "Alibaba Coding Plan",
127
- envVar: ALIBABA_ENV_VAR,
128
- baseUrl: ALIBABA_PROVIDERS.openai.baseUrl,
129
- api: "openai-completions",
130
- staticModels: ALIBABA_MODELS.map((m) => m.id),
131
- docUrl: "https://www.alibabacloud.com/help/en/model-studio/coding-plan",
132
- },
133
- {
134
- id: "opencode-go",
135
- displayName: "OpenCode Go (zen)",
136
- envVar: OPENCODE_GO_ENV_VAR,
137
- baseUrl: "https://opencode.ai/zen/go/v1",
138
- api: "openai-completions",
139
- staticModels: [],
140
- docUrl: OPENCODE_GO_AUTH_URL,
141
- },
142
- {
143
- id: "opencode",
144
- displayName: "OpenCode Zen",
145
- envVar: "OPENCODE_API_KEY",
146
- baseUrl: "https://opencode.ai/zen/v1",
147
- api: "openai-completions",
148
- staticModels: [],
149
- docUrl: OPENCODE_GO_AUTH_URL,
150
- },
151
- {
152
- id: "openai",
153
- displayName: "OpenAI",
154
- envVar: "OPENAI_API_KEY",
155
- baseUrl: "https://api.openai.com/v1",
156
- api: "openai-completions",
157
- staticModels: ["gpt-4o", "gpt-4o-mini", "o1", "o3-mini", "gpt-5"],
158
- supportsOAuth: true,
159
- },
160
- {
161
- id: "anthropic",
162
- displayName: "Anthropic",
163
- envVar: "ANTHROPIC_API_KEY",
164
- baseUrl: "https://api.anthropic.com/v1",
165
- api: "anthropic-messages",
166
- staticModels: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-3-5-haiku-20241022"],
167
- supportsOAuth: true,
168
- },
169
- {
170
- id: "google",
171
- displayName: "Google Gemini",
172
- envVar: "GOOGLE_API_KEY",
173
- baseUrl: "https://generativelanguage.googleapis.com/v1beta",
174
- api: "google",
175
- staticModels: ["gemini-2.5-pro", "gemini-2.5-flash"],
176
- supportsOAuth: true,
177
- },
178
- {
179
- id: "openrouter",
180
- displayName: "OpenRouter",
181
- envVar: "OPENROUTER_API_KEY",
182
- baseUrl: "https://openrouter.ai/api/v1",
183
- api: "openai-completions",
184
- staticModels: [],
185
- },
186
- {
187
- id: "groq",
188
- displayName: "Groq",
189
- envVar: "GROQ_API_KEY",
190
- baseUrl: "https://api.groq.com/openai/v1",
191
- api: "openai-completions",
192
- staticModels: ["llama-3.3-70b-versatile", "openai/gpt-oss-120b"],
193
- },
194
- {
195
- id: "ollama",
196
- displayName: "Ollama (local)",
197
- envVar: "OLLAMA",
198
- baseUrl: "http://localhost:11434/v1",
199
- api: "openai-completions",
200
- staticModels: [],
201
- local: true,
202
- probeUrl: "http://localhost:11434/v1/models",
203
- },
204
- {
205
- id: "lm-studio",
206
- displayName: "LM Studio (local)",
207
- envVar: "LM_STUDIO",
208
- baseUrl: "http://localhost:1234/v1",
209
- api: "openai-completions",
210
- staticModels: [],
211
- local: true,
212
- probeUrl: "http://localhost:1234/v1/models",
213
- },
214
- ];
215
- }
216
-
217
108
  // ─── Helpers ─────────────────────────────────────────────────────────────
109
+ // The provider catalog itself lives in providers/catalog.ts (shared with
110
+ // /phi-init and /benchmark).
218
111
 
219
- async function probeLocalProvider(provider: ProviderEntry): Promise<string[]> {
112
+ async function probeLocalProvider(provider: ProviderCatalogEntry): Promise<string[]> {
220
113
  if (!provider.local) return [];
221
114
  const result = await fetchLiveModels(provider.id, { forceRefresh: true, timeoutMs: 2_500 });
222
115
  return result.source === "live" ? result.models.map((m) => m.id) : [];
@@ -256,7 +149,10 @@ function maskKeyForDisplay(key: string | undefined): string {
256
149
  return ApiKeyStore.maskKey(key);
257
150
  }
258
151
 
259
- function buildRoutingConfig(defaultModel: string, orchestration: Record<string, RouteAssignment>): RoutingConfigOut {
152
+ export function buildRoutingConfig(
153
+ defaultModel: string,
154
+ orchestration: Record<string, RouteAssignment>,
155
+ ): RoutingConfigOut {
260
156
  const routes: RoutingConfigOut["routes"] = {};
261
157
  for (const role of ORCHESTRATION_ROLES) {
262
158
  const a = orchestration[role.key] ?? { preferred: defaultModel, fallback: defaultModel };
@@ -281,7 +177,7 @@ function buildRoutingConfig(defaultModel: string, orchestration: Record<string,
281
177
  };
282
178
  }
283
179
 
284
- async function writeRoutingConfig(routing: RoutingConfigOut): Promise<string> {
180
+ export async function writeRoutingConfig(routing: RoutingConfigOut): Promise<string> {
285
181
  const dir = join(homedir(), ".phi", "agent");
286
182
  await mkdir(dir, { recursive: true });
287
183
  const path = join(dir, "routing.json");
@@ -448,7 +344,7 @@ async function configureOpenCodeGo(
448
344
  async function configureGenericCloud(
449
345
  ui: ExtensionUIContext,
450
346
  store: ApiKeyStore,
451
- provider: ProviderEntry,
347
+ provider: ProviderCatalogEntry,
452
348
  ): Promise<{ providerId: string; modelCount: number } | undefined> {
453
349
  if (provider.supportsOAuth) {
454
350
  const authChoice = await ui.select(`Auth method for ${provider.displayName}`, [
@@ -538,7 +434,7 @@ async function configureGenericCloud(
538
434
  async function configureLocal(
539
435
  ui: ExtensionUIContext,
540
436
  store: ApiKeyStore,
541
- provider: ProviderEntry,
437
+ provider: ProviderCatalogEntry,
542
438
  ): Promise<{ providerId: string; modelCount: number } | undefined> {
543
439
  ui.setStatus("setup-probe", `Probing ${provider.displayName}...`);
544
440
  const models = await probeLocalProvider(provider);
@@ -586,7 +482,7 @@ async function pickModelFromCatalog(
586
482
  return models.find((m) => m.display === choice)?.ref;
587
483
  }
588
484
 
589
- async function configureAssignments(
485
+ export async function configureAssignments(
590
486
  ui: ExtensionUIContext,
591
487
  models: Array<{ ref: string; display: string }>,
592
488
  ): Promise<{ defaultModel: string; orchestration: Record<string, RouteAssignment> }> {
@@ -639,180 +535,184 @@ function installSetupUnhandledRejectionGuard(): void {
639
535
  });
640
536
  }
641
537
 
642
- export default function setupExtension(pi: ExtensionAPI) {
643
- installSetupUnhandledRejectionGuard();
644
- pi.registerCommand("setup", {
645
- description: "Phi Code setup wizard (refonte UX, replaces /phi-init)",
646
- handler: async (_args, ctx) => {
647
- const ui = ctx.ui;
648
- const store = getApiKeyStore();
649
- try {
650
- store.load();
651
- } catch {
652
- // empty file or missing, fine
653
- }
538
+ /**
539
+ * The full setup wizard flow. Exported so /phi-init (init.ts) delegates to the
540
+ * exact same wizard instead of maintaining a drifting second copy.
541
+ */
542
+ export async function runSetupWizard(ui: ExtensionUIContext): Promise<void> {
543
+ const store = getApiKeyStore();
544
+ try {
545
+ store.load();
546
+ } catch {
547
+ // empty file or missing, fine
548
+ }
654
549
 
655
- try {
656
- ui.notify(
657
- "**φ Phi Code Setup Wizard**\n\n" +
658
- "This wizard configures providers and assigns models to **orchestration roles** " +
659
- "(used by `/plan`).\n" +
660
- "The **chat default model is controlled via `/model`** and stays sticky across " +
661
- "prompts — this wizard will never change it.\n\n" +
662
- "Keys are stored in `~/.phi/agent/models.json` (chmod 0600 on Unix). " +
663
- "Edit that file directly later to hot-reload (no restart needed).",
664
- "info",
665
- );
550
+ try {
551
+ ui.notify(
552
+ "**φ Phi Code Setup Wizard**\n\n" +
553
+ "This wizard configures providers and assigns models to **orchestration roles** " +
554
+ "(used by `/plan`).\n" +
555
+ "The **chat default model is controlled via `/model`** and stays sticky across " +
556
+ "prompts — this wizard will never change it.\n\n" +
557
+ "Keys are stored in `~/.phi/agent/models.json` (chmod 0600 on Unix). " +
558
+ "Edit that file directly later to hot-reload (no restart needed).",
559
+ "info",
560
+ );
666
561
 
667
- const available = new Map<string, { source: "key" | "env" | "local"; modelCount: number }>();
668
- const assignments: { default?: string; orchestration: Record<string, RouteAssignment> } = {
669
- orchestration: {},
670
- };
671
-
672
- const refreshAvailable = (): void => {
673
- const catalog = getProviderCatalog();
674
- available.clear();
675
- for (const p of catalog) {
676
- const stored = store.getProvider(p.id);
677
- if (stored?.apiKey) {
678
- const source = stored.apiKey === "$OAUTH" ? "key" : stored.apiKey === "local" ? "local" : "key";
679
- const modelCount = Array.isArray(stored.models) ? stored.models.length : p.staticModels.length;
680
- available.set(p.id, { source, modelCount });
681
- continue;
682
- }
683
- if (!p.local && process.env[p.envVar]) {
684
- available.set(p.id, { source: "env", modelCount: p.staticModels.length });
685
- }
686
- }
687
- ui.setWidget("setup-status", buildStatusWidget(store, available, assignments));
688
- };
562
+ const available = new Map<string, { source: "key" | "env" | "local"; modelCount: number }>();
563
+ const assignments: { default?: string; orchestration: Record<string, RouteAssignment> } = {
564
+ orchestration: {},
565
+ };
689
566
 
690
- refreshAvailable();
567
+ const refreshAvailable = (): void => {
568
+ const catalog = getProviderCatalog();
569
+ available.clear();
570
+ for (const p of catalog) {
571
+ const stored = store.getProvider(p.id);
572
+ if (stored?.apiKey) {
573
+ const source = stored.apiKey === "$OAUTH" ? "key" : stored.apiKey === "local" ? "local" : "key";
574
+ const modelCount = Array.isArray(stored.models) ? stored.models.length : p.staticModels.length;
575
+ available.set(p.id, { source, modelCount });
576
+ continue;
577
+ }
578
+ if (!p.local && process.env[p.envVar]) {
579
+ available.set(p.id, { source: "env", modelCount: p.staticModels.length });
580
+ }
581
+ }
582
+ ui.setWidget("setup-status", buildStatusWidget(store, available, assignments));
583
+ };
691
584
 
692
- let done = false;
693
- while (!done) {
694
- const catalog = getProviderCatalog();
695
- const choices: string[] = [];
696
- for (const p of catalog) {
697
- const state = available.get(p.id);
698
- const tag = state ? "[ok]" : "[--]";
699
- const modelTag = state ? ` (${state.modelCount} models)` : "";
700
- choices.push(`${tag} ${p.displayName}${modelTag}`);
701
- }
702
- choices.push("---");
703
- choices.push("Assign models to agent roles");
704
- choices.push("Finish and save");
705
- choices.push("Quit without saving");
706
-
707
- const action = await ui.select("Phi Code Setup - choose an action", choices);
708
- if (!action) {
709
- done = true;
710
- break;
711
- }
585
+ refreshAvailable();
586
+
587
+ let done = false;
588
+ while (!done) {
589
+ const catalog = getProviderCatalog();
590
+ const choices: string[] = [];
591
+ for (const p of catalog) {
592
+ const state = available.get(p.id);
593
+ const tag = state ? "[ok]" : "[--]";
594
+ const modelTag = state ? ` (${state.modelCount} models)` : "";
595
+ choices.push(`${tag} ${p.displayName}${modelTag}`);
596
+ }
597
+ choices.push("---");
598
+ choices.push("Assign models to agent roles");
599
+ choices.push("Finish and save");
600
+ choices.push("Quit without saving");
601
+
602
+ const action = await ui.select("Phi Code Setup - choose an action", choices);
603
+ if (!action) {
604
+ done = true;
605
+ break;
606
+ }
712
607
 
713
- if (action === "Quit without saving") {
714
- const confirm = await ui.confirm(
715
- "Quit",
716
- "Discard all in-memory assignments? (provider keys already saved are kept)",
717
- );
718
- if (confirm) {
719
- ui.setWidget("setup-status", undefined);
720
- ui.notify("Setup cancelled (saved provider keys are unchanged).", "warning");
721
- return;
722
- }
723
- continue;
724
- }
608
+ if (action === "Quit without saving") {
609
+ const confirm = await ui.confirm(
610
+ "Quit",
611
+ "Discard all in-memory assignments? (provider keys already saved are kept)",
612
+ );
613
+ if (confirm) {
614
+ ui.setWidget("setup-status", undefined);
615
+ ui.notify("Setup cancelled (saved provider keys are unchanged).", "warning");
616
+ return;
617
+ }
618
+ continue;
619
+ }
725
620
 
726
- if (action === "Finish and save") {
727
- if (!assignments.default || Object.keys(assignments.orchestration).length === 0) {
728
- const proceed = await ui.confirm(
729
- "Assignments incomplete",
730
- "You have not assigned all roles. Save current state anyway?",
731
- );
732
- if (!proceed) continue;
733
- }
734
- done = true;
735
- break;
736
- }
621
+ if (action === "Finish and save") {
622
+ if (!assignments.default || Object.keys(assignments.orchestration).length === 0) {
623
+ const proceed = await ui.confirm(
624
+ "Assignments incomplete",
625
+ "You have not assigned all roles. Save current state anyway?",
626
+ );
627
+ if (!proceed) continue;
628
+ }
629
+ done = true;
630
+ break;
631
+ }
737
632
 
738
- if (action === "Assign models to agent roles") {
739
- const allModels: Array<{ ref: string; display: string }> = [];
740
- const seenRefs = new Set<string>();
741
- for (const p of catalog) {
742
- const stored = store.getProvider(p.id);
743
- if (!stored) continue;
744
- const models = Array.isArray(stored.models) ? stored.models : [];
745
- for (const m of models) {
746
- const id = (m as { id?: string }).id;
747
- if (typeof id !== "string") continue;
748
- // Provider-qualified ref so the same id from different providers stays distinct.
749
- const ref = `${p.id}/${id}`;
750
- if (seenRefs.has(ref)) continue;
751
- seenRefs.add(ref);
752
- allModels.push({ ref, display: `${id} [${p.id}]` });
753
- }
754
- }
755
- const { defaultModel, orchestration } = await configureAssignments(ui, allModels);
756
- assignments.default = defaultModel;
757
- assignments.orchestration = orchestration;
758
- refreshAvailable();
759
- continue;
633
+ if (action === "Assign models to agent roles") {
634
+ const allModels: Array<{ ref: string; display: string }> = [];
635
+ const seenRefs = new Set<string>();
636
+ for (const p of catalog) {
637
+ const stored = store.getProvider(p.id);
638
+ if (!stored) continue;
639
+ const models = Array.isArray(stored.models) ? stored.models : [];
640
+ for (const m of models) {
641
+ const id = (m as { id?: string }).id;
642
+ if (typeof id !== "string") continue;
643
+ // Provider-qualified ref so the same id from different providers stays distinct.
644
+ const ref = `${p.id}/${id}`;
645
+ if (seenRefs.has(ref)) continue;
646
+ seenRefs.add(ref);
647
+ allModels.push({ ref, display: `${id} [${p.id}]` });
760
648
  }
649
+ }
650
+ const { defaultModel, orchestration } = await configureAssignments(ui, allModels);
651
+ assignments.default = defaultModel;
652
+ assignments.orchestration = orchestration;
653
+ refreshAvailable();
654
+ continue;
655
+ }
761
656
 
762
- if (action === "---") continue;
763
-
764
- const providerIndex = choices.indexOf(action);
765
- if (providerIndex < 0 || providerIndex >= catalog.length) continue;
766
- const provider = catalog[providerIndex];
767
-
768
- let result: { providerId: string; modelCount: number } | undefined;
769
- try {
770
- if (provider.id === "alibaba-codingplan") {
771
- result = await configureAlibaba(ui, store);
772
- } else if (provider.id === "opencode-go") {
773
- result = await configureOpenCodeGo(ui, store);
774
- } else if (provider.local) {
775
- result = await configureLocal(ui, store, provider);
776
- } else {
777
- result = await configureGenericCloud(ui, store, provider);
778
- }
779
- } catch (err) {
780
- ui.notify(
781
- `Provider configuration failed: ${err instanceof Error ? err.message : String(err)}`,
782
- "error",
783
- );
784
- }
657
+ if (action === "---") continue;
785
658
 
786
- if (result) refreshAvailable();
787
- }
659
+ const providerIndex = choices.indexOf(action);
660
+ if (providerIndex < 0 || providerIndex >= catalog.length) continue;
661
+ const provider = catalog[providerIndex];
788
662
 
789
- // Save routing if assignments were made
790
- if (assignments.default) {
791
- try {
792
- const routing = buildRoutingConfig(assignments.default, assignments.orchestration);
793
- const routingPath = await writeRoutingConfig(routing);
794
- ui.notify(`Routing config written to \`${routingPath}\`.`, "info");
795
- } catch (err) {
796
- ui.notify(`Failed to write routing.json: ${err}`, "error");
797
- }
663
+ let result: { providerId: string; modelCount: number } | undefined;
664
+ try {
665
+ if (provider.id === "alibaba-codingplan") {
666
+ result = await configureAlibaba(ui, store);
667
+ } else if (provider.id === "opencode-go") {
668
+ result = await configureOpenCodeGo(ui, store);
669
+ } else if (provider.local) {
670
+ result = await configureLocal(ui, store, provider);
671
+ } else {
672
+ result = await configureGenericCloud(ui, store, provider);
798
673
  }
674
+ } catch (err) {
675
+ ui.notify(`Provider configuration failed: ${err instanceof Error ? err.message : String(err)}`, "error");
676
+ }
799
677
 
800
- ui.setWidget("setup-status", undefined);
801
- ui.notify(
802
- "**Setup complete.**\n\n" +
803
- "Next steps:\n" +
804
- " - `/keys` to list/manage saved keys\n" +
805
- " - `/models refresh` to re-fetch the catalog from each provider's API\n" +
806
- " - `/routing` to inspect routing\n" +
807
- " - `/agents` to list sub-agents\n" +
808
- " - `/skills` to list skills\n" +
809
- " - Edit `~/.phi/agent/models.json` or `routing.json` directly: hot-reload kicks in",
810
- "info",
811
- );
678
+ if (result) refreshAvailable();
679
+ }
680
+
681
+ // Save routing if assignments were made
682
+ if (assignments.default) {
683
+ try {
684
+ const routing = buildRoutingConfig(assignments.default, assignments.orchestration);
685
+ const routingPath = await writeRoutingConfig(routing);
686
+ ui.notify(`Routing config written to \`${routingPath}\`.`, "info");
812
687
  } catch (err) {
813
- ui.setWidget("setup-status", undefined);
814
- ui.notify(`Setup wizard error: ${err instanceof Error ? err.message : String(err)}`, "error");
688
+ ui.notify(`Failed to write routing.json: ${err}`, "error");
815
689
  }
690
+ }
691
+
692
+ ui.setWidget("setup-status", undefined);
693
+ ui.notify(
694
+ "**Setup complete.**\n\n" +
695
+ "Next steps:\n" +
696
+ " - `/keys` to list/manage saved keys\n" +
697
+ " - `/models refresh` to re-fetch the catalog from each provider's API\n" +
698
+ " - `/routing` to inspect routing\n" +
699
+ " - `/agents` to list sub-agents\n" +
700
+ " - `/skills` to list skills\n" +
701
+ " - Edit `~/.phi/agent/models.json` or `routing.json` directly: hot-reload kicks in",
702
+ "info",
703
+ );
704
+ } catch (err) {
705
+ ui.setWidget("setup-status", undefined);
706
+ ui.notify(`Setup wizard error: ${err instanceof Error ? err.message : String(err)}`, "error");
707
+ }
708
+ }
709
+
710
+ export default function setupExtension(pi: ExtensionAPI) {
711
+ installSetupUnhandledRejectionGuard();
712
+ pi.registerCommand("setup", {
713
+ description: "Phi Code setup wizard (refonte UX, replaces /phi-init)",
714
+ handler: async (_args, ctx) => {
715
+ await runSetupWizard(ctx.ui);
816
716
  },
817
717
  });
818
718
  }
@@ -65,23 +65,6 @@ export default function smartRouterExtension(pi: ExtensionAPI) {
65
65
  }
66
66
  }
67
67
 
68
- /**
69
- * Resolve a model name to an available model.
70
- * If the preferred model exists in the registry, use it.
71
- * Otherwise, fall back to the current model.
72
- */
73
- function _resolveModel(preferredModel: string, ctx: any): string {
74
- try {
75
- const available = ctx.modelRegistry?.getAvailable?.() || [];
76
- if (available.some((m: any) => m.id === preferredModel)) {
77
- return preferredModel;
78
- }
79
- return ctx.model?.id || preferredModel;
80
- } catch {
81
- return ctx.model?.id || preferredModel;
82
- }
83
- }
84
-
85
68
  // ─── Input Event ─────────────────────────────────────────────────
86
69
 
87
70
  pi.on("input", async (event, ctx) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phi-code-admin/phi-code",
3
- "version": "0.96.1",
3
+ "version": "0.97.0",
4
4
  "description": "Coding agent CLI with persistent memory, sub-agents, intelligent routing, and orchestration",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -66,9 +66,9 @@
66
66
  "phi-code-ai": "^0.74.4",
67
67
  "phi-code-tui": "^0.74.0",
68
68
  "proper-lockfile": "^4.1.2",
69
- "sigma-agents": "^0.1.7",
69
+ "sigma-agents": "^0.2.1",
70
70
  "sigma-memory": "^0.2.9",
71
- "sigma-skills": "^0.1.2",
71
+ "sigma-skills": "^0.1.5",
72
72
  "strip-ansi": "^7.1.0",
73
73
  "typebox": "^1.1.24",
74
74
  "undici": "^7.19.1",