@hheei/pi-ext-ui 0.5.0 → 0.5.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/README.md CHANGED
@@ -8,8 +8,8 @@ The shared view API owns fold levels, compact sections, status glyphs, copy feed
8
8
 
9
9
  Background Bash and subagent tools own their display formats through ext-core `ToolPresentation` providers. This resolver consumes those providers automatically, including nested codemode calls, and adds shared folding and copy controls. Without `pi-ext-ui`, the same tools retain native Pi renderers. No direct dependency on `pi-ext-ui` is required by the tool extensions.
10
10
 
11
- Opt into activity groups with `pi --ui-tool-groups` after installing this extension (Pi **>=1.0.1**). A heading such as `▸ codemode ×2 · grep ×3` keeps one live summary row per tool beneath a single outer rail. Each thinking round and notification also keeps a summary row; notifications are not counted. Groups form while tools run and can span consecutive tool/thinking rounds. Prose, user messages, unknown components, images, and unknown tool renderers break groups. Streaming arguments, partial results, completion, and errors update the existing row.
11
+ Activity groups are on by default for Pi **>=1.0.1** TUI sessions. Turn them off with the Tool UI setting `toolGroups.enabled` in `ext_settings.json` (the ext-core settings page). The change applies to the current session. A heading such as `▸ codemode ×2 · grep ×3` keeps one live summary row per tool beneath a single outer rail. Each thinking round and notification also keeps a summary row; notifications are not counted. Groups form while tools run and can span consecutive tool/thinking rounds. Prose, user messages, unknown components, images, and unknown tool renderers break groups. Streaming arguments, partial results, completion, and errors update the existing row.
12
12
 
13
13
  Fullscreen: click the group heading to restore the original component layouts and interactions beneath the outer rail. Both terminal modes: Ctrl+O forces groups open; closing global expansion restores each group’s local choice. Appending members preserves that choice. Original per-tool fold choices remain intact. Groups are presentation only and are rebuilt on history navigation; session data, model context, and HTML export remain unchanged. Thinking summaries keep a label; expanding respects native thinking visibility. Each `ctx.ui.notify` call retains its full text for expansion. Notifications remain session-local, as in Pi.
14
14
 
15
- This optional feature uses two centralized, version-checked host prototype hooks: tool lookup and extension notifications. Thinking uses the existing assistant message, with no extra hook. Unsupported hosts or incompatible layouts report a warning and retain normal rendering. Cleanup restores the original methods; if another extension replaces the same methods, restart Pi to unload the conflicting patch. For workspace development use `pnpm run pi-dev --ui-tool-groups`: running the bundled CLI beside physical host devDependencies can resolve a second host class, unlike the published installation.
15
+ Grouping uses two centralized, version-checked host prototype hooks: tool lookup and extension notifications. Thinking uses the existing assistant message, with no extra hook. Unsupported hosts or incompatible layouts report a warning and retain normal rendering. Cleanup restores the original methods; if another extension replaces the same methods, restart Pi to unload the conflicting patch. For workspace development use `pnpm run pi-dev`: running the bundled CLI beside physical host devDependencies can resolve a second host class, unlike the published installation.
package/dist/extension.js CHANGED
@@ -1,33 +1,50 @@
1
- import { messageViewPoint, registerExtensionHook, registerExtensionLifecycle, toolRendererPoint, } from "@hheei/pi-ext-core";
1
+ import { getRuntimeSettingsRegistry, messageViewPoint, registerExtensionHook, registerExtensionLifecycle, registerSettings, toolRendererPoint, } from "@hheei/pi-ext-core";
2
2
  import { installHostToolGroups } from "./host-transcript-patch.js";
3
3
  import { createMessageView } from "./message-view.js";
4
4
  import { createOptionalToolRendererFactory, registerCollapsibleToolRenderer } from "./renderer.js";
5
+ import { activityGroupsEnabled, createToolGroupSettings } from "./settings.js";
5
6
  import { clearCapturedNestedCalls } from "./tracker.js";
7
+ function sessionId(extension) {
8
+ const manager = extension.sessionManager;
9
+ if (typeof manager !== "object" || manager === null || !("getSessionId" in manager))
10
+ return "";
11
+ const read = manager.getSessionId;
12
+ return typeof read === "function" ? String(read.call(manager)) : "";
13
+ }
6
14
  export default function (pi) {
7
- pi.registerFlag("ui-tool-groups", {
8
- type: "boolean",
9
- default: false,
10
- description: "Group tool summaries, thinking and notifications (Pi >=1.0.1 runtime patch)",
11
- });
12
15
  let redrawGroups;
13
16
  pi.on("agent_settled", () => redrawGroups?.());
14
17
  registerCollapsibleToolRenderer(pi);
15
18
  registerExtensionLifecycle(pi, {
16
19
  key: "@hheei/pi-ext-ui",
17
- start(context) {
18
- if (context.extension.mode === "tui" && pi.getFlag("ui-tool-groups") === true) {
20
+ async start(context) {
21
+ let patch;
22
+ const apply = (enabled) => {
23
+ if (context.extension.mode !== "tui")
24
+ return;
25
+ if (!enabled) {
26
+ redrawGroups = undefined;
27
+ patch?.dispose();
28
+ patch = undefined;
29
+ return;
30
+ }
31
+ if (patch !== undefined)
32
+ return;
19
33
  try {
20
- const patch = installHostToolGroups(context.extension);
34
+ patch = installHostToolGroups(context.extension);
21
35
  redrawGroups = patch.requestRender;
22
- context.resources.add("tool-groups", () => {
23
- redrawGroups = undefined;
24
- patch.dispose();
25
- });
26
36
  }
27
37
  catch (error) {
28
38
  context.extension.ui.notify(error instanceof Error ? error.message : String(error), "warning");
29
39
  }
30
- }
40
+ };
41
+ const provider = createToolGroupSettings({ onEnabled: apply });
42
+ context.resources.add("tool-group-settings", registerSettings(provider, getRuntimeSettingsRegistry(pi)));
43
+ context.resources.add("tool-groups", () => {
44
+ redrawGroups = undefined;
45
+ patch?.dispose();
46
+ patch = undefined;
47
+ });
31
48
  context.resources.add("tracker-cleanup", () => {
32
49
  clearCapturedNestedCalls();
33
50
  });
@@ -35,6 +52,21 @@ export default function (pi) {
35
52
  context.resources.add("tool-renderer", () => toolRenderers.dispose());
36
53
  const handle = registerExtensionHook(context.pi, messageViewPoint, createMessageView);
37
54
  context.resources.add("message-view", () => handle.dispose());
55
+ try {
56
+ const state = await provider.storage.load({
57
+ sessionId: sessionId(context.extension),
58
+ signal: context.signal,
59
+ });
60
+ if (!context.signal.aborted)
61
+ apply(activityGroupsEnabled(state));
62
+ }
63
+ catch (error) {
64
+ if (!context.signal.aborted) {
65
+ const detail = error instanceof Error ? error.message : String(error);
66
+ context.extension.ui.notify(`Tool activity groups settings unreadable: ${detail}`, "warning");
67
+ apply(true);
68
+ }
69
+ }
38
70
  },
39
71
  });
40
72
  }
@@ -0,0 +1,6 @@
1
+ import { type SettingsProvider, type SettingsState } from "@hheei/pi-ext-core";
2
+ /** Missing or non-boolean values stay on; only an explicit false disables groups. */
3
+ export declare function activityGroupsEnabled(state: SettingsState | undefined): boolean;
4
+ export declare function createToolGroupSettings(options: {
5
+ readonly onEnabled: (enabled: boolean) => void;
6
+ }): SettingsProvider;
@@ -0,0 +1,36 @@
1
+ import { createJsonSettingsStorage, } from "@hheei/pi-ext-core";
2
+ const GROUP = "toolGroups";
3
+ const FIELD = "enabled";
4
+ /** Missing or non-boolean values stay on; only an explicit false disables groups. */
5
+ export function activityGroupsEnabled(state) {
6
+ const value = state?.[GROUP]?.[FIELD];
7
+ return value !== false;
8
+ }
9
+ export function createToolGroupSettings(options) {
10
+ return {
11
+ id: "pi-ext-ui",
12
+ title: "Tool UI",
13
+ origin: "@hheei/pi-ext-ui",
14
+ groups: [
15
+ {
16
+ id: GROUP,
17
+ title: "Tool activity",
18
+ fields: [
19
+ {
20
+ id: FIELD,
21
+ label: "Activity groups",
22
+ type: "boolean",
23
+ defaultValue: true,
24
+ description: "Group consecutive tool, thinking, and notification rows in the TUI transcript.",
25
+ parse: (draft) => draft === "true",
26
+ },
27
+ ],
28
+ },
29
+ ],
30
+ storage: createJsonSettingsStorage({ group: GROUP }),
31
+ onChange(change) {
32
+ if (change.groupId === GROUP && change.fieldId === FIELD)
33
+ options.onEnabled(change.value === true);
34
+ },
35
+ };
36
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hheei/pi-ext-ui",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Collapsible tool rendering frame and tool renderer pilot for Pi.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",