pi-bro 0.28.0 → 0.30.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/CHANGELOG.md +22 -0
- package/README.md +3 -0
- package/docs/README.md +1 -0
- package/docs/features/architecture.md +41 -0
- package/docs/reference/commands.md +6 -1
- package/docs/reference/data-and-permissions.md +10 -0
- package/docs/reference/settings.md +36 -3
- package/docs/user-guide.md +4 -0
- package/package.json +7 -3
- package/resources/architecture-docs/SKILL.md +57 -0
- package/resources/architecture-docs/assets/architecture-viewer.html +86 -0
- package/resources/architecture-docs/references/evidence-and-updates.md +14 -0
- package/resources/architecture-docs/references/project-patterns.md +31 -0
- package/resources/architecture-docs/references/writing-and-diagrams.md +19 -0
- package/resources/architecture-docs/scripts/check.mjs +87 -0
- package/resources/architecture-docs/scripts/inventory.mjs +83 -0
- package/resources/architecture-docs/scripts/layout.mjs +61 -0
- package/resources/architecture-docs/scripts/pipeline.mjs +228 -0
- package/resources/architecture-docs/scripts/render.mjs +66 -0
- package/src/architecture.ts +150 -0
- package/src/bro.ts +16 -2
- package/src/config-navigation-ui.ts +110 -0
- package/src/config-navigation.ts +75 -0
- package/src/config-ui.ts +25 -15
- package/src/doctor.ts +53 -26
- package/src/explain-modal.ts +5 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/** Compact navigation over existing settings/editors; no separate configuration state. */
|
|
2
|
+
import { getSelectListTheme } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { SelectList, matchesKey, wrapTextWithAnsi, type SelectItem, type Component } from "@earendil-works/pi-tui";
|
|
4
|
+
import { delegateMouse, modalHeight, renderFrame, type Theme, type TuiLike, type Area } from "./modal-kit.ts";
|
|
5
|
+
import type { BroMouseEvent } from "./ui-capabilities.ts";
|
|
6
|
+
import type { BroSettings } from "./settings.ts";
|
|
7
|
+
import {
|
|
8
|
+
CONFIG_ROOT, CONFIG_GLOBAL, CONFIG_FEATURES,
|
|
9
|
+
inheritedConfigDescription,
|
|
10
|
+
type ConfigNavAction, type ConfigNavState, type ConfigNavScreen,
|
|
11
|
+
} from "./config-navigation.ts";
|
|
12
|
+
|
|
13
|
+
type MenuItem = {value:string;label:string};
|
|
14
|
+
const rowsFor=(screen:ConfigNavScreen):readonly MenuItem[]=>{
|
|
15
|
+
if(screen==="root")return CONFIG_ROOT;
|
|
16
|
+
if(screen==="global")return CONFIG_GLOBAL;
|
|
17
|
+
if(screen==="features")return CONFIG_FEATURES;
|
|
18
|
+
if(screen==="advisor")return [
|
|
19
|
+
{value:"advisor-settings",label:"Backend, model and effort"},
|
|
20
|
+
{value:"advisor-steer",label:"Persistent advisor steering brief"},
|
|
21
|
+
];
|
|
22
|
+
return [{value:"btw-settings",label:"Open BTW's inherited backend settings"}];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function createConfigNavigationModal(
|
|
26
|
+
state:ConfigNavState,
|
|
27
|
+
settings:BroSettings,
|
|
28
|
+
): (tui:TuiLike,theme:Theme,keys:unknown,done:(result:ConfigNavAction)=>void)=>Component {
|
|
29
|
+
return (tui,theme,_keys,done)=>{
|
|
30
|
+
let closed=false;
|
|
31
|
+
let list:SelectList;
|
|
32
|
+
let listArea:Area={top:0,left:0,width:0,height:0};
|
|
33
|
+
const finish=(result:ConfigNavAction)=>{if(closed)return;closed=true;done(result);};
|
|
34
|
+
const go=(screen:ConfigNavScreen)=>{
|
|
35
|
+
state.screen=screen;
|
|
36
|
+
const items=rowsFor(screen) as SelectItem[];
|
|
37
|
+
list=new SelectList(items,Math.min(items.length,Math.max(1,modalHeight(tui)-10)),getSelectListTheme());
|
|
38
|
+
list.onSelect=item=>choose(item.value);
|
|
39
|
+
list.onCancel=back;
|
|
40
|
+
tui.requestRender();
|
|
41
|
+
};
|
|
42
|
+
const back=()=>{
|
|
43
|
+
if(state.screen==="root")return finish({kind:"close"});
|
|
44
|
+
if(state.screen==="global"||state.screen==="features"){go("root");return;}
|
|
45
|
+
go("features");
|
|
46
|
+
};
|
|
47
|
+
const choose=(value:string)=>{
|
|
48
|
+
if(state.screen==="root"){go(value==="global"?"global":"features");return;}
|
|
49
|
+
if(state.screen==="global"){
|
|
50
|
+
if(value==="defaults")return finish({kind:"settings",page:"defaults"});
|
|
51
|
+
if(value==="preferences")return finish({kind:"preferences"});
|
|
52
|
+
if(value==="doctor")return finish({kind:"doctor"});
|
|
53
|
+
}
|
|
54
|
+
if(state.screen==="features"){
|
|
55
|
+
if(value==="advisor"){go("advisor");return;}
|
|
56
|
+
if(value==="elevate"||value==="grill-me"||value==="remember-me"||value==="architecture"){
|
|
57
|
+
state.inherited=value;go("inherited");return;
|
|
58
|
+
}
|
|
59
|
+
if(value==="explain"||value==="show"||value==="btw"||value==="review")return finish({kind:"settings",page:value});
|
|
60
|
+
}
|
|
61
|
+
if(state.screen==="advisor"){
|
|
62
|
+
if(value==="advisor-steer")return finish({kind:"advisor-steer"});
|
|
63
|
+
if(value==="advisor-settings")return finish({kind:"settings",page:"advisor"});
|
|
64
|
+
}
|
|
65
|
+
if(state.screen==="inherited"&&value==="btw-settings"){
|
|
66
|
+
state.screen="features";return finish({kind:"settings",page:"btw"});
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
go(state.screen);
|
|
70
|
+
const title=()=>{
|
|
71
|
+
const s=state.screen;
|
|
72
|
+
return s==="root"?"Bro · config":
|
|
73
|
+
s==="global"?"Bro · config / Global":
|
|
74
|
+
s==="features"?"Bro · config / Features":
|
|
75
|
+
s==="advisor"?"Bro · config / Features / Advisor":
|
|
76
|
+
"Bro · config / Features / "+(state.inherited??"Inherited");
|
|
77
|
+
};
|
|
78
|
+
const subtitle=()=>{
|
|
79
|
+
if(state.screen==="root")return "Choose Global or Features. Enter drill down · Esc close.";
|
|
80
|
+
if(state.screen==="global")return "Defaults are shared. Doctor runs only when selected.";
|
|
81
|
+
if(state.screen==="features")return "Feature model overrides are optional; inherited features use BTW.";
|
|
82
|
+
if(state.screen==="advisor")return "Steering keeps its own file; changing models does not change steering.";
|
|
83
|
+
if(state.inherited)return inheritedConfigDescription(settings,state.inherited);
|
|
84
|
+
return "Inherits BTW";
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
render:(width:number)=>{
|
|
88
|
+
const h=modalHeight(tui),w=Math.max(1,width-2),lines=list.render(w);
|
|
89
|
+
// Derive mouse hit area from the same subtitle lines we render, including long
|
|
90
|
+
// inherited-backend descriptions and narrow-terminal layouts.
|
|
91
|
+
const subtitleLines=wrapTextWithAnsi(theme.fg("dim",subtitle()),w).slice(0,Math.max(0,h-5-lines.length));
|
|
92
|
+
listArea={top:3+subtitleLines.length,left:1,width:w,height:Math.max(0,Math.min(lines.length,h-5-subtitleLines.length))};
|
|
93
|
+
return renderFrame(theme,width,h,{
|
|
94
|
+
header:()=>theme.fg("accent",theme.bold(title())),
|
|
95
|
+
body:()=>[...subtitleLines,...lines],
|
|
96
|
+
hints:"↑/↓ select · Enter open · Esc back",
|
|
97
|
+
fill:false,
|
|
98
|
+
minBody:Math.max(1,lines.length),
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
invalidate:()=>list.invalidate(),
|
|
102
|
+
handleMouse:(event:BroMouseEvent)=>delegateMouse(list,event,listArea),
|
|
103
|
+
handleInput:(data:string)=>{
|
|
104
|
+
if(matchesKey(data,"escape")){back();return;}
|
|
105
|
+
list.handleInput(data);
|
|
106
|
+
tui.requestRender();
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Navigation taxonomy only. Existing config storage remains in settings.ts. */
|
|
2
|
+
import type { BroSettings, Capability } from "./settings.ts";
|
|
3
|
+
import { capabilityBackend, capabilityOverride, capabilityPair } from "./settings.ts";
|
|
4
|
+
import { reviewBackendNotice } from "./backend.ts";
|
|
5
|
+
|
|
6
|
+
export type ConfigSettingsPage = "defaults" | Capability;
|
|
7
|
+
export type ConfigNavScreen = "root" | "global" | "features" | "advisor" | "inherited";
|
|
8
|
+
export type ConfigNavState = { screen: ConfigNavScreen; inherited?: "elevate"|"grill-me"|"remember-me"|"architecture" };
|
|
9
|
+
export type ConfigNavAction =
|
|
10
|
+
| {kind:"settings";page:ConfigSettingsPage}
|
|
11
|
+
| {kind:"preferences"|"doctor"|"advisor-steer"|"close"};
|
|
12
|
+
|
|
13
|
+
export const CONFIG_ROOT = [
|
|
14
|
+
{value:"global",label:"Global — shared defaults, preferences and Doctor"},
|
|
15
|
+
{value:"features",label:"Features — specific settings and inherited behavior"},
|
|
16
|
+
] as const;
|
|
17
|
+
export const CONFIG_GLOBAL = [
|
|
18
|
+
{value:"defaults",label:"Default backend, model and effort"},
|
|
19
|
+
{value:"preferences",label:"Preferences — shared response style"},
|
|
20
|
+
{value:"doctor",label:"Doctor — run setup and model diagnostics"},
|
|
21
|
+
] as const;
|
|
22
|
+
export const CONFIG_FEATURES = [
|
|
23
|
+
{value:"explain",label:"Simplify — Explain override and default mode"},
|
|
24
|
+
{value:"show",label:"Show — backend override and default turn count"},
|
|
25
|
+
{value:"btw",label:"BTW — backend override; conversation/full access"},
|
|
26
|
+
{value:"review",label:"Guided Review — override and inspection limits"},
|
|
27
|
+
{value:"advisor",label:"Advisor — backend override and steering"},
|
|
28
|
+
{value:"elevate",label:"Elevate — inherits BTW"},
|
|
29
|
+
{value:"grill-me",label:"Grill Me — inherits BTW"},
|
|
30
|
+
{value:"remember-me",label:"Remember Me — inherits BTW"},
|
|
31
|
+
{value:"architecture",label:"Architecture Docs — inherits BTW"},
|
|
32
|
+
] as const;
|
|
33
|
+
|
|
34
|
+
export function effectiveConfigLabel(settings:BroSettings, capability:Capability):string {
|
|
35
|
+
const p=capabilityPair(settings,capability);
|
|
36
|
+
const source=capabilityOverride(settings,capability)?"override":"global default";
|
|
37
|
+
return (capabilityBackend(settings,capability))+" / "+p.model+" / "+p.effort+" ("+source+")";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function inheritedConfigDescription(settings:BroSettings, feature:"elevate"|"grill-me"|"remember-me"|"architecture"):string {
|
|
41
|
+
const purpose=feature==="architecture"?"Repository architecture documentation":feature==="elevate"?"Improve a request":feature==="grill-me"?"Private decision interview":"Personal memory writing";
|
|
42
|
+
return purpose+". This workflow inherits BTW's configured backend, model and effort: "+
|
|
43
|
+
effectiveConfigLabel(settings,"btw")+
|
|
44
|
+
". No separate override exists. Use Features > BTW to change the inherited selection.";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Show the selected backend's actual access boundary at the point of configuration.
|
|
50
|
+
* Informational only: does not alter backend invocation, tools or permissions.
|
|
51
|
+
* Matched to the existing backend adapter flags and reference/data-and-permissions.md.
|
|
52
|
+
*/
|
|
53
|
+
export function configFeatureAccessNote(settings: BroSettings, feature: "btw" | "review"): string {
|
|
54
|
+
const backend = capabilityBackend(settings,feature);
|
|
55
|
+
if(feature==="btw") {
|
|
56
|
+
const notes: Record<typeof backend,string> = {
|
|
57
|
+
agy:"Agy's conversation-only path uses a temporary directory and sandboxed shell; the sandbox is not a no-write guarantee.",
|
|
58
|
+
claude:"Claude disables tools in conversation-only mode.",
|
|
59
|
+
grok:"Grok's conversation-only limit is prompt guidance only: its sandbox stays off and permissions are bypassed.",
|
|
60
|
+
codex:"Codex allows workspace reads and sandboxed commands under its read-only sandbox; it is not tool-free.",
|
|
61
|
+
muse:"Muse disables shell, write and approvals in conversation-only mode, but other tools can remain available.",
|
|
62
|
+
pi:"Pi's conversation-only session has no tools, extensions or context files.",
|
|
63
|
+
};
|
|
64
|
+
return "BTW: /mode in the BTW modal toggles conversation-only and full workspace access; full mode bypasses backend permission checks. "+notes[backend];
|
|
65
|
+
}
|
|
66
|
+
const existing=reviewBackendNotice(backend);
|
|
67
|
+
if(existing)return existing;
|
|
68
|
+
const strict: Record<"claude"|"muse"|"pi",string>={
|
|
69
|
+
claude:"Claude uses Read/Grep/Glob file-inspection tools only in the captured checkout; no shell.",
|
|
70
|
+
muse:"Muse disables shell, writes and web access in the captured checkout; reads remain available.",
|
|
71
|
+
pi:"Pi permits only read/grep/find/ls in the captured checkout; no shell or workspace writes.",
|
|
72
|
+
};
|
|
73
|
+
return "Guided Review: "+strict[backend as keyof typeof strict]+
|
|
74
|
+
" PR content remains untrusted evidence; backend restrictions do not prove the review's conclusions.";
|
|
75
|
+
}
|
package/src/config-ui.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
SelectList,
|
|
7
7
|
SettingsList,
|
|
8
8
|
matchesKey,
|
|
9
|
+
wrapTextWithAnsi,
|
|
9
10
|
truncateToWidth,
|
|
10
11
|
} from "@earendil-works/pi-tui";
|
|
11
12
|
import { getSelectListTheme, getSettingsListTheme } from "@earendil-works/pi-coding-agent";
|
|
@@ -31,6 +32,7 @@ import {
|
|
|
31
32
|
withCapabilityOverride,
|
|
32
33
|
} from "./settings.ts";
|
|
33
34
|
import { BRO_MODES, parseBroMode } from "./prompt.ts";
|
|
35
|
+
import { type ConfigSettingsPage, effectiveConfigLabel, configFeatureAccessNote } from "./config-navigation.ts";
|
|
34
36
|
import { delegateMouse, formatNotice, modalHeight, renderFrame, type Area, type Theme, type TuiLike } from "./modal-kit.ts";
|
|
35
37
|
import type { BroMouseEvent } from "./ui-capabilities.ts";
|
|
36
38
|
import { errorMessage } from "./util.ts";
|
|
@@ -64,6 +66,7 @@ export function createConfigModal(
|
|
|
64
66
|
families: AgyModelFamily[],
|
|
65
67
|
persistSettings: (settings: BroSettings) => Promise<void>,
|
|
66
68
|
piModels: PiModelChoice[] = [],
|
|
69
|
+
page: ConfigSettingsPage | "all" = "all",
|
|
67
70
|
): (tui: TuiLike, theme: Theme, keybindings: unknown, done: (value?: void) => void) => Component & { dispose?(): void } {
|
|
68
71
|
return (tui, theme, _keybindings, done) => {
|
|
69
72
|
// Size the host list once, then stop interaction if a later resize cannot show the whole
|
|
@@ -294,13 +297,15 @@ export function createConfigModal(
|
|
|
294
297
|
}
|
|
295
298
|
refresh();
|
|
296
299
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
effortItem,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
300
|
+
// The existing pickers and save queue remain unchanged. Pages differ only in rows.
|
|
301
|
+
const items: SettingItem[] = page === "all"
|
|
302
|
+
? [modelItem, effortItem, modeItem, showTurnsItem, ...CAPABILITIES.flatMap((capability) => [capabilityItems[capability].model, capabilityItems[capability].effort])]
|
|
303
|
+
: page === "defaults"
|
|
304
|
+
? [modelItem, effortItem]
|
|
305
|
+
: [capabilityItems[page].model, capabilityItems[page].effort,
|
|
306
|
+
...(page === "explain" ? [modeItem] : []),
|
|
307
|
+
...(page === "show" ? [showTurnsItem] : []),
|
|
308
|
+
];
|
|
304
309
|
|
|
305
310
|
let notice = "";
|
|
306
311
|
let interactive = true;
|
|
@@ -414,27 +419,32 @@ export function createConfigModal(
|
|
|
414
419
|
const height = modalHeight(tui);
|
|
415
420
|
const innerWidth = Math.max(1, width - 2);
|
|
416
421
|
const list = settingsList.render(innerWidth);
|
|
422
|
+
// An access boundary must be visible whenever BTW/Review permissions are editable.
|
|
423
|
+
// If the terminal cannot show it alongside the controls, refuse blind edits.
|
|
424
|
+
const accessNote = page === "btw" || page === "review"
|
|
425
|
+
? wrapTextWithAnsi(theme.fg("warning", configFeatureAccessNote(settings, page)), innerWidth)
|
|
426
|
+
: [];
|
|
417
427
|
// renderFrame shrinks a notice to one line before taking minBody rows.
|
|
418
|
-
interactive = list.length <= Math.max(0, height - 5 - (notice ? 1 : 0));
|
|
428
|
+
interactive = list.length + accessNote.length <= Math.max(0, height - 5 - (notice ? 1 : 0));
|
|
419
429
|
return renderFrame(theme, width, height, {
|
|
420
430
|
header: () => theme.fg(
|
|
421
431
|
interactive ? "accent" : "warning",
|
|
422
|
-
theme.bold(interactive ? "Bro · config" : "Bro · config · enlarge terminal"),
|
|
432
|
+
theme.bold(interactive ? "Bro · config · " + (page === "all" ? "All" : page === "defaults" ? "Global defaults" : CAPABILITY_LABELS[page]) : "Bro · config · enlarge terminal"),
|
|
423
433
|
),
|
|
424
434
|
body: (rows) => {
|
|
425
435
|
if (!interactive) return [theme.fg("warning", "Enlarge the terminal to configure settings safely.")];
|
|
426
436
|
// The subtitle gives way before SettingsList's selection, scroll state and key hints.
|
|
427
|
-
const subtitle = rows > list.length
|
|
428
|
-
? [truncateToWidth(theme.fg("dim", "Shared defaults, with optional overrides per capability"), innerWidth)]
|
|
437
|
+
const subtitle = rows > list.length + accessNote.length
|
|
438
|
+
? [truncateToWidth(theme.fg("dim", page === "all" ? "Shared defaults, with optional overrides per capability" : page === "defaults" ? "Shared default selection" : "Effective: " + effectiveConfigLabel(settings, page)), innerWidth)]
|
|
429
439
|
: [];
|
|
430
|
-
//
|
|
431
|
-
listArea = { top: 3 + subtitle.length, left: 1, width: innerWidth, height: Math.min(list.length, rows - subtitle.length) };
|
|
432
|
-
return [...subtitle, ...list];
|
|
440
|
+
// Access notes always remain above the editable list, including after backend changes.
|
|
441
|
+
listArea = { top: 3 + subtitle.length + accessNote.length, left: 1, width: innerWidth, height: Math.min(list.length, rows - subtitle.length - accessNote.length) };
|
|
442
|
+
return [...subtitle, ...accessNote, ...list];
|
|
433
443
|
},
|
|
434
444
|
notice,
|
|
435
445
|
hints: interactive ? undefined : "Esc close",
|
|
436
446
|
fill: false,
|
|
437
|
-
minBody: interactive ? list.length : 1,
|
|
447
|
+
minBody: interactive ? list.length + accessNote.length : 1,
|
|
438
448
|
});
|
|
439
449
|
},
|
|
440
450
|
invalidate: () => settingsList.invalidate(),
|
package/src/doctor.ts
CHANGED
|
@@ -18,6 +18,9 @@ import {
|
|
|
18
18
|
} from "./advisor.ts";
|
|
19
19
|
import { agyFailureMessage, bridgePiRuntimeForCatalog, piEffectiveEffort, reviewBackendNotice, splitPiModel } from "./backend.ts";
|
|
20
20
|
import { createConfigModal } from "./config-ui.ts";
|
|
21
|
+
import { createConfigNavigationModal } from "./config-navigation-ui.ts";
|
|
22
|
+
import { type ConfigNavAction, type ConfigNavState } from "./config-navigation.ts";
|
|
23
|
+
import { showBroModal, showPreferencesModal, showAdvisorSteerModal } from "./explain-modal.ts";
|
|
21
24
|
import { openBroOverlay } from "./modal-kit.ts";
|
|
22
25
|
import {
|
|
23
26
|
type AgyEffort,
|
|
@@ -642,36 +645,60 @@ export async function doctorReport(pi: ExtensionAPI, ctx: ExtensionCommandContex
|
|
|
642
645
|
}`;
|
|
643
646
|
}
|
|
644
647
|
|
|
648
|
+
/** Global/Features navigation over the existing settings modal and editor contracts. */
|
|
645
649
|
export async function showBroConfigModal(ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
|
|
646
650
|
if (!hasBroCustomUi(ctx)) {
|
|
647
651
|
ctx.ui.notify("Use /bro config in Pi's interactive UI.", "warning");
|
|
648
652
|
return;
|
|
649
653
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
settings
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
654
|
+
const navigation: ConfigNavState = {screen:"root"};
|
|
655
|
+
for (;;) {
|
|
656
|
+
// Even invalid settings must not prevent access to Doctor. The placeholder is navigation-only:
|
|
657
|
+
// every editable page re-reads the actual settings and refuses to edit on failure.
|
|
658
|
+
let current: BroSettings;
|
|
659
|
+
try { current = await readSettings(); }
|
|
660
|
+
catch (error) {
|
|
661
|
+
ctx.ui.notify("Settings unavailable: "+errorMessage(error)+". Global > Doctor can diagnose.", "warning");
|
|
662
|
+
current = { backend:"agy",model:"(unavailable)",effort:"default",mode:"balanced",showTurns:1,overrides:{} };
|
|
663
|
+
}
|
|
664
|
+
const selected = await openBroOverlay<ConfigNavAction>(
|
|
665
|
+
ctx, createConfigNavigationModal(navigation,current), {mouse:true}
|
|
666
|
+
);
|
|
667
|
+
if (!selected || selected.kind === "close") return;
|
|
668
|
+
if (selected.kind === "preferences") {
|
|
669
|
+
await showPreferencesModal(ctx);
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
if (selected.kind === "advisor-steer") {
|
|
673
|
+
await showAdvisorSteerModal(ctx,pi);
|
|
674
|
+
continue;
|
|
675
|
+
}
|
|
676
|
+
if (selected.kind === "doctor") {
|
|
677
|
+
await showBroModal(ctx,{
|
|
678
|
+
loadingText:"Checking Bro setup…",
|
|
679
|
+
retryable:true,
|
|
680
|
+
retryLabel:"check again",
|
|
681
|
+
run:async(signal)=>({text:await doctorReport(pi,ctx,signal)}),
|
|
682
|
+
});
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
if (selected.kind !== "settings") continue;
|
|
686
|
+
// Catalog discovery is needed only when an editable settings page is opened, not on
|
|
687
|
+
// every navigation or diagnostic visit. Keep independent Agy/Pi failure handling.
|
|
688
|
+
let settings:BroSettings;
|
|
689
|
+
try { settings = await readSettings(); }
|
|
690
|
+
catch (error) { ctx.ui.notify(withDoctor(error),"error"); continue; }
|
|
691
|
+
let families:AgyModelFamily[]=[];
|
|
692
|
+
try { families=await listAgyModels(pi); }
|
|
693
|
+
catch { ctx.ui.notify("Agy catalog unavailable — other backends remain configurable.","warning"); }
|
|
694
|
+
let piModels:PiModelChoice[]=[];
|
|
695
|
+
try {
|
|
696
|
+
const catalog=await listPiModels(ctx);
|
|
697
|
+
piModels=catalog.models;
|
|
698
|
+
for(const diagnostic of catalog.diagnostics) ctx.ui.notify("Pi scoped models: "+diagnostic,"warning");
|
|
699
|
+
} catch(error) { ctx.ui.notify("Pi catalog unavailable: "+errorMessage(error),"warning"); }
|
|
700
|
+
await openBroOverlay<void>(
|
|
701
|
+
ctx,createConfigModal(settings,families,writeSettings,piModels,selected.page),{mouse:true}
|
|
702
|
+
);
|
|
675
703
|
}
|
|
676
|
-
await openBroOverlay<void>(ctx, createConfigModal(settings, families, writeSettings, piModels));
|
|
677
704
|
}
|
package/src/explain-modal.ts
CHANGED
|
@@ -393,6 +393,10 @@ Quick reference. Full user guide: https://github.com/tranhoangnguyen03/pi-bro/bl
|
|
|
393
393
|
- Inside Simplify: \`/simplify\`, \`/text <text>\`, \`/file <path>\`, \`/url <url>\`, \`/copy\`, \`/clear\`, \`/help\`. **M** changes the mode and re-explains; **R** retries. One source at a time, no chat thread.\n- \`/bro open\` — legacy last-result view (retained for compatibility)
|
|
394
394
|
- \`/bro show [n-turns] [query]\` — draw recent turns' conversation text as shapes; an optional query steers the focus
|
|
395
395
|
|
|
396
|
+
## Architecture documentation
|
|
397
|
+
|
|
398
|
+
- \`/bro architecture [focus]\` — inspect this project and create or refresh \`docs/architecture/\` (Markdown, diagrams and a self-contained HTML map). Inherits the BTW model selection. See docs/features/architecture.md.
|
|
399
|
+
|
|
396
400
|
## Guided Review
|
|
397
401
|
|
|
398
402
|
- \`/bro guided-review <PR number or URL>\` — automatically explain and assess a PR with captured code and optional private questions (local Pi interactive only; Git and authenticated gh required).
|
|
@@ -425,7 +429,7 @@ Quick reference. Full user guide: https://github.com/tranhoangnguyen03/pi-bro/bl
|
|
|
425
429
|
## Configure and check
|
|
426
430
|
|
|
427
431
|
- \`/bro preferences\` — tell Bro about yourself and how you like answers; added to explain, show, btw, Elevate and Guided Review prompts, never the advisor (**Ctrl+S** save, **Ctrl+K** delete, **Ctrl+C** copy, **Esc** close)
|
|
428
|
-
- \`/bro config\` —
|
|
432
|
+
- \`/bro config\` — Global (shared defaults, preferences, Doctor) and Features (Simplify, Show, BTW, Review, Advisor and BTW-inherited workflows). The same model pickers, safe saves and error handling remain; Esc backs out.
|
|
429
433
|
- \`/bro mode [brief|balanced|faithful]\` — view or choose the explanation mode
|
|
430
434
|
- \`/bro doctor\` — check settings, preferences, and every selected backend without running a model turn
|
|
431
435
|
|