@elyracode/coding-agent 0.6.2 → 0.6.4

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.
@@ -9,7 +9,7 @@ import * as path from "node:path";
9
9
  import { getProviders, } from "@elyracode/ai";
10
10
  import { CombinedAutocompleteProvider, Container, fuzzyFilter, Loader, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@elyracode/tui";
11
11
  import { spawn, spawnSync } from "child_process";
12
- import { APP_NAME, APP_TITLE, getAgentDir, getAuthPath, getBlueprintsDir, getDebugLogPath, getDocsPath, getProjectBlueprintsDir, getShareViewerUrl, VERSION, } from "../../config.js";
12
+ import { APP_NAME, APP_TITLE, getAgentDir, getAuthPath, getBlueprintsDir, getDebugLogPath, getDocsPath, getProjectBlueprintsDir, getProjectSnippetsDir, getShareViewerUrl, getSnippetsDir, VERSION, } from "../../config.js";
13
13
  import { parseSkillBlock } from "../../core/agent-session.js";
14
14
  import { SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
15
15
  import { FooterDataProvider } from "../../core/footer-data-provider.js";
@@ -328,6 +328,32 @@ export class InteractiveMode {
328
328
  }));
329
329
  };
330
330
  }
331
+ const snippetCommand = slashCommands.find((command) => command.name === "snippet");
332
+ if (snippetCommand) {
333
+ snippetCommand.getArgumentCompletions = (prefix) => {
334
+ const cwd = this.sessionManager.getCwd();
335
+ const dirs = [getProjectSnippetsDir(cwd), getSnippetsDir()];
336
+ const names = new Set();
337
+ for (const dir of dirs) {
338
+ if (!fs.existsSync(dir))
339
+ continue;
340
+ try {
341
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
342
+ if (entry.isFile() && entry.name.endsWith(".md")) {
343
+ names.add(entry.name.slice(0, -3));
344
+ }
345
+ }
346
+ }
347
+ catch {
348
+ // skip unreadable dirs
349
+ }
350
+ }
351
+ const filtered = Array.from(names).filter((n) => n.toLowerCase().includes(prefix.toLowerCase()));
352
+ if (filtered.length === 0)
353
+ return null;
354
+ return filtered.sort().map((n) => ({ value: n, label: n }));
355
+ };
356
+ }
331
357
  // Convert prompt templates to SlashCommand format for autocomplete
332
358
  const templateCommands = this.session.promptTemplates.map((cmd) => ({
333
359
  name: cmd.name,
@@ -2009,6 +2035,11 @@ export class InteractiveMode {
2009
2035
  this.handleBlueprintCommand(text.startsWith("/blueprint ") ? text.slice(11).trim() : undefined);
2010
2036
  return;
2011
2037
  }
2038
+ if (text === "/snippet" || text.startsWith("/snippet ")) {
2039
+ this.editor.setText("");
2040
+ this.handleSnippetCommand(text.startsWith("/snippet ") ? text.slice(9).trim() : undefined);
2041
+ return;
2042
+ }
2012
2043
  if (text === "/footer") {
2013
2044
  this.editor.setText("");
2014
2045
  this.handleFooterCommand();
@@ -3354,12 +3385,15 @@ export class InteractiveMode {
3354
3385
  fs.writeFileSync(path.join(elyraDir, "AGENTS.md"), agentsLines.join("\n"), "utf-8");
3355
3386
  // Create blueprints directory
3356
3387
  fs.mkdirSync(path.join(elyraDir, "blueprints"), { recursive: true });
3388
+ // Create snippets directory
3389
+ fs.mkdirSync(path.join(elyraDir, "snippets"), { recursive: true });
3357
3390
  // Build status message
3358
3391
  const parts = [];
3359
3392
  parts.push(theme.bold("Project initialized"));
3360
3393
  parts.push("");
3361
3394
  parts.push(` ${theme.fg("success", "Created")} .elyra/AGENTS.md`);
3362
3395
  parts.push(` ${theme.fg("success", "Created")} .elyra/blueprints/`);
3396
+ parts.push(` ${theme.fg("success", "Created")} .elyra/snippets/`);
3363
3397
  // Suggest extensions based on detected stack
3364
3398
  if (stackResult.stack) {
3365
3399
  const pkg = getSuggestedPackage(stackResult.stack);
@@ -3613,6 +3647,56 @@ export class InteractiveMode {
3613
3647
  this.showError(`Failed to read blueprint: ${bpPath}`);
3614
3648
  }
3615
3649
  }
3650
+ handleSnippetCommand(name) {
3651
+ const cwd = this.sessionManager.getCwd();
3652
+ const dirs = [getProjectSnippetsDir(cwd), getSnippetsDir()];
3653
+ const snippets = new Map();
3654
+ for (const dir of dirs) {
3655
+ if (!fs.existsSync(dir))
3656
+ continue;
3657
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
3658
+ if (!entry.isFile() || !entry.name.endsWith(".md"))
3659
+ continue;
3660
+ const snipName = entry.name.slice(0, -3);
3661
+ if (!snippets.has(snipName)) {
3662
+ snippets.set(snipName, path.resolve(dir, entry.name));
3663
+ }
3664
+ }
3665
+ }
3666
+ if (!name) {
3667
+ if (snippets.size === 0) {
3668
+ this.showStatus("No snippets found. Add .md files to .elyra/snippets/ or ~/.elyra/agent/snippets/");
3669
+ return;
3670
+ }
3671
+ // Show selector
3672
+ const items = Array.from(snippets.keys()).sort();
3673
+ this.showSelector((done) => {
3674
+ const selector = new ExtensionSelectorComponent("Select snippet", items, (selected) => {
3675
+ done();
3676
+ this.handleSnippetCommand(selected);
3677
+ }, () => done());
3678
+ return { component: selector, focus: selector };
3679
+ });
3680
+ return;
3681
+ }
3682
+ const filePath = snippets.get(name);
3683
+ if (!filePath) {
3684
+ const available = Array.from(snippets.keys()).join(", ");
3685
+ this.showError(`Snippet not found: "${name}". Available: ${available || "none"}`);
3686
+ return;
3687
+ }
3688
+ try {
3689
+ const content = fs.readFileSync(filePath, "utf-8").trim();
3690
+ if (!content) {
3691
+ this.showError(`Snippet "${name}" is empty`);
3692
+ return;
3693
+ }
3694
+ this.session.prompt(content);
3695
+ }
3696
+ catch {
3697
+ this.showError(`Failed to read snippet: ${filePath}`);
3698
+ }
3699
+ }
3616
3700
  handleFooterCommand() {
3617
3701
  const current = this.settingsManager.getMinimalFooter();
3618
3702
  this.settingsManager.setMinimalFooter(!current);