From d34ee3be0a5710382939581b078f7b826bde994e Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 14 Apr 2026 16:22:14 -0700 Subject: [PATCH 1/7] remove editor install step --- commands/create.ts | 45 ++++++--------------------------------------- 1 file changed, 6 insertions(+), 39 deletions(-) diff --git a/commands/create.ts b/commands/create.ts index 828811d..06ac8b7 100644 --- a/commands/create.ts +++ b/commands/create.ts @@ -1,9 +1,7 @@ -import { blue, bold, green } from "@std/fmt/colors"; +import { bold, green } from "@std/fmt/colors"; import { Input } from "@cliffy/prompt/input"; import * as path from "@std/path"; import { Confirm } from "@cliffy/prompt/confirm"; -import { delay } from "@std/async/delay"; -import { Spinner } from "@std/cli/unstable-spinner"; import { promptToInstallSkills } from "./skills.ts"; import type { CommonCommandOptions } from "./common.ts"; @@ -55,6 +53,11 @@ const Cursor: Editor = { }; async function openInEditorFlow(filename: string) { + const editor = await detectPreferredAndInstalledEditor(); + if (!editor) { + return; + } + console.log(); const openInEditor = await Confirm.prompt({ message: "Open created glue in editor?", @@ -62,18 +65,6 @@ async function openInEditorFlow(filename: string) { }); if (openInEditor) { - let editor = await detectPreferredAndInstalledEditor(); - if (!editor) { - const installCursor = await Confirm.prompt({ - message: "No editors found, install Cursor (recommended)?", - default: true, - }); - if (!installCursor) { - return; - } - await installEditor(Cursor); - editor = Cursor; - } await openEditor(editor, filename); } } @@ -106,30 +97,6 @@ async function isEditorInstalled(editor: Editor): Promise { } } -async function installEditor(editor: Editor): Promise { - if (Deno.build.os == "darwin") { - // TODO in the future we may install for the user - console.log(`Download and ${editor.name} install from: ${blue(bold(editor.installPage))}`); - } else { - console.log(`Download and ${editor.name} install from: ${blue(bold(editor.installPage))}`); - } - - const spinner = new Spinner({ - message: `Waiting for ${editor.name} to be installed...`, - }); - spinner.start(); - - while (true) { - try { - await new Deno.Command(editor.command, { args: ["--version"] }).output(); - break; - } catch (_e) { - await delay(1000); - } - } - spinner.stop(); -} - async function openEditor(editor: Editor, filename: string): Promise { await new Deno.Command(editor.command, { args: [filename] }).output(); } From 92e80e6cbcd7a2048c65976df0430d4d030dad5e Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 14 Apr 2026 16:24:44 -0700 Subject: [PATCH 2/7] don't prompt to install skills until after making glue file --- commands/create.ts | 4 ++-- commands/skills.ts | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/commands/create.ts b/commands/create.ts index 06ac8b7..5b0e18a 100644 --- a/commands/create.ts +++ b/commands/create.ts @@ -14,8 +14,6 @@ glue.webhook.onGet((_event) => { `; export async function create(_options: CommonCommandOptions) { - await promptToInstallSkills(); - let filename = await Input.prompt({ message: "Enter the filename for the new glue", default: DEFAULT_FILENAME, @@ -26,6 +24,8 @@ export async function create(_options: CommonCommandOptions) { await Deno.writeTextFile(filename, code); console.log(`${green("āœ”ļøŽ")} Successfully created new glue file: ${bold(filename)}`); + await promptToInstallSkills(); + await openInEditorFlow(filename); console.log(); console.log(`šŸ’” Run locally using ${green("glue dev " + filename)}`); diff --git a/commands/skills.ts b/commands/skills.ts index a9ac68e..36e63d0 100644 --- a/commands/skills.ts +++ b/commands/skills.ts @@ -87,6 +87,10 @@ export async function promptToInstallSkills(): Promise { return; } + console.log(); + console.log( + "We noticed you have Codex or Claude Code installed but don't have the Glue skill installed for them.", + ); const shouldInstall = await Confirm.prompt({ message: "Install the Glue agent skill for Codex or Claude Code now?", default: true, From c6093ed6fea259eef8d1fdbe72df2ccb1f8516c4 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 14 Apr 2026 16:35:49 -0700 Subject: [PATCH 3/7] simplify editor handling --- commands/create.ts | 49 ++++++++++++---------------------------------- commands/skills.ts | 4 ++++ 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/commands/create.ts b/commands/create.ts index 5b0e18a..81da6be 100644 --- a/commands/create.ts +++ b/commands/create.ts @@ -32,25 +32,7 @@ export async function create(_options: CommonCommandOptions) { return filename; } -interface Editor { - name: string; - command: string; - installPage: string; - macOSDownloadUrl: string; -} - -const VSCode: Editor = { - name: "VSCode", - command: "code", - installPage: "https://code.visualstudio.com/download", - macOSDownloadUrl: "https://code.visualstudio.com/download", -}; -const Cursor: Editor = { - name: "Cursor", - command: "cursor", - installPage: "https://cursor.com/download", - macOSDownloadUrl: "https://cursor.sh", -}; +const defaultEditors = ["cursor", "code", "zed"]; async function openInEditorFlow(filename: string) { const editor = await detectPreferredAndInstalledEditor(); @@ -60,7 +42,7 @@ async function openInEditorFlow(filename: string) { console.log(); const openInEditor = await Confirm.prompt({ - message: "Open created glue in editor?", + message: `Open created glue in editor? (Detected: ${editor})`, default: true, }); @@ -69,36 +51,31 @@ async function openInEditorFlow(filename: string) { } } -async function detectPreferredAndInstalledEditor(): Promise { +async function detectPreferredAndInstalledEditor(): Promise { const editorEnv = Deno.env.get("EDITOR"); const firstTerm = editorEnv?.split(/\s+/)[0]; - if (firstTerm === VSCode.command) { - return VSCode; - } - if (firstTerm === Cursor.command) { - return Cursor; + if (firstTerm && defaultEditors.includes(firstTerm)) { + return firstTerm; } - - if (await isEditorInstalled(Cursor)) { - return Cursor; - } - if (await isEditorInstalled(VSCode)) { - return VSCode; + for (const cmd of defaultEditors) { + if (await isEditorInstalled(cmd)) { + return cmd; + } } return undefined; } -async function isEditorInstalled(editor: Editor): Promise { +async function isEditorInstalled(editorCommand: string): Promise { try { - await new Deno.Command(editor.command, { args: ["--version"] }).output(); + await new Deno.Command(editorCommand, { args: ["--version"] }).output(); return true; } catch (_error) { return false; } } -async function openEditor(editor: Editor, filename: string): Promise { - await new Deno.Command(editor.command, { args: [filename] }).output(); +async function openEditor(editorCommand: string, filename: string): Promise { + await new Deno.Command(editorCommand, { args: [filename] }).output(); } function appendFileExtensionIfNotPresent(filename: string, extension: string): string { diff --git a/commands/skills.ts b/commands/skills.ts index 36e63d0..e1b6247 100644 --- a/commands/skills.ts +++ b/commands/skills.ts @@ -69,6 +69,10 @@ export async function installSkills(): Promise { ); } +/** + * Called at the end of `glue create` to offer to install the Glue skill if we + * detect a supported agent is installed. + */ export async function promptToInstallSkills(): Promise { const home = requireHomeDirectory(); From 89a0c068f7deeecad9bee0bb16725fb8b5036bea Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 14 Apr 2026 16:44:47 -0700 Subject: [PATCH 4/7] print IDE recommendations if none are found --- commands/create.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/commands/create.ts b/commands/create.ts index 81da6be..6f88c95 100644 --- a/commands/create.ts +++ b/commands/create.ts @@ -37,6 +37,12 @@ const defaultEditors = ["cursor", "code", "zed"]; async function openInEditorFlow(filename: string) { const editor = await detectPreferredAndInstalledEditor(); if (!editor) { + console.log(); + console.log("Couldn't detect a preferred IDE installed on your system."); + console.log("You may open the created glue file in any text editor."); + console.log( + "We recommend using an IDE such as Cursor (https://cursor.com/) or\nVisual Studio Code (https://code.visualstudio.com/).", + ); return; } From 486aac3ca53dd5d082e3eee831720c21ad05070a Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 14 Apr 2026 16:48:18 -0700 Subject: [PATCH 5/7] don't allow overwriting files --- commands/create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/create.ts b/commands/create.ts index 6f88c95..0fca100 100644 --- a/commands/create.ts +++ b/commands/create.ts @@ -21,7 +21,7 @@ export async function create(_options: CommonCommandOptions) { const code = TEMPLATE_CONTENT; filename = await uniquifyPath(filename); filename = appendFileExtensionIfNotPresent(filename, ".ts"); - await Deno.writeTextFile(filename, code); + await Deno.writeTextFile(filename, code, { createNew: true }); console.log(`${green("āœ”ļøŽ")} Successfully created new glue file: ${bold(filename)}`); await promptToInstallSkills(); From a96ad3d43103100de65a47e40aa8c6f0ebfd9443 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 14 Apr 2026 16:48:45 -0700 Subject: [PATCH 6/7] fix bug where non-unique filename could be used --- commands/create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/create.ts b/commands/create.ts index 0fca100..3930bf9 100644 --- a/commands/create.ts +++ b/commands/create.ts @@ -19,8 +19,8 @@ export async function create(_options: CommonCommandOptions) { default: DEFAULT_FILENAME, }); const code = TEMPLATE_CONTENT; - filename = await uniquifyPath(filename); filename = appendFileExtensionIfNotPresent(filename, ".ts"); + filename = await uniquifyPath(filename); await Deno.writeTextFile(filename, code, { createNew: true }); console.log(`${green("āœ”ļøŽ")} Successfully created new glue file: ${bold(filename)}`); From 8b23e4db11e4f954ccc82894b03663f7a02293ae Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 14 Apr 2026 16:52:23 -0700 Subject: [PATCH 7/7] recommend glue install-skills command --- commands/login.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/commands/login.ts b/commands/login.ts index 4fd0fa5..098b04f 100644 --- a/commands/login.ts +++ b/commands/login.ts @@ -39,5 +39,8 @@ export const login = async () => { await open(loginUrl); await server.finished; - console.log(`\nšŸ’” Run ${mod.green("glue create")} to create your first glue`); + console.log(`\nšŸ’” Run ${mod.green("glue create")} to create your first glue.`); + console.log( + `šŸ’” Run ${mod.green("glue install-skills")} to teach your local coding agents how to use Glue.`, + ); };