conductor-install 0.0.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 (61) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +81 -0
  3. package/dist/conductor/.github/workflows/release-please.yml +47 -0
  4. package/dist/conductor/.release-please-manifest.json +3 -0
  5. package/dist/conductor/CHANGELOG.md +39 -0
  6. package/dist/conductor/CONTRIBUTING.md +33 -0
  7. package/dist/conductor/GEMINI.md +41 -0
  8. package/dist/conductor/LICENSE +202 -0
  9. package/dist/conductor/README.md +128 -0
  10. package/dist/conductor/commands/conductor/implement.toml +179 -0
  11. package/dist/conductor/commands/conductor/newTrack.toml +154 -0
  12. package/dist/conductor/commands/conductor/revert.toml +130 -0
  13. package/dist/conductor/commands/conductor/review.toml +158 -0
  14. package/dist/conductor/commands/conductor/setup.toml +456 -0
  15. package/dist/conductor/commands/conductor/status.toml +57 -0
  16. package/dist/conductor/conductor/.github/workflows/release-please.yml +47 -0
  17. package/dist/conductor/conductor/.release-please-manifest.json +3 -0
  18. package/dist/conductor/conductor/CHANGELOG.md +39 -0
  19. package/dist/conductor/conductor/CONTRIBUTING.md +33 -0
  20. package/dist/conductor/conductor/GEMINI.md +41 -0
  21. package/dist/conductor/conductor/LICENSE +202 -0
  22. package/dist/conductor/conductor/README.md +128 -0
  23. package/dist/conductor/conductor/commands/conductor/implement.toml +179 -0
  24. package/dist/conductor/conductor/commands/conductor/newTrack.toml +154 -0
  25. package/dist/conductor/conductor/commands/conductor/revert.toml +130 -0
  26. package/dist/conductor/conductor/commands/conductor/review.toml +158 -0
  27. package/dist/conductor/conductor/commands/conductor/setup.toml +456 -0
  28. package/dist/conductor/conductor/commands/conductor/status.toml +57 -0
  29. package/dist/conductor/conductor/gemini-extension.json +5 -0
  30. package/dist/conductor/conductor/release-please-config.json +11 -0
  31. package/dist/conductor/conductor/templates/code_styleguides/cpp.md +113 -0
  32. package/dist/conductor/conductor/templates/code_styleguides/csharp.md +115 -0
  33. package/dist/conductor/conductor/templates/code_styleguides/dart.md +238 -0
  34. package/dist/conductor/conductor/templates/code_styleguides/general.md +23 -0
  35. package/dist/conductor/conductor/templates/code_styleguides/go.md +48 -0
  36. package/dist/conductor/conductor/templates/code_styleguides/html-css.md +49 -0
  37. package/dist/conductor/conductor/templates/code_styleguides/javascript.md +51 -0
  38. package/dist/conductor/conductor/templates/code_styleguides/python.md +37 -0
  39. package/dist/conductor/conductor/templates/code_styleguides/typescript.md +43 -0
  40. package/dist/conductor/conductor/templates/workflow.md +333 -0
  41. package/dist/conductor/gemini-extension.json +5 -0
  42. package/dist/conductor/release-please-config.json +11 -0
  43. package/dist/conductor/templates/code_styleguides/cpp.md +113 -0
  44. package/dist/conductor/templates/code_styleguides/csharp.md +115 -0
  45. package/dist/conductor/templates/code_styleguides/dart.md +238 -0
  46. package/dist/conductor/templates/code_styleguides/general.md +23 -0
  47. package/dist/conductor/templates/code_styleguides/go.md +48 -0
  48. package/dist/conductor/templates/code_styleguides/html-css.md +49 -0
  49. package/dist/conductor/templates/code_styleguides/javascript.md +51 -0
  50. package/dist/conductor/templates/code_styleguides/python.md +37 -0
  51. package/dist/conductor/templates/code_styleguides/typescript.md +43 -0
  52. package/dist/conductor/templates/workflow.md +333 -0
  53. package/dist/conductor-install.cjs +779 -0
  54. package/dist/conductor-install.js +752 -0
  55. package/dist/index.cjs +776 -0
  56. package/dist/index.js +749 -0
  57. package/dist/templates/.github/workflows/release-please.yml +47 -0
  58. package/dist/templates/.release-please-manifest.json +3 -0
  59. package/dist/templates/templates/.github/workflows/release-please.yml +47 -0
  60. package/dist/templates/templates/.release-please-manifest.json +3 -0
  61. package/package.json +53 -0
package/dist/index.js ADDED
@@ -0,0 +1,749 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/index.ts
4
+ import yargs from "yargs";
5
+ import { hideBin } from "yargs/helpers";
6
+
7
+ // src/cli/prompt.ts
8
+ import select from "@inquirer/select";
9
+ async function promptForInstallScope(agent) {
10
+ const isCodex = agent === "codex";
11
+ const isCline = agent === "cline";
12
+ const choices = isCodex ? [{ name: "Global (User Home Directory)", value: "global" }] : [{ name: "Project (Current Directory)", value: "project" }];
13
+ const answer = await select({
14
+ message: "Select installation method:",
15
+ choices,
16
+ default: isCodex ? "global" : "project"
17
+ });
18
+ return answer;
19
+ }
20
+ async function promptForAgent() {
21
+ const answer = await select({
22
+ message: "Select your coding agent:",
23
+ choices: [
24
+ {
25
+ name: "OpenCode",
26
+ value: "opencode",
27
+ description: "The open source AI coding agent"
28
+ },
29
+ {
30
+ name: "Claude Code",
31
+ value: "claude-code",
32
+ description: "Anthropic's coding assistant"
33
+ },
34
+ {
35
+ name: "Antigravity",
36
+ value: "antigravity",
37
+ description: "Google's agentic coding assistant"
38
+ },
39
+ {
40
+ name: "Cursor",
41
+ value: "cursor",
42
+ description: "Cursor IDE's AI agent"
43
+ },
44
+ {
45
+ name: "VS Code Copilot",
46
+ value: "vscode-copilot",
47
+ description: "VS Code Copilot's Prompt Files"
48
+ },
49
+ {
50
+ name: "Codex",
51
+ value: "codex",
52
+ description: "OpenAI Codex Agent"
53
+ },
54
+ {
55
+ name: "Windsurf",
56
+ value: "windsurf",
57
+ description: "Windsurf Cascade AI Agent"
58
+ },
59
+ {
60
+ name: "Cline",
61
+ value: "cline",
62
+ description: "Cline AI coding assistant"
63
+ },
64
+ {
65
+ name: "Gemini CLI",
66
+ value: "gemini",
67
+ description: "Google Gemini CLI agent"
68
+ }
69
+ ],
70
+ default: "opencode"
71
+ });
72
+ return answer;
73
+ }
74
+
75
+ // src/generators/default/strategy.ts
76
+ import { join as join2 } from "path";
77
+ import fs2 from "fs-extra";
78
+ import { parse } from "smol-toml";
79
+
80
+ // src/utils/template.ts
81
+ import { readFile } from "fs/promises";
82
+ import { join, resolve } from "path";
83
+ import { fileURLToPath } from "url";
84
+ import { homedir } from "os";
85
+ import { execSync } from "child_process";
86
+ import { createHash } from "crypto";
87
+ import fs from "fs-extra";
88
+ var __dirname2 = fileURLToPath(new URL(".", import.meta.url));
89
+ var DEFAULT_REPO = "https://github.com/gemini-cli-extensions/conductor";
90
+ var DEFAULT_BRANCH = "main";
91
+ function getCacheDir(repo = DEFAULT_REPO, branch = DEFAULT_BRANCH) {
92
+ const hash = createHash("md5").update(`${repo}#${branch}`).digest("hex");
93
+ return join(homedir(), ".gemini/cache/conductor", hash);
94
+ }
95
+ async function ensureTemplates(repo = DEFAULT_REPO, branch = DEFAULT_BRANCH) {
96
+ const cacheDir = getCacheDir(repo, branch);
97
+ if (!fs.existsSync(cacheDir)) {
98
+ await fs.ensureDir(cacheDir);
99
+ console.log(`Downloading templates from ${repo} [${branch}]...`);
100
+ try {
101
+ execSync(`git clone ${repo} --branch ${branch} --depth 1 .`, {
102
+ cwd: cacheDir,
103
+ stdio: ["ignore", "ignore", "pipe"]
104
+ });
105
+ } catch (e) {
106
+ await fs.remove(cacheDir);
107
+ throw new Error(
108
+ `Failed to clone templates: ${e instanceof Error ? e.message : String(e)}`
109
+ );
110
+ }
111
+ } else {
112
+ try {
113
+ console.log(`Updating templates from ${repo} [${branch}]...`);
114
+ execSync("git pull --rebase", {
115
+ cwd: cacheDir,
116
+ stdio: ["ignore", "ignore", "pipe"]
117
+ });
118
+ } catch (e) {
119
+ console.warn(
120
+ `Failed to update templates (using cached version): ${e instanceof Error ? e.message : String(e)}`
121
+ );
122
+ }
123
+ }
124
+ }
125
+ function substituteVariables(template, variables) {
126
+ return template.replace(/\{(\w+)\}/g, (match, key) => {
127
+ if (Object.prototype.hasOwnProperty.call(variables, key)) {
128
+ return variables[key];
129
+ }
130
+ return match;
131
+ });
132
+ }
133
+ function getBundledTemplateRoot() {
134
+ const prodDest = resolve(__dirname2, "conductor");
135
+ if (fs.existsSync(prodDest)) {
136
+ return prodDest;
137
+ }
138
+ return resolve(__dirname2, "../conductor");
139
+ }
140
+ async function getTemplateRoot(repo, branch) {
141
+ if (!repo && !branch) {
142
+ const bundledRoot = getBundledTemplateRoot();
143
+ if (await fs.pathExists(bundledRoot)) {
144
+ return bundledRoot;
145
+ }
146
+ }
147
+ await ensureTemplates(repo, branch);
148
+ return getCacheDir(repo, branch);
149
+ }
150
+ async function loadTemplate(templatePath, repo, branch) {
151
+ const bundledPath = resolve(getBundledTemplateRoot(), templatePath);
152
+ if (await fs.pathExists(bundledPath)) {
153
+ return readFile(bundledPath, "utf-8");
154
+ }
155
+ if (!repo && !branch) {
156
+ console.log(
157
+ `Bundled template not found: ${templatePath}, falling back to remote repository...`
158
+ );
159
+ await ensureTemplates(repo, branch);
160
+ }
161
+ const rootDir = await getTemplateRoot(repo, branch);
162
+ const fullPath = join(rootDir, templatePath);
163
+ return readFile(fullPath, "utf-8");
164
+ }
165
+
166
+ // src/generators/default/strategy.ts
167
+ var { writeFile } = fs2;
168
+ var DefaultContentStrategy = class {
169
+ process(templateContent, options) {
170
+ const { installPath, agentType } = options;
171
+ const parsed = parse(templateContent);
172
+ if (!parsed.prompt) {
173
+ return null;
174
+ }
175
+ let prompt = parsed.prompt;
176
+ prompt = prompt.replace(/__\$\$CODE_AGENT_INSTALL_PATH\$\$__/g, installPath);
177
+ const finalContent = substituteVariables(prompt, { agent_type: agentType });
178
+ if (parsed.description) {
179
+ return `---
180
+ description: ${parsed.description}
181
+ ---
182
+ ${finalContent}`;
183
+ }
184
+ return finalContent;
185
+ }
186
+ };
187
+ var DefaultFileStrategy = class {
188
+ async write(options) {
189
+ const { targetDir, agentDir, commandsDir, commandName, extension, content } = options;
190
+ const fileName = `conductor:${commandName}${extension}`;
191
+ await writeFile(join2(targetDir, agentDir, commandsDir, fileName), content);
192
+ }
193
+ };
194
+ var defaultContentStrategy = new DefaultContentStrategy();
195
+ var defaultFileStrategy = new DefaultFileStrategy();
196
+
197
+ // src/generators/opencode/config.ts
198
+ var opencodeConfig = {
199
+ agentType: "opencode",
200
+ agentDir: ".opencode",
201
+ commandsDir: "commands",
202
+ displayName: "OpenCode",
203
+ protocolFilename: "AGENTS.md"
204
+ };
205
+
206
+ // src/generators/ConfigurableGenerator.ts
207
+ import { join as join3 } from "path";
208
+ import select2 from "@inquirer/select";
209
+ import fs3 from "fs-extra";
210
+ var { existsSync, ensureDir, writeFile: writeFile2, copy } = fs3;
211
+ var ConfigurableGenerator = class {
212
+ constructor(config) {
213
+ this.config = config;
214
+ }
215
+ async validate(targetDir, scope) {
216
+ if (!existsSync(targetDir)) {
217
+ throw new Error(`Target directory does not exist: ${targetDir}`);
218
+ }
219
+ const { agentDir, commandsDir, displayName, extension, usesPrefix } = this.config;
220
+ const ext = extension || ".md";
221
+ const prefix = usesPrefix !== false ? "conductor:" : "";
222
+ const setupFileName = `${prefix}setup${ext}`;
223
+ const setupFile = join3(targetDir, agentDir, commandsDir, setupFileName);
224
+ const conductorPath = join3(targetDir, agentDir, "conductor");
225
+ if (existsSync(conductorPath) && existsSync(setupFile)) {
226
+ throw new Error(
227
+ `Conductor (${displayName}) is already installed in: ${targetDir}`
228
+ );
229
+ }
230
+ return targetDir;
231
+ }
232
+ async generate(targetDir, scope, repo, branch, force) {
233
+ const { agentDir, commandsDir, agentType } = this.config;
234
+ const agentPath = join3(targetDir, agentDir);
235
+ const targetCommandsDir = join3(agentPath, commandsDir);
236
+ let installPath = join3(agentDir, "conductor");
237
+ if (scope === "global") {
238
+ installPath = `~/${agentDir}/conductor`;
239
+ }
240
+ await ensureDir(targetCommandsDir);
241
+ await ensureDir(join3(agentPath, "conductor"));
242
+ const templateRoot = await getTemplateRoot(repo, branch);
243
+ try {
244
+ const templateSource = join3(templateRoot, "templates");
245
+ const templateDest = join3(agentPath, "conductor", "templates");
246
+ await copy(templateSource, templateDest);
247
+ } catch (e) {
248
+ console.warn("Failed to copy templates directory:", e);
249
+ }
250
+ const { protocolFilename } = this.config;
251
+ if (protocolFilename) {
252
+ try {
253
+ const protocolSource = join3(templateRoot, "GEMINI.md");
254
+ const protocolDest = join3(targetDir, agentDir, protocolFilename);
255
+ if (existsSync(protocolSource)) {
256
+ let shouldCopy = true;
257
+ if (existsSync(protocolDest) && !force) {
258
+ shouldCopy = await select2({
259
+ message: `The protocol file '${protocolFilename}' already exists. Do you want to overwrite it?`,
260
+ choices: [
261
+ { value: true, name: "Overwrite" },
262
+ { value: false, name: "Skip" }
263
+ ]
264
+ });
265
+ }
266
+ if (shouldCopy) {
267
+ await copy(protocolSource, protocolDest);
268
+ }
269
+ }
270
+ } catch (e) {
271
+ console.warn("Failed to handle protocol file:", e);
272
+ }
273
+ }
274
+ const commands = [
275
+ "setup",
276
+ "newTrack",
277
+ "implement",
278
+ "status",
279
+ "revert",
280
+ "review"
281
+ ];
282
+ const extension = this.config.extension || ".md";
283
+ const fixedAgent = this.config.fixedAgent;
284
+ for (const cmd of commands) {
285
+ try {
286
+ const tomlContent = await loadTemplate(
287
+ `commands/conductor/${cmd}.toml`,
288
+ repo,
289
+ branch
290
+ );
291
+ const contentStrategy = this.config.strategy?.content || defaultContentStrategy;
292
+ const finalContent = contentStrategy.process(tomlContent, {
293
+ installPath,
294
+ agentType,
295
+ fixedAgent,
296
+ commandName: cmd
297
+ });
298
+ if (finalContent) {
299
+ const fileStrategy = this.config.strategy?.file || defaultFileStrategy;
300
+ await fileStrategy.write({
301
+ targetDir,
302
+ agentDir,
303
+ commandsDir,
304
+ commandName: cmd,
305
+ extension,
306
+ content: finalContent
307
+ });
308
+ }
309
+ } catch (e) {
310
+ console.warn(`Failed to process ${cmd}:`, e);
311
+ }
312
+ }
313
+ }
314
+ };
315
+
316
+ // src/generators/factory.ts
317
+ function createGenerator(config) {
318
+ return new ConfigurableGenerator(config);
319
+ }
320
+
321
+ // src/generators/opencode/generator.ts
322
+ var OpenCodeGenerator = class {
323
+ generator = createGenerator(opencodeConfig);
324
+ validate(targetDir, scope) {
325
+ return this.generator.validate(targetDir, scope);
326
+ }
327
+ generate(targetDir, scope, repo, branch) {
328
+ return this.generator.generate(targetDir, scope, repo, branch);
329
+ }
330
+ };
331
+
332
+ // src/generators/claude-code/config.ts
333
+ var claudeCodeConfig = {
334
+ agentType: "claude-code",
335
+ agentDir: ".claude",
336
+ commandsDir: "commands",
337
+ displayName: "Claude Code",
338
+ protocolFilename: "CLAUDE.md"
339
+ };
340
+
341
+ // src/generators/claude-code/generator.ts
342
+ var ClaudeCodeGenerator = class {
343
+ generator = createGenerator(claudeCodeConfig);
344
+ validate(targetDir, scope) {
345
+ return this.generator.validate(targetDir, scope);
346
+ }
347
+ generate(targetDir, scope, repo, branch) {
348
+ return this.generator.generate(targetDir, scope, repo, branch);
349
+ }
350
+ };
351
+
352
+ // src/generators/antigravity/config.ts
353
+ var antigravityConfig = {
354
+ agentType: "antigravity",
355
+ agentDir: ".agent",
356
+ commandsDir: "workflows",
357
+ displayName: "Antigravity",
358
+ protocolFilename: "GEMINI.md"
359
+ };
360
+
361
+ // src/generators/antigravity/generator.ts
362
+ var AntigravityGenerator = class {
363
+ generator = createGenerator(antigravityConfig);
364
+ validate(targetDir, scope) {
365
+ return this.generator.validate(targetDir, scope);
366
+ }
367
+ generate(targetDir, scope, repo, branch) {
368
+ return this.generator.generate(targetDir, scope, repo, branch);
369
+ }
370
+ };
371
+
372
+ // src/generators/cursor/config.ts
373
+ var cursorConfig = {
374
+ agentType: "cursor",
375
+ agentDir: ".cursor",
376
+ commandsDir: "commands",
377
+ displayName: "Cursor",
378
+ protocolFilename: "AGENTS.md"
379
+ };
380
+
381
+ // src/generators/cursor/generator.ts
382
+ var CursorGenerator = class {
383
+ generator = createGenerator(cursorConfig);
384
+ validate(targetDir, scope) {
385
+ return this.generator.validate(targetDir, scope);
386
+ }
387
+ generate(targetDir, scope, repo, branch) {
388
+ return this.generator.generate(targetDir, scope, repo, branch);
389
+ }
390
+ };
391
+
392
+ // src/generators/vscode-copilot/strategy.ts
393
+ import { parse as parse2 } from "smol-toml";
394
+ var VsCodeCopilotContentStrategy = class {
395
+ process(templateContent, options) {
396
+ const { installPath, agentType, fixedAgent } = options;
397
+ const parsed = parse2(templateContent);
398
+ if (!parsed.prompt) {
399
+ return null;
400
+ }
401
+ let prompt = parsed.prompt;
402
+ prompt = prompt.replace(/__\$\$CODE_AGENT_INSTALL_PATH\$\$__/g, installPath);
403
+ const finalContent = substituteVariables(prompt, { agent_type: agentType });
404
+ return `---
405
+ description: ${parsed.description || ""}
406
+ agent: ${fixedAgent}
407
+ ---
408
+ ${finalContent}`;
409
+ }
410
+ };
411
+ var vscodeCopilotContentStrategy = new VsCodeCopilotContentStrategy();
412
+
413
+ // src/generators/vscode-copilot/config.ts
414
+ var vscodeCopilotConfig = {
415
+ agentType: "vscode-copilot",
416
+ agentDir: ".github",
417
+ commandsDir: "prompts",
418
+ displayName: "VS Code Copilot",
419
+ protocolFilename: "AGENTS.md",
420
+ extension: ".prompt.md",
421
+ fixedAgent: "agent",
422
+ strategy: {
423
+ content: vscodeCopilotContentStrategy
424
+ }
425
+ };
426
+
427
+ // src/generators/vscode-copilot/generator.ts
428
+ var VSCodeCopilotGenerator = class {
429
+ generator = createGenerator(vscodeCopilotConfig);
430
+ validate(targetDir, scope) {
431
+ return this.generator.validate(targetDir, scope);
432
+ }
433
+ generate(targetDir, scope, repo, branch) {
434
+ return this.generator.generate(targetDir, scope, repo, branch);
435
+ }
436
+ };
437
+
438
+ // src/generators/codex/config.ts
439
+ var codexConfig = {
440
+ agentType: "codex",
441
+ agentDir: ".codex",
442
+ commandsDir: "prompts",
443
+ displayName: "Codex",
444
+ protocolFilename: "AGENTS.md",
445
+ extension: ".md"
446
+ };
447
+
448
+ // src/generators/codex/generator.ts
449
+ import { homedir as homedir2 } from "os";
450
+ var CodexGenerator = class {
451
+ generator = createGenerator(codexConfig);
452
+ validate(targetDir, scope) {
453
+ if (scope === "global") {
454
+ targetDir = homedir2();
455
+ }
456
+ return this.generator.validate(targetDir, scope);
457
+ }
458
+ generate(targetDir, scope, repo, branch) {
459
+ if (scope === "global") {
460
+ targetDir = homedir2();
461
+ }
462
+ return this.generator.generate(targetDir, scope, repo, branch);
463
+ }
464
+ };
465
+
466
+ // src/generators/windsurf/config.ts
467
+ var windsurfConfig = {
468
+ agentType: "windsurf",
469
+ agentDir: ".windsurf",
470
+ commandsDir: "workflows",
471
+ displayName: "Windsurf",
472
+ protocolFilename: "AGENTS.md"
473
+ };
474
+
475
+ // src/generators/windsurf/generator.ts
476
+ var WindsurfGenerator = class {
477
+ generator = createGenerator(windsurfConfig);
478
+ validate(targetDir, scope) {
479
+ return this.generator.validate(targetDir, scope);
480
+ }
481
+ generate(targetDir, scope, repo, branch) {
482
+ return this.generator.generate(targetDir, scope, repo, branch);
483
+ }
484
+ };
485
+
486
+ // src/generators/cline/strategy.ts
487
+ import { parse as parse3 } from "smol-toml";
488
+ var ClineContentStrategy = class {
489
+ process(templateContent, options) {
490
+ const { installPath, agentType, commandName } = options;
491
+ const parsed = parse3(templateContent);
492
+ if (!parsed.prompt) {
493
+ return null;
494
+ }
495
+ let prompt = parsed.prompt;
496
+ prompt = prompt.replace(/__\$\$CODE_AGENT_INSTALL_PATH\$\$__/g, installPath);
497
+ const finalContent = substituteVariables(prompt, { agent_type: agentType });
498
+ const title = commandName ? commandName.charAt(0).toUpperCase() + commandName.slice(1) : "Command";
499
+ return `# Conductor ${title}${parsed.description ? "\n\n" + parsed.description + "\n\n" : "\n\n"}${finalContent}`;
500
+ }
501
+ };
502
+ var clineContentStrategy = new ClineContentStrategy();
503
+
504
+ // src/generators/cline/config.ts
505
+ var clineConfig = {
506
+ agentType: "cline",
507
+ agentDir: ".clinerules",
508
+ commandsDir: "workflows",
509
+ displayName: "Cline",
510
+ protocolFilename: "AGENTS.md",
511
+ strategy: {
512
+ content: clineContentStrategy
513
+ }
514
+ };
515
+
516
+ // src/generators/cline/generator.ts
517
+ var ClineGenerator = class {
518
+ generator = createGenerator(clineConfig);
519
+ validate(targetDir, scope) {
520
+ return this.generator.validate(targetDir, scope);
521
+ }
522
+ generate(targetDir, scope, repo, branch) {
523
+ return this.generator.generate(targetDir, scope, repo, branch);
524
+ }
525
+ };
526
+
527
+ // src/generators/gemini/strategy.ts
528
+ import { join as join4 } from "path";
529
+ import fs4 from "fs-extra";
530
+ import { parse as parse4 } from "smol-toml";
531
+ var { writeFile: writeFile3 } = fs4;
532
+ var GeminiContentStrategy = class {
533
+ process(templateContent, options) {
534
+ const { installPath, agentType } = options;
535
+ const parsed = parse4(templateContent);
536
+ if (!parsed.prompt) {
537
+ return null;
538
+ }
539
+ const content = templateContent.replace(/__\$\$CODE_AGENT_INSTALL_PATH\$\$__/g, installPath);
540
+ return substituteVariables(content, { agent_type: agentType });
541
+ }
542
+ };
543
+ var GeminiFileStrategy = class {
544
+ async write(options) {
545
+ const { targetDir, agentDir, commandsDir, commandName, extension, content } = options;
546
+ const fileName = `${commandName}${extension}`;
547
+ await writeFile3(join4(targetDir, agentDir, commandsDir, fileName), content);
548
+ }
549
+ };
550
+ var geminiContentStrategy = new GeminiContentStrategy();
551
+ var geminiFileStrategy = new GeminiFileStrategy();
552
+
553
+ // src/generators/gemini/config.ts
554
+ var geminiConfig = {
555
+ agentType: "gemini",
556
+ agentDir: ".gemini",
557
+ commandsDir: "commands/conductor",
558
+ displayName: "Gemini CLI",
559
+ protocolFilename: "GEMINI.md",
560
+ extension: ".toml",
561
+ usesPrefix: false,
562
+ strategy: {
563
+ content: geminiContentStrategy,
564
+ file: geminiFileStrategy
565
+ }
566
+ };
567
+
568
+ // src/generators/gemini/generator.ts
569
+ var GeminiGenerator = class {
570
+ generator = createGenerator(geminiConfig);
571
+ async validate(targetDir, scope) {
572
+ if (scope === "global") {
573
+ throw new Error("Gemini CLI agent only supports project-level installation");
574
+ }
575
+ return this.generator.validate(targetDir, scope);
576
+ }
577
+ async generate(targetDir, scope, repo, branch) {
578
+ if (scope === "global") {
579
+ throw new Error("Gemini CLI agent only supports project-level installation");
580
+ }
581
+ return this.generator.generate(targetDir, scope, repo, branch);
582
+ }
583
+ };
584
+
585
+ // src/generators/index.ts
586
+ function getGenerator(agentType) {
587
+ switch (agentType) {
588
+ case "claude-code":
589
+ return new ClaudeCodeGenerator();
590
+ case "antigravity":
591
+ return new AntigravityGenerator();
592
+ case "cursor":
593
+ return new CursorGenerator();
594
+ case "vscode-copilot":
595
+ return new VSCodeCopilotGenerator();
596
+ case "codex":
597
+ return new CodexGenerator();
598
+ case "windsurf":
599
+ return new WindsurfGenerator();
600
+ case "cline":
601
+ return new ClineGenerator();
602
+ case "gemini":
603
+ return new GeminiGenerator();
604
+ case "opencode":
605
+ default:
606
+ return new OpenCodeGenerator();
607
+ }
608
+ }
609
+
610
+ // src/commands/install.ts
611
+ import { resolve as resolve2 } from "path";
612
+ import select3 from "@inquirer/select";
613
+ async function installHandler(argv) {
614
+ const targetDir = resolve2(process.cwd(), argv.path);
615
+ const force = argv.force ?? false;
616
+ try {
617
+ console.log(`Initializing Conductor in: ${targetDir}`);
618
+ let agent;
619
+ if (argv.agent) {
620
+ agent = argv.agent;
621
+ console.log(`Using provided agent: ${agent}`);
622
+ } else {
623
+ console.log("Step 1: Prompting for agent selection...");
624
+ agent = await promptForAgent();
625
+ console.log(`\u2714 Selected agent: ${agent}`);
626
+ }
627
+ let scope;
628
+ if (argv.scope) {
629
+ scope = argv.scope;
630
+ console.log(`Using provided scope: ${scope}`);
631
+ } else {
632
+ scope = await promptForInstallScope(agent);
633
+ }
634
+ console.log(`\u2714 Selected scope: ${scope}`);
635
+ const generator = getGenerator(agent);
636
+ console.log("\nStep 3: Validating project directory...");
637
+ let validatedPath;
638
+ try {
639
+ validatedPath = await generator.validate(targetDir, scope);
640
+ } catch (err) {
641
+ if (err instanceof Error && err.message.includes("already installed")) {
642
+ if (force) {
643
+ console.log("\u26A0 Force mode: Overwriting existing installation");
644
+ validatedPath = targetDir;
645
+ } else {
646
+ const shouldOverwrite = await select3({
647
+ message: `${err.message}
648
+ Do you want to overwrite the existing installation?`,
649
+ choices: [
650
+ { value: true, name: "Yes, overwrite" },
651
+ { value: false, name: "No, cancel" }
652
+ ]
653
+ });
654
+ if (shouldOverwrite) {
655
+ console.log("Overwriting existing installation...");
656
+ validatedPath = targetDir;
657
+ } else {
658
+ console.log("Installation cancelled.");
659
+ return;
660
+ }
661
+ }
662
+ } else {
663
+ throw err;
664
+ }
665
+ }
666
+ console.log(`\u2714 Validation complete: ${validatedPath}`);
667
+ console.log("\nStep 4: Generating files...");
668
+ await generator.generate(
669
+ validatedPath,
670
+ scope,
671
+ argv.repo,
672
+ argv.branch,
673
+ force
674
+ );
675
+ console.log("\u2714 Files generated");
676
+ console.log("\n\u2714 Conductor initialized successfully!");
677
+ } catch (err) {
678
+ console.error(
679
+ "\n\u2718 Installation failed:",
680
+ err instanceof Error ? err.message : err
681
+ );
682
+ process.exit(1);
683
+ }
684
+ }
685
+
686
+ // src/cli/index.ts
687
+ var cli = yargs(hideBin(process.argv)).scriptName("conductor").usage("$0 <cmd> [args]").command(
688
+ "install [path]",
689
+ "Install Conductor in the specified directory",
690
+ (yargs2) => {
691
+ return yargs2.positional("path", {
692
+ describe: "Directory to install Conductor",
693
+ default: ".",
694
+ type: "string"
695
+ }).option("agent", {
696
+ alias: "a",
697
+ describe: "Specify the coding agent",
698
+ type: "string",
699
+ choices: [
700
+ "opencode",
701
+ "claude-code",
702
+ "antigravity",
703
+ "cursor",
704
+ "vscode-copilot",
705
+ "codex",
706
+ "windsurf",
707
+ "cline",
708
+ "gemini"
709
+ ]
710
+ }).option("repo", {
711
+ alias: "r",
712
+ describe: "Git repository URL for templates",
713
+ type: "string"
714
+ }).option("branch", {
715
+ alias: "b",
716
+ describe: "Branch name for templates",
717
+ type: "string"
718
+ }).option("scope", {
719
+ alias: "s",
720
+ describe: "Installation scope (project or global)",
721
+ type: "string",
722
+ choices: ["project", "global"]
723
+ }).option("force", {
724
+ alias: "f",
725
+ describe: "Force overwrite existing installation",
726
+ type: "boolean",
727
+ default: false
728
+ });
729
+ },
730
+ installHandler
731
+ ).help();
732
+
733
+ // src/utils/banner.ts
734
+ import gradient from "gradient-string";
735
+ var CONDUCTOR_BANNER = `
736
+ __________ _ ______ __ __________________ ____ __ __ ___ __ __
737
+ / ____/ __ \\/ | / / __ \\/ / / / ____/_ __/ __ \\/ __ \\ / // / / | / / / /
738
+ / / / / / / |/ / / / / / / / / / / / / / / /_/ / / // /_ / /| | / / / /
739
+ / /___/ /_/ / /| / /_/ / /_/ / /___ / / / /_/ / _, _/ /__ __/ / ___ |/ /___/ /___
740
+ \\____/\\____/_/ |_/_____/\\____/\\____/ /_/ \\____/_/ |_| /_/ /_/ |_/_____/_____/
741
+
742
+ `;
743
+ function printBanner() {
744
+ console.log(gradient("green", "blue")(CONDUCTOR_BANNER));
745
+ }
746
+
747
+ // src/index.ts
748
+ printBanner();
749
+ cli.parse();