@elyracode/coding-agent 0.2.0 → 0.3.0
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 +8 -0
- package/dist/cli/config-selector.d.ts +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +8 -3
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +1 -1
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +3 -3
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +1 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +9 -9
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +12 -12
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/session-manager.d.ts +6 -6
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +4 -4
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/stack-detector.d.ts +21 -0
- package/dist/core/stack-detector.d.ts.map +1 -0
- package/dist/core/stack-detector.js +120 -0
- package/dist/core/stack-detector.js.map +1 -0
- package/dist/core/system-prompt.d.ts +2 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +13 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -2
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -3
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +1 -1
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +1 -1
- package/dist/migrations.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 +18 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +10 -10
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/docs/extensions.md +17 -17
- package/docs/index.md +1 -1
- package/docs/prompt-templates.md +1 -1
- package/docs/providers.md +1 -1
- package/docs/quickstart.md +5 -5
- package/docs/rpc.md +6 -6
- package/docs/sdk.md +2 -2
- package/docs/session-format.md +3 -3
- package/docs/settings.md +4 -4
- package/docs/skills.md +2 -2
- package/docs/termux.md +3 -3
- package/docs/themes.md +1 -1
- package/docs/tui.md +1 -1
- package/docs/usage.md +2 -2
- package/examples/extensions/auto-commit-on-exit.ts +5 -5
- package/examples/extensions/bash-spawn-hook.ts +2 -2
- package/examples/extensions/bookmark.ts +5 -5
- package/examples/extensions/border-status-editor.ts +7 -7
- package/examples/extensions/built-in-tool-renderer.ts +5 -5
- package/examples/extensions/claude-rules.ts +3 -3
- package/examples/extensions/commands.ts +4 -4
- package/examples/extensions/confirm-destructive.ts +3 -3
- package/examples/extensions/custom-compaction.ts +2 -2
- package/examples/extensions/custom-footer.ts +2 -2
- package/examples/extensions/custom-header.ts +3 -3
- package/examples/extensions/custom-provider-anthropic/index.ts +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/package.json +2 -2
- package/examples/extensions/dirty-repo-guard.ts +7 -7
- package/examples/extensions/doom-overlay/index.ts +2 -2
- package/examples/extensions/dynamic-resources/index.ts +2 -2
- package/examples/extensions/dynamic-tools.ts +4 -4
- package/examples/extensions/event-bus.ts +8 -8
- package/examples/extensions/file-trigger.ts +3 -3
- package/examples/extensions/git-checkpoint.ts +7 -7
- package/examples/extensions/github-issue-autocomplete.ts +6 -6
- package/examples/extensions/handoff.ts +2 -2
- package/examples/extensions/hello.ts +2 -2
- package/examples/extensions/hidden-thinking-label.ts +3 -3
- package/examples/extensions/inline-bash.ts +3 -3
- package/examples/extensions/input-transform.ts +2 -2
- package/examples/extensions/interactive-shell.ts +2 -2
- package/examples/extensions/mac-system-theme.ts +3 -3
- package/examples/extensions/message-renderer.ts +4 -4
- package/examples/extensions/minimal-mode.ts +8 -8
- package/examples/extensions/modal-editor.ts +2 -2
- package/examples/extensions/model-status.ts +2 -2
- package/examples/extensions/notify.ts +2 -2
- package/examples/extensions/overlay-qa-tests.ts +14 -14
- package/examples/extensions/overlay-test.ts +2 -2
- package/examples/extensions/permission-gate.ts +2 -2
- package/examples/extensions/pirate.ts +3 -3
- package/examples/extensions/plan-mode/index.ts +22 -22
- package/examples/extensions/preset.ts +23 -23
- package/examples/extensions/prompt-customizer.ts +2 -2
- package/examples/extensions/protected-paths.ts +2 -2
- package/examples/extensions/provider-payload.ts +3 -3
- package/examples/extensions/qna.ts +2 -2
- package/examples/extensions/question.ts +2 -2
- package/examples/extensions/questionnaire.ts +2 -2
- package/examples/extensions/rainbow-editor.ts +2 -2
- package/examples/extensions/reload-runtime.ts +4 -4
- package/examples/extensions/rpc-demo.ts +10 -10
- package/examples/extensions/sandbox/index.ts +8 -8
- package/examples/extensions/sandbox/package.json +2 -2
- package/examples/extensions/send-user-message.ts +13 -13
- package/examples/extensions/session-name.ts +4 -4
- package/examples/extensions/shutdown-command.ts +10 -10
- package/examples/extensions/snake.ts +3 -3
- package/examples/extensions/space-invaders.ts +3 -3
- package/examples/extensions/ssh.ts +10 -10
- package/examples/extensions/status-line.ts +4 -4
- package/examples/extensions/structured-output.ts +2 -2
- package/examples/extensions/subagent/index.ts +3 -3
- package/examples/extensions/summarize.ts +2 -2
- package/examples/extensions/system-prompt-header.ts +3 -3
- package/examples/extensions/tic-tac-toe.ts +15 -15
- package/examples/extensions/timed-confirm.ts +4 -4
- package/examples/extensions/titlebar-spinner.ts +8 -8
- package/examples/extensions/todo.ts +5 -5
- package/examples/extensions/tool-override.ts +3 -3
- package/examples/extensions/tools.ts +9 -9
- package/examples/extensions/trigger-compact.ts +3 -3
- package/examples/extensions/truncated-tool.ts +3 -3
- package/examples/extensions/widget-placement.ts +2 -2
- package/examples/extensions/with-deps/index.ts +2 -2
- package/examples/extensions/with-deps/package.json +2 -2
- package/examples/extensions/working-indicator.ts +5 -5
- package/examples/extensions/working-message-test.ts +2 -2
- package/package.json +5 -5
|
@@ -35,12 +35,12 @@ function getTextContent(message: AssistantMessage): string {
|
|
|
35
35
|
.join("\n");
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export default function planModeExtension(
|
|
38
|
+
export default function planModeExtension(elyra: ExtensionAPI): void {
|
|
39
39
|
let planModeEnabled = false;
|
|
40
40
|
let executionMode = false;
|
|
41
41
|
let todoItems: TodoItem[] = [];
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
elyra.registerFlag("plan", {
|
|
44
44
|
description: "Start in plan mode (read-only exploration)",
|
|
45
45
|
type: "boolean",
|
|
46
46
|
default: false,
|
|
@@ -79,29 +79,29 @@ export default function planModeExtension(pi: ExtensionAPI): void {
|
|
|
79
79
|
todoItems = [];
|
|
80
80
|
|
|
81
81
|
if (planModeEnabled) {
|
|
82
|
-
|
|
82
|
+
elyra.setActiveTools(PLAN_MODE_TOOLS);
|
|
83
83
|
ctx.ui.notify(`Plan mode enabled. Tools: ${PLAN_MODE_TOOLS.join(", ")}`);
|
|
84
84
|
} else {
|
|
85
|
-
|
|
85
|
+
elyra.setActiveTools(NORMAL_MODE_TOOLS);
|
|
86
86
|
ctx.ui.notify("Plan mode disabled. Full access restored.");
|
|
87
87
|
}
|
|
88
88
|
updateStatus(ctx);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
function persistState(): void {
|
|
92
|
-
|
|
92
|
+
elyra.appendEntry("plan-mode", {
|
|
93
93
|
enabled: planModeEnabled,
|
|
94
94
|
todos: todoItems,
|
|
95
95
|
executing: executionMode,
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
elyra.registerCommand("plan", {
|
|
100
100
|
description: "Toggle plan mode (read-only exploration)",
|
|
101
101
|
handler: async (_args, ctx) => togglePlanMode(ctx),
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
elyra.registerCommand("todos", {
|
|
105
105
|
description: "Show current plan todo list",
|
|
106
106
|
handler: async (_args, ctx) => {
|
|
107
107
|
if (todoItems.length === 0) {
|
|
@@ -113,13 +113,13 @@ export default function planModeExtension(pi: ExtensionAPI): void {
|
|
|
113
113
|
},
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
elyra.registerShortcut(Key.ctrlAlt("p"), {
|
|
117
117
|
description: "Toggle plan mode",
|
|
118
118
|
handler: async (ctx) => togglePlanMode(ctx),
|
|
119
119
|
});
|
|
120
120
|
|
|
121
121
|
// Block destructive bash commands in plan mode
|
|
122
|
-
|
|
122
|
+
elyra.on("tool_call", async (event) => {
|
|
123
123
|
if (!planModeEnabled || event.toolName !== "bash") return;
|
|
124
124
|
|
|
125
125
|
const command = event.input.command as string;
|
|
@@ -132,7 +132,7 @@ export default function planModeExtension(pi: ExtensionAPI): void {
|
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
// Filter out stale plan mode context when not in plan mode
|
|
135
|
-
|
|
135
|
+
elyra.on("context", async (event) => {
|
|
136
136
|
if (planModeEnabled) return;
|
|
137
137
|
|
|
138
138
|
return {
|
|
@@ -156,7 +156,7 @@ export default function planModeExtension(pi: ExtensionAPI): void {
|
|
|
156
156
|
});
|
|
157
157
|
|
|
158
158
|
// Inject plan/execution context before agent starts
|
|
159
|
-
|
|
159
|
+
elyra.on("before_agent_start", async () => {
|
|
160
160
|
if (planModeEnabled) {
|
|
161
161
|
return {
|
|
162
162
|
message: {
|
|
@@ -205,7 +205,7 @@ After completing a step, include a [DONE:n] tag in your response.`,
|
|
|
205
205
|
});
|
|
206
206
|
|
|
207
207
|
// Track progress after each turn
|
|
208
|
-
|
|
208
|
+
elyra.on("turn_end", async (event, ctx) => {
|
|
209
209
|
if (!executionMode || todoItems.length === 0) return;
|
|
210
210
|
if (!isAssistantMessage(event.message)) return;
|
|
211
211
|
|
|
@@ -217,18 +217,18 @@ After completing a step, include a [DONE:n] tag in your response.`,
|
|
|
217
217
|
});
|
|
218
218
|
|
|
219
219
|
// Handle plan completion and plan mode UI
|
|
220
|
-
|
|
220
|
+
elyra.on("agent_end", async (event, ctx) => {
|
|
221
221
|
// Check if execution is complete
|
|
222
222
|
if (executionMode && todoItems.length > 0) {
|
|
223
223
|
if (todoItems.every((t) => t.completed)) {
|
|
224
224
|
const completedList = todoItems.map((t) => `~~${t.text}~~`).join("\n");
|
|
225
|
-
|
|
225
|
+
elyra.sendMessage(
|
|
226
226
|
{ customType: "plan-complete", content: `**Plan Complete!** ✓\n\n${completedList}`, display: true },
|
|
227
227
|
{ triggerTurn: false },
|
|
228
228
|
);
|
|
229
229
|
executionMode = false;
|
|
230
230
|
todoItems = [];
|
|
231
|
-
|
|
231
|
+
elyra.setActiveTools(NORMAL_MODE_TOOLS);
|
|
232
232
|
updateStatus(ctx);
|
|
233
233
|
persistState(); // Save cleared state so resume doesn't restore old execution mode
|
|
234
234
|
}
|
|
@@ -249,7 +249,7 @@ After completing a step, include a [DONE:n] tag in your response.`,
|
|
|
249
249
|
// Show plan steps and prompt for next action
|
|
250
250
|
if (todoItems.length > 0) {
|
|
251
251
|
const todoListText = todoItems.map((t, i) => `${i + 1}. ☐ ${t.text}`).join("\n");
|
|
252
|
-
|
|
252
|
+
elyra.sendMessage(
|
|
253
253
|
{
|
|
254
254
|
customType: "plan-todo-list",
|
|
255
255
|
content: `**Plan Steps (${todoItems.length}):**\n\n${todoListText}`,
|
|
@@ -268,28 +268,28 @@ After completing a step, include a [DONE:n] tag in your response.`,
|
|
|
268
268
|
if (choice?.startsWith("Execute")) {
|
|
269
269
|
planModeEnabled = false;
|
|
270
270
|
executionMode = todoItems.length > 0;
|
|
271
|
-
|
|
271
|
+
elyra.setActiveTools(NORMAL_MODE_TOOLS);
|
|
272
272
|
updateStatus(ctx);
|
|
273
273
|
|
|
274
274
|
const execMessage =
|
|
275
275
|
todoItems.length > 0
|
|
276
276
|
? `Execute the plan. Start with: ${todoItems[0].text}`
|
|
277
277
|
: "Execute the plan you just created.";
|
|
278
|
-
|
|
278
|
+
elyra.sendMessage(
|
|
279
279
|
{ customType: "plan-mode-execute", content: execMessage, display: true },
|
|
280
280
|
{ triggerTurn: true },
|
|
281
281
|
);
|
|
282
282
|
} else if (choice === "Refine the plan") {
|
|
283
283
|
const refinement = await ctx.ui.editor("Refine the plan:", "");
|
|
284
284
|
if (refinement?.trim()) {
|
|
285
|
-
|
|
285
|
+
elyra.sendUserMessage(refinement.trim());
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
});
|
|
289
289
|
|
|
290
290
|
// Restore state on session start/resume
|
|
291
|
-
|
|
292
|
-
if (
|
|
291
|
+
elyra.on("session_start", async (_event, ctx) => {
|
|
292
|
+
if (elyra.getFlag("plan") === true) {
|
|
293
293
|
planModeEnabled = true;
|
|
294
294
|
}
|
|
295
295
|
|
|
@@ -333,7 +333,7 @@ After completing a step, include a [DONE:n] tag in your response.`,
|
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
if (planModeEnabled) {
|
|
336
|
-
|
|
336
|
+
elyra.setActiveTools(PLAN_MODE_TOOLS);
|
|
337
337
|
}
|
|
338
338
|
updateStatus(ctx);
|
|
339
339
|
});
|
|
@@ -104,14 +104,14 @@ interface OriginalState {
|
|
|
104
104
|
tools: string[];
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
export default function presetExtension(
|
|
107
|
+
export default function presetExtension(elyra: ExtensionAPI) {
|
|
108
108
|
let presets: PresetsConfig = {};
|
|
109
109
|
let activePresetName: string | undefined;
|
|
110
110
|
let activePreset: Preset | undefined;
|
|
111
111
|
let originalState: OriginalState | undefined;
|
|
112
112
|
|
|
113
113
|
// Register --preset CLI flag
|
|
114
|
-
|
|
114
|
+
elyra.registerFlag("preset", {
|
|
115
115
|
description: "Preset configuration to use",
|
|
116
116
|
type: "string",
|
|
117
117
|
});
|
|
@@ -124,8 +124,8 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
124
124
|
if (activePresetName === undefined) {
|
|
125
125
|
originalState = {
|
|
126
126
|
model: ctx.model,
|
|
127
|
-
thinkingLevel:
|
|
128
|
-
tools:
|
|
127
|
+
thinkingLevel: elyra.getThinkingLevel(),
|
|
128
|
+
tools: elyra.getActiveTools(),
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -133,7 +133,7 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
133
133
|
if (preset.provider && preset.model) {
|
|
134
134
|
const model = ctx.modelRegistry.find(preset.provider, preset.model);
|
|
135
135
|
if (model) {
|
|
136
|
-
const success = await
|
|
136
|
+
const success = await elyra.setModel(model);
|
|
137
137
|
if (!success) {
|
|
138
138
|
ctx.ui.notify(`Preset "${name}": No API key for ${preset.provider}/${preset.model}`, "warning");
|
|
139
139
|
}
|
|
@@ -144,12 +144,12 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
144
144
|
|
|
145
145
|
// Apply thinking level if specified
|
|
146
146
|
if (preset.thinkingLevel) {
|
|
147
|
-
|
|
147
|
+
elyra.setThinkingLevel(preset.thinkingLevel);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// Apply tools if specified
|
|
151
151
|
if (preset.tools && preset.tools.length > 0) {
|
|
152
|
-
const allToolNames =
|
|
152
|
+
const allToolNames = elyra.getAllTools().map((t) => t.name);
|
|
153
153
|
const validTools = preset.tools.filter((t) => allToolNames.includes(t));
|
|
154
154
|
const invalidTools = preset.tools.filter((t) => !allToolNames.includes(t));
|
|
155
155
|
|
|
@@ -158,7 +158,7 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
if (validTools.length > 0) {
|
|
161
|
-
|
|
161
|
+
elyra.setActiveTools(validTools);
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
@@ -273,12 +273,12 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
273
273
|
activePreset = undefined;
|
|
274
274
|
if (originalState) {
|
|
275
275
|
if (originalState.model) {
|
|
276
|
-
await
|
|
276
|
+
await elyra.setModel(originalState.model);
|
|
277
277
|
}
|
|
278
|
-
|
|
279
|
-
|
|
278
|
+
elyra.setThinkingLevel(originalState.thinkingLevel);
|
|
279
|
+
elyra.setActiveTools(originalState.tools);
|
|
280
280
|
} else {
|
|
281
|
-
|
|
281
|
+
elyra.setActiveTools(["read", "bash", "edit", "write"]);
|
|
282
282
|
}
|
|
283
283
|
ctx.ui.notify("Preset cleared, defaults restored", "info");
|
|
284
284
|
updateStatus(ctx);
|
|
@@ -329,12 +329,12 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
329
329
|
activePreset = undefined;
|
|
330
330
|
if (originalState) {
|
|
331
331
|
if (originalState.model) {
|
|
332
|
-
await
|
|
332
|
+
await elyra.setModel(originalState.model);
|
|
333
333
|
}
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
elyra.setThinkingLevel(originalState.thinkingLevel);
|
|
335
|
+
elyra.setActiveTools(originalState.tools);
|
|
336
336
|
} else {
|
|
337
|
-
|
|
337
|
+
elyra.setActiveTools(["read", "bash", "edit", "write"]);
|
|
338
338
|
}
|
|
339
339
|
ctx.ui.notify("Preset cleared, defaults restored", "info");
|
|
340
340
|
updateStatus(ctx);
|
|
@@ -349,7 +349,7 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
349
349
|
updateStatus(ctx);
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
-
|
|
352
|
+
elyra.registerShortcut(Key.ctrlShift("u"), {
|
|
353
353
|
description: "Cycle presets",
|
|
354
354
|
handler: async (ctx) => {
|
|
355
355
|
await cyclePreset(ctx);
|
|
@@ -357,7 +357,7 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
357
357
|
});
|
|
358
358
|
|
|
359
359
|
// Register /preset command
|
|
360
|
-
|
|
360
|
+
elyra.registerCommand("preset", {
|
|
361
361
|
description: "Switch preset configuration",
|
|
362
362
|
handler: async (args, ctx) => {
|
|
363
363
|
// If preset name provided, apply directly
|
|
@@ -383,7 +383,7 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
383
383
|
});
|
|
384
384
|
|
|
385
385
|
// Inject preset instructions into system prompt
|
|
386
|
-
|
|
386
|
+
elyra.on("before_agent_start", async (event) => {
|
|
387
387
|
if (activePreset?.instructions) {
|
|
388
388
|
return {
|
|
389
389
|
systemPrompt: `${event.systemPrompt}\n\n${activePreset.instructions}`,
|
|
@@ -392,12 +392,12 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
392
392
|
});
|
|
393
393
|
|
|
394
394
|
// Initialize on session start
|
|
395
|
-
|
|
395
|
+
elyra.on("session_start", async (_event, ctx) => {
|
|
396
396
|
// Load presets from config files
|
|
397
397
|
presets = loadPresets(ctx.cwd);
|
|
398
398
|
|
|
399
399
|
// Check for --preset flag
|
|
400
|
-
const presetFlag =
|
|
400
|
+
const presetFlag = elyra.getFlag("preset");
|
|
401
401
|
if (typeof presetFlag === "string" && presetFlag) {
|
|
402
402
|
const preset = presets[presetFlag];
|
|
403
403
|
if (preset) {
|
|
@@ -428,9 +428,9 @@ export default function presetExtension(pi: ExtensionAPI) {
|
|
|
428
428
|
});
|
|
429
429
|
|
|
430
430
|
// Persist preset state
|
|
431
|
-
|
|
431
|
+
elyra.on("turn_start", async () => {
|
|
432
432
|
if (activePresetName) {
|
|
433
|
-
|
|
433
|
+
elyra.appendEntry("preset-state", { name: activePresetName });
|
|
434
434
|
}
|
|
435
435
|
});
|
|
436
436
|
}
|
|
@@ -83,8 +83,8 @@ If you have additional requirements, configure them via --append-system-prompt o
|
|
|
83
83
|
return extensionSpecific;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
export default function promptCustomizer(
|
|
87
|
-
|
|
86
|
+
export default function promptCustomizer(elyra: ExtensionAPI) {
|
|
87
|
+
elyra.on("before_agent_start", async (event) => {
|
|
88
88
|
const { systemPrompt, systemPromptOptions } = event;
|
|
89
89
|
|
|
90
90
|
const customPrompt = addToolGuidance(systemPromptOptions, systemPrompt);
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
9
9
|
|
|
10
|
-
export default function (
|
|
10
|
+
export default function (elyra: ExtensionAPI) {
|
|
11
11
|
const protectedPaths = [".env", ".git/", "node_modules/"];
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
elyra.on("tool_call", async (event, ctx) => {
|
|
14
14
|
if (event.toolName !== "write" && event.toolName !== "edit") {
|
|
15
15
|
return undefined;
|
|
16
16
|
}
|
|
@@ -2,17 +2,17 @@ import { appendFileSync } from "node:fs";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
4
4
|
|
|
5
|
-
export default function (
|
|
5
|
+
export default function (elyra: ExtensionAPI) {
|
|
6
6
|
const logFile = join(process.cwd(), ".elyra", "provider-payload.log");
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
elyra.on("before_provider_request", (event) => {
|
|
9
9
|
appendFileSync(logFile, `${JSON.stringify(event.payload, null, 2)}\n\n`, "utf8");
|
|
10
10
|
|
|
11
11
|
// Optional: replace the payload instead of only logging it.
|
|
12
12
|
// return { ...event.payload, temperature: 0 };
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
elyra.on("after_provider_response", (event) => {
|
|
16
16
|
appendFileSync(logFile, `[${event.status}] ${JSON.stringify(event.headers)}\n\n`, "utf8");
|
|
17
17
|
});
|
|
18
18
|
}
|
|
@@ -27,8 +27,8 @@ A:
|
|
|
27
27
|
|
|
28
28
|
Keep questions in the order they appeared. Be concise.`;
|
|
29
29
|
|
|
30
|
-
export default function (
|
|
31
|
-
|
|
30
|
+
export default function (elyra: ExtensionAPI) {
|
|
31
|
+
elyra.registerCommand("qna", {
|
|
32
32
|
description: "Extract questions from last assistant message into editor",
|
|
33
33
|
handler: async (_args, ctx) => {
|
|
34
34
|
if (!ctx.hasUI) {
|
|
@@ -33,8 +33,8 @@ const QuestionParams = Type.Object({
|
|
|
33
33
|
options: Type.Array(OptionSchema, { description: "Options for the user to choose from" }),
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
export default function question(
|
|
37
|
-
|
|
36
|
+
export default function question(elyra: ExtensionAPI) {
|
|
37
|
+
elyra.registerTool({
|
|
38
38
|
name: "question",
|
|
39
39
|
label: "Question",
|
|
40
40
|
description: "Ask the user a question and let them pick from options. Use when you need user input to proceed.",
|
|
@@ -73,8 +73,8 @@ function errorResult(
|
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
export default function questionnaire(
|
|
77
|
-
|
|
76
|
+
export default function questionnaire(elyra: ExtensionAPI) {
|
|
77
|
+
elyra.registerTool({
|
|
78
78
|
name: "questionnaire",
|
|
79
79
|
label: "Questionnaire",
|
|
80
80
|
description:
|
|
@@ -81,8 +81,8 @@ class RainbowEditor extends CustomEditor {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
export default function (
|
|
85
|
-
|
|
84
|
+
export default function (elyra: ExtensionAPI) {
|
|
85
|
+
elyra.on("session_start", (_event, ctx) => {
|
|
86
86
|
ctx.ui.setEditorComponent((tui, theme, kb) => new RainbowEditor(tui, theme, kb));
|
|
87
87
|
});
|
|
88
88
|
}
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
9
9
|
import { Type } from "typebox";
|
|
10
10
|
|
|
11
|
-
export default function (
|
|
11
|
+
export default function (elyra: ExtensionAPI) {
|
|
12
12
|
// Command entrypoint for reload.
|
|
13
13
|
// Treat reload as terminal for this handler.
|
|
14
|
-
|
|
14
|
+
elyra.registerCommand("reload-runtime", {
|
|
15
15
|
description: "Reload extensions, skills, prompts, and themes",
|
|
16
16
|
handler: async (_args, ctx) => {
|
|
17
17
|
await ctx.reload();
|
|
@@ -21,13 +21,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
21
21
|
|
|
22
22
|
// LLM-callable tool. Tools get ExtensionContext, so they cannot call ctx.reload() directly.
|
|
23
23
|
// Instead, queue a follow-up user command that executes the command above.
|
|
24
|
-
|
|
24
|
+
elyra.registerTool({
|
|
25
25
|
name: "reload_runtime",
|
|
26
26
|
label: "Reload Runtime",
|
|
27
27
|
description: "Reload extensions, skills, prompts, and themes",
|
|
28
28
|
parameters: Type.Object({}),
|
|
29
29
|
async execute() {
|
|
30
|
-
|
|
30
|
+
elyra.sendUserMessage("/reload-runtime", { deliverAs: "followUp" });
|
|
31
31
|
return {
|
|
32
32
|
content: [{ type: "text", text: "Queued /reload-runtime as a follow-up command." }],
|
|
33
33
|
details: {},
|
|
@@ -19,31 +19,31 @@
|
|
|
19
19
|
|
|
20
20
|
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
21
21
|
|
|
22
|
-
export default function (
|
|
22
|
+
export default function (elyra: ExtensionAPI) {
|
|
23
23
|
let turnCount = 0;
|
|
24
24
|
|
|
25
25
|
// -- setTitle, setWidget, setStatus on session lifecycle --
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
ctx.ui.setTitle(event.reason === "new" ? "
|
|
27
|
+
elyra.on("session_start", async (event, ctx) => {
|
|
28
|
+
ctx.ui.setTitle(event.reason === "new" ? "elyra RPC Demo (new session)" : "elyra RPC Demo");
|
|
29
29
|
ctx.ui.setWidget("rpc-demo", ["--- RPC Extension UI Demo ---", "Loaded and ready."]);
|
|
30
30
|
ctx.ui.setStatus("rpc-demo", `Turns: ${turnCount}`);
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
// -- setStatus on turn lifecycle --
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
elyra.on("turn_start", async (_event, ctx) => {
|
|
36
36
|
turnCount++;
|
|
37
37
|
ctx.ui.setStatus("rpc-demo", `Turn ${turnCount} running...`);
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
elyra.on("turn_end", async (_event, ctx) => {
|
|
41
41
|
ctx.ui.setStatus("rpc-demo", `Turn ${turnCount} done`);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
// -- select on dangerous tool calls --
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
elyra.on("tool_call", async (event, ctx) => {
|
|
47
47
|
if (event.toolName !== "bash") return undefined;
|
|
48
48
|
|
|
49
49
|
const command = event.input.command as string;
|
|
@@ -67,7 +67,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
67
67
|
|
|
68
68
|
// -- confirm on session clear --
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
elyra.on("session_before_switch", async (event, ctx) => {
|
|
71
71
|
if (event.reason !== "new") return;
|
|
72
72
|
if (!ctx.hasUI) return;
|
|
73
73
|
|
|
@@ -80,7 +80,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
80
80
|
|
|
81
81
|
// -- input via command --
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
elyra.registerCommand("rpc-input", {
|
|
84
84
|
description: "Prompt for text input (demonstrates ctx.ui.input in RPC)",
|
|
85
85
|
handler: async (_args, ctx) => {
|
|
86
86
|
const value = await ctx.ui.input("Enter a value", "type something...");
|
|
@@ -94,7 +94,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
94
94
|
|
|
95
95
|
// -- editor via command --
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
elyra.registerCommand("rpc-editor", {
|
|
98
98
|
description: "Open multi-line editor (demonstrates ctx.ui.editor in RPC)",
|
|
99
99
|
handler: async (_args, ctx) => {
|
|
100
100
|
const text = await ctx.ui.editor("Edit some text", "Line 1\nLine 2\nLine 3");
|
|
@@ -108,7 +108,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
108
108
|
|
|
109
109
|
// -- setEditorText via command --
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
elyra.registerCommand("rpc-prefill", {
|
|
112
112
|
description: "Prefill the input editor (demonstrates ctx.ui.setEditorText in RPC)",
|
|
113
113
|
handler: async (_args, ctx) => {
|
|
114
114
|
ctx.ui.setEditorText("This text was set by the rpc-demo extension.");
|
|
@@ -198,8 +198,8 @@ function createSandboxedBashOps(): BashOperations {
|
|
|
198
198
|
};
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
-
export default function (
|
|
202
|
-
|
|
201
|
+
export default function (elyra: ExtensionAPI) {
|
|
202
|
+
elyra.registerFlag("no-sandbox", {
|
|
203
203
|
description: "Disable OS-level sandboxing for bash commands",
|
|
204
204
|
type: "boolean",
|
|
205
205
|
default: false,
|
|
@@ -211,7 +211,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
211
211
|
let sandboxEnabled = false;
|
|
212
212
|
let sandboxInitialized = false;
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
elyra.registerTool({
|
|
215
215
|
...localBash,
|
|
216
216
|
label: "bash (sandboxed)",
|
|
217
217
|
async execute(id, params, signal, onUpdate, _ctx) {
|
|
@@ -226,13 +226,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
226
226
|
},
|
|
227
227
|
});
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
elyra.on("user_bash", () => {
|
|
230
230
|
if (!sandboxEnabled || !sandboxInitialized) return;
|
|
231
231
|
return { operations: createSandboxedBashOps() };
|
|
232
232
|
});
|
|
233
233
|
|
|
234
|
-
|
|
235
|
-
const noSandbox =
|
|
234
|
+
elyra.on("session_start", async (_event, ctx) => {
|
|
235
|
+
const noSandbox = elyra.getFlag("no-sandbox") as boolean;
|
|
236
236
|
|
|
237
237
|
if (noSandbox) {
|
|
238
238
|
sandboxEnabled = false;
|
|
@@ -284,7 +284,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
284
284
|
}
|
|
285
285
|
});
|
|
286
286
|
|
|
287
|
-
|
|
287
|
+
elyra.on("session_shutdown", async () => {
|
|
288
288
|
if (sandboxInitialized) {
|
|
289
289
|
try {
|
|
290
290
|
await SandboxManager.reset();
|
|
@@ -294,7 +294,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
294
294
|
}
|
|
295
295
|
});
|
|
296
296
|
|
|
297
|
-
|
|
297
|
+
elyra.registerCommand("sandbox", {
|
|
298
298
|
description: "Show sandbox configuration",
|
|
299
299
|
handler: async (_args, ctx) => {
|
|
300
300
|
if (!sandboxEnabled) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Send User Message Example
|
|
3
3
|
*
|
|
4
|
-
* Demonstrates
|
|
5
|
-
* Unlike
|
|
4
|
+
* Demonstrates elyra.sendUserMessage() for sending user messages from extensions.
|
|
5
|
+
* Unlike elyra.sendMessage() which sends custom messages, sendUserMessage() sends
|
|
6
6
|
* actual user messages that appear in the conversation as if typed by the user.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
15
15
|
|
|
16
|
-
export default function (
|
|
16
|
+
export default function (elyra: ExtensionAPI) {
|
|
17
17
|
// Simple command that sends a user message
|
|
18
|
-
|
|
18
|
+
elyra.registerCommand("ask", {
|
|
19
19
|
description: "Send a user message to the agent",
|
|
20
20
|
handler: async (args, ctx) => {
|
|
21
21
|
if (!args.trim()) {
|
|
@@ -30,12 +30,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
elyra.sendUserMessage(args);
|
|
34
34
|
},
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
// Command that steers the agent mid-conversation
|
|
38
|
-
|
|
38
|
+
elyra.registerCommand("steer", {
|
|
39
39
|
description: "Send a steering message (interrupts current processing)",
|
|
40
40
|
handler: async (args, ctx) => {
|
|
41
41
|
if (!args.trim()) {
|
|
@@ -45,16 +45,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
45
45
|
|
|
46
46
|
if (ctx.isIdle()) {
|
|
47
47
|
// Not streaming, just send normally
|
|
48
|
-
|
|
48
|
+
elyra.sendUserMessage(args);
|
|
49
49
|
} else {
|
|
50
50
|
// Streaming - use steer to interrupt
|
|
51
|
-
|
|
51
|
+
elyra.sendUserMessage(args, { deliverAs: "steer" });
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
// Command that queues a follow-up message
|
|
57
|
-
|
|
57
|
+
elyra.registerCommand("followup", {
|
|
58
58
|
description: "Queue a follow-up message (waits for current processing)",
|
|
59
59
|
handler: async (args, ctx) => {
|
|
60
60
|
if (!args.trim()) {
|
|
@@ -64,17 +64,17 @@ export default function (pi: ExtensionAPI) {
|
|
|
64
64
|
|
|
65
65
|
if (ctx.isIdle()) {
|
|
66
66
|
// Not streaming, just send normally
|
|
67
|
-
|
|
67
|
+
elyra.sendUserMessage(args);
|
|
68
68
|
} else {
|
|
69
69
|
// Streaming - queue as follow-up
|
|
70
|
-
|
|
70
|
+
elyra.sendUserMessage(args, { deliverAs: "followUp" });
|
|
71
71
|
ctx.ui.notify("Follow-up queued", "info");
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
// Example with content array (text + images would go here)
|
|
77
|
-
|
|
77
|
+
elyra.registerCommand("askwith", {
|
|
78
78
|
description: "Send a user message with structured content",
|
|
79
79
|
handler: async (args, ctx) => {
|
|
80
80
|
if (!args.trim()) {
|
|
@@ -88,7 +88,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// sendUserMessage accepts string or (TextContent | ImageContent)[]
|
|
91
|
-
|
|
91
|
+
elyra.sendUserMessage([
|
|
92
92
|
{ type: "text", text: `User request: ${args}` },
|
|
93
93
|
{ type: "text", text: "Please respond concisely." },
|
|
94
94
|
]);
|