pi-btw 0.5.0 → 0.6.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/README.md +46 -2
- package/extensions/btw.ts +61 -7
- package/package.json +1 -1
- package/skills/btw/SKILL.md +30 -0
package/README.md
CHANGED
|
@@ -11,7 +11,9 @@ A small [pi](https://github.com/earendil-works/pi-mono) extension that adds a `/
|
|
|
11
11
|
- opens a parallel side conversation without interrupting the main run
|
|
12
12
|
- runs that side conversation as a real pi sub-session with `read` / `bash` / `edit` / `write` tool access
|
|
13
13
|
- keeps a continuous BTW thread by default
|
|
14
|
+
- accepts `/side` as an alias for the `/btw` entry command
|
|
14
15
|
- supports `/btw:tangent` for a contextless side thread that does not inherit the current main-session conversation
|
|
16
|
+
- supports `/btw:ask` for a read-only side thread that inherits main-session context but exposes only `read` / `grep` / `find` / `ls`
|
|
15
17
|
- opens a focused BTW modal shell with its own composer and transcript
|
|
16
18
|
- keeps the BTW overlay open while you switch focus back to the main editor with `Alt+/`, `Super+/`, or `Ctrl+Alt+W` (all remappable)
|
|
17
19
|
- keeps BTW thread entries out of the main agent's future context
|
|
@@ -51,10 +53,13 @@ pi install /absolute/path/to/pi-btw
|
|
|
51
53
|
|
|
52
54
|
```text
|
|
53
55
|
/btw what file defines this route?
|
|
56
|
+
/side what file defines this route?
|
|
54
57
|
/btw how would you refactor this parser?
|
|
55
58
|
/btw --save summarize the last error in one sentence
|
|
56
59
|
/btw:new let's start a fresh thread about auth
|
|
57
60
|
/btw:tangent brainstorm from first principles without using the current chat context
|
|
61
|
+
/btw:ask what does this module do?
|
|
62
|
+
/btw:ask --save explain the latest test failure
|
|
58
63
|
/btw:model openai gpt-5-mini openai-responses
|
|
59
64
|
/btw:thinking low
|
|
60
65
|
/btw:inject implement the plan we just discussed
|
|
@@ -77,6 +82,12 @@ pi install /absolute/path/to/pi-btw
|
|
|
77
82
|
- persists the BTW exchange as hidden thread state
|
|
78
83
|
- with `--save`, also saves that single exchange as a visible session note
|
|
79
84
|
|
|
85
|
+
### `/side [--save] <question>`
|
|
86
|
+
|
|
87
|
+
- alias for `/btw`, matching the equivalent command in Codex
|
|
88
|
+
- shares the same thread, overlay, persistence, model, and thinking settings as `/btw`
|
|
89
|
+
- `/btw` stays canonical; lifecycle commands remain under the `/btw:*` namespace, so there is no `/side:new` or `/side:clear`
|
|
90
|
+
|
|
80
91
|
## Overlay controls
|
|
81
92
|
|
|
82
93
|
- `Alt+w` toggles the overlay between the framed window layout (inset from the terminal edges) and a full-width layout
|
|
@@ -107,6 +118,17 @@ pi install /absolute/path/to/pi-btw
|
|
|
107
118
|
- opens or refreshes the same focused BTW modal shell
|
|
108
119
|
- with `--save`, also saves that single exchange as a visible session note
|
|
109
120
|
|
|
121
|
+
### `/btw:ask [--save] <question>`
|
|
122
|
+
|
|
123
|
+
- starts or continues an enforced read-only side thread
|
|
124
|
+
- inherits the current main-session conversation, exactly like `/btw`
|
|
125
|
+
- exposes only pi's built-in read-only tools (`read`, `grep`, `find`, `ls`); `bash`, `edit`, and `write` are never available to it
|
|
126
|
+
- follows up read-only for the lifetime of the thread
|
|
127
|
+
- identifies the thread as read-only in the overlay title
|
|
128
|
+
- if you switch between `/btw`, `/btw:tangent`, and `/btw:ask`, the previous side thread is cleared and the child session is recreated so the capability boundary stays unambiguous
|
|
129
|
+
- opens or refreshes the same focused BTW modal shell
|
|
130
|
+
- with `--save`, also saves that single exchange as a visible session note
|
|
131
|
+
|
|
110
132
|
### `/btw:clear`
|
|
111
133
|
|
|
112
134
|
- dismisses the BTW modal/widget
|
|
@@ -148,6 +170,7 @@ BTW is implemented as an actual pi sub-session with its own in-memory session st
|
|
|
148
170
|
|
|
149
171
|
- contextual `/btw` threads seed that sub-session from the current main-session branch while filtering out BTW-visible notes from the parent context
|
|
150
172
|
- `/btw:tangent` starts the same BTW UI in a contextless mode with no inherited main-session conversation
|
|
173
|
+
- `/btw:ask` seeds the same main-session context as `/btw` but restricts the child session's tool surface to pi's read-only tools, so the boundary is structural rather than prompt-based
|
|
151
174
|
- BTW can inherit the main thread model/thinking settings or use BTW-only overrides via `/btw:model` and `/btw:thinking`
|
|
152
175
|
- `/btw:summarize` uses the current effective BTW model but keeps thinking off
|
|
153
176
|
- the overlay transcript/status line is driven from sub-session events, so tool activity, streaming deltas, failures, and recovery are all visible without scraping rendered output
|
|
@@ -157,7 +180,7 @@ BTW is implemented as an actual pi sub-session with its own in-memory session st
|
|
|
157
180
|
|
|
158
181
|
Inside the BTW modal composer, slash handling is split at the BTW/session boundary:
|
|
159
182
|
|
|
160
|
-
- `/btw:new`, `/btw:tangent`, `/btw:clear`, `/btw:model`, `/btw:thinking`, `/btw:inject`, and `/btw:summarize` stay owned by BTW because they control BTW lifecycle, configuration, or handoff behavior
|
|
183
|
+
- `/btw:new`, `/btw:tangent`, `/btw:ask`, `/btw:clear`, `/btw:model`, `/btw:thinking`, `/btw:inject`, and `/btw:summarize` stay owned by BTW because they control BTW lifecycle, configuration, or handoff behavior
|
|
161
184
|
- any other slash-prefixed input is routed through the BTW sub-session's normal `prompt()` path
|
|
162
185
|
- this means ordinary pi slash commands like `/help` are handled by the sub-session instead of being rejected by a modal-only fallback
|
|
163
186
|
- if the sub-session cannot handle a slash command, BTW surfaces the real sub-session failure through the transcript/status state instead of inventing an "unsupported slash input" warning
|
|
@@ -172,7 +195,7 @@ BTW exchanges are persisted in the session as hidden custom entries so they:
|
|
|
172
195
|
|
|
173
196
|
- survive reloads and restarts
|
|
174
197
|
- rehydrate the BTW modal shell for the current branch
|
|
175
|
-
- preserve whether the current side thread is a normal `/btw` thread or a
|
|
198
|
+
- preserve whether the current side thread is a normal `/btw` thread, a contextless `/btw:tangent`, or a read-only `/btw:ask` thread
|
|
176
199
|
- preserve the current BTW-only model and thinking overrides for that session history
|
|
177
200
|
- stay out of the main agent's LLM context
|
|
178
201
|
|
|
@@ -210,6 +233,27 @@ To use it without installing:
|
|
|
210
233
|
pi -e /path/to/pi-btw
|
|
211
234
|
```
|
|
212
235
|
|
|
236
|
+
## DeepSeek Harness
|
|
237
|
+
|
|
238
|
+
pi-btw also runs unmodified on [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) through the [pi2dsh](https://github.com/weijiafu14/pi2dsh) compatibility bridge.
|
|
239
|
+
|
|
240
|
+
For DSH Web, install the **dsh-work-x** suite, which includes pi-btw, pi2dsh, a browser side-chat window, and other extensions:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
dsh plugin --profile web add dsh-work-x
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
To install just the bridge and this extension instead:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
dsh plugin --profile web add pi2dsh
|
|
250
|
+
dsh plugin --profile web add pi-btw
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Restart DSH after installation, then use `/btw <question>` to start a side conversation. The suite presents it in a browser side-chat window backed by a native DSH child session. DSH uses hyphens for the command family: for example, `/btw:inject` becomes `/btw-inject`.
|
|
254
|
+
|
|
255
|
+
See the [DSH side-conversation guide](https://github.com/weijiafu14/pi2dsh/tree/main/examples/side-conversation) for CLI-only installation, usage, and screenshots, and the [versioned validation results](https://github.com/weijiafu14/pi2dsh/tree/main/community/release-0.25.1) for the tested releases. Report DSH integration problems to [pi2dsh](https://github.com/weijiafu14/pi2dsh/issues).
|
|
256
|
+
|
|
213
257
|
## License
|
|
214
258
|
|
|
215
259
|
MIT
|
package/extensions/btw.ts
CHANGED
|
@@ -176,7 +176,7 @@ const BTW_CONTINUE_THREAD_USER_TEXT = "[The following is a separate side convers
|
|
|
176
176
|
const BTW_CONTINUE_THREAD_ASSISTANT_TEXT = "Understood, continuing our side conversation.";
|
|
177
177
|
|
|
178
178
|
type SessionThinkingLevel = "off" | AiThinkingLevel;
|
|
179
|
-
type BtwThreadMode = "contextual" | "tangent";
|
|
179
|
+
type BtwThreadMode = "contextual" | "tangent" | "readonly";
|
|
180
180
|
type SessionModel = NonNullable<ExtensionCommandContext["model"]>;
|
|
181
181
|
/**
|
|
182
182
|
* Loose model reference parsed from `/btw:model <provider> <id> <api>` and persisted to
|
|
@@ -443,6 +443,17 @@ function formatModelRef(model: Pick<SessionModel, "provider" | "id" | "api">): s
|
|
|
443
443
|
return `${model.provider}/${model.id} (${model.api})`;
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
+
/**
|
|
447
|
+
* Tool surfaces keyed by BTW mode. Read-only mode exposes only pi's built-in
|
|
448
|
+
* read-only tools so the child session cannot mutate the workspace; every other
|
|
449
|
+
* mode matches pi's default coding-agent toolset (read/bash/edit/write).
|
|
450
|
+
*/
|
|
451
|
+
const BTW_TOOLS_BY_MODE: Record<BtwThreadMode, readonly string[]> = {
|
|
452
|
+
contextual: ["read", "bash", "edit", "write"],
|
|
453
|
+
tangent: ["read", "bash", "edit", "write"],
|
|
454
|
+
readonly: ["read", "grep", "find", "ls"],
|
|
455
|
+
};
|
|
456
|
+
|
|
446
457
|
function buildBtwSeedState(
|
|
447
458
|
ctx: ExtensionCommandContext,
|
|
448
459
|
thread: BtwDetails[],
|
|
@@ -451,7 +462,7 @@ function buildBtwSeedState(
|
|
|
451
462
|
): { messages: Message[]; sideThreadStartIndex: number } {
|
|
452
463
|
const messages: Message[] = [];
|
|
453
464
|
|
|
454
|
-
if (mode === "contextual") {
|
|
465
|
+
if (mode === "contextual" || mode === "readonly") {
|
|
455
466
|
try {
|
|
456
467
|
messages.push(
|
|
457
468
|
...(buildSessionContext(ctx.sessionManager.getEntries(), ctx.sessionManager.getLeafId()).messages as Message[]).filter(
|
|
@@ -1217,7 +1228,7 @@ function canRenderBtwOverlay(ctx: ExtensionContext | ExtensionCommandContext): b
|
|
|
1217
1228
|
|
|
1218
1229
|
function notifyInlineQuestionRequired(
|
|
1219
1230
|
ctx: ExtensionCommandContext,
|
|
1220
|
-
command: "/btw" | "/btw:tangent" | "/btw:new",
|
|
1231
|
+
command: "/btw" | "/btw:tangent" | "/btw:new" | "/btw:ask",
|
|
1221
1232
|
): void {
|
|
1222
1233
|
notify(ctx, `${command} cannot open its composer outside Pi's TUI. Pass the question inline instead.`, "warning");
|
|
1223
1234
|
}
|
|
@@ -1234,7 +1245,13 @@ const BTW_OVERLAY_CHROME_LINES = 9;
|
|
|
1234
1245
|
const BTW_BLOCK_INDENT = " ";
|
|
1235
1246
|
|
|
1236
1247
|
function getOverlayTitle(mode: BtwThreadMode): string {
|
|
1237
|
-
|
|
1248
|
+
if (mode === "tangent") {
|
|
1249
|
+
return "BTW tangent";
|
|
1250
|
+
}
|
|
1251
|
+
if (mode === "readonly") {
|
|
1252
|
+
return "BTW ask · read-only";
|
|
1253
|
+
}
|
|
1254
|
+
return "BTW";
|
|
1238
1255
|
}
|
|
1239
1256
|
|
|
1240
1257
|
function buildTranscriptBadge(
|
|
@@ -1964,8 +1981,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
1964
1981
|
model: settings.model,
|
|
1965
1982
|
...modelRuntimeOptions,
|
|
1966
1983
|
thinkingLevel: settings.thinkingLevel,
|
|
1967
|
-
//
|
|
1968
|
-
tools: [
|
|
1984
|
+
// Read-only mode narrows this to pi's built-in read-only toolset.
|
|
1985
|
+
tools: [...BTW_TOOLS_BY_MODE[mode]],
|
|
1969
1986
|
resourceLoader: createBtwResourceLoader(ctx),
|
|
1970
1987
|
};
|
|
1971
1988
|
const { session } = await createAgentSession(sessionOptions);
|
|
@@ -2138,6 +2155,29 @@ export default function (pi: ExtensionAPI) {
|
|
|
2138
2155
|
return true;
|
|
2139
2156
|
}
|
|
2140
2157
|
|
|
2158
|
+
if (name === "btw:ask") {
|
|
2159
|
+
const { question, save } = parseBtwArgs(trimmedArgs);
|
|
2160
|
+
if (!question && !canRenderBtwOverlay(ctx)) {
|
|
2161
|
+
notifyInlineQuestionRequired(ctx, "/btw:ask");
|
|
2162
|
+
return true;
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
// Read-only mode is a distinct capability boundary, so switching into it
|
|
2166
|
+
// resets the thread and lets ensureBtwSession recreate the child session.
|
|
2167
|
+
if (pendingMode !== "readonly") {
|
|
2168
|
+
await resetThread(ctx, true, "readonly");
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
if (!question) {
|
|
2172
|
+
await ensureBtwSession(ctx, "readonly");
|
|
2173
|
+
await ensureOverlay(ctx);
|
|
2174
|
+
return true;
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
await runBtw(ctx, question, save, "readonly");
|
|
2178
|
+
return true;
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2141
2181
|
if (name === "btw:new") {
|
|
2142
2182
|
const { question, save } = parseBtwArgs(trimmedArgs);
|
|
2143
2183
|
if (!question && !canRenderBtwOverlay(ctx)) {
|
|
@@ -2274,7 +2314,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2274
2314
|
|
|
2275
2315
|
function parseOverlayBtwCommand(value: string): { name: string; args: string } | null {
|
|
2276
2316
|
const trimmed = value.trim();
|
|
2277
|
-
const match = trimmed.match(/^\/(btw:(?:new|tangent|clear|inject|summarize|model|thinking))(?:\s+(.*))?$/);
|
|
2317
|
+
const match = trimmed.match(/^\/(btw:(?:new|ask|tangent|clear|inject|summarize|model|thinking))(?:\s+(.*))?$/);
|
|
2278
2318
|
if (!match) {
|
|
2279
2319
|
return null;
|
|
2280
2320
|
}
|
|
@@ -2755,6 +2795,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
2755
2795
|
},
|
|
2756
2796
|
});
|
|
2757
2797
|
|
|
2798
|
+
pi.registerCommand("side", {
|
|
2799
|
+
description: "Alias for /btw: continue a side conversation in a focused BTW modal.",
|
|
2800
|
+
handler: async (args, ctx) => {
|
|
2801
|
+
await dispatchBtwCommand("btw", args, ctx);
|
|
2802
|
+
},
|
|
2803
|
+
});
|
|
2804
|
+
|
|
2758
2805
|
pi.registerCommand("btw:tangent", {
|
|
2759
2806
|
description: "Start or continue a contextless BTW tangent in the focused BTW modal.",
|
|
2760
2807
|
handler: async (args, ctx) => {
|
|
@@ -2762,6 +2809,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
2762
2809
|
},
|
|
2763
2810
|
});
|
|
2764
2811
|
|
|
2812
|
+
pi.registerCommand("btw:ask", {
|
|
2813
|
+
description: "Ask a read-only side question: inherits main-session context but exposes only read/grep/find/ls tools.",
|
|
2814
|
+
handler: async (args, ctx) => {
|
|
2815
|
+
await dispatchBtwCommand("btw:ask", args, ctx);
|
|
2816
|
+
},
|
|
2817
|
+
});
|
|
2818
|
+
|
|
2765
2819
|
pi.registerCommand("btw:new", {
|
|
2766
2820
|
description: "Start a fresh BTW thread with main-session context. Optionally ask the first question immediately.",
|
|
2767
2821
|
handler: async (args, ctx) => {
|
package/package.json
CHANGED
package/skills/btw/SKILL.md
CHANGED
|
@@ -22,10 +22,13 @@ Use these commands in your guidance to the user:
|
|
|
22
22
|
|
|
23
23
|
```text
|
|
24
24
|
/btw <question>
|
|
25
|
+
/side <question>
|
|
25
26
|
/btw --save <question>
|
|
26
27
|
/btw:new [question]
|
|
27
28
|
/btw:tangent <question>
|
|
28
29
|
/btw:tangent --save <question>
|
|
30
|
+
/btw:ask <question>
|
|
31
|
+
/btw:ask --save <question>
|
|
29
32
|
/btw:clear
|
|
30
33
|
/btw:model [<provider> <model> <api> | clear]
|
|
31
34
|
/btw:thinking [<level> | clear]
|
|
@@ -33,6 +36,8 @@ Use these commands in your guidance to the user:
|
|
|
33
36
|
/btw:summarize [instructions]
|
|
34
37
|
```
|
|
35
38
|
|
|
39
|
+
`/side` is an alias for `/btw` and shares the same thread, overlay, and settings. `/btw` is canonical; the lifecycle commands stay in the `/btw:*` namespace.
|
|
40
|
+
|
|
36
41
|
## How to guide the user
|
|
37
42
|
|
|
38
43
|
### For a quick side question
|
|
@@ -45,6 +50,8 @@ Recommend:
|
|
|
45
50
|
|
|
46
51
|
Use this when the user wants an immediate aside and does not need a visible saved note.
|
|
47
52
|
|
|
53
|
+
Users coming from Codex may reach for `/side` instead; it is an alias for `/btw` and can be used anywhere `/btw` is used.
|
|
54
|
+
|
|
48
55
|
### For a saved one-off note
|
|
49
56
|
|
|
50
57
|
Recommend:
|
|
@@ -87,6 +94,22 @@ or
|
|
|
87
94
|
|
|
88
95
|
Use this when the user wants a side conversation that does not include the current main-session context.
|
|
89
96
|
|
|
97
|
+
### For an enforced read-only side question
|
|
98
|
+
|
|
99
|
+
Recommend:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
/btw:ask <question>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
or
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
/btw:ask --save <question>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Use this when the user wants a side question that inherits the current main-session context but must not be able to change anything. The read-only thread only has `read`, `grep`, `find`, and `ls`; it never has `bash`, `edit`, or `write`.
|
|
112
|
+
|
|
90
113
|
### To hand the full thread back to the main agent
|
|
91
114
|
|
|
92
115
|
Recommend:
|
|
@@ -122,6 +145,7 @@ Use these when the main thread should keep its current model or thinking level,
|
|
|
122
145
|
|
|
123
146
|
- Prefer `/btw` over normal chat when the user explicitly wants a side conversation.
|
|
124
147
|
- Prefer `/btw:tangent` when the user wants that side conversation to be contextless.
|
|
148
|
+
- Prefer `/btw:ask` when the user wants a side conversation that cannot modify the workspace.
|
|
125
149
|
- Prefer `/btw:summarize` over `/btw:inject` for long exploratory threads.
|
|
126
150
|
- Prefer `/btw:inject` when precise wording, detailed tradeoffs, or a full plan matters.
|
|
127
151
|
- Suggest `/btw:new` before starting a totally unrelated side topic when main-session context is still useful.
|
|
@@ -156,6 +180,12 @@ When helping the user use BTW:
|
|
|
156
180
|
/btw:tangent think through this from first principles without using the current chat context
|
|
157
181
|
```
|
|
158
182
|
|
|
183
|
+
### Example: ask a read-only side question
|
|
184
|
+
|
|
185
|
+
```text
|
|
186
|
+
/btw:ask what does the token refresh path do without changing anything?
|
|
187
|
+
```
|
|
188
|
+
|
|
159
189
|
### Example: send the result back
|
|
160
190
|
|
|
161
191
|
```text
|