@xzzpig/pi-starline 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.
@@ -0,0 +1,9 @@
1
+ # Fork release notes
2
+
3
+ ## 0.5.1 — Release candidate
4
+
5
+ - Recognize the optional `@xzzpig/transcript-expand-target.v1` contract for group summary clicks. Invalid or absent providers fall back to the existing component resolver; no new mandatory package dependency or default-setting change.
6
+ - Add `build:types` and `prepack` to include `dist/public.d.ts` alongside the extension sources.
7
+ - Keep historical upstream/fork release notes in `CHANGELOG.md`; this fork-only file records the new compatibility release without expanding upstream documentation edits.
8
+
9
+ Validated host: Pi 1.1.0. Native drag-selection acceptance and OpenSpec archival are release gates, not implied by a successful package build.
package/README.md CHANGED
@@ -227,3 +227,26 @@ Inspired by:
227
227
  ## License
228
228
 
229
229
  MIT
230
+
231
+ ## Compatibility: explicit expand targets (fork-only)
232
+
233
+ This fork's click-to-expand resolution (`mouse/tool-box.ts`) checks an
234
+ optional, versioned **explicit expand-target protocol** before its own
235
+ `setExpanded`/hint logic:
236
+
237
+ - Providers publish a resolver on a component instance under
238
+ `Symbol.for("@xzzpig/transcript-expand-target.v1")` with
239
+ `{ version: 1, resolveLocalTarget(localRow, width) }`. The consumer is
240
+ `mouse/explicit-expand-target.ts` (fork-only file).
241
+ - Today the only provider is
242
+ [`@xzzpig/pi-group-collapse`](../pi-group-collapse): its group summaries
243
+ resolve to the independent group object, so clicking a summary toggles
244
+ the group instead of the tool that carries it.
245
+ - Without a provider nothing changes: no published protocol, a wrong
246
+ version, a non-callable resolver, a thrown resolution, or an invalid
247
+ resolved shape all fall through to the existing resolution. Installing
248
+ the provider is never required, and load order in either direction
249
+ works (the resolver is read per click, not cached).
250
+ - Drag selection, double-click word selection, hyperlinks, wheel, and
251
+ overlay behavior are unaffected; the explicit target only answers for
252
+ the specific local rows it owns.
@@ -0,0 +1,5 @@
1
+ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+
3
+ declare function export_default(pi: ExtensionAPI): void;
4
+
5
+ export { export_default as default };
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Fork-only consumer for the versioned explicit expand-target protocol
3
+ * (`@xzzpig/transcript-expand-target.v1`).
4
+ *
5
+ * Providers (pi-group-collapse today) publish a resolver on the component
6
+ * instance that draws a group summary. Starline checks that resolver for
7
+ * the component's *local* row before its own `setExpanded`/hint logic, so a
8
+ * click on a summary toggles the group object instead of the first tool
9
+ * inside it.
10
+ *
11
+ * The contract is defensive by requirement (see the mouse-api spec):
12
+ * no published protocol, a wrong version, a non-callable resolver, a
13
+ * thrown resolution, or an invalid resolved shape all fall back to the
14
+ * existing component path — installing the provider is never required and
15
+ * a broken provider cannot break clicks that used to work.
16
+ *
17
+ * This module deliberately depends on nothing: the symbol key is its only
18
+ * tie to the provider, so Starline keeps working with the provider absent,
19
+ * and any number of providers can publish the same key.
20
+ */
21
+
22
+ /** The shared protocol key; `Symbol.for` so every copy in the process agrees. */
23
+ export const EXPAND_TARGET_KEY = Symbol.for("@xzzpig/transcript-expand-target.v1");
24
+
25
+ /** The slice of the protocol Starline reads. */
26
+ type ExpandTargetProtocol = {
27
+ version: 1;
28
+ resolveLocalTarget: (localRow: number, width: number) => unknown;
29
+ };
30
+
31
+ /** The resolved target, validated before use. */
32
+ export type ExplicitExpandTarget = {
33
+ component: { setExpanded(expanded: boolean): void };
34
+ expanded: boolean;
35
+ };
36
+
37
+ /**
38
+ * Resolve an explicit expand target for a component's local row, or
39
+ * undefined when there is no provider, no hit, or anything invalid.
40
+ */
41
+ export function explicitExpandTargetAt(
42
+ component: unknown,
43
+ localRow: number,
44
+ width: number,
45
+ ): ExplicitExpandTarget | undefined {
46
+ if (typeof component !== "object" || component === null) return undefined;
47
+ let protocol: unknown;
48
+ try {
49
+ protocol = (component as Record<PropertyKey, unknown>)[EXPAND_TARGET_KEY];
50
+ } catch {
51
+ return undefined;
52
+ }
53
+ if (
54
+ typeof protocol !== "object" ||
55
+ protocol === null ||
56
+ (protocol as ExpandTargetProtocol).version !== 1 ||
57
+ typeof (protocol as ExpandTargetProtocol).resolveLocalTarget !== "function"
58
+ ) {
59
+ return undefined;
60
+ }
61
+ let resolved: unknown;
62
+ try {
63
+ resolved = (protocol as ExpandTargetProtocol).resolveLocalTarget(localRow, width);
64
+ } catch {
65
+ return undefined;
66
+ }
67
+ if (
68
+ typeof resolved !== "object" ||
69
+ resolved === null ||
70
+ typeof (resolved as ExplicitExpandTarget).expanded !== "boolean"
71
+ ) {
72
+ return undefined;
73
+ }
74
+ const target = resolved as {
75
+ component?: { setExpanded?: unknown };
76
+ expanded: boolean;
77
+ };
78
+ if (
79
+ typeof target.component !== "object" ||
80
+ target.component === null ||
81
+ typeof target.component.setExpanded !== "function"
82
+ ) {
83
+ return undefined;
84
+ }
85
+ return {
86
+ component: target.component as { setExpanded(expanded: boolean): void },
87
+ expanded: target.expanded,
88
+ };
89
+ }
@@ -87,6 +87,7 @@
87
87
 
88
88
  import { stripTerminalSequences } from "@earendil-works/pi-tui";
89
89
  import { createComponentTree, isComponentLike, isExpandableComponent } from "./component-tree";
90
+ import { explicitExpandTargetAt } from "./explicit-expand-target";
90
91
  import { type BoxLike, boxesAt, scrollContentLinesFor, scrollContentOrigin } from "./hit-test";
91
92
  import { keyTextFor } from "./key-text";
92
93
 
@@ -242,6 +243,9 @@ export function expandTargetAt(
242
243
 
243
244
  for (let index = path.length - 1; index >= 0; index--) {
244
245
  const span = path[index];
246
+ // Fork seam: a versioned explicit target on this component's local row wins over the component's own expand state, so a group summary toggles its group instead of the tool carrying it. No provider, wrong version, or invalid shape falls through untouched.
247
+ const explicit = explicitExpandTargetAt(span.component, row - span.start, origin.rect.width);
248
+ if (explicit) return { component: explicit.component, expanded: explicit.expanded };
245
249
  if (!isExpandableComponent(span.component)) continue;
246
250
  const component = span.component as ExpandableComponent;
247
251
  // The hint is matched against this component's own rendered row, not
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xzzpig/pi-starline",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "A Starship-inspired statusline and Opencode-style TUI for Pi.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,12 +20,14 @@
20
20
  "tui"
21
21
  ],
22
22
  "files": [
23
- "extensions"
23
+ "extensions",
24
+ "dist",
25
+ "FORK-CHANGELOG.md"
24
26
  ],
25
27
  "peerDependencies": {
26
- "@earendil-works/pi-ai": ">=0.86.0 <0.88",
27
- "@earendil-works/pi-coding-agent": ">=0.86.0 <0.88",
28
- "@earendil-works/pi-tui": ">=0.86.0 <0.88",
28
+ "@earendil-works/pi-ai": ">=1.0.0 <2",
29
+ "@earendil-works/pi-coding-agent": ">=1.0.0 <2",
30
+ "@earendil-works/pi-tui": ">=1.0.0 <2",
29
31
  "@xzzpig/pi-mouse-events": ">=0.2.0 <3"
30
32
  },
31
33
  "pi": {
@@ -39,10 +41,12 @@
39
41
  },
40
42
  "devDependencies": {
41
43
  "@biomejs/biome": "^2.5.0",
42
- "@earendil-works/pi-ai": "^0.87.1",
43
- "@earendil-works/pi-coding-agent": "^0.87.1",
44
- "@earendil-works/pi-tui": "^0.87.1",
44
+ "@earendil-works/pi-ai": "1.1.0",
45
+ "@earendil-works/pi-coding-agent": "1.1.0",
46
+ "@earendil-works/pi-tui": "1.1.0",
45
47
  "@types/node": "^26.0.0",
48
+ "rollup": "^4.62.2",
49
+ "rollup-plugin-dts": "^6.4.1",
46
50
  "typescript": "^7.0.2",
47
51
  "vitest": "^4.1.8",
48
52
  "@xzzpig/pi-mouse-events": "0.2.0"
@@ -55,6 +59,7 @@
55
59
  "scripts": {
56
60
  "lint": "biome check .",
57
61
  "typecheck": "tsc --noEmit",
62
+ "build:types": "rollup -c rollup.dts.config.mjs && biome format --write dist/public.d.ts",
58
63
  "test": "vitest run",
59
64
  "pi:dev": "${PI_BIN:-/opt/homebrew/bin/pi} --no-extensions -e ./extensions/starline/index.ts",
60
65
  "pi:install-local": "${PI_BIN:-/opt/homebrew/bin/pi} install ./ -l",