Repository navigation
chore: rename packages to @frontal-labs/code-* and add Zed extension #143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package(default_visibility = ["//visibility:public"]) | ||
|
|
||
| filegroup( | ||
| name = "srcs", | ||
| srcs = glob( | ||
| ["**/*"], | ||
| exclude = [ | ||
| "node_modules/**", | ||
| ".git/**", | ||
| "BUILD.bazel", | ||
| ], | ||
| ), | ||
| ) | ||
|
|
||
| sh_test( | ||
| name = "lint", | ||
| size = "small", | ||
| srcs = ["//tools:extension.sh"], | ||
| data = [":srcs", "//:biome.json", "//:ultracite.json", "//:.gitignore", "package.json"], | ||
| args = [ | ||
| "extensions/zed", | ||
| "lint", | ||
| ], | ||
| tags = [ | ||
| "lint", | ||
| "typescript", | ||
| ], | ||
| ) | ||
|
|
||
| sh_test( | ||
| name = "build", | ||
| srcs = ["//tools:extension.sh"], | ||
| data = [":srcs", "//:biome.json", "//:ultracite.json", "//:.gitignore", "package.json"], | ||
| args = [ | ||
| "extensions/zed", | ||
| "build", | ||
| ], | ||
| tags = [ | ||
| "build", | ||
| "typescript", | ||
| ], | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Frontal Code Zed Extension | ||
|
|
||
| Local Frontal Code integration for the [Zed](https://zed.dev) editor. | ||
|
|
||
| ## Commands | ||
|
|
||
| - `frontal-code.startRepl` — Start the Frontal Code REPL | ||
| - `frontal-code.askInput` — Ask Frontal Code a question | ||
| - `frontal-code.askSelection` — Ask Frontal Code about the current selection | ||
|
|
||
| ## Settings | ||
|
|
||
| - `frontal-code.cliPath` (default: `frontal-code` from PATH, or `code`) | ||
|
|
||
| ## Installation | ||
|
|
||
| Zed discovers extensions placed in `~/.config/zed/extensions/` or workspace-level `extensions/` directories. Copy or symlink the contents of this package into your Zed extensions directory, or use `zed extension install` from a published marketplace entry. | ||
|
|
||
| ## `/ide` Integration | ||
|
|
||
| `/ide` currently supports `vscode`, `cursor`, `antigravity`, and `windsurf`. Zed support will be added as a future target. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| const { zed } = require("@zed-industries/extension-api"); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implement the integration through Zed's supported extension host. Zed loads an Replace this implementation and manifest with a supported Zed integration. Select a supported extension capability before wiring the CLI commands.
|
||
| const { execFile } = require("node:child_process"); | ||
| const { accessSync, constants } = require("node:fs"); | ||
| const path = require("node:path"); | ||
|
|
||
| // The two names every install channel provides for the same CLI. | ||
| const COMMAND_NAMES = ["frontal-code", "code"]; | ||
|
|
||
| /** @param {import("@zed-industries/extension-api").ExtensionContext} context */ | ||
| function activate(context) { | ||
| context.subscriptions.push( | ||
| zed.registerCommand("frontal-code.startRepl", () => startRepl()), | ||
| zed.registerCommand("frontal-code.askSelection", () => askSelection()), | ||
| zed.registerCommand("frontal-code.askInput", () => askInput()), | ||
| ); | ||
| } | ||
|
|
||
| function deactivate() { | ||
| // Intentionally empty: Zed owns extension teardown. | ||
| } | ||
|
|
||
| function frontalCodeCliPath() { | ||
| const inspected = zed.config().get("frontal-code.cliPath"); | ||
| const value = | ||
| typeof inspected === "string" && inspected.trim().length > 0 | ||
| ? inspected.trim() | ||
| : defaultCliCommand(); | ||
| return value; | ||
| } | ||
|
|
||
| // `frontal-code` when it is on PATH, otherwise `code`: the same program under either name. | ||
| function defaultCliCommand() { | ||
| for (const name of COMMAND_NAMES) { | ||
| if (isOnPath(name)) { | ||
| return name; | ||
| } | ||
| } | ||
| return COMMAND_NAMES[0]; | ||
| } | ||
|
|
||
| function isOnPath(name) { | ||
| const dirs = (process.env.PATH || "").split(path.delimiter).filter((dir) => dir.length > 0); | ||
| const suffixes = process.platform === "win32" ? [".exe", ""] : [""]; | ||
| return dirs.some((dir) => | ||
| suffixes.some((suffix) => { | ||
| try { | ||
| accessSync(path.join(dir, name + suffix), constants.X_OK); | ||
| return true; | ||
| } catch { | ||
| return false; | ||
| } | ||
| }), | ||
| ); | ||
| } | ||
|
|
||
| function startRepl() { | ||
| if (!requireTrustedWorkspace()) { | ||
| return; | ||
| } | ||
| const terminal = zed.window.createTerminal({ | ||
| name: "Frontal Code", | ||
| shellPath: frontalCodeCliPath(), | ||
| shellArgs: [], | ||
| }); | ||
| terminal.show(true); | ||
| } | ||
|
|
||
| function requireTrustedWorkspace() { | ||
| if (zed.workspace.isTrusted) { | ||
| return true; | ||
| } | ||
| zed.window.showWarningMessage("Frontal Code: trust this workspace to run the CLI."); | ||
| return false; | ||
| } | ||
|
|
||
| async function askInput() { | ||
| const question = await zed.window.showInputBox({ | ||
| prompt: "Ask Frontal Code", | ||
| placeHolder: "Explain the active file", | ||
| }); | ||
| if (!question?.trim()) { | ||
| return; | ||
| } | ||
| await runFrontalCodePrompt(question.trim()); | ||
| } | ||
|
|
||
| async function askSelection() { | ||
| const editor = zed.window.activeTextEditor; | ||
| if (!editor) { | ||
| zed.window.showWarningMessage("Frontal Code: open an editor first."); | ||
| return; | ||
| } | ||
| const selected = editor.document.getText(editor.selection).trim(); | ||
| if (!selected) { | ||
| zed.window.showWarningMessage("Frontal Code: select some text first."); | ||
| return; | ||
| } | ||
| const question = await zed.window.showInputBox({ | ||
| prompt: "What should Frontal Code do with this selection?", | ||
| placeHolder: "Explain this code", | ||
| }); | ||
| if (!question?.trim()) { | ||
| return; | ||
| } | ||
| const prompt = `${question.trim()}\n\nSelected code:\n${selected}`; | ||
| await runFrontalCodePrompt(prompt); | ||
| } | ||
|
|
||
| async function runFrontalCodePrompt(prompt) { | ||
| if (!requireTrustedWorkspace()) { | ||
| return; | ||
| } | ||
| const output = zed.window.createOutputChannel("Frontal Code"); | ||
| output.show(true); | ||
| output.appendLine("Running Frontal Code..."); | ||
|
|
||
| const args = ["--output-format", "text", "prompt", prompt]; | ||
| const cwd = zed.workspace.workspaceFolders?.[0]?.uri?.fsPath; | ||
| const execOptions = cwd ? { cwd, maxBuffer: 16 * 1024 * 1024 } : { maxBuffer: 16 * 1024 * 1024 }; | ||
|
|
||
| const startedAt = Date.now(); | ||
| execFile(frontalCodeCliPath(), args, execOptions, (error, stdout, stderr) => { | ||
| const elapsedMs = Date.now() - startedAt; | ||
| output.appendLine(`Frontal Code finished in ${elapsedMs} ms.`); | ||
| if (stdout?.trim()) { | ||
| output.appendLine(""); | ||
| output.appendLine(stdout.trimEnd()); | ||
| } | ||
| if (stderr?.trim()) { | ||
| output.appendLine(""); | ||
| output.appendLine("stderr:"); | ||
| output.appendLine(stderr.trimEnd()); | ||
| } | ||
|
|
||
| if (error) { | ||
| const message = `Frontal Code command failed: ${error.message}`; | ||
| output.appendLine(message); | ||
| zed.window.showErrorMessage(message); | ||
| return; | ||
| } | ||
|
|
||
| zed.window.showInformationMessage("Frontal Code response ready."); | ||
| }); | ||
| } | ||
|
|
||
| module.exports = { | ||
| activate, | ||
| deactivate, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| { | ||
| "name": "@frontal-labs/code-zed", | ||
| "displayName": "Frontal Code Zed", | ||
| "description": "Frontal Code integration for the Zed editor", | ||
| "version": "0.1.0", | ||
| "publisher": "frontal-labs", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/frontal-labs/code.git", | ||
| "directory": "extensions/zed" | ||
| }, | ||
| "keywords": [ | ||
| "frontal-code", | ||
| "zed", | ||
| "extension" | ||
| ], | ||
| "author": "Frontal Labs", | ||
| "license": "Apache-2.0", | ||
| "scripts": { | ||
| "build": "node --check extension.js" | ||
| }, | ||
| "dependencies": { | ||
| "@zed-industries/extension-api": "^0.4.2" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Declared extension API package is not on the public npm registry.
Zed documents its extension API as the Rust curl --fail-with-body --silent --show-error \
'https://registry.npmjs.org/@zed-industries%2Fextension-api' |
python -c 'import json,sys; d=json.load(sys.stdin); print(d.get("error", sorted(d.get("versions", {}))))'
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| { | ||
| "id": "frontal-code", | ||
| "name": "Frontal Code", | ||
| "description": "Frontal Code integration for the Zed editor", | ||
| "version": "0.1.0", | ||
| "author": { | ||
| "name": "Frontal Labs" | ||
| }, | ||
| "homepage": "https://github.com/frontal-labs/code", | ||
| "repository": "https://github.com/frontal-labs/code", | ||
| "license": "Apache-2.0", | ||
| "icon": "", | ||
| "features": { | ||
| "commands": { | ||
| "startRepl": "Start the Frontal Code REPL", | ||
| "askSelection": "Ask Frontal Code about the current selection", | ||
| "askInput": "Ask Frontal Code a question" | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use a valid VS Code extension name.
@frontal-labs/code-vscodecontains@and/, which VS Code's packaging tool rejects.vsce packagetherefore cannot produce a VSIX. Use an unscoped extension name and keep the organization in thepublisherfield. (raw.githubusercontent.com)