@phi-code-admin/phi-code 0.59.5 → 0.59.7

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.
@@ -714,4 +714,104 @@ _Edit this file to customize Phi Code's behavior for your project._
714
714
  }
715
715
  },
716
716
  });
717
+
718
+ // ─── API Key Management Command ─────────────────────────────────
719
+
720
+ pi.registerCommand("api-key", {
721
+ description: "Set or view API keys (usage: /api-key set <provider> <key> | /api-key list)",
722
+ handler: async (args, ctx) => {
723
+ const parts = args.trim().split(/\s+/);
724
+ const action = parts[0]?.toLowerCase();
725
+
726
+ const PROVIDERS: Record<string, { envVar: string; name: string }> = {
727
+ alibaba: { envVar: "ALIBABA_CODING_PLAN_KEY", name: "Alibaba Coding Plan" },
728
+ dashscope: { envVar: "DASHSCOPE_API_KEY", name: "DashScope (Alibaba)" },
729
+ openai: { envVar: "OPENAI_API_KEY", name: "OpenAI" },
730
+ anthropic: { envVar: "ANTHROPIC_API_KEY", name: "Anthropic" },
731
+ google: { envVar: "GOOGLE_API_KEY", name: "Google" },
732
+ openrouter: { envVar: "OPENROUTER_API_KEY", name: "OpenRouter" },
733
+ groq: { envVar: "GROQ_API_KEY", name: "Groq" },
734
+ brave: { envVar: "BRAVE_API_KEY", name: "Brave Search" },
735
+ };
736
+
737
+ if (!action || action === "help") {
738
+ ctx.ui.notify(`**🔑 API Key Management**
739
+
740
+ Usage:
741
+ /api-key set <provider> <key> — Set an API key for this session
742
+ /api-key list — Show configured providers
743
+ /api-key providers — List all supported providers
744
+
745
+ Supported providers: ${Object.keys(PROVIDERS).join(", ")}
746
+
747
+ Example:
748
+ /api-key set alibaba sk-sp-xxx
749
+ /api-key set openai sk-xxx
750
+
751
+ Keys set with /api-key are active for the current session.
752
+ For persistence, set environment variables:
753
+ • Windows: setx ALIBABA_CODING_PLAN_KEY "your-key"
754
+ • Linux/Mac: export ALIBABA_CODING_PLAN_KEY="your-key"`, "info");
755
+ return;
756
+ }
757
+
758
+ if (action === "list") {
759
+ let found = 0;
760
+ let msg = "**🔑 Configured API Keys:**\n";
761
+ for (const [id, info] of Object.entries(PROVIDERS)) {
762
+ const key = process.env[info.envVar];
763
+ if (key) {
764
+ const masked = key.substring(0, 6) + "..." + key.substring(key.length - 4);
765
+ msg += ` ✅ ${info.name} (${id}): ${masked}\n`;
766
+ found++;
767
+ }
768
+ }
769
+ if (found === 0) {
770
+ msg += " ❌ No API keys configured\n";
771
+ msg += "\nUse `/api-key set <provider> <key>` to add one.";
772
+ }
773
+ ctx.ui.notify(msg, "info");
774
+ return;
775
+ }
776
+
777
+ if (action === "providers") {
778
+ let msg = "**Supported Providers:**\n";
779
+ for (const [id, info] of Object.entries(PROVIDERS)) {
780
+ const status = process.env[info.envVar] ? "✅" : "⬜";
781
+ msg += ` ${status} **${id}** — ${info.name} (${info.envVar})\n`;
782
+ }
783
+ ctx.ui.notify(msg, "info");
784
+ return;
785
+ }
786
+
787
+ if (action === "set") {
788
+ const provider = parts[1]?.toLowerCase();
789
+ const key = parts[2];
790
+
791
+ if (!provider || !key) {
792
+ ctx.ui.notify("Usage: /api-key set <provider> <key>\nExample: /api-key set alibaba sk-sp-xxx", "warning");
793
+ return;
794
+ }
795
+
796
+ const info = PROVIDERS[provider];
797
+ if (!info) {
798
+ ctx.ui.notify(`Unknown provider "${provider}". Supported: ${Object.keys(PROVIDERS).join(", ")}`, "error");
799
+ return;
800
+ }
801
+
802
+ // Set in current process environment
803
+ process.env[info.envVar] = key;
804
+ // Also set common aliases
805
+ if (provider === "alibaba") {
806
+ process.env.DASHSCOPE_API_KEY = key;
807
+ }
808
+
809
+ const masked = key.substring(0, 6) + "..." + key.substring(key.length - 4);
810
+ ctx.ui.notify(`✅ **${info.name}** API key set: ${masked}\n\n⚠️ Active for this session only. For persistence:\n • Windows: \`setx ${info.envVar} "${key.substring(0, 6)}..."\`\n • Linux/Mac: Add \`export ${info.envVar}="..."\` to ~/.bashrc`, "info");
811
+ return;
812
+ }
813
+
814
+ ctx.ui.notify("Unknown action. Use: /api-key set|list|providers|help", "warning");
815
+ },
816
+ });
717
817
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phi-code-admin/phi-code",
3
- "version": "0.59.5",
3
+ "version": "0.59.7",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Post-install script: copies bundled extensions, agents, and skills
4
- * to ~/.phi/agent/ so Pi discovers them automatically.
4
+ * to ~/.phi/agent/ and makes sigma packages resolvable from there.
5
5
  */
6
- const { existsSync, mkdirSync, cpSync, readdirSync } = require("fs");
7
- const { join } = require("path");
6
+ const { existsSync, mkdirSync, cpSync, readdirSync, symlinkSync, unlinkSync, readlinkSync } = require("fs");
7
+ const { join, dirname } = require("path");
8
8
  const { homedir } = require("os");
9
9
 
10
10
  const agentDir = join(homedir(), ".phi", "agent");
11
- const packageDir = __dirname.replace(/[/\\]scripts$/, "");
11
+ const packageDir = __dirname.replace(/[\\/]scripts$/, "");
12
12
 
13
+ // 1. Copy extensions, agents, skills
13
14
  const copies = [
14
15
  { src: "extensions/phi", dest: join(agentDir, "extensions"), label: "extensions" },
15
16
  { src: "agents", dest: join(agentDir, "agents"), label: "agents" },
@@ -19,22 +20,61 @@ const copies = [
19
20
  for (const { src, dest, label } of copies) {
20
21
  const srcDir = join(packageDir, src);
21
22
  if (!existsSync(srcDir)) continue;
22
-
23
23
  mkdirSync(dest, { recursive: true });
24
-
25
24
  const files = readdirSync(srcDir);
26
25
  let copied = 0;
27
26
  for (const file of files) {
28
- const srcPath = join(srcDir, file);
29
- const destPath = join(dest, file);
30
27
  try {
31
- cpSync(srcPath, destPath, { recursive: true, force: true });
28
+ cpSync(join(srcDir, file), join(dest, file), { recursive: true, force: true });
32
29
  copied++;
33
- } catch (e) {
34
- // Skip files that can't be copied (permissions, etc.)
30
+ } catch (e) { /* skip */ }
31
+ }
32
+ if (copied > 0) console.log(` Φ Installed ${copied} ${label} to ${dest}`);
33
+ }
34
+
35
+ // 2. Make sigma packages resolvable from ~/.phi/agent/extensions/
36
+ // Create node_modules with symlinks to the actual packages
37
+ const sigmaPackages = ["sigma-memory", "sigma-agents", "sigma-skills"];
38
+ const extensionsNodeModules = join(agentDir, "extensions", "node_modules");
39
+ mkdirSync(extensionsNodeModules, { recursive: true });
40
+
41
+ for (const pkg of sigmaPackages) {
42
+ const srcPkg = join(packageDir, "node_modules", pkg);
43
+ const destLink = join(extensionsNodeModules, pkg);
44
+
45
+ if (!existsSync(srcPkg)) {
46
+ // Try parent node_modules (hoisted)
47
+ let parent = dirname(packageDir);
48
+ while (parent !== dirname(parent)) {
49
+ const hoisted = join(parent, "node_modules", pkg);
50
+ if (existsSync(hoisted)) {
51
+ createLink(hoisted, destLink, pkg);
52
+ break;
53
+ }
54
+ parent = dirname(parent);
35
55
  }
56
+ continue;
36
57
  }
37
- if (copied > 0) {
38
- console.log(` Φ Installed ${copied} ${label} to ${dest}`);
58
+ createLink(srcPkg, destLink, pkg);
59
+ }
60
+
61
+ function createLink(src, dest, name) {
62
+ try {
63
+ // Remove existing (symlink or directory)
64
+ if (existsSync(dest)) {
65
+ try { unlinkSync(dest); } catch {
66
+ try { cpSync(src, dest, { recursive: true, force: true }); return; } catch { return; }
67
+ }
68
+ }
69
+ // Try symlink first, fall back to copy (Windows may not support symlinks)
70
+ try {
71
+ symlinkSync(src, dest, "junction");
72
+ console.log(` Φ Linked ${name}`);
73
+ } catch {
74
+ cpSync(src, dest, { recursive: true, force: true });
75
+ console.log(` Φ Copied ${name}`);
76
+ }
77
+ } catch (e) {
78
+ console.log(` ⚠ Could not install ${name}: ${e.message}`);
39
79
  }
40
80
  }
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "REST API design patterns, versioning, error handling, and documentation"
3
+ ---
1
4
  # API Design Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "Code quality standards, naming conventions, and best practices"
3
+ ---
1
4
  # Coding Standards Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "Database design, queries, migrations, and optimization"
3
+ ---
1
4
  # Database Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "CI/CD pipelines, deployment, monitoring, and infrastructure"
3
+ ---
1
4
  # DevOps Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "Docker containers, Compose, images, and orchestration"
3
+ ---
1
4
  # Docker Operations Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "Git branching, commits, merges, and collaboration workflows"
3
+ ---
1
4
  # Git Workflow Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "GitHub Actions, PRs, issues, releases, and repository management"
3
+ ---
1
4
  # GitHub Workflow Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "Performance profiling, optimization, caching, and benchmarking"
3
+ ---
1
4
  # Performance Optimization Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "Crafting production-grade structured prompts for AI systems"
3
+ ---
1
4
  # Prompt Architect Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "Security auditing, vulnerability scanning, and hardening"
3
+ ---
1
4
  # Security Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "Continuous learning from errors, corrections, and discoveries"
3
+ ---
1
4
  # Self-Improving Agent Skill
2
5
 
3
6
  ## When to use
@@ -1,3 +1,6 @@
1
+ ---
2
+ description: "Test strategy, unit tests, integration tests, and test automation"
3
+ ---
1
4
  # Testing Skill
2
5
 
3
6
  ## When to use