@elyracode/coding-agent 0.9.0 → 0.9.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.
- package/CHANGELOG.md +13 -0
- package/dist/core/agent-session.d.ts +7 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +18 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +8 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +4 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/modes/interactive/components/diff-viewer.d.ts +32 -0
- package/dist/modes/interactive/components/diff-viewer.d.ts.map +1 -0
- package/dist/modes/interactive/components/diff-viewer.js +136 -0
- package/dist/modes/interactive/components/diff-viewer.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +6 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +131 -15
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- 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.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -40,6 +40,7 @@ import { CountdownTimer } from "./components/countdown-timer.js";
|
|
|
40
40
|
import { CustomEditor } from "./components/custom-editor.js";
|
|
41
41
|
import { CustomMessageComponent } from "./components/custom-message.js";
|
|
42
42
|
import { DaxnutsComponent } from "./components/daxnuts.js";
|
|
43
|
+
import { DiffViewerComponent } from "./components/diff-viewer.js";
|
|
43
44
|
import { DynamicBorder } from "./components/dynamic-border.js";
|
|
44
45
|
import { EarendilAnnouncementComponent } from "./components/earendil-announcement.js";
|
|
45
46
|
import { ExtensionEditorComponent } from "./components/extension-editor.js";
|
|
@@ -2027,9 +2028,9 @@ export class InteractiveMode {
|
|
|
2027
2028
|
this.handleCostCommand();
|
|
2028
2029
|
return;
|
|
2029
2030
|
}
|
|
2030
|
-
if (text === "/diff") {
|
|
2031
|
+
if (text === "/diff" || text.startsWith("/diff ")) {
|
|
2031
2032
|
this.editor.setText("");
|
|
2032
|
-
await this.handleDiffCommand();
|
|
2033
|
+
await this.handleDiffCommand(text.slice("/diff".length).trim());
|
|
2033
2034
|
return;
|
|
2034
2035
|
}
|
|
2035
2036
|
if (text === "/pin" || text.startsWith("/pin ")) {
|
|
@@ -3259,6 +3260,7 @@ export class InteractiveMode {
|
|
|
3259
3260
|
smartRouting: this.settingsManager.getSmartRouting(),
|
|
3260
3261
|
codebaseMemory: this.settingsManager.getCodebaseMemory(),
|
|
3261
3262
|
autoSkills: this.settingsManager.getAutoSkills(),
|
|
3263
|
+
diffInEditor: this.settingsManager.getDiffInEditor(),
|
|
3262
3264
|
doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
|
|
3263
3265
|
treeFilterMode: this.settingsManager.getTreeFilterMode(),
|
|
3264
3266
|
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
|
@@ -3352,6 +3354,9 @@ export class InteractiveMode {
|
|
|
3352
3354
|
onAutoSkillsChange: (enabled) => {
|
|
3353
3355
|
this.settingsManager.setAutoSkills(enabled);
|
|
3354
3356
|
},
|
|
3357
|
+
onDiffInEditorChange: (enabled) => {
|
|
3358
|
+
this.settingsManager.setDiffInEditor(enabled);
|
|
3359
|
+
},
|
|
3355
3360
|
onQuietStartupChange: (enabled) => {
|
|
3356
3361
|
this.settingsManager.setQuietStartup(enabled);
|
|
3357
3362
|
},
|
|
@@ -3765,7 +3770,7 @@ export class InteractiveMode {
|
|
|
3765
3770
|
` ${theme.fg("muted", "/model")} Switch model`,
|
|
3766
3771
|
` ${theme.fg("muted", "/theme")} Switch theme`,
|
|
3767
3772
|
` ${theme.fg("muted", "/cost")} Token usage and cost`,
|
|
3768
|
-
` ${theme.fg("muted", "/diff")} Show
|
|
3773
|
+
` ${theme.fg("muted", "/diff")} Show changes (--session, --cached, or <path>)`,
|
|
3769
3774
|
` ${theme.fg("muted", "/pin <path>")} Pin file to context`,
|
|
3770
3775
|
` ${theme.fg("muted", "/memory")} View project memory`,
|
|
3771
3776
|
` ${theme.fg("muted", "/blueprint")} Apply session template`,
|
|
@@ -3799,25 +3804,136 @@ export class InteractiveMode {
|
|
|
3799
3804
|
this.chatContainer.addChild(new Text(info, 1, 0));
|
|
3800
3805
|
this.ui.requestRender();
|
|
3801
3806
|
}
|
|
3802
|
-
async handleDiffCommand() {
|
|
3807
|
+
async handleDiffCommand(args) {
|
|
3803
3808
|
const cwd = this.sessionManager.getCwd();
|
|
3809
|
+
// Parse flags and an optional path filter from the argument string.
|
|
3810
|
+
const tokens = args.split(/\s+/).filter(Boolean);
|
|
3811
|
+
let sessionMode = false;
|
|
3812
|
+
let cachedMode = false;
|
|
3813
|
+
let editorMode = false;
|
|
3814
|
+
let inlineMode = false;
|
|
3815
|
+
const pathArgs = [];
|
|
3816
|
+
for (const token of tokens) {
|
|
3817
|
+
if (token === "--session" || token === "-s")
|
|
3818
|
+
sessionMode = true;
|
|
3819
|
+
else if (token === "--cached" || token === "--staged")
|
|
3820
|
+
cachedMode = true;
|
|
3821
|
+
else if (token === "--editor" || token === "-e")
|
|
3822
|
+
editorMode = true;
|
|
3823
|
+
else if (token === "--inline")
|
|
3824
|
+
inlineMode = true;
|
|
3825
|
+
else
|
|
3826
|
+
pathArgs.push(token);
|
|
3827
|
+
}
|
|
3828
|
+
// Respect the diffInEditor preference unless an explicit flag overrides it.
|
|
3829
|
+
if (!editorMode && !inlineMode && this.settingsManager.getDiffInEditor()) {
|
|
3830
|
+
editorMode = true;
|
|
3831
|
+
}
|
|
3832
|
+
const runGit = (gitArgs) => {
|
|
3833
|
+
const result = spawnSync("git", gitArgs, {
|
|
3834
|
+
cwd,
|
|
3835
|
+
encoding: "utf-8",
|
|
3836
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
3837
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
3838
|
+
});
|
|
3839
|
+
if (result.status !== 0 && result.error)
|
|
3840
|
+
throw result.error;
|
|
3841
|
+
return result.stdout ?? "";
|
|
3842
|
+
};
|
|
3804
3843
|
try {
|
|
3805
|
-
|
|
3806
|
-
const
|
|
3844
|
+
// Verify this is a git repository up front for a clear error.
|
|
3845
|
+
const insideRepo = spawnSync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
3846
|
+
cwd,
|
|
3847
|
+
encoding: "utf-8",
|
|
3848
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
3849
|
+
});
|
|
3850
|
+
if (insideRepo.status !== 0) {
|
|
3851
|
+
this.showError("Not a git repository.");
|
|
3852
|
+
return;
|
|
3853
|
+
}
|
|
3854
|
+
let diff = "";
|
|
3855
|
+
let title;
|
|
3856
|
+
const pathSpec = pathArgs.length > 0 ? ["--", ...pathArgs] : [];
|
|
3857
|
+
if (sessionMode) {
|
|
3858
|
+
// Diff the working tree against the session's first checkpoint, so the
|
|
3859
|
+
// user sees only what the agent changed during this session.
|
|
3860
|
+
const baseline = this.session.getSessionBaselineRef();
|
|
3861
|
+
if (!baseline) {
|
|
3862
|
+
this.showStatus("No session baseline yet (the agent hasn't taken a turn, or this isn't a git repo).");
|
|
3863
|
+
return;
|
|
3864
|
+
}
|
|
3865
|
+
diff = runGit(["diff", baseline, ...pathSpec]);
|
|
3866
|
+
title = "Changes This Session";
|
|
3867
|
+
}
|
|
3868
|
+
else if (cachedMode) {
|
|
3869
|
+
diff = runGit(["diff", "--cached", ...pathSpec]);
|
|
3870
|
+
title = "Staged Changes";
|
|
3871
|
+
}
|
|
3872
|
+
else {
|
|
3873
|
+
diff = runGit(["diff", ...pathSpec]);
|
|
3874
|
+
title = "Uncommitted Changes";
|
|
3875
|
+
// Include untracked files (not shown by plain `git diff`) when not
|
|
3876
|
+
// filtering by an explicit path.
|
|
3877
|
+
if (pathArgs.length === 0) {
|
|
3878
|
+
const untracked = runGit(["ls-files", "--others", "--exclude-standard"]).split("\n").filter(Boolean);
|
|
3879
|
+
if (untracked.length > 0) {
|
|
3880
|
+
diff += `\n${untracked.map((f) => `+ (untracked) ${f}`).join("\n")}`;
|
|
3881
|
+
}
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3807
3884
|
if (!diff.trim()) {
|
|
3808
|
-
this.showStatus("No
|
|
3885
|
+
this.showStatus(pathArgs.length > 0 ? `No changes in ${pathArgs.join(", ")}` : "No changes");
|
|
3809
3886
|
return;
|
|
3810
3887
|
}
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3888
|
+
// Open the diff directly in the user's editor when requested or preferred.
|
|
3889
|
+
if (editorMode) {
|
|
3890
|
+
this.openTextInExternalEditor(diff, ".diff");
|
|
3891
|
+
return;
|
|
3892
|
+
}
|
|
3893
|
+
// Default: show the scrollable in-TUI diff viewer.
|
|
3894
|
+
const diffText = diff;
|
|
3895
|
+
this.showSelector((done) => {
|
|
3896
|
+
const viewer = new DiffViewerComponent(this.ui, diffText, title, {
|
|
3897
|
+
onOpenEditor: () => this.openTextInExternalEditor(diffText, ".diff"),
|
|
3898
|
+
onClose: done,
|
|
3899
|
+
});
|
|
3900
|
+
return { component: viewer, focus: viewer };
|
|
3901
|
+
});
|
|
3818
3902
|
}
|
|
3819
3903
|
catch {
|
|
3820
|
-
this.showError("Failed to run git diff.
|
|
3904
|
+
this.showError("Failed to run git diff.");
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3907
|
+
/**
|
|
3908
|
+
* Open read-only text content in the user's external editor ($VISUAL/$EDITOR).
|
|
3909
|
+
* Suspends the TUI while the editor runs, then restores it. The `suffix`
|
|
3910
|
+
* controls the temp file extension so editors apply the right syntax highlighting.
|
|
3911
|
+
*/
|
|
3912
|
+
openTextInExternalEditor(content, suffix) {
|
|
3913
|
+
const editorCmd = process.env.VISUAL || process.env.EDITOR;
|
|
3914
|
+
if (!editorCmd) {
|
|
3915
|
+
this.showWarning("No editor configured. Set $VISUAL or $EDITOR environment variable.");
|
|
3916
|
+
return;
|
|
3917
|
+
}
|
|
3918
|
+
const tmpFile = path.join(os.tmpdir(), `elyra-diff-${Date.now()}${suffix}`);
|
|
3919
|
+
try {
|
|
3920
|
+
fs.writeFileSync(tmpFile, content, "utf-8");
|
|
3921
|
+
this.ui.stop();
|
|
3922
|
+
const [editor, ...editorArgs] = editorCmd.split(" ");
|
|
3923
|
+
spawnSync(editor, [...editorArgs, tmpFile], {
|
|
3924
|
+
stdio: "inherit",
|
|
3925
|
+
shell: process.platform === "win32",
|
|
3926
|
+
});
|
|
3927
|
+
}
|
|
3928
|
+
finally {
|
|
3929
|
+
try {
|
|
3930
|
+
fs.unlinkSync(tmpFile);
|
|
3931
|
+
}
|
|
3932
|
+
catch {
|
|
3933
|
+
// Ignore cleanup errors
|
|
3934
|
+
}
|
|
3935
|
+
this.ui.start();
|
|
3936
|
+
this.ui.requestRender(true);
|
|
3821
3937
|
}
|
|
3822
3938
|
}
|
|
3823
3939
|
handlePinCommand(filePath) {
|