@elyracode/coding-agent 0.2.0 → 0.3.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 +17 -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
|
@@ -9,17 +9,17 @@
|
|
|
9
9
|
|
|
10
10
|
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
11
11
|
|
|
12
|
-
export default function (
|
|
13
|
-
|
|
12
|
+
export default function (elyra: ExtensionAPI) {
|
|
13
|
+
elyra.registerCommand("session-name", {
|
|
14
14
|
description: "Set or show session name (usage: /session-name [new name])",
|
|
15
15
|
handler: async (args, ctx) => {
|
|
16
16
|
const name = args.trim();
|
|
17
17
|
|
|
18
18
|
if (name) {
|
|
19
|
-
|
|
19
|
+
elyra.setSessionName(name);
|
|
20
20
|
ctx.ui.notify(`Session named: ${name}`, "info");
|
|
21
21
|
} else {
|
|
22
|
-
const current =
|
|
22
|
+
const current = elyra.getSessionName();
|
|
23
23
|
ctx.ui.notify(current ? `Session: ${current}` : "No session name set", "info");
|
|
24
24
|
}
|
|
25
25
|
},
|
|
@@ -2,26 +2,26 @@
|
|
|
2
2
|
* Shutdown Command Extension
|
|
3
3
|
*
|
|
4
4
|
* Adds a /quit command that allows extensions to trigger clean shutdown.
|
|
5
|
-
* Demonstrates how extensions can use ctx.shutdown() to exit
|
|
5
|
+
* Demonstrates how extensions can use ctx.shutdown() to exit elyra cleanly.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
9
9
|
import { Type } from "typebox";
|
|
10
10
|
|
|
11
|
-
export default function (
|
|
12
|
-
// Register a /quit command that cleanly exits
|
|
13
|
-
|
|
14
|
-
description: "Exit
|
|
11
|
+
export default function (elyra: ExtensionAPI) {
|
|
12
|
+
// Register a /quit command that cleanly exits elyra
|
|
13
|
+
elyra.registerCommand("quit", {
|
|
14
|
+
description: "Exit elyra cleanly",
|
|
15
15
|
handler: async (_args, ctx) => {
|
|
16
16
|
ctx.shutdown();
|
|
17
17
|
},
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
// You can also create a tool that shuts down after completing work
|
|
21
|
-
|
|
21
|
+
elyra.registerTool({
|
|
22
22
|
name: "finish_and_exit",
|
|
23
23
|
label: "Finish and Exit",
|
|
24
|
-
description: "Complete a task and exit
|
|
24
|
+
description: "Complete a task and exit elyra",
|
|
25
25
|
parameters: Type.Object({}),
|
|
26
26
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
27
27
|
// Do any final work here...
|
|
@@ -37,10 +37,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
// You could also create a more complex tool with parameters
|
|
40
|
-
|
|
40
|
+
elyra.registerTool({
|
|
41
41
|
name: "deploy_and_exit",
|
|
42
42
|
label: "Deploy and Exit",
|
|
43
|
-
description: "Deploy the application and exit
|
|
43
|
+
description: "Deploy the application and exit elyra",
|
|
44
44
|
parameters: Type.Object({
|
|
45
45
|
environment: Type.String({ description: "Target environment (e.g., production, staging)" }),
|
|
46
46
|
}),
|
|
@@ -48,7 +48,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
48
48
|
onUpdate?.({ content: [{ type: "text", text: `Deploying to ${params.environment}...` }], details: {} });
|
|
49
49
|
|
|
50
50
|
// Example deployment logic
|
|
51
|
-
// const result = await
|
|
51
|
+
// const result = await elyra.exec("npm", ["run", "deploy", params.environment], { signal });
|
|
52
52
|
|
|
53
53
|
// On success, request graceful shutdown
|
|
54
54
|
onUpdate?.({ content: [{ type: "text", text: "Deployment complete, exiting..." }], details: {} });
|
|
@@ -306,8 +306,8 @@ class SnakeComponent {
|
|
|
306
306
|
|
|
307
307
|
const SNAKE_SAVE_TYPE = "snake-save";
|
|
308
308
|
|
|
309
|
-
export default function (
|
|
310
|
-
|
|
309
|
+
export default function (elyra: ExtensionAPI) {
|
|
310
|
+
elyra.registerCommand("snake", {
|
|
311
311
|
description: "Play Snake!",
|
|
312
312
|
|
|
313
313
|
handler: async (_args, ctx) => {
|
|
@@ -333,7 +333,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
333
333
|
() => done(undefined),
|
|
334
334
|
(state) => {
|
|
335
335
|
// Save or clear state
|
|
336
|
-
|
|
336
|
+
elyra.appendEntry(SNAKE_SAVE_TYPE, state);
|
|
337
337
|
},
|
|
338
338
|
savedState,
|
|
339
339
|
);
|
|
@@ -524,8 +524,8 @@ class SpaceInvadersComponent {
|
|
|
524
524
|
|
|
525
525
|
const INVADERS_SAVE_TYPE = "space-invaders-save";
|
|
526
526
|
|
|
527
|
-
export default function (
|
|
528
|
-
|
|
527
|
+
export default function (elyra: ExtensionAPI) {
|
|
528
|
+
elyra.registerCommand("invaders", {
|
|
529
529
|
description: "Play Space Invaders!",
|
|
530
530
|
|
|
531
531
|
handler: async (_args, ctx) => {
|
|
@@ -550,7 +550,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
550
550
|
tui,
|
|
551
551
|
() => done(undefined),
|
|
552
552
|
(state) => {
|
|
553
|
-
|
|
553
|
+
elyra.appendEntry(INVADERS_SAVE_TYPE, state);
|
|
554
554
|
},
|
|
555
555
|
savedState,
|
|
556
556
|
);
|
|
@@ -111,8 +111,8 @@ function createRemoteBashOps(remote: string, remoteCwd: string, localCwd: string
|
|
|
111
111
|
};
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
export default function (
|
|
115
|
-
|
|
114
|
+
export default function (elyra: ExtensionAPI) {
|
|
115
|
+
elyra.registerFlag("ssh", { description: "SSH remote: user@host or user@host:/path", type: "string" });
|
|
116
116
|
|
|
117
117
|
const localCwd = process.cwd();
|
|
118
118
|
const localRead = createReadTool(localCwd);
|
|
@@ -125,7 +125,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
125
125
|
|
|
126
126
|
const getSsh = () => resolvedSsh;
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
elyra.registerTool({
|
|
129
129
|
...localRead,
|
|
130
130
|
async execute(id, params, signal, onUpdate, _ctx) {
|
|
131
131
|
const ssh = getSsh();
|
|
@@ -139,7 +139,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
139
139
|
},
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
elyra.registerTool({
|
|
143
143
|
...localWrite,
|
|
144
144
|
async execute(id, params, signal, onUpdate, _ctx) {
|
|
145
145
|
const ssh = getSsh();
|
|
@@ -153,7 +153,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
153
153
|
},
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
elyra.registerTool({
|
|
157
157
|
...localEdit,
|
|
158
158
|
async execute(id, params, signal, onUpdate, _ctx) {
|
|
159
159
|
const ssh = getSsh();
|
|
@@ -167,7 +167,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
167
167
|
},
|
|
168
168
|
});
|
|
169
169
|
|
|
170
|
-
|
|
170
|
+
elyra.registerTool({
|
|
171
171
|
...localBash,
|
|
172
172
|
async execute(id, params, signal, onUpdate, _ctx) {
|
|
173
173
|
const ssh = getSsh();
|
|
@@ -181,9 +181,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
181
181
|
},
|
|
182
182
|
});
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
elyra.on("session_start", async (_event, ctx) => {
|
|
185
185
|
// Resolve SSH config now that CLI flags are available
|
|
186
|
-
const arg =
|
|
186
|
+
const arg = elyra.getFlag("ssh") as string | undefined;
|
|
187
187
|
if (arg) {
|
|
188
188
|
if (arg.includes(":")) {
|
|
189
189
|
const [remote, path] = arg.split(":");
|
|
@@ -200,14 +200,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
200
200
|
});
|
|
201
201
|
|
|
202
202
|
// Handle user ! commands via SSH
|
|
203
|
-
|
|
203
|
+
elyra.on("user_bash", (_event) => {
|
|
204
204
|
const ssh = getSsh();
|
|
205
205
|
if (!ssh) return; // No SSH, use local execution
|
|
206
206
|
return { operations: createRemoteBashOps(ssh.remote, ssh.remoteCwd, localCwd) };
|
|
207
207
|
});
|
|
208
208
|
|
|
209
209
|
// Replace local cwd with remote cwd in system prompt
|
|
210
|
-
|
|
210
|
+
elyra.on("before_agent_start", async (event) => {
|
|
211
211
|
const ssh = getSsh();
|
|
212
212
|
if (ssh) {
|
|
213
213
|
const modified = event.systemPrompt.replace(
|
|
@@ -7,15 +7,15 @@
|
|
|
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
|
let turnCount = 0;
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
elyra.on("session_start", async (_event, ctx) => {
|
|
14
14
|
const theme = ctx.ui.theme;
|
|
15
15
|
ctx.ui.setStatus("status-demo", theme.fg("dim", "Ready"));
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
elyra.on("turn_start", async (_event, ctx) => {
|
|
19
19
|
turnCount++;
|
|
20
20
|
const theme = ctx.ui.theme;
|
|
21
21
|
const spinner = theme.fg("accent", "●");
|
|
@@ -23,7 +23,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
23
23
|
ctx.ui.setStatus("status-demo", spinner + text);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
elyra.on("turn_end", async (_event, ctx) => {
|
|
27
27
|
const theme = ctx.ui.theme;
|
|
28
28
|
const check = theme.fg("success", "✓");
|
|
29
29
|
const text = theme.fg("dim", ` Turn ${turnCount} complete`);
|
|
@@ -208,7 +208,7 @@ async function mapWithConcurrencyLimit<TIn, TOut>(
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
async function writePromptToTempFile(agentName: string, prompt: string): Promise<{ dir: string; filePath: string }> {
|
|
211
|
-
const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "
|
|
211
|
+
const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "elyra-subagent-"));
|
|
212
212
|
const safeName = agentName.replace(/[^\w.-]+/g, "_");
|
|
213
213
|
const filePath = path.join(tmpDir, `prompt-${safeName}.md`);
|
|
214
214
|
await withFileMutationQueue(filePath, async () => {
|
|
@@ -428,8 +428,8 @@ const SubagentParams = Type.Object({
|
|
|
428
428
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process (single mode)" })),
|
|
429
429
|
});
|
|
430
430
|
|
|
431
|
-
export default function (
|
|
432
|
-
|
|
431
|
+
export default function (elyra: ExtensionAPI) {
|
|
432
|
+
elyra.registerTool({
|
|
433
433
|
name: "subagent",
|
|
434
434
|
label: "Subagent",
|
|
435
435
|
description: [
|
|
@@ -142,8 +142,8 @@ const showSummaryUi = async (summary: string, ctx: ExtensionCommandContext) => {
|
|
|
142
142
|
});
|
|
143
143
|
};
|
|
144
144
|
|
|
145
|
-
export default function (
|
|
146
|
-
|
|
145
|
+
export default function (elyra: ExtensionAPI) {
|
|
146
|
+
elyra.registerCommand("summarize", {
|
|
147
147
|
description: "Summarize the current conversation in a custom UI",
|
|
148
148
|
handler: async (_args, ctx) => {
|
|
149
149
|
const branch = ctx.sessionManager.getBranch();
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
7
7
|
|
|
8
|
-
export default function (
|
|
9
|
-
|
|
8
|
+
export default function (elyra: ExtensionAPI) {
|
|
9
|
+
elyra.on("agent_start", (_event, ctx) => {
|
|
10
10
|
const prompt = ctx.getSystemPrompt();
|
|
11
11
|
ctx.ui.setStatus("system-prompt", `System: ${prompt.length} chars`);
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
elyra.on("session_shutdown", (_event, ctx) => {
|
|
15
15
|
ctx.ui.setStatus("system-prompt", undefined);
|
|
16
16
|
});
|
|
17
17
|
}
|
|
@@ -655,9 +655,9 @@ function getBoardDetails(): BoardDetails {
|
|
|
655
655
|
};
|
|
656
656
|
}
|
|
657
657
|
|
|
658
|
-
export default function (
|
|
659
|
-
|
|
660
|
-
|
|
658
|
+
export default function (elyra: ExtensionAPI) {
|
|
659
|
+
elyra.on("session_start", async (_event, ctx) => reconstructState(ctx));
|
|
660
|
+
elyra.on("session_tree", async (_event, ctx) => reconstructState(ctx));
|
|
661
661
|
|
|
662
662
|
// Sent once per game at end-of-game. The custom renderer paints the banner;
|
|
663
663
|
// `content` is a plain-text fallback for any non-TUI consumer and for the
|
|
@@ -671,7 +671,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
671
671
|
: gameState.status === "draw"
|
|
672
672
|
? "Draw"
|
|
673
673
|
: "Game over";
|
|
674
|
-
|
|
674
|
+
elyra.sendMessage({
|
|
675
675
|
customType: GAME_OVER_MESSAGE_TYPE,
|
|
676
676
|
content: `Game over: ${label}.`,
|
|
677
677
|
display: true,
|
|
@@ -682,7 +682,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
682
682
|
// -----------------------------------------------------------------------
|
|
683
683
|
// Custom message renderer for user move messages
|
|
684
684
|
// -----------------------------------------------------------------------
|
|
685
|
-
|
|
685
|
+
elyra.registerMessageRenderer(MOVE_MESSAGE_TYPE, (message, { expanded }, theme) => {
|
|
686
686
|
const details = message.details as BoardDetails | undefined;
|
|
687
687
|
const turnLabel =
|
|
688
688
|
details?.currentTurn === "O"
|
|
@@ -695,7 +695,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
695
695
|
// -----------------------------------------------------------------------
|
|
696
696
|
// Custom message renderer for game-over messages
|
|
697
697
|
// -----------------------------------------------------------------------
|
|
698
|
-
|
|
698
|
+
elyra.registerMessageRenderer(GAME_OVER_MESSAGE_TYPE, (message, _options, theme) => {
|
|
699
699
|
const details = message.details as BoardDetails | undefined;
|
|
700
700
|
const status = (details?.status ?? "draw") as GameStatus;
|
|
701
701
|
return new GameOverMessageComponent(status, details, theme);
|
|
@@ -704,7 +704,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
704
704
|
// -----------------------------------------------------------------------
|
|
705
705
|
// before_agent_start - inject game instructions each turn
|
|
706
706
|
// -----------------------------------------------------------------------
|
|
707
|
-
|
|
707
|
+
elyra.on("before_agent_start", async (event) => {
|
|
708
708
|
if (!gameActive) return undefined;
|
|
709
709
|
|
|
710
710
|
const instructions = `
|
|
@@ -775,7 +775,7 @@ Decide the target cell first, then dump every action for the turn in one go.
|
|
|
775
775
|
// -----------------------------------------------------------------------
|
|
776
776
|
// /tic-tac-toe command
|
|
777
777
|
// -----------------------------------------------------------------------
|
|
778
|
-
|
|
778
|
+
elyra.registerCommand("tic-tac-toe", {
|
|
779
779
|
description: "Play tic-tac-toe against the agent",
|
|
780
780
|
|
|
781
781
|
handler: async (_args, ctx) => {
|
|
@@ -789,7 +789,7 @@ Decide the target cell first, then dump every action for the turn in one go.
|
|
|
789
789
|
gameState = createInitialState();
|
|
790
790
|
}
|
|
791
791
|
gameActive = true;
|
|
792
|
-
|
|
792
|
+
elyra.setSessionName("Tic-Tac-Toe");
|
|
793
793
|
|
|
794
794
|
await ctx.ui.custom<void>((tui, _theme, _kb, done) => {
|
|
795
795
|
component = new TicTacToeComponent(
|
|
@@ -806,7 +806,7 @@ Decide the target cell first, then dump every action for the turn in one go.
|
|
|
806
806
|
gameState.currentTurn = gameState.agentMark;
|
|
807
807
|
}
|
|
808
808
|
component?.updateState(gameState);
|
|
809
|
-
|
|
809
|
+
elyra.appendEntry(SAVE_TYPE, getBoardDetails());
|
|
810
810
|
|
|
811
811
|
if (gameState.status === "playing") {
|
|
812
812
|
// IMPORTANT: user play does NOT touch the agent cursor.
|
|
@@ -816,7 +816,7 @@ Decide the target cell first, then dump every action for the turn in one go.
|
|
|
816
816
|
gameState.agentCursorRow,
|
|
817
817
|
gameState.agentCursorCol,
|
|
818
818
|
);
|
|
819
|
-
|
|
819
|
+
elyra.sendMessage(
|
|
820
820
|
{
|
|
821
821
|
customType: MOVE_MESSAGE_TYPE,
|
|
822
822
|
content:
|
|
@@ -856,7 +856,7 @@ Decide the target cell first, then dump every action for the turn in one go.
|
|
|
856
856
|
play: 0,
|
|
857
857
|
};
|
|
858
858
|
|
|
859
|
-
|
|
859
|
+
elyra.registerTool({
|
|
860
860
|
name: "tic_tac_toe",
|
|
861
861
|
label: "Tic-Tac-Toe",
|
|
862
862
|
description:
|
|
@@ -910,7 +910,7 @@ Decide the target cell first, then dump every action for the turn in one go.
|
|
|
910
910
|
// Do NOT reset the cursor on failure. The agent can retry
|
|
911
911
|
// from the cursor's current position.
|
|
912
912
|
component?.updateState(gameState);
|
|
913
|
-
|
|
913
|
+
elyra.appendEntry(SAVE_TYPE, getBoardDetails());
|
|
914
914
|
throw new TicTacToeError(
|
|
915
915
|
`Cell (${r},${c}) is already ${gameState.board[r][c]}. Your cursor is still at (${r},${c}). Move to an empty cell and retry play.`,
|
|
916
916
|
);
|
|
@@ -939,7 +939,7 @@ Decide the target cell first, then dump every action for the turn in one go.
|
|
|
939
939
|
}
|
|
940
940
|
|
|
941
941
|
component?.updateState(gameState);
|
|
942
|
-
|
|
942
|
+
elyra.appendEntry(SAVE_TYPE, getBoardDetails());
|
|
943
943
|
|
|
944
944
|
return {
|
|
945
945
|
content: [{ type: "text", text: result }],
|
|
@@ -969,7 +969,7 @@ Decide the target cell first, then dump every action for the turn in one go.
|
|
|
969
969
|
// -----------------------------------------------------------------------
|
|
970
970
|
// tic_tac_toe_see_board tool - inspect board + agent cursor.
|
|
971
971
|
// -----------------------------------------------------------------------
|
|
972
|
-
|
|
972
|
+
elyra.registerTool({
|
|
973
973
|
name: "tic_tac_toe_see_board",
|
|
974
974
|
label: "See Board",
|
|
975
975
|
description:
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
11
11
|
|
|
12
|
-
export default function (
|
|
12
|
+
export default function (elyra: ExtensionAPI) {
|
|
13
13
|
// Simple approach: use timeout option (recommended)
|
|
14
|
-
|
|
14
|
+
elyra.registerCommand("timed", {
|
|
15
15
|
description: "Show a timed confirmation dialog (auto-cancels in 5s with countdown)",
|
|
16
16
|
handler: async (_args, ctx) => {
|
|
17
17
|
const confirmed = await ctx.ui.confirm(
|
|
@@ -28,7 +28,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
elyra.registerCommand("timed-select", {
|
|
32
32
|
description: "Show a timed select dialog (auto-cancels in 10s with countdown)",
|
|
33
33
|
handler: async (_args, ctx) => {
|
|
34
34
|
const choice = await ctx.ui.select("Pick an option", ["Option A", "Option B", "Option C"], { timeout: 10000 });
|
|
@@ -42,7 +42,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
// Manual approach: use AbortSignal for more control
|
|
45
|
-
|
|
45
|
+
elyra.registerCommand("timed-signal", {
|
|
46
46
|
description: "Show a timed confirm using AbortSignal (manual approach)",
|
|
47
47
|
handler: async (_args, ctx) => {
|
|
48
48
|
const controller = new AbortController();
|
|
@@ -13,13 +13,13 @@ import type { ExtensionAPI, ExtensionContext } from "@elyracode/coding-agent";
|
|
|
13
13
|
|
|
14
14
|
const BRAILLE_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
15
15
|
|
|
16
|
-
function getBaseTitle(
|
|
16
|
+
function getBaseTitle(elyra: ExtensionAPI): string {
|
|
17
17
|
const cwd = path.basename(process.cwd());
|
|
18
|
-
const session =
|
|
18
|
+
const session = elyra.getSessionName();
|
|
19
19
|
return session ? `π - ${session} - ${cwd}` : `π - ${cwd}`;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export default function (
|
|
22
|
+
export default function (elyra: ExtensionAPI) {
|
|
23
23
|
let timer: ReturnType<typeof setInterval> | null = null;
|
|
24
24
|
let frameIndex = 0;
|
|
25
25
|
|
|
@@ -29,7 +29,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
29
29
|
timer = null;
|
|
30
30
|
}
|
|
31
31
|
frameIndex = 0;
|
|
32
|
-
ctx.ui.setTitle(getBaseTitle(
|
|
32
|
+
ctx.ui.setTitle(getBaseTitle(elyra));
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function startAnimation(ctx: ExtensionContext) {
|
|
@@ -37,22 +37,22 @@ export default function (pi: ExtensionAPI) {
|
|
|
37
37
|
timer = setInterval(() => {
|
|
38
38
|
const frame = BRAILLE_FRAMES[frameIndex % BRAILLE_FRAMES.length];
|
|
39
39
|
const cwd = path.basename(process.cwd());
|
|
40
|
-
const session =
|
|
40
|
+
const session = elyra.getSessionName();
|
|
41
41
|
const title = session ? `${frame} π - ${session} - ${cwd}` : `${frame} π - ${cwd}`;
|
|
42
42
|
ctx.ui.setTitle(title);
|
|
43
43
|
frameIndex++;
|
|
44
44
|
}, 80);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
elyra.on("agent_start", async (_event, ctx) => {
|
|
48
48
|
startAnimation(ctx);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
elyra.on("agent_end", async (_event, ctx) => {
|
|
52
52
|
stopAnimation(ctx);
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
elyra.on("session_shutdown", async (_event, ctx) => {
|
|
56
56
|
stopAnimation(ctx);
|
|
57
57
|
});
|
|
58
58
|
}
|
|
@@ -102,7 +102,7 @@ class TodoListComponent {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
export default function (
|
|
105
|
+
export default function (elyra: ExtensionAPI) {
|
|
106
106
|
// In-memory state (reconstructed from session on load)
|
|
107
107
|
let todos: Todo[] = [];
|
|
108
108
|
let nextId = 1;
|
|
@@ -129,11 +129,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
129
129
|
};
|
|
130
130
|
|
|
131
131
|
// Reconstruct state on session events
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
elyra.on("session_start", async (_event, ctx) => reconstructState(ctx));
|
|
133
|
+
elyra.on("session_tree", async (_event, ctx) => reconstructState(ctx));
|
|
134
134
|
|
|
135
135
|
// Register the todo tool for the LLM
|
|
136
|
-
|
|
136
|
+
elyra.registerTool({
|
|
137
137
|
name: "todo",
|
|
138
138
|
label: "Todo",
|
|
139
139
|
description: "Manage a todo list. Actions: list, add (text), toggle (id), clear",
|
|
@@ -281,7 +281,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
281
281
|
});
|
|
282
282
|
|
|
283
283
|
// Register the /todos command for users
|
|
284
|
-
|
|
284
|
+
elyra.registerCommand("todos", {
|
|
285
285
|
description: "Show all todos on the current branch",
|
|
286
286
|
handler: async (_args, ctx) => {
|
|
287
287
|
if (!ctx.hasUI) {
|
|
@@ -65,8 +65,8 @@ const readSchema = Type.Object({
|
|
|
65
65
|
limit: Type.Optional(Type.Number({ description: "Maximum number of lines to read" })),
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
export default function (
|
|
69
|
-
|
|
68
|
+
export default function (elyra: ExtensionAPI) {
|
|
69
|
+
elyra.registerTool({
|
|
70
70
|
name: "read", // Same name as built-in - this will override it
|
|
71
71
|
label: "read (audited)",
|
|
72
72
|
description:
|
|
@@ -129,7 +129,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
129
129
|
});
|
|
130
130
|
|
|
131
131
|
// Also register a command to view the access log
|
|
132
|
-
|
|
132
|
+
elyra.registerCommand("read-log", {
|
|
133
133
|
description: "View the file access log",
|
|
134
134
|
handler: async (_args, ctx) => {
|
|
135
135
|
try {
|
|
@@ -18,26 +18,26 @@ interface ToolsState {
|
|
|
18
18
|
enabledTools: string[];
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export default function toolsExtension(
|
|
21
|
+
export default function toolsExtension(elyra: ExtensionAPI) {
|
|
22
22
|
// Track enabled tools
|
|
23
23
|
let enabledTools: Set<string> = new Set();
|
|
24
24
|
let allTools: ToolInfo[] = [];
|
|
25
25
|
|
|
26
26
|
// Persist current state
|
|
27
27
|
function persistState() {
|
|
28
|
-
|
|
28
|
+
elyra.appendEntry<ToolsState>("tools-config", {
|
|
29
29
|
enabledTools: Array.from(enabledTools),
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// Apply current tool selection
|
|
34
34
|
function applyTools() {
|
|
35
|
-
|
|
35
|
+
elyra.setActiveTools(Array.from(enabledTools));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// Find the last tools-config entry in the current branch
|
|
39
39
|
function restoreFromBranch(ctx: ExtensionContext) {
|
|
40
|
-
allTools =
|
|
40
|
+
allTools = elyra.getAllTools();
|
|
41
41
|
|
|
42
42
|
// Get entries in current branch only
|
|
43
43
|
const branchEntries = ctx.sessionManager.getBranch();
|
|
@@ -59,16 +59,16 @@ export default function toolsExtension(pi: ExtensionAPI) {
|
|
|
59
59
|
applyTools();
|
|
60
60
|
} else {
|
|
61
61
|
// No saved state - sync with currently active tools
|
|
62
|
-
enabledTools = new Set(
|
|
62
|
+
enabledTools = new Set(elyra.getActiveTools());
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// Register /tools command
|
|
67
|
-
|
|
67
|
+
elyra.registerCommand("tools", {
|
|
68
68
|
description: "Enable/disable tools",
|
|
69
69
|
handler: async (_args, ctx) => {
|
|
70
70
|
// Refresh tool list
|
|
71
|
-
allTools =
|
|
71
|
+
allTools = elyra.getAllTools();
|
|
72
72
|
|
|
73
73
|
await ctx.ui.custom((tui, theme, _kb, done) => {
|
|
74
74
|
// Build settings items for each tool
|
|
@@ -130,12 +130,12 @@ export default function toolsExtension(pi: ExtensionAPI) {
|
|
|
130
130
|
});
|
|
131
131
|
|
|
132
132
|
// Restore state on session start
|
|
133
|
-
|
|
133
|
+
elyra.on("session_start", async (_event, ctx) => {
|
|
134
134
|
restoreFromBranch(ctx);
|
|
135
135
|
});
|
|
136
136
|
|
|
137
137
|
// Restore state when navigating the session tree
|
|
138
|
-
|
|
138
|
+
elyra.on("session_tree", async (_event, ctx) => {
|
|
139
139
|
restoreFromBranch(ctx);
|
|
140
140
|
});
|
|
141
141
|
}
|
|
@@ -2,7 +2,7 @@ import type { ExtensionAPI, ExtensionContext } from "@elyracode/coding-agent";
|
|
|
2
2
|
|
|
3
3
|
const COMPACT_THRESHOLD_TOKENS = 100_000;
|
|
4
4
|
|
|
5
|
-
export default function (
|
|
5
|
+
export default function (elyra: ExtensionAPI) {
|
|
6
6
|
let previousTokens: number | null | undefined;
|
|
7
7
|
|
|
8
8
|
const triggerCompaction = (ctx: ExtensionContext, customInstructions?: string) => {
|
|
@@ -24,7 +24,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
24
24
|
});
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
elyra.on("turn_end", (_event, ctx) => {
|
|
28
28
|
const usage = ctx.getContextUsage();
|
|
29
29
|
const currentTokens = usage?.tokens ?? null;
|
|
30
30
|
if (currentTokens === null) {
|
|
@@ -40,7 +40,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
40
40
|
triggerCompaction(ctx);
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
elyra.registerCommand("trigger-compact", {
|
|
44
44
|
description: "Trigger compaction immediately",
|
|
45
45
|
handler: async (args, ctx) => {
|
|
46
46
|
const instructions = args.trim() || undefined;
|
|
@@ -45,8 +45,8 @@ interface RgDetails {
|
|
|
45
45
|
fullOutputPath?: string;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
export default function (
|
|
49
|
-
|
|
48
|
+
export default function (elyra: ExtensionAPI) {
|
|
49
|
+
elyra.registerTool({
|
|
50
50
|
name: "rg",
|
|
51
51
|
label: "ripgrep",
|
|
52
52
|
// Document the truncation limits in the tool description so the LLM knows
|
|
@@ -109,7 +109,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
109
109
|
|
|
110
110
|
if (truncation.truncated) {
|
|
111
111
|
// Save full output to a temp file so LLM can access it if needed
|
|
112
|
-
const tempDir = await mkdtemp(join(tmpdir(), "
|
|
112
|
+
const tempDir = await mkdtemp(join(tmpdir(), "elyra-rg-"));
|
|
113
113
|
const tempFile = join(tempDir, "output.txt");
|
|
114
114
|
await withFileMutationQueue(tempFile, async () => {
|
|
115
115
|
await writeFile(tempFile, output, "utf8");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
2
2
|
|
|
3
|
-
export default function widgetPlacementExtension(
|
|
4
|
-
|
|
3
|
+
export default function widgetPlacementExtension(elyra: ExtensionAPI) {
|
|
4
|
+
elyra.on("session_start", (_event, ctx) => {
|
|
5
5
|
if (!ctx.hasUI) return;
|
|
6
6
|
ctx.ui.setWidget("widget-above", ["Above editor widget"]);
|
|
7
7
|
ctx.ui.setWidget("widget-below", ["Below editor widget"], { placement: "belowEditor" });
|