pi-bro 0.19.0 → 0.19.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 +7 -0
- package/README.md +1 -0
- package/bro.ts +11 -9
- package/docs/README.md +8 -0
- package/docs/pig-compatibility.md +42 -0
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to pi-bro are documented here.
|
|
4
4
|
|
|
5
|
+
## [0.19.1] - 2026-09-30
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Always enforce Bro's restrictive content policy on generated HTML, including when model output contains a permissive policy or CSP-looking comment (#69).
|
|
10
|
+
- Isolate smoke-test temporary artifacts and block real backend CLIs during offline tests. Order settings mutations by RPC acknowledgements instead of fixed sleeps, and support spaces in settings-test checkout paths (#70).
|
|
11
|
+
|
|
5
12
|
## [0.19.0] - 2026-09-25
|
|
6
13
|
|
|
7
14
|
### Added
|
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ plain-language explanation — or open a separate side conversation with
|
|
|
5
5
|
`/bro btw` — without adding anything to your main agent's context.
|
|
6
6
|
|
|
7
7
|
`pi-bro` is an extension for [Earendil Pi](https://github.com/earendil-works/pi).
|
|
8
|
+
Experimental [PiG 0.3.0 compatibility](docs/pig-compatibility.md) uses the same npm package and requires Node.js. See the compatibility notes for verified coverage and the PiG RPC tool-exclusion limitation.
|
|
8
9
|
It opens explanations in a separate modal and runs them through a CLI backend
|
|
9
10
|
you already have installed and signed in to. Explain, show, BTW, and the
|
|
10
11
|
advisor all work across five backends:
|
package/bro.ts
CHANGED
|
@@ -5,12 +5,12 @@ import { mkdir, mkdtemp, readdir, readFile, realpath, rm, stat, writeFile } from
|
|
|
5
5
|
import { request as httpRequest, type IncomingMessage } from "node:http";
|
|
6
6
|
import { request as httpsRequest } from "node:https";
|
|
7
7
|
import { BlockList, isIP } from "node:net";
|
|
8
|
-
import {
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
9
|
import { extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
10
10
|
import { stripVTControlCharacters } from "node:util";
|
|
11
11
|
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, SessionEntry } from "@earendil-works/pi-coding-agent";
|
|
12
12
|
import { Container, Editor, Input, Markdown, SettingsList, SelectList, Text, matchesKey, truncateToWidth, visibleWidth, type Component, type EditorTheme, type Focusable, type SelectItem, type SettingItem, type TUI } from "@earendil-works/pi-tui";
|
|
13
|
-
import { convertToLlm, copyToClipboard, getMarkdownTheme, getSelectListTheme, getSettingsListTheme } from "@earendil-works/pi-coding-agent";
|
|
13
|
+
import { convertToLlm, copyToClipboard, getAgentDir, getMarkdownTheme, getSelectListTheme, getSettingsListTheme } from "@earendil-works/pi-coding-agent";
|
|
14
14
|
import { Defuddle } from "defuddle/node";
|
|
15
15
|
import { parseHTML } from "linkedom";
|
|
16
16
|
import mammoth from "mammoth";
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
|
|
36
36
|
export { agyFailureMessage, agySelection, advisorFlagErrorHint, parseBtwAgyLine };
|
|
37
37
|
|
|
38
|
-
const AGENT_DIR =
|
|
38
|
+
const AGENT_DIR = getAgentDir();
|
|
39
39
|
const ENV_MODEL = process.env.PI_BRO_MODEL?.trim();
|
|
40
40
|
const DEFAULT_MODEL = ENV_MODEL || "gemini-3.7-flash";
|
|
41
41
|
const PROMPT_FILE = join(AGENT_DIR, "bro-prompt.md");
|
|
@@ -57,7 +57,7 @@ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
|
|
|
57
57
|
type Theme = ExtensionCommandContext["ui"]["theme"];
|
|
58
58
|
type TuiLike = {
|
|
59
59
|
readonly mode: "regular" | "fullscreen";
|
|
60
|
-
readonly terminal?: { write?: (data: string) => void };
|
|
60
|
+
readonly terminal?: { rows?: number; write?: (data: string) => void };
|
|
61
61
|
requestRender(): void;
|
|
62
62
|
};
|
|
63
63
|
type ModalKind = "loading" | "streaming" | "result" | "help" | "empty" | "error";
|
|
@@ -1561,10 +1561,12 @@ export function showHtmlDirectory(): string {
|
|
|
1561
1561
|
|
|
1562
1562
|
function withShowCsp(html: string): string {
|
|
1563
1563
|
// Defense in depth: the prompt forbids external resources and scripts;
|
|
1564
|
-
// a meta CSP blocks them anyway if the model slips.
|
|
1564
|
+
// a meta CSP blocks them anyway if the model slips. Always inserted: multiple
|
|
1565
|
+
// policies are enforced together, so a model-supplied CSP can only tighten it.
|
|
1566
|
+
// Skip only simple leading comments: browsers accept comment terminators that
|
|
1567
|
+
// a general regex misses. Ambiguous markup gets the policy prepended instead.
|
|
1565
1568
|
const meta = '<meta http-equiv="Content-Security-Policy" content="default-src \'none\'; style-src \'unsafe-inline\'; img-src data:;">';
|
|
1566
|
-
|
|
1567
|
-
return html.replace(/^(\s*(?:<!doctype[^>]*>\s*)?)/i, `$1\n${meta}\n`);
|
|
1569
|
+
return html.replace(/^(\s*(?:<!--[^<>]*-->\s*)*(?:<!doctype[^>]*>\s*)?)/i, `$1\n${meta}\n`);
|
|
1568
1570
|
}
|
|
1569
1571
|
|
|
1570
1572
|
export async function writeShowHtml(html: string): Promise<string> {
|
|
@@ -2798,7 +2800,7 @@ class BroModal implements Focusable {
|
|
|
2798
2800
|
render(width: number): string[] {
|
|
2799
2801
|
const dialogWidth = Math.max(24, width);
|
|
2800
2802
|
const innerWidth = Math.max(22, dialogWidth - 2);
|
|
2801
|
-
const terminalRows = process.stdout.rows ?? 30;
|
|
2803
|
+
const terminalRows = this.tui.terminal?.rows ?? process.stdout.rows ?? 30;
|
|
2802
2804
|
const dialogHeight = Math.min(32, Math.max(7, Math.floor(terminalRows * 0.78)));
|
|
2803
2805
|
this.bodyHeight = Math.max(1, dialogHeight - 6);
|
|
2804
2806
|
|
|
@@ -3231,7 +3233,7 @@ class BtwModal implements Focusable {
|
|
|
3231
3233
|
render(width: number): string[] {
|
|
3232
3234
|
const dialogWidth = Math.max(24, width);
|
|
3233
3235
|
const innerWidth = Math.max(22, dialogWidth - 2);
|
|
3234
|
-
const terminalRows = process.stdout.rows ?? 30;
|
|
3236
|
+
const terminalRows = this.tui.terminal?.rows ?? process.stdout.rows ?? 30;
|
|
3235
3237
|
const dialogHeight = Math.min(34, Math.max(8, Math.floor(terminalRows * 0.82)));
|
|
3236
3238
|
this.bodyHeight = Math.max(1, dialogHeight - 7);
|
|
3237
3239
|
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# pi-bro docs
|
|
2
|
+
|
|
3
|
+
- [README](../README.md) — the user guide (authoritative for behavior).
|
|
4
|
+
- [DEVELOPMENT.md](DEVELOPMENT.md) — code map, settings and BTW continuation model, invariants, test commands.
|
|
5
|
+
- [TESTING.md](TESTING.md) — the manual end-to-end checklist across backends.
|
|
6
|
+
- [plans/](plans/README.md) — historical design notes and plans; not the current spec.
|
|
7
|
+
- [images/](images/) — screenshots used by the README.
|
|
8
|
+
- [benchmark/README.md](../benchmark/README.md) — the manual, live prompt benchmark.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# PiG compatibility
|
|
2
|
+
|
|
3
|
+
Bro uses one TypeScript package on Pi and Pi-in-Go (PiG). PiG runs Bro in a Node subprocess; it is not a Go port or a fused native extension.
|
|
4
|
+
|
|
5
|
+
## Target and installation
|
|
6
|
+
|
|
7
|
+
PiG **0.3.0+0.87.1**, Node **>=22.19.0**. Compatibility is experimental; the checks below are not a guarantee for every PiG release or platform.
|
|
8
|
+
|
|
9
|
+
Install the PiG binary from https://github.com/MichaelKinsy/PiG/releases/tag/v0.3.0, then:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pig install npm:pi-bro
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
That command installs the published Bro version; these compatibility changes take effect only after a Bro release containing them. To test this checkout now, install dependencies and use `pig -e ./bro.ts`.
|
|
16
|
+
|
|
17
|
+
At initial verification, `@pi-in-go/pig@0.3.0` was not available from npm. CI therefore downloads the pinned GitHub binary and verifies its published SHA-256 checksum.
|
|
18
|
+
|
|
19
|
+
Bro follows the host's `getAgentDir()`: normally `~/.pi/agent` on Pi and `~/.pig/agent` on PiG. PiG supports `PIG_CODING_AGENT_DIR`, `PIG_HOME`, XDG configuration and explicit `PIG_USE_PI_DIRS=1` sharing. No automatic migration or copying of existing Bro settings takes place. `PI_BRO_MODEL` remains the same Bro-specific override on both hosts.
|
|
20
|
+
|
|
21
|
+
## Known limitations
|
|
22
|
+
|
|
23
|
+
- **PiG 0.3.0 RPC does not enforce `--exclude-tools`.** Excluded tools may remain active and reach provider requests. This is not a sandbox boundary. Use an explicit `--tools` allowlist instead; do not rely on `/bro doctor` to prove exclusion. Bro does not mask this defect by falsely reporting an active tool as unavailable.
|
|
24
|
+
- The smoke suite retains Pi's strict exclusion assertion. The PiG lane has an explicit version-specific expected failure; a changed result fails the lane so the exception must be reviewed/removed.
|
|
25
|
+
- Mouse-wheel forwarding is not qualified; use keyboard scrolling.
|
|
26
|
+
- Remote/SSH OSC 52 clipboard forwarding is not qualified. Local clipboard behavior depends on the host and installed platform utilities.
|
|
27
|
+
- Windows support is not qualified by these checks.
|
|
28
|
+
|
|
29
|
+
## Verification and release gate
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
npm test
|
|
33
|
+
PIG_BIN=/absolute/path/to/pig sh pig-test.sh
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The PiG lane checks the exact binary version, real host settings isolation, advisor snapshot compaction/branch projection, and the existing fake-backend RPC smoke suite. Existing Node tests cover backend cancellation/process cleanup and modal geometry, but are not substitutes for real-host interactive tests.
|
|
37
|
+
|
|
38
|
+
CI and publishing call `.github/workflows/pig.yml`; publication requires both host lanes. A green PiG job includes the clearly printed RPC exclusion expected failure, not a claim of complete parity.
|
|
39
|
+
|
|
40
|
+
Manual macOS terminal checks confirmed help rendering/scrolling/resize, opening the BTW composer and switching `/mode`, and the advisor-steering editor displaying `Saved` after a correctly encoded Ctrl+S. Full end-to-end advisor model execution, interactive configuration persistence, clipboard, and host reload/shutdown with active backend processes still require qualification. No paid backend calls are part of CI.
|
|
41
|
+
|
|
42
|
+
Tracking: https://github.com/tranhoangnguyen03/pi-bro/issues/64 and the original loading fix https://github.com/MichaelKinsy/PiG/issues/88.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-bro",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.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, opens a sandboxed side conversation with /bro btw, and provides a second-opinion advisor tool for executor agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
"README.md",
|
|
43
43
|
"CHANGELOG.md",
|
|
44
44
|
"LICENSE",
|
|
45
|
-
"THIRD_PARTY_NOTICES.md"
|
|
45
|
+
"THIRD_PARTY_NOTICES.md",
|
|
46
|
+
"docs/pig-compatibility.md"
|
|
46
47
|
],
|
|
47
48
|
"publishConfig": {
|
|
48
49
|
"access": "public"
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
},
|
|
53
54
|
"scripts": {
|
|
54
55
|
"typecheck": "tsc --noEmit",
|
|
55
|
-
"test": "npm run typecheck && node --test prompt.test.ts backend.test.ts claude.test.ts grok.test.ts codex.test.ts muse.test.ts settings.test.ts benchmark/*.test.ts && sh ./smoke-test.sh",
|
|
56
|
+
"test": "npm run typecheck && node --test prompt.test.ts backend.test.ts claude.test.ts grok.test.ts codex.test.ts muse.test.ts settings.test.ts show-html.test.ts smoke-rpc.test.ts benchmark/*.test.ts && sh ./smoke-test.sh",
|
|
56
57
|
"benchmark:dry-run": "node benchmark/run.ts dry-run",
|
|
57
58
|
"benchmark:run": "node benchmark/run.ts run",
|
|
58
59
|
"benchmark:report": "node benchmark/run.ts report",
|