pi-bro 0.13.0 → 0.13.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 CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to pi-bro are documented here.
4
4
 
5
+ ## [0.13.1] - 2026-09-17
6
+
7
+ ### Changed
8
+
9
+ - Renamed `/bro btw` composer commands from `/send` and `/send all` to `/copy` and `/copy-all` (also accepts `/copy all`), with `/copy!` and `/copy-all!` force variants to replace existing main-editor drafts. Legacy `/send` commands remain supported as aliases.
10
+
5
11
  ## [0.13.0] - 2026-09-15
6
12
 
7
13
  ### Added
package/README.md CHANGED
@@ -108,7 +108,7 @@ your terminal mode; press **C** to copy the complete explanation reliably.
108
108
  `/bro btw` opens a separate multi-turn conversation in a modal, so you can ask
109
109
  a quick side question while the main agent keeps working. It runs through Agy,
110
110
  the same backend as the rest of Bro, and never adds anything to Pi's
111
- conversation unless you explicitly send it back.
111
+ conversation unless you explicitly copy it into the editor.
112
112
 
113
113
  - **Sandboxed by default**: the side conversation is read-only (no project
114
114
  access). Add `--full` to let it read and edit the workspace.
@@ -119,8 +119,8 @@ conversation unless you explicitly send it back.
119
119
  conversation text (40,000 characters max, with a truncation notice); the
120
120
  side agent can also read the repo itself when running in `--full` mode.
121
121
  - **In the modal**: type a question and press Enter (empty Enter re-asks the
122
- last question). `/send` copies the latest answer into the main editor
123
- without submitting (use `/send!` to replace an existing draft); `/send all`
122
+ last question). `/copy` copies the latest answer into the main editor
123
+ without submitting (use `/copy!` to replace an existing draft); `/copy-all`
124
124
  copies the full thread; `/retry` re-asks
125
125
  the last question; `/clear` resets the thread; Esc closes. A visible
126
126
  `full · edits repo` badge shows whenever `--full` mode is active.
package/bro.ts CHANGED
@@ -1098,7 +1098,7 @@ Press **R** to simplify the captured source again. Run a new \`/bro text\`, \`/b
1098
1098
 
1099
1099
  ## Side conversation
1100
1100
 
1101
- - \`/bro btw [--fresh] [--full] [question]\` — open a side conversation. Sandboxed (read-only) by default; add \`--full\` to let it read and edit the workspace, and \`--fresh\` to start without main-session context. Inside the side thread, type questions and press Enter (empty Enter re-asks); \`/send\` copies the latest answer to the main editor without submitting (use \`/send!\` to replace an existing draft), \`/send all\` the full thread, \`/retry\` re-asks the last question, and \`/clear\` resets the thread. Esc closes.
1101
+ - \`/bro btw [--fresh] [--full] [question]\` — open a side conversation. Sandboxed (read-only) by default; add \`--full\` to let it read and edit the workspace, and \`--fresh\` to start without main-session context. Inside the side thread, type questions and press Enter (empty Enter re-asks); \`/copy\` copies the latest answer to the main editor without submitting (use \`/copy!\` to replace an existing draft), \`/copy-all\` the full thread, \`/retry\` re-asks the last question, and \`/clear\` resets the thread. Esc closes.
1102
1102
 
1103
1103
  ## Current settings
1104
1104
 
@@ -1496,6 +1496,37 @@ export function parseBtwAgyLine(line: string): { delta?: string; result?: string
1496
1496
  return { conversationId };
1497
1497
  }
1498
1498
 
1499
+ export type BtwComposerAction =
1500
+ | { kind: "clear" }
1501
+ | { kind: "retry" }
1502
+ | { kind: "copy"; all: boolean; force: boolean }
1503
+ | { kind: "question"; text: string };
1504
+
1505
+ export function parseBtwComposerCommand(value: string): BtwComposerAction {
1506
+ const command = value.trim();
1507
+ if (command === "/clear") return { kind: "clear" };
1508
+ if (command === "/retry" || command === "") return { kind: "retry" };
1509
+ if (
1510
+ command === "/copy" ||
1511
+ command === "/copy!" ||
1512
+ command === "/copy-all" ||
1513
+ command === "/copy-all!" ||
1514
+ command === "/copy all" ||
1515
+ command === "/copy all!" ||
1516
+ command === "/send" ||
1517
+ command === "/send!" ||
1518
+ command === "/send all" ||
1519
+ command === "/send all!"
1520
+ ) {
1521
+ const all =
1522
+ command.startsWith("/copy-all") ||
1523
+ command.startsWith("/copy all") ||
1524
+ command.startsWith("/send all");
1525
+ return { kind: "copy", all, force: command.endsWith("!") };
1526
+ }
1527
+ return { kind: "question", text: command };
1528
+ }
1529
+
1499
1530
  async function runBtwTurn(
1500
1531
  prompt: string,
1501
1532
  selection: ReturnType<typeof agySelection>,
@@ -1725,7 +1756,7 @@ class BtwModal implements Focusable {
1725
1756
 
1726
1757
  const controls = this.running
1727
1758
  ? this.theme.fg("dim", "Thinking… · Esc cancel")
1728
- : this.theme.fg("dim", "Enter ask · Esc close · /send · /send all · /clear · /retry");
1759
+ : this.theme.fg("dim", "Enter ask · Esc close · /copy · /copy-all · /clear · /retry");
1729
1760
 
1730
1761
  const lines = [
1731
1762
  this.borderLine(innerWidth, "top"),
@@ -1845,35 +1876,35 @@ async function openBtwModal(
1845
1876
  const handoff = (all: boolean, force: boolean) => {
1846
1877
  const text = all ? transcript() : (thread.turns.at(-1)?.answer ?? "");
1847
1878
  if (!text.trim()) {
1848
- modal.setNotice("Nothing to send yet.");
1879
+ modal.setNotice("Nothing to copy yet.");
1849
1880
  return;
1850
1881
  }
1851
1882
  if (ctx.ui.getEditorText().trim() && !force) {
1852
- modal.setNotice("Main editor has a draft. Use /send! (or /send all!) to replace it.");
1883
+ modal.setNotice("Main editor has a draft. Use /copy! (or /copy-all!) to replace it.");
1853
1884
  return;
1854
1885
  }
1855
1886
  ctx.ui.setEditorText(text);
1856
- modal.setNotice(all ? "Sent the full thread to the editor." : "Sent the latest answer to the editor.");
1887
+ modal.setNotice(all ? "Copied the full thread to the editor." : "Copied the latest answer to the editor.");
1857
1888
  };
1858
1889
 
1859
1890
  function submit(value: string): void {
1860
- const command = value.trim();
1861
- if (command === "/clear") {
1891
+ const action = parseBtwComposerCommand(value);
1892
+ if (action.kind === "clear") {
1862
1893
  modal.clearComposer();
1863
1894
  clear();
1864
1895
  return;
1865
1896
  }
1866
- if (command === "/send" || command === "/send all" || command === "/send!" || command === "/send all!") {
1897
+ if (action.kind === "copy") {
1867
1898
  modal.clearComposer();
1868
- handoff(command === "/send all" || command === "/send all!", command.endsWith("!"));
1899
+ handoff(action.all, action.force);
1869
1900
  return;
1870
1901
  }
1871
- if (command === "/retry" || command === "") {
1902
+ if (action.kind === "retry") {
1872
1903
  modal.clearComposer();
1873
1904
  retry();
1874
1905
  return;
1875
1906
  }
1876
- void runTurn(command);
1907
+ void runTurn(action.text);
1877
1908
  }
1878
1909
 
1879
1910
  modal.setFull(thread.full);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-bro",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "An Earendil Pi extension that explains pasted text, assistant responses, local documents, public webpages, and recent session turns (as shapes) in a context-isolated window, and opens a sandboxed side conversation with /bro btw.",
5
5
  "type": "module",
6
6
  "license": "MIT",