supipowers 0.1.0 → 0.1.3

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/bin/install.mjs CHANGED
@@ -12,8 +12,8 @@ import {
12
12
  note,
13
13
  } from "@clack/prompts";
14
14
  import { spawnSync } from "node:child_process";
15
- import { readdirSync, readFileSync, existsSync } from "node:fs";
16
- import { resolve, extname, dirname, join } from "node:path";
15
+ import { readFileSync, existsSync } from "node:fs";
16
+ import { resolve, dirname, join } from "node:path";
17
17
  import { fileURLToPath } from "node:url";
18
18
  import { homedir } from "node:os";
19
19
 
@@ -59,53 +59,29 @@ function findOmpBinary() {
59
59
  const LSP_SERVERS = [
60
60
  {
61
61
  language: "TypeScript / JavaScript",
62
- extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"],
63
62
  server: "typescript-language-server",
64
63
  installCmd: "bun add -g typescript-language-server typescript",
65
64
  },
66
65
  {
67
66
  language: "Python",
68
- extensions: [".py"],
69
67
  server: "pyright",
70
68
  installCmd: "pip install pyright",
71
69
  },
72
70
  {
73
71
  language: "Rust",
74
- extensions: [".rs"],
75
72
  server: "rust-analyzer",
76
73
  installCmd: "rustup component add rust-analyzer",
77
74
  },
78
75
  {
79
76
  language: "Go",
80
- extensions: [".go"],
81
77
  server: "gopls",
82
78
  installCmd: "go install golang.org/x/tools/gopls@latest",
83
79
  },
84
80
  ];
85
81
 
86
- function detectLanguages(dir) {
87
- const detected = new Set();
88
- try {
89
- const entries = readdirSync(dir, { withFileTypes: true });
90
- for (const entry of entries) {
91
- if (entry.isFile()) {
92
- detected.add(extname(entry.name));
93
- } else if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
94
- // One level deep
95
- try {
96
- const subEntries = readdirSync(join(dir, entry.name), { withFileTypes: true });
97
- for (const sub of subEntries) {
98
- if (sub.isFile()) detected.add(extname(sub.name));
99
- }
100
- } catch {
101
- // skip unreadable dirs
102
- }
103
- }
104
- }
105
- } catch {
106
- // skip
107
- }
108
- return detected;
82
+ function isInstalled(binary) {
83
+ const result = run("which", [binary]);
84
+ return result.status === 0;
109
85
  }
110
86
 
111
87
  // ── Main ─────────────────────────────────────────────────────
@@ -178,33 +154,33 @@ async function main() {
178
154
 
179
155
  // ── Step 3: LSP setup (optional) ──────────────────────────
180
156
 
181
- const detectedExts = detectLanguages(process.cwd());
182
- const matchingServers = LSP_SERVERS.filter((srv) =>
183
- srv.extensions.some((ext) => detectedExts.has(ext))
184
- );
185
-
186
- if (matchingServers.length > 0) {
187
- const selected = await multiselect({
188
- message: "Detected project languages. Install LSP servers for better code intelligence?",
189
- options: matchingServers.map((srv) => ({
157
+ const selected = await multiselect({
158
+ message: "Install LSP servers for better code intelligence?",
159
+ options: LSP_SERVERS.map((srv) => {
160
+ const installed = isInstalled(srv.server);
161
+ return {
190
162
  value: srv,
191
163
  label: srv.language,
192
- hint: srv.server,
193
- })),
194
- required: false,
195
- });
164
+ hint: installed ? `${srv.server} (installed)` : srv.server,
165
+ };
166
+ }),
167
+ required: false,
168
+ });
196
169
 
197
- if (!isCancel(selected) && selected.length > 0) {
198
- for (const srv of selected) {
199
- const ls = spinner();
200
- ls.start(`Installing ${srv.server}...`);
201
- const [cmd, ...args] = srv.installCmd.split(" ");
202
- const r = run(cmd, args);
203
- if (r.status !== 0) {
204
- ls.stop(`Failed to install ${srv.server} — you can install manually: ${srv.installCmd}`);
205
- } else {
206
- ls.stop(`${srv.server} installed`);
207
- }
170
+ if (!isCancel(selected) && selected.length > 0) {
171
+ for (const srv of selected) {
172
+ if (isInstalled(srv.server)) {
173
+ note(`${srv.server} is already installed, skipping.`, srv.language);
174
+ continue;
175
+ }
176
+ const ls = spinner();
177
+ ls.start(`Installing ${srv.server}...`);
178
+ const [cmd, ...args] = srv.installCmd.split(" ");
179
+ const r = run(cmd, args);
180
+ if (r.status !== 0) {
181
+ ls.stop(`Failed to install ${srv.server} — you can install manually: ${srv.installCmd}`);
182
+ } else {
183
+ ls.stop(`${srv.server} installed`);
208
184
  }
209
185
  }
210
186
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supipowers",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "description": "OMP-native workflow extension inspired by Superpowers.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -21,7 +21,7 @@ export function registerConfigCommand(pi: ExtensionAPI): void {
21
21
  `Max fix retries: ${config.orchestration.maxFixRetries}`,
22
22
  `Max nesting depth: ${config.orchestration.maxNestingDepth}`,
23
23
  `Model preference: ${config.orchestration.modelPreference}`,
24
- `LSP auto-detect: ${config.lsp.autoDetect}`,
24
+ `LSP setup guide: ${config.lsp.setupGuide}`,
25
25
  `Notification verbosity: ${config.notifications.verbosity}`,
26
26
  `QA framework: ${config.qa.framework ?? "not detected"}`,
27
27
  `Release pipeline: ${config.release.pipeline ?? "not configured"}`,
@@ -11,7 +11,6 @@ export const DEFAULT_CONFIG: SupipowersConfig = {
11
11
  modelPreference: "auto",
12
12
  },
13
13
  lsp: {
14
- autoDetect: true,
15
14
  setupGuide: true,
16
15
  },
17
16
  notifications: {
@@ -13,7 +13,6 @@ const ConfigSchema = Type.Object({
13
13
  modelPreference: Type.String(),
14
14
  }),
15
15
  lsp: Type.Object({
16
- autoDetect: Type.Boolean(),
17
16
  setupGuide: Type.Boolean(),
18
17
  }),
19
18
  notifications: Type.Object({
@@ -1,36 +1,31 @@
1
1
  // src/lsp/detector.ts
2
- import type { SupipowersConfig } from "../types.js";
2
+ import { LSP_SERVERS, type LspServerEntry } from "./setup-guide.js";
3
3
 
4
- export interface LspStatus {
5
- available: boolean;
6
- servers: LspServerInfo[];
7
- }
8
-
9
- export interface LspServerInfo {
10
- name: string;
11
- status: "running" | "stopped" | "error";
12
- fileTypes: string[];
13
- error?: string;
4
+ export interface LspServerStatus {
5
+ server: LspServerEntry;
6
+ installed: boolean;
14
7
  }
15
8
 
16
9
  /**
17
- * Check LSP availability by invoking the lsp tool's "status" action.
18
- * Uses pi.exec to call the lsp tool programmatically.
10
+ * Check which LSP servers are installed by looking for their binaries.
19
11
  */
20
- export async function detectLsp(
12
+ export async function checkInstalledServers(
21
13
  exec: (cmd: string, args: string[]) => Promise<{ stdout: string; exitCode: number }>
22
- ): Promise<LspStatus> {
23
- try {
24
- // We check by looking for LSP config files or running servers
25
- // In OMP, LSP is a built-in tool — we check if it's in active tools
26
- return { available: false, servers: [] };
27
- } catch {
28
- return { available: false, servers: [] };
14
+ ): Promise<LspServerStatus[]> {
15
+ const results: LspServerStatus[] = [];
16
+ for (const server of LSP_SERVERS) {
17
+ try {
18
+ const result = await exec("which", [server.server]);
19
+ results.push({ server, installed: result.exitCode === 0 });
20
+ } catch {
21
+ results.push({ server, installed: false });
22
+ }
29
23
  }
24
+ return results;
30
25
  }
31
26
 
32
27
  /**
33
- * Check if LSP is available from the extension context.
28
+ * Check if LSP is available from the OMP extension context at runtime.
34
29
  * Reads the active tools list to see if "lsp" is registered.
35
30
  */
36
31
  export function isLspAvailable(activeTools: string[]): boolean {
@@ -1,13 +1,13 @@
1
1
  // src/lsp/setup-guide.ts
2
2
 
3
- export interface SetupInstruction {
3
+ export interface LspServerEntry {
4
4
  language: string;
5
5
  server: string;
6
6
  installCommand: string;
7
7
  notes: string;
8
8
  }
9
9
 
10
- const COMMON_LSP_SERVERS: SetupInstruction[] = [
10
+ export const LSP_SERVERS: LspServerEntry[] = [
11
11
  {
12
12
  language: "TypeScript/JavaScript",
13
13
  server: "typescript-language-server",
@@ -34,47 +34,16 @@ const COMMON_LSP_SERVERS: SetupInstruction[] = [
34
34
  },
35
35
  ];
36
36
 
37
- /** Get setup instructions for detected project languages */
38
- export function getSetupInstructions(detectedLanguages: string[]): SetupInstruction[] {
39
- return COMMON_LSP_SERVERS.filter((s) =>
40
- detectedLanguages.some((lang) =>
41
- s.language.toLowerCase().includes(lang.toLowerCase())
42
- )
43
- );
44
- }
45
-
46
- /** Detect project languages from file extensions */
47
- export function detectProjectLanguages(files: string[]): string[] {
48
- const extMap: Record<string, string> = {
49
- ".ts": "typescript",
50
- ".tsx": "typescript",
51
- ".js": "javascript",
52
- ".jsx": "javascript",
53
- ".py": "python",
54
- ".rs": "rust",
55
- ".go": "go",
56
- ".java": "java",
57
- ".rb": "ruby",
58
- ".php": "php",
59
- };
60
- const languages = new Set<string>();
61
- for (const file of files) {
62
- const ext = file.slice(file.lastIndexOf("."));
63
- if (extMap[ext]) languages.add(extMap[ext]);
64
- }
65
- return [...languages];
66
- }
67
-
68
- /** Format setup instructions as readable text */
69
- export function formatSetupGuide(instructions: SetupInstruction[]): string {
70
- if (instructions.length === 0) {
71
- return "No LSP setup instructions available for your project languages.";
37
+ /** Format all LSP servers as readable text */
38
+ export function formatSetupGuide(servers: LspServerEntry[] = LSP_SERVERS): string {
39
+ if (servers.length === 0) {
40
+ return "No LSP servers available.";
72
41
  }
73
42
  const lines = ["LSP Setup Guide:", ""];
74
- for (const inst of instructions) {
75
- lines.push(`## ${inst.language} — ${inst.server}`);
76
- lines.push(`Install: ${inst.installCommand}`);
77
- lines.push(`Note: ${inst.notes}`);
43
+ for (const srv of servers) {
44
+ lines.push(`## ${srv.language} — ${srv.server}`);
45
+ lines.push(`Install: ${srv.installCommand}`);
46
+ lines.push(`Note: ${srv.notes}`);
78
47
  lines.push("");
79
48
  }
80
49
  return lines.join("\n");
package/src/types.ts CHANGED
@@ -110,7 +110,6 @@ export interface SupipowersConfig {
110
110
  modelPreference: string;
111
111
  };
112
112
  lsp: {
113
- autoDetect: boolean;
114
113
  setupGuide: boolean;
115
114
  };
116
115
  notifications: {