holycodex 0.2.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.
Files changed (93) hide show
  1. package/LICENSE.md +82 -0
  2. package/README.md +107 -0
  3. package/THIRD-PARTY-NOTICES.md +7 -0
  4. package/bin/holycodex.js +2 -0
  5. package/marketplace.json +12 -0
  6. package/package.json +59 -0
  7. package/plugin/.codex-plugin/plugin.json +29 -0
  8. package/plugin/.mcp.json +8 -0
  9. package/plugin/agents/explorer.toml +6 -0
  10. package/plugin/agents/librarian.toml +6 -0
  11. package/plugin/agents/worker.toml +6 -0
  12. package/plugin/hooks/hooks.json +93 -0
  13. package/plugin/runtime/bootstrap.js +23 -0
  14. package/plugin/runtime/cli.js +233 -0
  15. package/plugin/runtime/git-bash.js +359 -0
  16. package/plugin/runtime/lsp.js +3674 -0
  17. package/plugin/runtime/rules.js +146 -0
  18. package/plugin/runtime/src-tRIOClWZ.js +209 -0
  19. package/plugin/skills/ast-grep/LICENSE +21 -0
  20. package/plugin/skills/ast-grep/SKILL.md +20 -0
  21. package/plugin/skills/ast-grep/references/cli.md +3 -0
  22. package/plugin/skills/ast-grep/references/install.md +3 -0
  23. package/plugin/skills/ast-grep/references/patterns.md +3 -0
  24. package/plugin/skills/ast-grep/references/pitfalls.md +3 -0
  25. package/plugin/skills/ast-grep/references/recipes.md +9 -0
  26. package/plugin/skills/ast-grep/references/sgconfig.md +3 -0
  27. package/plugin/skills/ast-grep/references/yaml-rules.md +3 -0
  28. package/plugin/skills/caveman/LICENSE +21 -0
  29. package/plugin/skills/caveman/SKILL.md +84 -0
  30. package/plugin/skills/comment-checker/SKILL.md +16 -0
  31. package/plugin/skills/compress/SKILL.md +26 -0
  32. package/plugin/skills/debugging/SKILL.md +23 -0
  33. package/plugin/skills/debugging/references/runtimes/README.md +9 -0
  34. package/plugin/skills/debugging/references/tools/README.md +8 -0
  35. package/plugin/skills/define-goal/LICENSE.txt +201 -0
  36. package/plugin/skills/define-goal/SKILL.md +36 -0
  37. package/plugin/skills/frontend/ATTRIBUTION.md +218 -0
  38. package/plugin/skills/frontend/LICENSE-Apache-2.0.txt +201 -0
  39. package/plugin/skills/frontend/SKILL.md +42 -0
  40. package/plugin/skills/frontend/references/perfection/README.md +5 -0
  41. package/plugin/skills/frontend/references/perfection/react-perf-tooling.md +3 -0
  42. package/plugin/skills/frontend/references/ui-ux-db/README.md +5 -0
  43. package/plugin/skills/frontend/references/ui-ux-db/data/charts.csv +26 -0
  44. package/plugin/skills/frontend/references/ui-ux-db/data/colors.csv +162 -0
  45. package/plugin/skills/frontend/references/ui-ux-db/data/icons.csv +106 -0
  46. package/plugin/skills/frontend/references/ui-ux-db/data/landing.csv +35 -0
  47. package/plugin/skills/frontend/references/ui-ux-db/data/products.csv +162 -0
  48. package/plugin/skills/frontend/references/ui-ux-db/data/react-performance.csv +45 -0
  49. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/astro.csv +54 -0
  50. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/flutter.csv +53 -0
  51. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/html-tailwind.csv +56 -0
  52. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/jetpack-compose.csv +53 -0
  53. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/nextjs.csv +53 -0
  54. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/nuxt-ui.csv +51 -0
  55. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/nuxtjs.csv +59 -0
  56. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/react-native.csv +52 -0
  57. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/react.csv +54 -0
  58. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/shadcn.csv +61 -0
  59. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/svelte.csv +54 -0
  60. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/swiftui.csv +51 -0
  61. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/vue.csv +50 -0
  62. package/plugin/skills/frontend/references/ui-ux-db/data/styles.csv +85 -0
  63. package/plugin/skills/frontend/references/ui-ux-db/data/typography.csv +74 -0
  64. package/plugin/skills/frontend/references/ui-ux-db/data/ui-reasoning.csv +162 -0
  65. package/plugin/skills/frontend/references/ui-ux-db/data/ux-guidelines.csv +100 -0
  66. package/plugin/skills/frontend/references/ui-ux-db/data/web-interface.csv +31 -0
  67. package/plugin/skills/frontend/references/ui-ux-db/scripts/core.py +262 -0
  68. package/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +1148 -0
  69. package/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +114 -0
  70. package/plugin/skills/handoff/SKILL.md +10 -0
  71. package/plugin/skills/lsp/SKILL.md +35 -0
  72. package/plugin/skills/lsp-setup/SKILL.md +18 -0
  73. package/plugin/skills/lsp-setup/scripts/detect-lsp.ts +233 -0
  74. package/plugin/skills/lsp-setup/scripts/lsp-server-table.ts +188 -0
  75. package/plugin/skills/lsp-setup/scripts/tsconfig.json +17 -0
  76. package/plugin/skills/lsp-setup/scripts/verify-lsp.ts +166 -0
  77. package/plugin/skills/plan/SKILL.md +14 -0
  78. package/plugin/skills/plan-review/SKILL.md +12 -0
  79. package/plugin/skills/programming/SKILL.md +35 -0
  80. package/plugin/skills/programming/references/code-smells.md +3 -0
  81. package/plugin/skills/programming/references/go/README.md +3 -0
  82. package/plugin/skills/programming/references/logging.md +3 -0
  83. package/plugin/skills/programming/references/python/README.md +3 -0
  84. package/plugin/skills/programming/references/rust/README.md +3 -0
  85. package/plugin/skills/programming/references/rust-ub/README.md +3 -0
  86. package/plugin/skills/programming/references/typescript/README.md +3 -0
  87. package/plugin/skills/refactor/SKILL.md +21 -0
  88. package/plugin/skills/remove-ai-slops/SKILL.md +20 -0
  89. package/plugin/skills/rules/SKILL.md +16 -0
  90. package/plugin/skills/security-research/SKILL.md +38 -0
  91. package/plugin/skills/tdd/SKILL.md +24 -0
  92. package/plugin/skills/tdd/mocking.md +60 -0
  93. package/plugin/skills/tdd/tests.md +77 -0
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ UI/UX Pro Max Search - BM25 search engine for UI/UX style guides
5
+ Usage: python search.py "<query>" [--domain <domain>] [--stack <stack>] [--max-results 3]
6
+ python search.py "<query>" --design-system [-p "Project Name"]
7
+ python search.py "<query>" --design-system --persist [-p "Project Name"] [--page "dashboard"]
8
+
9
+ Domains: style, prompt, color, chart, landing, product, ux, typography, google-fonts
10
+ Stacks: react, nextjs, vue, svelte, astro, swiftui, react-native, flutter, nuxtjs, nuxt-ui, html-tailwind, shadcn, jetpack-compose, threejs
11
+
12
+ Persistence (Master + Overrides pattern):
13
+ --persist Save design system to design-system/MASTER.md
14
+ --page Also create a page-specific override file in design-system/pages/
15
+ """
16
+
17
+ import argparse
18
+ import sys
19
+ import io
20
+ from core import CSV_CONFIG, AVAILABLE_STACKS, MAX_RESULTS, search, search_stack
21
+ from design_system import generate_design_system, persist_design_system
22
+
23
+ # Force UTF-8 for stdout/stderr to handle emojis on Windows (cp1252 default)
24
+ if sys.stdout.encoding and sys.stdout.encoding.lower() != 'utf-8':
25
+ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
26
+ if sys.stderr.encoding and sys.stderr.encoding.lower() != 'utf-8':
27
+ sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
28
+
29
+
30
+ def format_output(result):
31
+ """Format results for Claude consumption (token-optimized)"""
32
+ if "error" in result:
33
+ return f"Error: {result['error']}"
34
+
35
+ output = []
36
+ if result.get("stack"):
37
+ output.append(f"## UI Pro Max Stack Guidelines")
38
+ output.append(f"**Stack:** {result['stack']} | **Query:** {result['query']}")
39
+ else:
40
+ output.append(f"## UI Pro Max Search Results")
41
+ output.append(f"**Domain:** {result['domain']} | **Query:** {result['query']}")
42
+ output.append(f"**Source:** {result['file']} | **Found:** {result['count']} results\n")
43
+
44
+ for i, row in enumerate(result['results'], 1):
45
+ output.append(f"### Result {i}")
46
+ for key, value in row.items():
47
+ value_str = str(value)
48
+ if len(value_str) > 300:
49
+ value_str = value_str[:300] + "..."
50
+ output.append(f"- **{key}:** {value_str}")
51
+ output.append("")
52
+
53
+ return "\n".join(output)
54
+
55
+
56
+ if __name__ == "__main__":
57
+ parser = argparse.ArgumentParser(description="UI Pro Max Search")
58
+ parser.add_argument("query", help="Search query")
59
+ parser.add_argument("--domain", "-d", choices=list(CSV_CONFIG.keys()), help="Search domain")
60
+ parser.add_argument("--stack", "-s", choices=AVAILABLE_STACKS, help=f"Stack-specific search. Available: {', '.join(AVAILABLE_STACKS)}")
61
+ parser.add_argument("--max-results", "-n", type=int, default=MAX_RESULTS, help="Max results (default: 3)")
62
+ parser.add_argument("--json", action="store_true", help="Output as JSON")
63
+ # Design system generation
64
+ parser.add_argument("--design-system", "-ds", action="store_true", help="Generate complete design system recommendation")
65
+ parser.add_argument("--project-name", "-p", type=str, default=None, help="Project name for design system output")
66
+ parser.add_argument("--format", "-f", choices=["ascii", "markdown"], default="ascii", help="Output format for design system")
67
+ # Persistence (Master + Overrides pattern)
68
+ parser.add_argument("--persist", action="store_true", help="Save design system to design-system/MASTER.md (creates hierarchical structure)")
69
+ parser.add_argument("--page", type=str, default=None, help="Create page-specific override file in design-system/pages/")
70
+ parser.add_argument("--output-dir", "-o", type=str, default=None, help="Output directory for persisted files (default: current directory)")
71
+
72
+ args = parser.parse_args()
73
+
74
+ # Design system takes priority
75
+ if args.design_system:
76
+ result = generate_design_system(
77
+ args.query,
78
+ args.project_name,
79
+ args.format,
80
+ persist=args.persist,
81
+ page=args.page,
82
+ output_dir=args.output_dir
83
+ )
84
+ print(result)
85
+
86
+ # Print persistence confirmation
87
+ if args.persist:
88
+ project_slug = args.project_name.lower().replace(' ', '-') if args.project_name else "default"
89
+ print("\n" + "=" * 60)
90
+ print(f"✅ Design system persisted to design-system/{project_slug}/")
91
+ print(f" 📄 design-system/{project_slug}/MASTER.md (Global Source of Truth)")
92
+ if args.page:
93
+ page_filename = args.page.lower().replace(' ', '-')
94
+ print(f" 📄 design-system/{project_slug}/pages/{page_filename}.md (Page Overrides)")
95
+ print("")
96
+ print(f"📖 Usage: When building a page, check design-system/{project_slug}/pages/[page].md first.")
97
+ print(f" If exists, its rules override MASTER.md. Otherwise, use MASTER.md.")
98
+ print("=" * 60)
99
+ # Stack search
100
+ elif args.stack:
101
+ result = search_stack(args.query, args.stack, args.max_results)
102
+ if args.json:
103
+ import json
104
+ print(json.dumps(result, indent=2, ensure_ascii=False))
105
+ else:
106
+ print(format_output(result))
107
+ # Domain search
108
+ else:
109
+ result = search(args.query, args.domain, args.max_results)
110
+ if args.json:
111
+ import json
112
+ print(json.dumps(result, indent=2, ensure_ascii=False))
113
+ else:
114
+ print(format_output(result))
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: handoff
3
+ description: Compact conversation state into a safe resumable handoff. Use when asked to hand off, save context, or prepare another agent/session to continue.
4
+ ---
5
+
6
+ # Handoff
7
+
8
+ Write handoff to OS temp directory, never workspace. Tailor it to any user-provided next-session focus.
9
+
10
+ Include current objective, completed work, state, key decisions, blockers, next steps, verification, and suggested skills. Reference existing specs, plans, ADRs, issues, commits, and diffs by path or URL instead of duplicating them. Redact secrets, credentials, and personal data.
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: lsp
3
+ description: Use when Codex needs language-server diagnostics, definitions, references, symbols, or rename safety checks in the current workspace.
4
+ ---
5
+
6
+ # Codex LSP
7
+
8
+ Call `lsp` MCP tools through the tool interface; `lsp.*`/`mcp__lsp__*` are tool-call names, not shell commands.
9
+
10
+ ## Tools
11
+
12
+ - `lsp.status`: list configured, installed, missing, disabled, and active language servers.
13
+ - `lsp.diagnostics`: check one file or directory for LSP diagnostics. Prefer `severity: "error"` after edits.
14
+ - `lsp.goto_definition`: locate a symbol definition from file, line, and character.
15
+ - `lsp.find_references`: find usages of a symbol across the workspace.
16
+ - `lsp.symbols`: inspect document symbols or search workspace symbols.
17
+ - `lsp.prepare_rename`: check whether a rename is valid at a position.
18
+ - `lsp.rename`: apply a language-server workspace edit for a rename.
19
+
20
+ ## Config
21
+
22
+ Project config lives at `.codex/lsp-client.json`; user config lives at `~/.codex/lsp-client.json`.
23
+
24
+ ```json
25
+ {
26
+ "lsp": {
27
+ "typescript": {
28
+ "command": ["typescript-language-server", "--stdio"],
29
+ "extensions": [".ts", ".tsx", ".js", ".jsx"]
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ Use `lsp.status` first when diagnostics report a missing language server.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: lsp-setup
3
+ description: Configure and verify one language server. Use when semantic tooling is missing, unconfigured, or reports that its server is not installed.
4
+ ---
5
+
6
+ # LSP Setup
7
+
8
+ Use when user asks setup/install/configure, or required server is missing. Do not install silently.
9
+
10
+ 1. Detect language, project root, package manager, existing server, and current `.codex/lsp-client.json` or project setting.
11
+ 2. Run `scripts/detect-lsp.ts` or inspect `scripts/lsp-server-table.ts` for matching server, command, extensions, and install hint.
12
+ 3. Prefer project-local maintained server. Preserve existing config.
13
+ 4. If install changes machine or network state, ask unless user already authorized setup.
14
+ 5. Add smallest config entry: command, args, extensions, root markers only when needed.
15
+ 6. Verify executable, start server, run diagnostics on one representative file.
16
+ 7. Report server, version, config path, verification result.
17
+
18
+ No duplicate server for same extension without explicit priority. No global install when project-local works. No broad editor configuration changes.
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env bun
2
+ // detect-lsp.ts <targetDir> [--json] — scan a directory for source languages and
3
+ // report, per detected language: the builtin LSP server, whether its executable
4
+ // is on PATH, an install hint, and whether a project LSP config references it.
5
+
6
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
7
+ import { delimiter, extname, join, sep } from "node:path";
8
+ import process from "node:process";
9
+
10
+ import { LANGUAGES, type LanguageServer, PROJECT_CONFIG_FILES } from "./lsp-server-table";
11
+
12
+ const SKIP_DIRECTORIES = new Set<string>([
13
+ "node_modules",
14
+ ".git",
15
+ "dist",
16
+ "build",
17
+ ".next",
18
+ "out",
19
+ "target",
20
+ ".venv",
21
+ "venv",
22
+ "vendor",
23
+ ".cache",
24
+ "__pycache__",
25
+ ".turbo",
26
+ "coverage",
27
+ ]);
28
+
29
+ const MAX_FILES = 50_000;
30
+
31
+ // Mirrors effectiveExtension() in packages/lsp-tools-mcp/src/lsp/effective-extension.ts:
32
+ // extensionless Dockerfile/Containerfile resolve to .dockerfile (exact-case basenames).
33
+ const BASENAME_EXTENSIONS: Record<string, string> = {
34
+ Dockerfile: ".dockerfile",
35
+ Containerfile: ".dockerfile",
36
+ };
37
+
38
+ interface ConfigFileState {
39
+ readonly path: string;
40
+ readonly exists: boolean;
41
+ readonly serverIds: readonly string[];
42
+ }
43
+
44
+ interface DetectionResult {
45
+ readonly server: LanguageServer;
46
+ readonly executable: string;
47
+ readonly installed: boolean;
48
+ readonly resolvedPath: string | null;
49
+ readonly configuredIn: readonly string[];
50
+ }
51
+
52
+ function collectExtensions(root: string): ReadonlySet<string> {
53
+ const found = new Set<string>();
54
+ const stack: string[] = [root];
55
+ let visited = 0;
56
+
57
+ while (stack.length > 0) {
58
+ const current = stack.pop();
59
+ if (current === undefined) break;
60
+
61
+ let entries: string[];
62
+ try {
63
+ entries = readdirSync(current);
64
+ } catch {
65
+ continue;
66
+ }
67
+
68
+ for (const entry of entries) {
69
+ if (visited >= MAX_FILES) return found;
70
+ const fullPath = join(current, entry);
71
+
72
+ let kind: "dir" | "file" | "other" = "other";
73
+ try {
74
+ const stat = statSync(fullPath);
75
+ kind = stat.isDirectory() ? "dir" : stat.isFile() ? "file" : "other";
76
+ } catch {
77
+ continue;
78
+ }
79
+
80
+ if (kind === "dir") {
81
+ if (!SKIP_DIRECTORIES.has(entry)) stack.push(fullPath);
82
+ } else if (kind === "file") {
83
+ visited += 1;
84
+ const ext = (BASENAME_EXTENSIONS[entry] ?? extname(entry)).toLowerCase();
85
+ if (ext.length > 0) found.add(ext);
86
+ }
87
+ }
88
+ }
89
+
90
+ return found;
91
+ }
92
+
93
+ function pathDirectories(): readonly string[] {
94
+ return (process.env["PATH"] ?? "").split(delimiter).filter((dir: string) => dir.length > 0);
95
+ }
96
+
97
+ function resolveExecutable(command: string): string | null {
98
+ const extensions =
99
+ process.platform === "win32"
100
+ ? (process.env["PATHEXT"]?.split(";") ?? [".EXE", ".CMD", ".BAT"])
101
+ : [""];
102
+ const bases =
103
+ command.includes("/") || command.includes(sep)
104
+ ? [command]
105
+ : pathDirectories().map((dir: string) => join(dir, command));
106
+
107
+ for (const base of bases) {
108
+ for (const ext of extensions) {
109
+ const candidate = ext.length > 0 ? `${base}${ext}` : base;
110
+ try {
111
+ if (existsSync(candidate) && statSync(candidate).isFile()) return candidate;
112
+ } catch {
113
+ continue;
114
+ }
115
+ }
116
+ }
117
+ return null;
118
+ }
119
+
120
+ function isRecord(value: unknown): value is Record<string, unknown> {
121
+ return typeof value === "object" && value !== null && !Array.isArray(value);
122
+ }
123
+
124
+ function parseConfiguredServerIds(path: string): readonly string[] {
125
+ let parsed: unknown;
126
+ try {
127
+ parsed = JSON.parse(readFileSync(path, "utf-8"));
128
+ } catch {
129
+ return [];
130
+ }
131
+ if (!isRecord(parsed)) return [];
132
+ const lsp = parsed["lsp"];
133
+ return isRecord(lsp) ? Object.keys(lsp) : [];
134
+ }
135
+
136
+ function readConfigState(root: string): readonly ConfigFileState[] {
137
+ return PROJECT_CONFIG_FILES.map((relative: string): ConfigFileState => {
138
+ const path = join(root, relative);
139
+ if (!existsSync(path)) return { path: relative, exists: false, serverIds: [] };
140
+ return { path: relative, exists: true, serverIds: parseConfiguredServerIds(path) };
141
+ });
142
+ }
143
+
144
+ function detect(root: string, configState: readonly ConfigFileState[]): readonly DetectionResult[] {
145
+ const extensions = collectExtensions(root);
146
+ const results: DetectionResult[] = [];
147
+
148
+ for (const server of LANGUAGES) {
149
+ if (!server.extensions.some((ext: string) => extensions.has(ext))) continue;
150
+
151
+ const executable = server.command[0] ?? server.serverId;
152
+ const resolvedPath = resolveExecutable(executable);
153
+ const configuredIn = configState
154
+ .filter((state) => state.serverIds.includes(server.serverId))
155
+ .map((state) => state.path);
156
+
157
+ results.push({
158
+ server,
159
+ executable,
160
+ installed: resolvedPath !== null,
161
+ resolvedPath,
162
+ configuredIn,
163
+ });
164
+ }
165
+
166
+ return results;
167
+ }
168
+
169
+ function renderReport(
170
+ root: string,
171
+ results: readonly DetectionResult[],
172
+ configState: readonly ConfigFileState[],
173
+ ): string {
174
+ const lines: string[] = [`LSP setup scan: ${root}`];
175
+ const configSummary = configState
176
+ .map(
177
+ (state) =>
178
+ `${state.path} (${state.exists ? `present: ${state.serverIds.length} server(s)` : "absent"})`,
179
+ )
180
+ .join(", ");
181
+ lines.push(`Config files: ${configSummary}`, "");
182
+
183
+ if (results.length === 0) {
184
+ lines.push("No languages with a builtin LSP server were detected here.");
185
+ return lines.join("\n");
186
+ }
187
+
188
+ lines.push("DETECTED LANGUAGES (primary builtin server per language)");
189
+ for (const result of results) {
190
+ const mark = result.installed ? "OK " : "MISS";
191
+ const state = result.installed ? `installed (${result.resolvedPath})` : "NOT installed";
192
+ const config =
193
+ result.configuredIn.length > 0
194
+ ? `configured in ${result.configuredIn.join(", ")}`
195
+ : "builtin-default";
196
+ lines.push(
197
+ `[${mark}] ${result.server.language.padEnd(12)} server=${result.server.serverId} exe=${result.executable} ${state} ${config}`,
198
+ );
199
+ if (!result.installed) lines.push(` install: ${result.server.installHint}`);
200
+ }
201
+
202
+ const missing = results.filter((result) => !result.installed);
203
+ lines.push(
204
+ "",
205
+ missing.length === 0
206
+ ? `All ${results.length} detected server(s) installed.`
207
+ : `${missing.length}/${results.length} server(s) NOT installed: ${missing.map((m) => m.server.language).join(", ")}`,
208
+ "Next: read references/<language>/README.md, then configure .codex/lsp-client.json AND .codex/lsp.json.",
209
+ );
210
+ return lines.join("\n");
211
+ }
212
+
213
+ function main(): void {
214
+ const args = process.argv.slice(2);
215
+ const wantsJson = args.includes("--json");
216
+ const root = args.find((arg: string) => !arg.startsWith("--")) ?? process.cwd();
217
+
218
+ if (!existsSync(root)) {
219
+ process.stderr.write(`detect-lsp: target directory does not exist: ${root}\n`);
220
+ process.exit(2);
221
+ }
222
+
223
+ const configState = readConfigState(root);
224
+ const results = detect(root, configState);
225
+
226
+ if (wantsJson) {
227
+ process.stdout.write(`${JSON.stringify({ root, configState, results }, null, 2)}\n`);
228
+ return;
229
+ }
230
+ process.stdout.write(`${renderReport(root, results, configState)}\n`);
231
+ }
232
+
233
+ main();
@@ -0,0 +1,188 @@
1
+ // SOURCE OF TRUTH: packages/lsp-tools-mcp/src/lsp/server-definitions.ts
2
+ // (BUILTIN_SERVERS + LSP_INSTALL_HINTS). This is a hand-maintained snapshot of
3
+ // the primary builtin server per reference language, embedded so detect-lsp.ts
4
+ // runs standalone in any user project. Mirror command/extensions when that file
5
+ // changes.
6
+
7
+ export interface LanguageServer {
8
+ readonly language: string;
9
+ readonly serverId: string;
10
+ readonly command: readonly string[];
11
+ readonly extensions: readonly string[];
12
+ readonly installHint: string;
13
+ }
14
+
15
+ export const LANGUAGES: readonly LanguageServer[] = [
16
+ {
17
+ language: "typescript",
18
+ serverId: "typescript",
19
+ command: ["typescript-language-server", "--stdio"],
20
+ extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"],
21
+ installHint: "npm install -g typescript-language-server typescript",
22
+ },
23
+ {
24
+ language: "python",
25
+ serverId: "basedpyright",
26
+ command: ["basedpyright-langserver", "--stdio"],
27
+ extensions: [".py", ".pyi"],
28
+ installHint: "pip install basedpyright (or: uv tool install basedpyright)",
29
+ },
30
+ {
31
+ language: "go",
32
+ serverId: "gopls",
33
+ command: ["gopls"],
34
+ extensions: [".go"],
35
+ installHint: "go install golang.org/x/tools/gopls@latest",
36
+ },
37
+ {
38
+ language: "rust",
39
+ serverId: "rust",
40
+ command: ["rust-analyzer"],
41
+ extensions: [".rs"],
42
+ installHint: "rustup component add rust-analyzer",
43
+ },
44
+ {
45
+ language: "c-cpp",
46
+ serverId: "clangd",
47
+ command: ["clangd", "--background-index", "--clang-tidy"],
48
+ extensions: [".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"],
49
+ installHint:
50
+ "macOS: brew install llvm | Linux: apt install clangd | https://clangd.llvm.org/installation",
51
+ },
52
+ {
53
+ language: "java",
54
+ serverId: "jdtls",
55
+ command: ["jdtls"],
56
+ extensions: [".java"],
57
+ installHint: "macOS: brew install jdtls | https://github.com/eclipse-jdtls/eclipse.jdt.ls",
58
+ },
59
+ {
60
+ language: "kotlin",
61
+ serverId: "kotlin-ls",
62
+ command: ["kotlin-lsp"],
63
+ extensions: [".kt", ".kts"],
64
+ installHint: "https://github.com/Kotlin/kotlin-lsp",
65
+ },
66
+ {
67
+ language: "csharp",
68
+ serverId: "csharp",
69
+ command: ["csharp-ls"],
70
+ extensions: [".cs"],
71
+ installHint: "dotnet tool install -g csharp-ls",
72
+ },
73
+ {
74
+ language: "razor",
75
+ serverId: "razor",
76
+ command: ["roslyn-language-server", "--stdio"],
77
+ extensions: [".razor", ".cshtml"],
78
+ installHint:
79
+ "dotnet tool install -g roslyn-language-server --prerelease (see references/csharp/README.md)",
80
+ },
81
+ {
82
+ language: "swift",
83
+ serverId: "sourcekit-lsp",
84
+ command: ["sourcekit-lsp"],
85
+ extensions: [".swift", ".objc", ".objcpp"],
86
+ installHint: "Included with Xcode (xcode-select --install) or the Swift toolchain",
87
+ },
88
+ {
89
+ language: "ruby",
90
+ serverId: "ruby-lsp",
91
+ command: ["rubocop", "--lsp"],
92
+ extensions: [".rb", ".rake", ".gemspec", ".ru"],
93
+ installHint: "gem install ruby-lsp (builtin runs `rubocop --lsp`; gem install rubocop)",
94
+ },
95
+ {
96
+ language: "php",
97
+ serverId: "php",
98
+ command: ["intelephense", "--stdio"],
99
+ extensions: [".php"],
100
+ installHint: "npm install -g intelephense",
101
+ },
102
+ {
103
+ language: "dart",
104
+ serverId: "dart",
105
+ command: ["dart", "language-server", "--lsp"],
106
+ extensions: [".dart"],
107
+ installHint: "Included with the Dart/Flutter SDK",
108
+ },
109
+ {
110
+ language: "elixir",
111
+ serverId: "elixir-ls",
112
+ command: ["elixir-ls"],
113
+ extensions: [".ex", ".exs"],
114
+ installHint: "https://github.com/elixir-lsp/elixir-ls",
115
+ },
116
+ {
117
+ language: "zig",
118
+ serverId: "zls",
119
+ command: ["zls"],
120
+ extensions: [".zig", ".zon"],
121
+ installHint: "https://github.com/zigtools/zls (match zls version to your zig version)",
122
+ },
123
+ {
124
+ language: "lua",
125
+ serverId: "lua-ls",
126
+ command: ["lua-language-server"],
127
+ extensions: [".lua"],
128
+ installHint:
129
+ "macOS: brew install lua-language-server | https://github.com/LuaLS/lua-language-server",
130
+ },
131
+ {
132
+ language: "bash",
133
+ serverId: "bash",
134
+ command: ["bash-language-server", "start"],
135
+ extensions: [".sh", ".bash", ".zsh", ".ksh"],
136
+ installHint: "npm install -g bash-language-server",
137
+ },
138
+ {
139
+ language: "yaml",
140
+ serverId: "yaml-ls",
141
+ command: ["yaml-language-server", "--stdio"],
142
+ extensions: [".yaml", ".yml"],
143
+ installHint: "npm install -g yaml-language-server",
144
+ },
145
+ {
146
+ language: "terraform",
147
+ serverId: "terraform",
148
+ command: ["terraform-ls", "serve"],
149
+ extensions: [".tf", ".tfvars"],
150
+ installHint:
151
+ "macOS: brew install hashicorp/tap/terraform-ls | https://github.com/hashicorp/terraform-ls",
152
+ },
153
+ {
154
+ language: "dockerfile",
155
+ serverId: "dockerfile",
156
+ command: ["docker-langserver", "--stdio"],
157
+ extensions: [".dockerfile"],
158
+ installHint: "npm install -g dockerfile-language-server-nodejs",
159
+ },
160
+ {
161
+ language: "haskell",
162
+ serverId: "haskell-language-server",
163
+ command: ["haskell-language-server-wrapper", "--lsp"],
164
+ extensions: [".hs", ".lhs"],
165
+ installHint: "ghcup install hls",
166
+ },
167
+ {
168
+ language: "julia",
169
+ serverId: "julials",
170
+ command: [
171
+ "julia",
172
+ "--startup-file=no",
173
+ "--history-file=no",
174
+ "-e",
175
+ "using LanguageServer; runserver()",
176
+ ],
177
+ extensions: [".jl"],
178
+ installHint:
179
+ "julia -e 'using Pkg; Pkg.add(\"LanguageServer\")' (see references/julia/README.md)",
180
+ },
181
+ ] as const;
182
+
183
+ export const PROJECT_CONFIG_FILES: readonly string[] = [
184
+ ".codex/lsp-client.json",
185
+ ".codex/lsp.json",
186
+ ".codex/lsp.json",
187
+ ".codex/lsp-client.json",
188
+ ] as const;
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "noUncheckedIndexedAccess": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "noEmit": true,
13
+ "lib": ["ESNext"],
14
+ "types": ["bun-types"]
15
+ },
16
+ "include": ["*.ts"]
17
+ }