Skip to content
This repository was archived by the owner on Jan 29, 2026. It is now read-only.

Commit 81c59df

Browse files
authored
Fix: Use full GitHub URLs in extension installation commands (#76)
This pull request updates all documentation to clarify and enforce the correct installation method for the `gemini-flow` extension. The shorthand `github:username/repo` syntax is no longer supported; users must use the full GitHub URL (`https://github.com/username/repo`) when installing extensions via the Gemini CLI. Additional notes and warnings have been added to prevent installation errors. **Documentation updates to installation instructions:** * Updated all references in `GEMINI.md`, `README.md`, `docs/releases/GEMINI_CLI_EXTENSIONS_IMPLEMENTATION.md`, and `extensions/gemini-cli/README.md` to use the full GitHub URL for `gemini extensions install`, replacing the unsupported shorthand syntax. [[1]](diffhunk://#diff-399080f41ccf73c6004e0f85c0a58fc1767080a0ef19bb3f3a90caa14f94bd79L32-R32) [[2]](diffhunk://#diff-399080f41ccf73c6004e0f85c0a58fc1767080a0ef19bb3f3a90caa14f94bd79L160-R162) [[3]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L39-R39) [[4]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L492-R492) [[5]](diffhunk://#diff-907131cd4052ab578e08c0789774605fdae373f9dc8bc7ac72acd792b9dd5fb6L86-R90) [[6]](diffhunk://#diff-907131cd4052ab578e08c0789774605fdae373f9dc8bc7ac72acd792b9dd5fb6L279-R279) [[7]](diffhunk://#diff-3fa8814b6d943af60390c832bc271fbe00a4a1085d269289cf705e159eb68d8aL20-R24) * Updated extension management command examples to use the full GitHub URL for installing additional extensions, ensuring consistency and preventing user confusion. [[1]](diffhunk://#diff-399080f41ccf73c6004e0f85c0a58fc1767080a0ef19bb3f3a90caa14f94bd79L103-R105) [[2]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L563-R565) [[3]](diffhunk://#diff-907131cd4052ab578e08c0789774605fdae373f9dc8bc7ac72acd792b9dd5fb6L86-R90) * Added explicit notes and warnings in the documentation to inform users that the shorthand syntax is not supported and will cause installation errors. [[1]](diffhunk://#diff-399080f41ccf73c6004e0f85c0a58fc1767080a0ef19bb3f3a90caa14f94bd79R42-R43) [[2]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R502-R503) [[3]](diffhunk://#diff-3fa8814b6d943af60390c832bc271fbe00a4a1085d269289cf705e159eb68d8aL20-R24)
1 parent 8e22487 commit 81c59df

File tree

8 files changed

+562
-15
lines changed

8 files changed

+562
-15
lines changed

GEMINI.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ gemini-flow is now available as an official Gemini CLI extension, packaging:
2929

3030
```bash
3131
# Install from GitHub
32-
gemini extensions install github:clduab11/gemini-flow
32+
gemini extensions install https://github.com/clduab11/gemini-flow
3333

3434
# Install from local clone
3535
cd /path/to/gemini-flow
@@ -39,6 +39,8 @@ gemini extensions install .
3939
gemini extensions enable gemini-flow
4040
```
4141

42+
> **⚠️ Important**: Use the full GitHub URL (`https://github.com/clduab11/gemini-flow`). The shorthand syntax `github:username/repo` is **not supported** and will cause installation errors.
43+
4244
### Using gemini-flow Commands
4345

4446
Once enabled, use gemini-flow commands directly in Gemini CLI:
@@ -100,7 +102,7 @@ gemini-flow also includes its own extension management commands:
100102

101103
```bash
102104
# Using gem-extensions command
103-
gemini-flow gem-extensions install github:user/extension
105+
gemini-flow gem-extensions install https://github.com/user/extension
104106
gemini-flow gem-extensions list
105107
gemini-flow gem-extensions enable extension-name
106108
gemini-flow gem-extensions info extension-name
@@ -157,7 +159,7 @@ This documentation is specifically engineered for **Gemini Code Assist** using G
157159
gemini-flow is now available as an official Gemini CLI extension. Install it with:
158160

159161
```bash
160-
gemini extensions install github:clduab11/gemini-flow
162+
gemini extensions install https://github.com/clduab11/gemini-flow
161163
```
162164

163165
---

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ gemini-flow init --protocols a2a,mcp --topology hierarchical
3636
gemini-flow agents spawn --count 50 --specialization "enterprise-ready"
3737

3838
# NEW: Official Gemini CLI Extension (October 8, 2025)
39-
gemini extensions install github:clduab11/gemini-flow # Install as Gemini extension
40-
gemini extensions enable gemini-flow # Enable the extension
41-
gemini hive-mind spawn "Build AI application" # Use commands in Gemini CLI
39+
gemini extensions install https://github.com/clduab11/gemini-flow # Install as Gemini extension
40+
gemini extensions enable gemini-flow # Enable the extension
41+
gemini hive-mind spawn "Build AI application" # Use commands in Gemini CLI
4242
```
4343

4444
**🚀 Modern Protocol Support**: Native A2A and MCP integration for seamless inter-agent communication and model coordination
@@ -489,7 +489,7 @@ gemini-flow is now available as an **official Gemini CLI extension**, providing
489489

490490
```bash
491491
# Install from GitHub
492-
gemini extensions install github:clduab11/gemini-flow
492+
gemini extensions install https://github.com/clduab11/gemini-flow
493493

494494
# Install from local clone
495495
cd /path/to/gemini-flow
@@ -499,6 +499,8 @@ gemini extensions install .
499499
gemini extensions enable gemini-flow
500500
```
501501

502+
> **Note**: Always use the full GitHub URL format (`https://github.com/username/repo`). The shorthand syntax `github:username/repo` is **not supported** by Gemini CLI and will result in "Install source not found" errors.
503+
502504
### What's Included
503505

504506
The extension packages gemini-flow's complete AI orchestration platform:
@@ -560,7 +562,7 @@ gemini-flow also includes its own extension management commands:
560562

561563
```bash
562564
# Using gem-extensions command
563-
gemini-flow gem-extensions install github:user/extension
565+
gemini-flow gem-extensions install https://github.com/user/extension
564566
gemini-flow gem-extensions list
565567
gemini-flow gem-extensions enable extension-name
566568
gemini-flow gem-extensions info extension-name
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/**
2+
* Gemini CLI Extensions Command
3+
*
4+
* Manages Gemini CLI Extensions (October 2025 framework).
5+
* Supports install, enable, disable, update, uninstall, list, and info commands.
6+
*/
7+
import { Command } from "commander";
8+
import chalk from "chalk";
9+
import ora from "ora";
10+
import { Logger } from "../../utils/logger.js";
11+
import { getExtensionManager } from "../../services/extension-manager.js";
12+
export class GemExtensionsCommand extends Command {
13+
constructor() {
14+
super("gem-extensions");
15+
this.logger = new Logger("GemExtensions");
16+
this.description("Manage Gemini CLI Extensions (Official Framework)")
17+
.alias("gem-ext")
18+
.addCommand(this.createInstallCommand())
19+
.addCommand(this.createListCommand())
20+
.addCommand(this.createEnableCommand())
21+
.addCommand(this.createDisableCommand())
22+
.addCommand(this.createUpdateCommand())
23+
.addCommand(this.createUninstallCommand())
24+
.addCommand(this.createInfoCommand());
25+
}
26+
/**
27+
* Install command
28+
*/
29+
createInstallCommand() {
30+
return new Command("install")
31+
.description("Install extension from GitHub or local path")
32+
.argument("<source>", "GitHub URL (github:user/repo) or local path")
33+
.option("--enable", "Enable extension after installation", false)
34+
.action(async (source, options) => {
35+
const spinner = ora(`Installing extension from ${source}...`).start();
36+
try {
37+
const manager = getExtensionManager();
38+
const metadata = await manager.install(source);
39+
spinner.succeed(`Extension ${chalk.bold(metadata.name)} installed`);
40+
console.log(chalk.blue("\n📦 Extension Details:"));
41+
console.log(chalk.gray(` Name: ${metadata.name}`));
42+
console.log(chalk.gray(` Version: ${metadata.version}`));
43+
console.log(chalk.gray(` Description: ${metadata.description || 'N/A'}`));
44+
if (options.enable) {
45+
spinner.start("Enabling extension...");
46+
await manager.enable(metadata.name);
47+
spinner.succeed(`Extension ${chalk.bold(metadata.name)} enabled`);
48+
}
49+
else {
50+
console.log(chalk.yellow("\n💡 Run 'gem-extensions enable ${metadata.name}' to activate"));
51+
}
52+
}
53+
catch (error) {
54+
spinner.fail("Installation failed");
55+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : error);
56+
process.exit(1);
57+
}
58+
});
59+
}
60+
/**
61+
* List command
62+
*/
63+
createListCommand() {
64+
return new Command("list")
65+
.description("List all installed extensions")
66+
.option("--enabled", "Show only enabled extensions")
67+
.option("--disabled", "Show only disabled extensions")
68+
.action(async (options) => {
69+
const spinner = ora("Loading extensions...").start();
70+
try {
71+
const manager = getExtensionManager();
72+
let extensions = await manager.list();
73+
if (options.enabled) {
74+
extensions = extensions.filter(ext => ext.enabled);
75+
}
76+
else if (options.disabled) {
77+
extensions = extensions.filter(ext => !ext.enabled);
78+
}
79+
spinner.succeed("Extensions loaded");
80+
if (extensions.length === 0) {
81+
console.log(chalk.yellow("\nNo extensions found"));
82+
console.log(chalk.gray("Install an extension with: gem-extensions install <source>"));
83+
return;
84+
}
85+
console.log(chalk.blue("\n📦 Installed Extensions:\n"));
86+
for (const ext of extensions) {
87+
const status = ext.enabled
88+
? chalk.green("✓ Enabled")
89+
: chalk.gray("○ Disabled");
90+
console.log(chalk.bold(` ${ext.name}`) + chalk.gray(` v${ext.version}`));
91+
console.log(` Status: ${status}`);
92+
console.log(chalk.gray(` ${ext.description || 'No description'}`));
93+
console.log(chalk.gray(` Installed: ${new Date(ext.installedAt).toLocaleDateString()}`));
94+
console.log();
95+
}
96+
console.log(chalk.gray(`Total: ${extensions.length} extension(s)`));
97+
}
98+
catch (error) {
99+
spinner.fail("Failed to load extensions");
100+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : error);
101+
process.exit(1);
102+
}
103+
});
104+
}
105+
/**
106+
* Enable command
107+
*/
108+
createEnableCommand() {
109+
return new Command("enable")
110+
.description("Enable an installed extension")
111+
.argument("<name>", "Extension name")
112+
.action(async (name) => {
113+
const spinner = ora(`Enabling extension ${name}...`).start();
114+
try {
115+
const manager = getExtensionManager();
116+
await manager.enable(name);
117+
spinner.succeed(`Extension ${chalk.bold(name)} enabled`);
118+
console.log(chalk.green("\n✓ Extension is now active"));
119+
}
120+
catch (error) {
121+
spinner.fail("Failed to enable extension");
122+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : error);
123+
process.exit(1);
124+
}
125+
});
126+
}
127+
/**
128+
* Disable command
129+
*/
130+
createDisableCommand() {
131+
return new Command("disable")
132+
.description("Disable an enabled extension")
133+
.argument("<name>", "Extension name")
134+
.action(async (name) => {
135+
const spinner = ora(`Disabling extension ${name}...`).start();
136+
try {
137+
const manager = getExtensionManager();
138+
await manager.disable(name);
139+
spinner.succeed(`Extension ${chalk.bold(name)} disabled`);
140+
console.log(chalk.yellow("\n⚠️ Extension is now inactive"));
141+
}
142+
catch (error) {
143+
spinner.fail("Failed to disable extension");
144+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : error);
145+
process.exit(1);
146+
}
147+
});
148+
}
149+
/**
150+
* Update command
151+
*/
152+
createUpdateCommand() {
153+
return new Command("update")
154+
.description("Update an installed extension")
155+
.argument("<name>", "Extension name")
156+
.action(async (name) => {
157+
const spinner = ora(`Updating extension ${name}...`).start();
158+
try {
159+
const manager = getExtensionManager();
160+
await manager.update(name);
161+
spinner.succeed(`Extension ${chalk.bold(name)} updated`);
162+
console.log(chalk.green("\n✓ Extension updated to latest version"));
163+
}
164+
catch (error) {
165+
spinner.fail("Failed to update extension");
166+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : error);
167+
process.exit(1);
168+
}
169+
});
170+
}
171+
/**
172+
* Uninstall command
173+
*/
174+
createUninstallCommand() {
175+
return new Command("uninstall")
176+
.description("Uninstall an extension")
177+
.argument("<name>", "Extension name")
178+
.option("--force", "Skip confirmation prompt", false)
179+
.action(async (name, options) => {
180+
if (!options.force) {
181+
console.log(chalk.yellow(`\n⚠️ This will permanently remove extension: ${chalk.bold(name)}`));
182+
// In a real implementation, we'd use inquirer to prompt for confirmation
183+
console.log(chalk.gray("Use --force to skip this confirmation\n"));
184+
}
185+
const spinner = ora(`Uninstalling extension ${name}...`).start();
186+
try {
187+
const manager = getExtensionManager();
188+
await manager.uninstall(name);
189+
spinner.succeed(`Extension ${chalk.bold(name)} uninstalled`);
190+
console.log(chalk.green("\n✓ Extension removed successfully"));
191+
}
192+
catch (error) {
193+
spinner.fail("Failed to uninstall extension");
194+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : error);
195+
process.exit(1);
196+
}
197+
});
198+
}
199+
/**
200+
* Info command
201+
*/
202+
createInfoCommand() {
203+
return new Command("info")
204+
.description("Show detailed information about an extension")
205+
.argument("<name>", "Extension name")
206+
.action(async (name) => {
207+
const spinner = ora(`Loading extension info...`).start();
208+
try {
209+
const manager = getExtensionManager();
210+
const info = await manager.info(name);
211+
if (!info) {
212+
spinner.fail(`Extension ${name} not found`);
213+
return;
214+
}
215+
spinner.succeed("Extension info loaded");
216+
console.log(chalk.blue("\n📦 Extension Details:\n"));
217+
console.log(chalk.bold(` Name: `) + info.name);
218+
console.log(chalk.bold(` Display Name: `) + (info.displayName || info.name));
219+
console.log(chalk.bold(` Version: `) + info.version);
220+
console.log(chalk.bold(` Author: `) + (info.author || 'Unknown'));
221+
console.log(chalk.bold(` Description: `) + (info.description || 'N/A'));
222+
console.log(chalk.bold(` Status: `) + (info.enabled ? chalk.green("Enabled") : chalk.gray("Disabled")));
223+
console.log(chalk.bold(` Source: `) + info.source);
224+
console.log(chalk.bold(` Installed: `) + new Date(info.installedAt).toLocaleString());
225+
if (info.updatedAt) {
226+
console.log(chalk.bold(` Updated: `) + new Date(info.updatedAt).toLocaleString());
227+
}
228+
console.log();
229+
}
230+
catch (error) {
231+
spinner.fail("Failed to load extension info");
232+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : error);
233+
process.exit(1);
234+
}
235+
});
236+
}
237+
}
238+
export default GemExtensionsCommand;

dist/cli/commands/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ export { WorkspaceCommand } from "./workspace.js";
1818
export { GeminiCommand } from "./gemini.js";
1919
export { DGMCommand } from "./dgm.js";
2020
export { JulesCommand } from "./jules.js";
21-
export { ExtensionsCommand } from "./extensions.js";
21+
export { GemExtensionsCommand } from "./gem-extensions.js";

dist/cli/full-index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { fileURLToPath } from "url";
1212
import { Logger } from "../utils/logger.js";
1313
import { ConfigManager } from "./config/config-manager.js";
1414
// Import all command modules
15-
import { InitCommand, SwarmCommand, AgentCommand, TaskCommand, SparcCommand, HiveMindCommand, MemoryCommand, HooksCommand, SecurityFlagsCommand, ConfigCommand, WorkspaceCommand, GeminiCommand, DGMCommand, JulesCommand, ExtensionsCommand, } from "./commands/index.js";
15+
import { InitCommand, SwarmCommand, AgentCommand, TaskCommand, SparcCommand, HiveMindCommand, MemoryCommand, HooksCommand, SecurityFlagsCommand, ConfigCommand, WorkspaceCommand, GeminiCommand, DGMCommand, JulesCommand, GemExtensionsCommand, } from "./commands/index.js";
1616
// ES module equivalent of __dirname
1717
const __filename = fileURLToPath(import.meta.url);
1818
const __dirname = dirname(__filename);
@@ -83,7 +83,7 @@ function setupCommands() {
8383
program.addCommand(new GeminiCommand());
8484
program.addCommand(new DGMCommand());
8585
program.addCommand(new JulesCommand());
86-
program.addCommand(new ExtensionsCommand());
86+
program.addCommand(new GemExtensionsCommand());
8787
// QueryCommand has a special constructor, let's skip it for now
8888
// program.addCommand(new QueryCommand());
8989
// Additional aliases for commonly used commands

0 commit comments

Comments
 (0)