@elyracode/coding-agent 0.6.0 → 0.6.2
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 +13 -0
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +3 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +150 -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
|
@@ -14,6 +14,7 @@ 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";
|
|
16
16
|
import { KeybindingsManager } from "../../core/keybindings.js";
|
|
17
|
+
import { getMemoryPath, loadMemory } from "../../core/memory.js";
|
|
17
18
|
import { createCompactionSummaryMessage } from "../../core/messages.js";
|
|
18
19
|
import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope } from "../../core/model-resolver.js";
|
|
19
20
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
@@ -447,7 +448,7 @@ export class InteractiveMode {
|
|
|
447
448
|
hint("app.tools.expand", "more"),
|
|
448
449
|
].join(theme.fg("muted", " · "));
|
|
449
450
|
const compactOnboarding = theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help and loaded resources.`);
|
|
450
|
-
const onboarding = theme.fg("dim", `
|
|
451
|
+
const onboarding = theme.fg("dim", `Docs and guides at elyracode.com. Type / for commands, /ext for extensions.`);
|
|
451
452
|
this.builtInHeader = new ExpandableText(() => `${logo}\n${compactInstructions}\n${compactOnboarding}\n\n${onboarding}`, () => `${logo}\n${expandedInstructions}\n\n${onboarding}`, this.getStartupExpansionState(), 1, 0);
|
|
452
453
|
// Setup UI layout
|
|
453
454
|
this.headerContainer.addChild(new Spacer(1));
|
|
@@ -459,6 +460,21 @@ export class InteractiveMode {
|
|
|
459
460
|
this.builtInHeader = new Text("", 0, 0);
|
|
460
461
|
this.headerContainer.addChild(this.builtInHeader);
|
|
461
462
|
}
|
|
463
|
+
// Show first-run help for new projects
|
|
464
|
+
if (!this.settingsManager.getQuietStartup() &&
|
|
465
|
+
!fs.existsSync(path.join(this.sessionManager.getCwd(), ".elyra"))) {
|
|
466
|
+
const examples = [
|
|
467
|
+
theme.fg("dim", "Try one of these to get started:"),
|
|
468
|
+
"",
|
|
469
|
+
theme.fg("muted", " Summarize this codebase and explain the architecture"),
|
|
470
|
+
theme.fg("muted", " Find and fix bugs in src/auth/"),
|
|
471
|
+
theme.fg("muted", " Add tests for the user registration flow"),
|
|
472
|
+
theme.fg("muted", " Review the payment module for security issues"),
|
|
473
|
+
"",
|
|
474
|
+
theme.fg("dim", "Type / for commands, /ext for extensions. Docs at elyracode.com"),
|
|
475
|
+
].join("\n");
|
|
476
|
+
this.chatContainer.addChild(new Text(examples, 1, 0));
|
|
477
|
+
}
|
|
462
478
|
this.ui.addChild(this.chatContainer);
|
|
463
479
|
this.ui.addChild(this.pendingMessagesContainer);
|
|
464
480
|
this.ui.addChild(this.statusContainer);
|
|
@@ -1943,6 +1959,16 @@ export class InteractiveMode {
|
|
|
1943
1959
|
if (!text)
|
|
1944
1960
|
return;
|
|
1945
1961
|
// Handle commands
|
|
1962
|
+
if (text === "/help") {
|
|
1963
|
+
this.editor.setText("");
|
|
1964
|
+
this.handleHelpCommand();
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1967
|
+
if (text === "/init") {
|
|
1968
|
+
this.editor.setText("");
|
|
1969
|
+
await this.handleInitCommand();
|
|
1970
|
+
return;
|
|
1971
|
+
}
|
|
1946
1972
|
if (text === "/settings") {
|
|
1947
1973
|
this.showSettingsSelector();
|
|
1948
1974
|
this.editor.setText("");
|
|
@@ -1973,6 +1999,11 @@ export class InteractiveMode {
|
|
|
1973
1999
|
this.handlePinsCommand();
|
|
1974
2000
|
return;
|
|
1975
2001
|
}
|
|
2002
|
+
if (text === "/memory" || text.startsWith("/memory ")) {
|
|
2003
|
+
this.editor.setText("");
|
|
2004
|
+
this.handleMemoryCommand(text.startsWith("/memory ") ? text.slice(8).trim() : undefined);
|
|
2005
|
+
return;
|
|
2006
|
+
}
|
|
1976
2007
|
if (text === "/blueprint" || text.startsWith("/blueprint ")) {
|
|
1977
2008
|
this.editor.setText("");
|
|
1978
2009
|
this.handleBlueprintCommand(text.startsWith("/blueprint ") ? text.slice(11).trim() : undefined);
|
|
@@ -3296,6 +3327,93 @@ export class InteractiveMode {
|
|
|
3296
3327
|
return { component: selector, focus: selector.getSettingsList() };
|
|
3297
3328
|
});
|
|
3298
3329
|
}
|
|
3330
|
+
async handleInitCommand() {
|
|
3331
|
+
const cwd = this.sessionManager.getCwd();
|
|
3332
|
+
const elyraDir = path.join(cwd, ".elyra");
|
|
3333
|
+
if (fs.existsSync(elyraDir)) {
|
|
3334
|
+
this.showStatus(".elyra/ already exists in this project");
|
|
3335
|
+
return;
|
|
3336
|
+
}
|
|
3337
|
+
// Detect stack
|
|
3338
|
+
const stackResult = detectStack(cwd);
|
|
3339
|
+
// Create .elyra/ directory
|
|
3340
|
+
fs.mkdirSync(elyraDir, { recursive: true });
|
|
3341
|
+
// Create AGENTS.md with project context
|
|
3342
|
+
const agentsLines = [
|
|
3343
|
+
"# Project Rules",
|
|
3344
|
+
"",
|
|
3345
|
+
"## Overview",
|
|
3346
|
+
"",
|
|
3347
|
+
"<!-- Describe your project here. The agent reads this on every session. -->",
|
|
3348
|
+
"",
|
|
3349
|
+
];
|
|
3350
|
+
if (stackResult.summary) {
|
|
3351
|
+
agentsLines.push(`## Stack`, "", stackResult.summary, "");
|
|
3352
|
+
}
|
|
3353
|
+
agentsLines.push("## Conventions", "", "<!-- Add coding conventions, patterns, and preferences here. -->", "");
|
|
3354
|
+
fs.writeFileSync(path.join(elyraDir, "AGENTS.md"), agentsLines.join("\n"), "utf-8");
|
|
3355
|
+
// Create blueprints directory
|
|
3356
|
+
fs.mkdirSync(path.join(elyraDir, "blueprints"), { recursive: true });
|
|
3357
|
+
// Build status message
|
|
3358
|
+
const parts = [];
|
|
3359
|
+
parts.push(theme.bold("Project initialized"));
|
|
3360
|
+
parts.push("");
|
|
3361
|
+
parts.push(` ${theme.fg("success", "Created")} .elyra/AGENTS.md`);
|
|
3362
|
+
parts.push(` ${theme.fg("success", "Created")} .elyra/blueprints/`);
|
|
3363
|
+
// Suggest extensions based on detected stack
|
|
3364
|
+
if (stackResult.stack) {
|
|
3365
|
+
const pkg = getSuggestedPackage(stackResult.stack);
|
|
3366
|
+
parts.push("");
|
|
3367
|
+
parts.push(` ${theme.fg("accent", "Detected:")} ${stackResult.stack} stack`);
|
|
3368
|
+
parts.push(` ${theme.fg("dim", "Install:")} elyra install npm:${pkg}`);
|
|
3369
|
+
}
|
|
3370
|
+
if (stackResult.frameworks.some((f) => f.name === "Filament")) {
|
|
3371
|
+
parts.push(` ${theme.fg("dim", "Install:")} elyra install npm:@elyracode/stack-filament`);
|
|
3372
|
+
}
|
|
3373
|
+
if (stackResult.frameworks.some((f) => f.name === "Laravel AI SDK")) {
|
|
3374
|
+
parts.push(` ${theme.fg("dim", "Install:")} elyra install npm:@elyracode/stack-laravel-ai`);
|
|
3375
|
+
}
|
|
3376
|
+
// Check for Docker
|
|
3377
|
+
if (fs.existsSync(path.join(cwd, "docker-compose.yml")) || fs.existsSync(path.join(cwd, "compose.yml"))) {
|
|
3378
|
+
parts.push(` ${theme.fg("dim", "Install:")} elyra install npm:@elyracode/docker`);
|
|
3379
|
+
}
|
|
3380
|
+
// Always suggest useful general extensions
|
|
3381
|
+
parts.push("");
|
|
3382
|
+
parts.push(theme.fg("dim", "Edit .elyra/AGENTS.md to add project rules and conventions."));
|
|
3383
|
+
parts.push(theme.fg("dim", "Browse all extensions with /ext."));
|
|
3384
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3385
|
+
this.chatContainer.addChild(new Text(parts.join("\n"), 1, 0));
|
|
3386
|
+
this.ui.requestRender();
|
|
3387
|
+
}
|
|
3388
|
+
handleHelpCommand() {
|
|
3389
|
+
const help = [
|
|
3390
|
+
theme.bold("Elyra"),
|
|
3391
|
+
"",
|
|
3392
|
+
theme.fg("accent", "Example prompts:"),
|
|
3393
|
+
" Summarize this codebase and explain the architecture",
|
|
3394
|
+
" Add a REST API for user profiles with validation and tests",
|
|
3395
|
+
" Find and fix the bug in the checkout flow",
|
|
3396
|
+
" Refactor the notification system to use events",
|
|
3397
|
+
" Review src/auth/ for security issues",
|
|
3398
|
+
"",
|
|
3399
|
+
theme.fg("accent", "Useful commands:"),
|
|
3400
|
+
` ${theme.fg("muted", "/model")} Switch model`,
|
|
3401
|
+
` ${theme.fg("muted", "/theme")} Switch theme`,
|
|
3402
|
+
` ${theme.fg("muted", "/cost")} Token usage and cost`,
|
|
3403
|
+
` ${theme.fg("muted", "/diff")} Show uncommitted changes`,
|
|
3404
|
+
` ${theme.fg("muted", "/pin <path>")} Pin file to context`,
|
|
3405
|
+
` ${theme.fg("muted", "/memory")} View project memory`,
|
|
3406
|
+
` ${theme.fg("muted", "/blueprint")} Apply session template`,
|
|
3407
|
+
` ${theme.fg("muted", "/ext")} Browse extensions`,
|
|
3408
|
+
` ${theme.fg("muted", "/settings")} Full settings menu`,
|
|
3409
|
+
` ${theme.fg("muted", "/hotkeys")} Keyboard shortcuts`,
|
|
3410
|
+
"",
|
|
3411
|
+
theme.fg("dim", "Docs and guides at elyracode.com"),
|
|
3412
|
+
].join("\n");
|
|
3413
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3414
|
+
this.chatContainer.addChild(new Text(help, 1, 0));
|
|
3415
|
+
this.ui.requestRender();
|
|
3416
|
+
}
|
|
3299
3417
|
handleCostCommand() {
|
|
3300
3418
|
const stats = this.session.getSessionStats();
|
|
3301
3419
|
const fmt = (n) => n.toLocaleString();
|
|
@@ -3382,6 +3500,37 @@ export class InteractiveMode {
|
|
|
3382
3500
|
this.chatContainer.addChild(new Text(info, 1, 0));
|
|
3383
3501
|
this.ui.requestRender();
|
|
3384
3502
|
}
|
|
3503
|
+
handleMemoryCommand(subcommand) {
|
|
3504
|
+
const cwd = this.sessionManager.getCwd();
|
|
3505
|
+
if (subcommand === "clear") {
|
|
3506
|
+
const memoryPath = getMemoryPath(cwd);
|
|
3507
|
+
if (fs.existsSync(memoryPath)) {
|
|
3508
|
+
fs.unlinkSync(memoryPath);
|
|
3509
|
+
this.showStatus("Memory cleared for this project");
|
|
3510
|
+
}
|
|
3511
|
+
else {
|
|
3512
|
+
this.showStatus("No memory to clear");
|
|
3513
|
+
}
|
|
3514
|
+
return;
|
|
3515
|
+
}
|
|
3516
|
+
if (subcommand === "path") {
|
|
3517
|
+
const memoryPath = getMemoryPath(cwd);
|
|
3518
|
+
this.showStatus(memoryPath);
|
|
3519
|
+
return;
|
|
3520
|
+
}
|
|
3521
|
+
const memory = loadMemory(cwd);
|
|
3522
|
+
if (!memory) {
|
|
3523
|
+
this.showStatus("No project memory yet. Memory is generated automatically after sessions.");
|
|
3524
|
+
return;
|
|
3525
|
+
}
|
|
3526
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3527
|
+
this.chatContainer.addChild(new DynamicBorder());
|
|
3528
|
+
this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "Project Memory")), 1, 0));
|
|
3529
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3530
|
+
this.chatContainer.addChild(new Markdown(memory, 1, 1, this.getMarkdownThemeWithSettings()));
|
|
3531
|
+
this.chatContainer.addChild(new DynamicBorder());
|
|
3532
|
+
this.ui.requestRender();
|
|
3533
|
+
}
|
|
3385
3534
|
handleBlueprintCommand(name) {
|
|
3386
3535
|
const cwd = this.sessionManager.getCwd();
|
|
3387
3536
|
const dirs = [getProjectBlueprintsDir(cwd), getBlueprintsDir()];
|