@elyracode/coding-agent 0.6.2 → 0.6.3
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.
- package/CHANGELOG.md +6 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +85 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -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);
|