@elyracode/btw 0.7.15
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 +11 -0
- package/README.md +38 -0
- package/extensions/index.ts +142 -0
- package/package.json +37 -0
- package/skills/elyra-btw/SKILL.md +32 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.7.15] - 2026-05-25
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `/btw` command: parallel side conversations with tool access
|
|
7
|
+
- `/btw:inject` to send thread back to main agent
|
|
8
|
+
- `/btw:summarize` to summarize and inject
|
|
9
|
+
- `/btw:clear` to clear the thread
|
|
10
|
+
- `/btw:thread` to show current thread
|
|
11
|
+
- `elyra-btw` skill for side conversation guidance
|
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# @elyracode/btw
|
|
2
|
+
|
|
3
|
+
Side conversations for Elyra. Ask questions while the main agent works, explore ideas without derailing the session, and inject results back when ready.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
elyra install npm:@elyracode/btw
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
| Command | Description |
|
|
14
|
+
|---------|-------------|
|
|
15
|
+
| `/btw <question>` | Ask a side question with tool access (runs in parallel) |
|
|
16
|
+
| `/btw:inject` | Send the BTW thread back to the main agent |
|
|
17
|
+
| `/btw:summarize` | Summarize the BTW thread and inject the summary |
|
|
18
|
+
| `/btw:clear` | Clear the BTW thread |
|
|
19
|
+
| `/btw:thread` | Show the current BTW thread |
|
|
20
|
+
|
|
21
|
+
## Why
|
|
22
|
+
|
|
23
|
+
Sometimes you want to:
|
|
24
|
+
- Ask a clarifying question while the main agent keeps working
|
|
25
|
+
- Check something quickly without polluting the main context
|
|
26
|
+
- Think through an approach before committing to it
|
|
27
|
+
- Explore an idea, then inject it back once it's ready
|
|
28
|
+
|
|
29
|
+
BTW runs as an isolated sub-process with full tool access (read, bash, edit, write). Its context is separate from the main session — no token tax on the main agent.
|
|
30
|
+
|
|
31
|
+
## Examples
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
/btw what does the validateToken method return?
|
|
35
|
+
/btw how many tests are in the auth module?
|
|
36
|
+
/btw:inject implement the approach we discussed
|
|
37
|
+
/btw:clear
|
|
38
|
+
```
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@elyracode/coding-agent";
|
|
2
|
+
|
|
3
|
+
// ── Types ───────────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
interface BtwEntry {
|
|
6
|
+
role: "user" | "assistant";
|
|
7
|
+
text: string;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// ── Extension ───────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
export default function (elyra: ExtensionAPI): void {
|
|
14
|
+
let cwd = "";
|
|
15
|
+
const thread: BtwEntry[] = [];
|
|
16
|
+
|
|
17
|
+
elyra.on("session_start", async (_event, ctx) => {
|
|
18
|
+
cwd = ctx.cwd;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// ── /btw <question> ──────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
elyra.registerCommand("btw", {
|
|
24
|
+
description: "Side conversation — ask a question in parallel without affecting the main session",
|
|
25
|
+
async handler(args, ctx) {
|
|
26
|
+
// Sub-commands
|
|
27
|
+
if (args === ":clear" || args.startsWith(":clear ")) {
|
|
28
|
+
thread.length = 0;
|
|
29
|
+
ctx.ui.notify("BTW thread cleared", "info");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (args === ":thread" || args.startsWith(":thread ")) {
|
|
34
|
+
if (thread.length === 0) {
|
|
35
|
+
ctx.ui.notify("BTW thread is empty", "info");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const formatted = thread
|
|
39
|
+
.map((e) => `[${e.role}] ${e.text}`)
|
|
40
|
+
.join("\n\n");
|
|
41
|
+
ctx.ui.notify(`BTW thread (${thread.length} entries):\n\n${formatted}`, "info");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (args === ":inject" || args.startsWith(":inject ")) {
|
|
46
|
+
if (thread.length === 0) {
|
|
47
|
+
ctx.ui.notify("BTW thread is empty, nothing to inject", "info");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const extra = args.slice(":inject".length).trim();
|
|
51
|
+
const formatted = thread
|
|
52
|
+
.map((e) => `[${e.role}] ${e.text}`)
|
|
53
|
+
.join("\n\n");
|
|
54
|
+
const message = extra
|
|
55
|
+
? `From a side conversation (BTW):\n\n${formatted}\n\nInstructions: ${extra}`
|
|
56
|
+
: `From a side conversation (BTW):\n\n${formatted}`;
|
|
57
|
+
await ctx.sendUserMessage(message);
|
|
58
|
+
thread.length = 0;
|
|
59
|
+
ctx.ui.notify("BTW thread injected into main session and cleared", "info");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (args === ":summarize" || args.startsWith(":summarize ")) {
|
|
64
|
+
if (thread.length === 0) {
|
|
65
|
+
ctx.ui.notify("BTW thread is empty, nothing to summarize", "info");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const extra = args.slice(":summarize".length).trim();
|
|
69
|
+
const formatted = thread
|
|
70
|
+
.map((e) => `[${e.role}] ${e.text}`)
|
|
71
|
+
.join("\n\n");
|
|
72
|
+
|
|
73
|
+
// Use elyra -p to summarize in isolation
|
|
74
|
+
ctx.ui.notify("Summarizing BTW thread...", "info");
|
|
75
|
+
const summaryPrompt = `Summarize this side conversation concisely. Focus on decisions, findings, and actionable conclusions.\n\n${formatted}${extra ? `\n\nFocus: ${extra}` : ""}`;
|
|
76
|
+
|
|
77
|
+
const result = await elyra.exec("elyra", ["-p", "--no-session", summaryPrompt], {
|
|
78
|
+
timeout: 60_000,
|
|
79
|
+
cwd,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const summary = result.stdout.trim() || "(summary failed)";
|
|
83
|
+
await ctx.sendUserMessage(`Summary from a side conversation (BTW):\n\n${summary}`);
|
|
84
|
+
thread.length = 0;
|
|
85
|
+
ctx.ui.notify("BTW summary injected and thread cleared", "info");
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Main /btw <question> handler
|
|
90
|
+
const question = args.trim();
|
|
91
|
+
if (!question) {
|
|
92
|
+
if (thread.length === 0) {
|
|
93
|
+
ctx.ui.notify(
|
|
94
|
+
"Usage: /btw <question>\n\nSub-commands: :inject, :summarize, :clear, :thread",
|
|
95
|
+
"info",
|
|
96
|
+
);
|
|
97
|
+
} else {
|
|
98
|
+
ctx.ui.notify(
|
|
99
|
+
`BTW thread has ${thread.length} entries.\n\nSub-commands: :inject, :summarize, :clear, :thread`,
|
|
100
|
+
"info",
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Build context from thread history for continuity
|
|
107
|
+
const historyContext = thread.length > 0
|
|
108
|
+
? `Previous side conversation:\n${thread.map((e) => `[${e.role}] ${e.text}`).join("\n")}\n\nNew question: ${question}`
|
|
109
|
+
: question;
|
|
110
|
+
|
|
111
|
+
// Add user entry
|
|
112
|
+
thread.push({ role: "user", text: question, timestamp: Date.now() });
|
|
113
|
+
|
|
114
|
+
ctx.ui.notify(`BTW: "${truncate(question, 60)}" — working...`, "info");
|
|
115
|
+
|
|
116
|
+
// Run in isolated process with tool access
|
|
117
|
+
const result = await elyra.exec("elyra", ["-p", "--no-session", historyContext], {
|
|
118
|
+
timeout: 120_000,
|
|
119
|
+
cwd,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const response = result.stdout.trim();
|
|
123
|
+
if (result.code !== 0 || !response) {
|
|
124
|
+
const error = result.stderr.trim() || "No response";
|
|
125
|
+
thread.push({ role: "assistant", text: `(error: ${error})`, timestamp: Date.now() });
|
|
126
|
+
ctx.ui.notify(`BTW error: ${truncate(error, 200)}`, "error");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Add assistant entry
|
|
131
|
+
thread.push({ role: "assistant", text: response, timestamp: Date.now() });
|
|
132
|
+
|
|
133
|
+
// Show response
|
|
134
|
+
ctx.ui.notify(`BTW response:\n\n${response}`, "info");
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function truncate(text: string, maxLen: number): string {
|
|
140
|
+
if (text.length <= maxLen) return text;
|
|
141
|
+
return `${text.slice(0, maxLen)}...`;
|
|
142
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elyracode/btw",
|
|
3
|
+
"version": "0.7.15",
|
|
4
|
+
"description": "Side conversations for Elyra -- ask questions while the agent works, inject results back when ready",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"elyra-package",
|
|
8
|
+
"btw",
|
|
9
|
+
"side-chat",
|
|
10
|
+
"parallel",
|
|
11
|
+
"subagent"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Knut W. Horne",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/kwhorne/elyra.git",
|
|
18
|
+
"directory": "packages/btw"
|
|
19
|
+
},
|
|
20
|
+
"elyra": {
|
|
21
|
+
"extensions": [
|
|
22
|
+
"./extensions/index.ts"
|
|
23
|
+
],
|
|
24
|
+
"skills": [
|
|
25
|
+
"./skills"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@elyracode/coding-agent": "*",
|
|
30
|
+
"typebox": "*"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"clean": "echo 'nothing to clean'",
|
|
34
|
+
"build": "echo 'nothing to build'",
|
|
35
|
+
"check": "echo 'nothing to check'"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: elyra-btw
|
|
3
|
+
description: Side conversations. Use when the user wants to ask a quick question without interrupting the main task, explore an idea in parallel, or have a scratchpad conversation that can be injected back later.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Side Conversations with /btw
|
|
7
|
+
|
|
8
|
+
## When to Suggest
|
|
9
|
+
|
|
10
|
+
Suggest `/btw` when:
|
|
11
|
+
- The user asks a tangential question while you're working on something
|
|
12
|
+
- The user wants to check something without derailing the current task
|
|
13
|
+
- The user says "by the way" or "quick question" or "while you're at it"
|
|
14
|
+
- The user wants to brainstorm before committing to an approach
|
|
15
|
+
|
|
16
|
+
## Commands
|
|
17
|
+
|
|
18
|
+
| Command | What it does |
|
|
19
|
+
|---------|-------------|
|
|
20
|
+
| `/btw <question>` | Ask a question in a parallel side session with tool access |
|
|
21
|
+
| `/btw:inject` | Send the full BTW thread into this conversation |
|
|
22
|
+
| `/btw:summarize` | Summarize the BTW thread and inject the summary |
|
|
23
|
+
| `/btw:clear` | Clear the BTW thread |
|
|
24
|
+
| `/btw:thread` | Show the current BTW thread history |
|
|
25
|
+
|
|
26
|
+
## Key Behavior
|
|
27
|
+
|
|
28
|
+
- BTW runs in an isolated process — its context is separate from this session
|
|
29
|
+
- BTW has full tool access (read, bash, edit, write, grep, find, ls)
|
|
30
|
+
- BTW thread persists across questions until cleared
|
|
31
|
+
- BTW does NOT affect the main agent's context window
|
|
32
|
+
- Use `/btw:inject` or `/btw:summarize` to bring results back when ready
|