@pi-unipi/unipi 3.0.0-alpha.38 → 3.0.0-alpha.39

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
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.0.0-alpha.39] — 2026-10-11
10
+
11
+ ### Added
12
+ - UniPi app: switch a session's working mode from the app. The app sees the current mode and changes it live (`none` returns to regular mode; another work mode is entered without a prompt). A mode switch is refused while another paused task already holds the park slot.
13
+ - Long-horizon: new `unipi:lh-mode` runner used for that switch.
14
+
9
15
  ## [3.0.0-alpha.38] — 2026-10-11
10
16
 
11
17
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/unipi",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "All-in-one extension suite for Pi coding agent",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -80,28 +80,28 @@
80
80
  "typebox": "^1.1.38"
81
81
  },
82
82
  "dependencies": {
83
- "@pi-unipi/app-bridge": "3.0.0-alpha.38",
84
- "@pi-unipi/ask-user": "3.0.0-alpha.38",
85
- "@pi-unipi/background-tasks": "3.0.0-alpha.38",
86
- "@pi-unipi/btw": "3.0.0-alpha.38",
87
- "@pi-unipi/command-enchantment": "3.0.0-alpha.38",
88
- "@pi-unipi/compactor": "3.0.0-alpha.38",
89
- "@pi-unipi/core": "3.0.0-alpha.38",
90
- "@pi-unipi/dream": "3.0.0-alpha.38",
91
- "@pi-unipi/footer": "3.0.0-alpha.38",
92
- "@pi-unipi/fusion": "3.0.0-alpha.38",
93
- "@pi-unipi/info-screen": "3.0.0-alpha.38",
94
- "@pi-unipi/input-shortcuts": "3.0.0-alpha.38",
95
- "@pi-unipi/kanboard": "3.0.0-alpha.38",
96
- "@pi-unipi/mcp": "3.0.0-alpha.38",
97
- "@pi-unipi/memory": "3.0.0-alpha.38",
98
- "@pi-unipi/notify": "3.0.0-alpha.38",
99
- "@pi-unipi/skill-registry": "3.0.0-alpha.38",
100
- "@pi-unipi/subagents": "3.0.0-alpha.38",
101
- "@pi-unipi/updater": "3.0.0-alpha.38",
102
- "@pi-unipi/utility": "3.0.0-alpha.38",
103
- "@pi-unipi/web-api": "3.0.0-alpha.38",
104
- "@pi-unipi/workflow": "3.0.0-alpha.38",
83
+ "@pi-unipi/app-bridge": "3.0.0-alpha.39",
84
+ "@pi-unipi/ask-user": "3.0.0-alpha.39",
85
+ "@pi-unipi/background-tasks": "3.0.0-alpha.39",
86
+ "@pi-unipi/btw": "3.0.0-alpha.39",
87
+ "@pi-unipi/command-enchantment": "3.0.0-alpha.39",
88
+ "@pi-unipi/compactor": "3.0.0-alpha.39",
89
+ "@pi-unipi/core": "3.0.0-alpha.39",
90
+ "@pi-unipi/dream": "3.0.0-alpha.39",
91
+ "@pi-unipi/footer": "3.0.0-alpha.39",
92
+ "@pi-unipi/fusion": "3.0.0-alpha.39",
93
+ "@pi-unipi/info-screen": "3.0.0-alpha.39",
94
+ "@pi-unipi/input-shortcuts": "3.0.0-alpha.39",
95
+ "@pi-unipi/kanboard": "3.0.0-alpha.39",
96
+ "@pi-unipi/mcp": "3.0.0-alpha.39",
97
+ "@pi-unipi/memory": "3.0.0-alpha.39",
98
+ "@pi-unipi/notify": "3.0.0-alpha.39",
99
+ "@pi-unipi/skill-registry": "3.0.0-alpha.39",
100
+ "@pi-unipi/subagents": "3.0.0-alpha.39",
101
+ "@pi-unipi/updater": "3.0.0-alpha.39",
102
+ "@pi-unipi/utility": "3.0.0-alpha.39",
103
+ "@pi-unipi/web-api": "3.0.0-alpha.39",
104
+ "@pi-unipi/workflow": "3.0.0-alpha.39",
105
105
  "@resvg/resvg-wasm": "^2.6.2",
106
106
  "beautiful-mermaid": "^1.1.3"
107
107
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/app-bridge",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Live bridge between a pi TUI session and the UniPi phone app — streaming chat, prompts, steering and dialogs from the phone",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -31,7 +31,7 @@
31
31
  "access": "public"
32
32
  },
33
33
  "dependencies": {
34
- "@pi-unipi/core": "3.0.0-alpha.38"
34
+ "@pi-unipi/core": "3.0.0-alpha.39"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -24,6 +24,7 @@ import {
24
24
  type FusionPresetInfo,
25
25
  type FusionStatusInfo,
26
26
  type LhProgressInfo,
27
+ type LhModeInfo,
27
28
  type DreamDetailInfo,
28
29
  type DreamStatusInfo,
29
30
  type InMsg,
@@ -43,7 +44,7 @@ import { fileSuggestions } from "./files.js";
43
44
  import { statPaths } from "./paths.js";
44
45
  import { registerPath, resolveMedia } from "./media.js";
45
46
  import { listWorkItems, stopWorkItem, backgroundWorkItem, workLogPage } from "./work.js";
46
- import { bus, pendingWorkLabel, silenceCommandEcho, subscribePendingWork, UNIPI_EVENTS } from "@pi-unipi/core";
47
+ import { bus, callCommandRunner, pendingWorkLabel, silenceCommandEcho, subscribePendingWork, UNIPI_EVENTS } from "@pi-unipi/core";
47
48
  import type { BtwListPage } from "./wire.js";
48
49
 
49
50
  /** `media_chunk.data` (base64) stays well under the 900 KiB bridge line
@@ -51,6 +52,15 @@ import type { BtwListPage } from "./wire.js";
51
52
  const MEDIA_CHUNK_CHARS = 700 * 1024;
52
53
  /** UNI-222: lh_progress pushes coalesce within this window (≤ 4/s). */
53
54
  export const LH_PROGRESS_COALESCE_MS = 250;
55
+ /** UNI-269: the discovery record's `lhMode`/`lhPaused` (host → chat_list → list badge). */
56
+ export function recordLhMode(state: LhModeInfo | undefined): { lhMode: string | null; lhPaused: string | null } {
57
+ const mode = typeof state?.mode === "string" && state.mode && state.mode !== "none" ? state.mode : null;
58
+ const paused = typeof state?.paused === "string" && state.paused && state.paused !== "none" && state.paused !== mode ? state.paused : null;
59
+ return { lhMode: mode, lhPaused: paused };
60
+ }
61
+
62
+ /** UNI-269: long-horizon's command runner behind `set_lh_mode` (packages/long-horizon/src/commands.ts). */
63
+ export const LH_MODE_RUNNER = "unipi:lh-mode";
54
64
  /** UNI-118: dream_status pushes coalesce within this window. */
55
65
  export const DREAM_COALESCE_MS = 250;
56
66
 
@@ -645,6 +655,8 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
645
655
 
646
656
  // UNI-222: long-horizon progress (sticky LH_PROGRESS on the core bus).
647
657
  const lhProgress = (): LhProgressInfo | undefined => bus.get(UNIPI_EVENTS.LH_PROGRESS) as LhProgressInfo | undefined;
658
+ // UNI-269: the working mode (sticky LH_STATE — the footer's "Graph Mode").
659
+ const lhMode = (): LhModeInfo | undefined => bus.get(UNIPI_EVENTS.LH_STATE) as LhModeInfo | undefined;
648
660
 
649
661
  const hello = (): OutMsg => {
650
662
  const c = ctx!;
@@ -664,6 +676,7 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
664
676
  fusion: fusionPreset(),
665
677
  work: workItems(),
666
678
  ...(lhProgress() ? { lhProgress: lhProgress() } : {}),
679
+ ...(lhMode() ? { lhMode: lhMode() } : {}),
667
680
  ...(() => {
668
681
  const dream = dreamStatus();
669
682
  return dream ? { dream } : {};
@@ -751,6 +764,9 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
751
764
  // background subagent, a fusion handoff) — the host passes it into
752
765
  // chat_list so lists show "Working…" instead of idle/finished.
753
766
  pendingWork: currentPendingWork(),
767
+ // UNI-269: the working mode for the host's chat_list badge (null =
768
+ // regular / long-horizon not loaded); a parked owner's mode apart.
769
+ ...recordLhMode(lhMode()),
754
770
  };
755
771
  try {
756
772
  const file = join(dir, `${process.pid}.json`);
@@ -1516,6 +1532,23 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
1516
1532
  case "lh_progress_get":
1517
1533
  write(sock, { t: "lh_progress", progress: lhProgress(), ref: msg.ref });
1518
1534
  return;
1535
+ case "set_lh_mode": {
1536
+ // Through long-horizon's own runner (no hard dependency on the package).
1537
+ try {
1538
+ const out = await callCommandRunner<{ ok: boolean; reason?: string }>(LH_MODE_RUNNER, ctx, { mode: msg.mode });
1539
+ if (!out.found) return fail("Long-horizon modes need a newer unipi on this PC.");
1540
+ if (!out.result?.ok) return fail(out.result?.reason ?? "Could not switch the mode.");
1541
+ ack();
1542
+ // The runner's LH_STATE emit already queued a coalesced push; send
1543
+ // the fresh value now too so the phone's chip settles at once.
1544
+ lastLhMode = JSON.stringify(lhMode() ?? null);
1545
+ writeRecord();
1546
+ send({ t: "lh_mode", mode: lhMode() });
1547
+ } catch (error) {
1548
+ fail(error instanceof Error ? error.message : String(error));
1549
+ }
1550
+ return;
1551
+ }
1519
1552
  case "dream_get":
1520
1553
  write(sock, { t: "dream_status", status: dreamStatus(), ref: msg.ref });
1521
1554
  return;
@@ -1791,6 +1824,23 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
1791
1824
  lhTimer.unref?.();
1792
1825
  });
1793
1826
 
1827
+ // UNI-269: working-mode pushes, coalesced and only on a real change (the
1828
+ // owner lifecycle re-publishes LH_STATE with the same payload often).
1829
+ let lhModeTimer: ReturnType<typeof setTimeout> | undefined;
1830
+ let lastLhMode = JSON.stringify(lhMode() ?? null);
1831
+ bus.on(pi, UNIPI_EVENTS.LH_STATE, () => {
1832
+ if (lhModeTimer) return;
1833
+ lhModeTimer = setTimeout(() => {
1834
+ lhModeTimer = undefined;
1835
+ const now = JSON.stringify(lhMode() ?? null);
1836
+ if (now === lastLhMode) return;
1837
+ lastLhMode = now;
1838
+ writeRecord();
1839
+ send({ t: "lh_mode", mode: lhMode() });
1840
+ }, LH_PROGRESS_COALESCE_MS);
1841
+ lhModeTimer.unref?.();
1842
+ });
1843
+
1794
1844
  // UNI-118: Dream status pushes (run started/finished, proposal decided…),
1795
1845
  // coalesced. Subscribed lazily: the dream module may load after us.
1796
1846
  let dreamTimer: ReturnType<typeof setTimeout> | undefined;
@@ -131,6 +131,20 @@ export type LhProgressInfo = {
131
131
  updatedAt: number;
132
132
  };
133
133
 
134
+ /** UNI-269: the session's long-horizon working mode (`@pi-unipi/core`
135
+ * LhStateEvent), relayed verbatim. `mode` = what the next turn runs in
136
+ * (`none` = regular); `paused` = a parked owner's mode. */
137
+ export type LhModeInfo = {
138
+ mode: string;
139
+ paused?: string;
140
+ owner?: { kind: string; status: "active" | "parked" };
141
+ lastStop?: { kind: string; at: number };
142
+ };
143
+
144
+ /** UNI-269: the modes `set_lh_mode` accepts. */
145
+ export const LH_MODE_IDS = ["goal", "ralph", "swarm", "graph", "none"] as const;
146
+ export type LhModeId = (typeof LH_MODE_IDS)[number];
147
+
134
148
  /** One row of the phone's "Running" section (UNI-160 §4): a background task,
135
149
  * a subagent, or the Fusion sidekick, in one shape. */
136
150
  export interface WorkItemInfo {
@@ -231,6 +245,8 @@ export type OutMsg =
231
245
  work: WorkItemInfo[];
232
246
  /** UNI-222: the long-horizon progress snapshot at connect time; absent when long-horizon never published one. */
233
247
  lhProgress?: LhProgressInfo;
248
+ /** UNI-269: the working mode at connect time; absent when long-horizon isn't loaded. */
249
+ lhMode?: LhModeInfo;
234
250
  /** UNI-118: Dream status at connect time; absent when the dream module isn't loaded. */
235
251
  dream?: DreamStatusInfo;
236
252
  }
@@ -303,6 +319,8 @@ export type OutMsg =
303
319
  * client, coalesced ≤ 4/s), or the reply to `lh_progress_get` (`ref`).
304
320
  * `progress` undefined = long-horizon isn't loaded / never published. */
305
321
  | { t: "lh_progress"; progress: LhProgressInfo | undefined; ref?: string }
322
+ /** UNI-269: the working mode changed (pushed to every client, coalesced). */
323
+ | { t: "lh_mode"; mode: LhModeInfo | undefined }
306
324
  /** UNI-118: Dream status changed (pushed to every client, coalesced), or the
307
325
  * reply to `dream_get` (`ref`). `status` undefined = the dream module isn't loaded. */
308
326
  | { t: "dream_status"; status: DreamStatusInfo | undefined; ref?: string }
@@ -437,6 +455,9 @@ export type InMsg =
437
455
  | { t: "work_background"; id: string; ref?: string }
438
456
  /** UNI-222: the current long-horizon progress snapshot; replies `lh_progress{progress, ref}`. */
439
457
  | { t: "lh_progress_get"; ref?: string }
458
+ /** UNI-269: switch the working mode (no prompt); `none` = /unipi:regular.
459
+ * Replies `ack` (then an `lh_mode` push) or `error{message}`. */
460
+ | { t: "set_lh_mode"; mode: LhModeId; ref?: string }
440
461
  /** UNI-118: the current Dream status; replies `dream_status{status, ref}`. */
441
462
  | { t: "dream_get"; ref?: string }
442
463
  /** UNI-118: one run's report + trajectory; replies `dream_detail` (or `error`). */
@@ -480,6 +501,7 @@ const IN_TYPES = new Set([
480
501
  "work_rerun",
481
502
  "work_background",
482
503
  "lh_progress_get",
504
+ "set_lh_mode",
483
505
  "dream_get",
484
506
  "dream_detail",
485
507
  "dream_action",
@@ -613,6 +635,11 @@ export function parseIn(line: string): InMsg | { bad: string; ref?: string } | u
613
635
  return { t: "work_background", id: m.id, ref };
614
636
  case "lh_progress_get":
615
637
  return { t: "lh_progress_get", ref };
638
+ case "set_lh_mode":
639
+ if (typeof m.mode !== "string" || !(LH_MODE_IDS as readonly string[]).includes(m.mode)) {
640
+ return { bad: "set_lh_mode.mode must be goal|ralph|swarm|graph|none", ref };
641
+ }
642
+ return { t: "set_lh_mode", mode: m.mode as LhModeId, ref };
616
643
  case "dream_get":
617
644
  return { t: "dream_get", ref };
618
645
  case "dream_detail":
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/ask-user",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Structured user input tool for Pi coding agent — single-select, multi-select, freeform",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -42,7 +42,7 @@
42
42
  "access": "public"
43
43
  },
44
44
  "dependencies": {
45
- "@pi-unipi/core": "3.0.0-alpha.38"
45
+ "@pi-unipi/core": "3.0.0-alpha.39"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/command-enchantment",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Enhanced TUI autocomplete for /unipi:* commands — colored, sorted, and grouped by package",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/background-tasks",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Background tasks for UniPi — durable shell jobs and delegated background agents with a footer dock",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@earendil-works/pi-ai": "^0.87.1",
13
- "@pi-unipi/core": "3.0.0-alpha.38",
13
+ "@pi-unipi/core": "3.0.0-alpha.39",
14
14
  "turndown": "^7.2.4"
15
15
  },
16
16
  "devDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/btw",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "A pi extension for parallel side conversations with /unipi:btw — part of the Unipi suite",
5
5
  "type": "module",
6
6
  "main": "extensions/btw.ts",
@@ -37,7 +37,7 @@
37
37
  "@earendil-works/pi-tui": "^0.87.1"
38
38
  },
39
39
  "dependencies": {
40
- "@pi-unipi/core": "3.0.0-alpha.38"
40
+ "@pi-unipi/core": "3.0.0-alpha.39"
41
41
  },
42
42
  "pi": {
43
43
  "extensions": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/compactor",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Compaction for Pi — lossless zero-LLM or model summaries, rebuilt from full history, with session recall",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -33,8 +33,8 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "3.0.0-alpha.38",
37
- "@pi-unipi/info-screen": "3.0.0-alpha.38",
36
+ "@pi-unipi/core": "3.0.0-alpha.39",
37
+ "@pi-unipi/info-screen": "3.0.0-alpha.39",
38
38
  "@earendil-works/pi-agent-core": "^0.87.1"
39
39
  },
40
40
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/core",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Shared utilities, event types, and constants for Unipi extension suite",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/dream",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "A pi extension that dreams: reviews past session struggles in the background, turns repeated false paths into memory lessons, and crafts skills from errors — part of the Unipi suite",
5
5
  "type": "module",
6
6
  "main": "extensions/dream.ts",
@@ -39,7 +39,7 @@
39
39
  "@earendil-works/pi-tui": "^0.87.1"
40
40
  },
41
41
  "dependencies": {
42
- "@pi-unipi/core": "3.0.0-alpha.38"
42
+ "@pi-unipi/core": "3.0.0-alpha.39"
43
43
  },
44
44
  "pi": {
45
45
  "extensions": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/footer",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Persistent status bar for Unipi — subscribes to UNIPI_EVENTS and renders key stats from all unipi packages",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -32,8 +32,8 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "3.0.0-alpha.38",
36
- "@pi-unipi/background-tasks": "3.0.0-alpha.38"
35
+ "@pi-unipi/core": "3.0.0-alpha.39",
36
+ "@pi-unipi/background-tasks": "3.0.0-alpha.39"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/fusion",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Devin-style model picker, fusion presets (lead + sidekick), and Local Fusion runtime for UniPi",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -32,9 +32,9 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "3.0.0-alpha.38",
36
- "@pi-unipi/subagents": "3.0.0-alpha.38",
37
- "@pi-unipi/utility": "3.0.0-alpha.38"
35
+ "@pi-unipi/core": "3.0.0-alpha.39",
36
+ "@pi-unipi/subagents": "3.0.0-alpha.39",
37
+ "@pi-unipi/utility": "3.0.0-alpha.39"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@earendil-works/pi-ai": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/info-screen",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Unicrab startup splash and the /unipi:info dashboard — this session, context, usage, compaction savings",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "3.0.0-alpha.38"
36
+ "@pi-unipi/core": "3.0.0-alpha.39"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/input-shortcuts",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle — chord-based overlay system",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "3.0.0-alpha.38"
36
+ "@pi-unipi/core": "3.0.0-alpha.39"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/kanboard",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Kanboard v3 — deferred-work board: CLI/daemon bridge, task runner and skill",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -31,7 +31,7 @@
31
31
  "access": "public"
32
32
  },
33
33
  "dependencies": {
34
- "@pi-unipi/core": "3.0.0-alpha.38"
34
+ "@pi-unipi/core": "3.0.0-alpha.39"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -48,10 +48,10 @@
48
48
  "themes": []
49
49
  },
50
50
  "optionalDependencies": {
51
- "@pi-unipi/kanboard-linux-x64": "3.0.0-alpha.38",
52
- "@pi-unipi/kanboard-linux-arm64": "3.0.0-alpha.38",
53
- "@pi-unipi/kanboard-darwin-x64": "3.0.0-alpha.38",
54
- "@pi-unipi/kanboard-darwin-arm64": "3.0.0-alpha.38",
55
- "@pi-unipi/kanboard-win32-x64": "3.0.0-alpha.38"
51
+ "@pi-unipi/kanboard-linux-x64": "3.0.0-alpha.39",
52
+ "@pi-unipi/kanboard-linux-arm64": "3.0.0-alpha.39",
53
+ "@pi-unipi/kanboard-darwin-x64": "3.0.0-alpha.39",
54
+ "@pi-unipi/kanboard-darwin-arm64": "3.0.0-alpha.39",
55
+ "@pi-unipi/kanboard-win32-x64": "3.0.0-alpha.39"
56
56
  }
57
57
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/long-horizon",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Long-horizon execution for Pi — mode-gated /goal /ralph /swarm /graph orchestration with a TypeSafe prompt judge",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -37,7 +37,7 @@
37
37
  "access": "public"
38
38
  },
39
39
  "dependencies": {
40
- "@pi-unipi/core": "3.0.0-alpha.38",
40
+ "@pi-unipi/core": "3.0.0-alpha.39",
41
41
  "@resvg/resvg-wasm": "^2.6.2",
42
42
  "beautiful-mermaid": "^1.1.3"
43
43
  },
@@ -16,9 +16,9 @@
16
16
  */
17
17
 
18
18
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
19
- import { bus, appendProgress, sendHarnessUserMessage, UNIPI_EVENTS, type ProgressData } from "@pi-unipi/core";
19
+ import { bus, appendProgress, registerCommandRunner, sendHarnessUserMessage, UNIPI_EVENTS, type ProgressData } from "@pi-unipi/core";
20
20
  import type { LhMode, OwnerKind } from "./modes.js";
21
- import { MODE_REGISTRY } from "./modes.js";
21
+ import { isLhMode, MODE_REGISTRY, modeForOwnerKind } from "./modes.js";
22
22
  import type { Gate } from "./gate.js";
23
23
  import type { OwnerCoordinator } from "./owner.js";
24
24
  import type { RalphLoop } from "./engine/ralph.js";
@@ -324,4 +324,59 @@ export function registerLongHorizonCommands(
324
324
  },
325
325
  });
326
326
 
327
+ // UNI-269: the app's mode chip (app-bridge `set_lh_mode`) — switch the
328
+ // session's working mode without sending a prompt.
329
+ registerCommandRunner(LH_MODE_RUNNER, async (_ctx, args) =>
330
+ selectSessionMode(gate, owner, String((args as { mode?: unknown } | undefined)?.mode ?? ""), stopActiveOwnerFor, machine),
331
+ );
332
+ }
333
+
334
+ /** Runner name the app bridge calls for `set_lh_mode` (UNI-269). */
335
+ export const LH_MODE_RUNNER = "unipi:lh-mode";
336
+
337
+ export type SelectModeResult = { ok: true; mode: LhMode } | { ok: false; reason: string };
338
+
339
+ /**
340
+ * UNI-269: pick the session's working mode from outside the TUI (the app's
341
+ * mode chip), with no prompt. Mirrors the slash commands:
342
+ * - `none` = /unipi:regular: ends the active owner (terminal) and pins
343
+ * regular mode.
344
+ * - a work mode = /unipi:<mode> minus the prompt: an active owner of
345
+ * another mode is parked first (refused when the park slot is held),
346
+ * then the mode is sticky for the next turns and shows at once.
347
+ * - the active owner's own mode is a no-op.
348
+ */
349
+ export function selectSessionMode(
350
+ gate: Gate,
351
+ owner: OwnerCoordinator,
352
+ mode: string,
353
+ stopActive: () => string | undefined,
354
+ machine?: GoalMachine,
355
+ ): SelectModeResult {
356
+ if (!isLhMode(mode)) return { ok: false, reason: `unknown mode "${mode}"` };
357
+ if (mode === "none") {
358
+ stopActive();
359
+ gate.setSessionMode("none");
360
+ return { ok: true, mode };
361
+ }
362
+ const active = owner.getActive();
363
+ if (active && modeForOwnerKind(active.kind) === mode) return { ok: true, mode };
364
+ if (active) {
365
+ // Same as the gate's suspend-and-switch hook: a goal pauses with its owner.
366
+ if (active.kind === "goal") machine?.pause("paused(superseded)");
367
+ const reason = `paused(superseded_by:${mode})`;
368
+ const suspended = owner.suspend(reason);
369
+ if (!suspended) {
370
+ const parked = owner.getParked();
371
+ return {
372
+ ok: false,
373
+ reason: parked
374
+ ? `A ${parked.kind === "ralph-loop" ? "ralph loop" : parked.kind} ("${parked.label}") is already parked — resume or clear it first.`
375
+ : "The running work could not be parked.",
376
+ };
377
+ }
378
+ bus.emit(UNIPI_EVENTS.LONG_HORIZON_OWNER_CHANGED, { event: "suspended", ownerId: suspended.ownerId, reason });
379
+ }
380
+ gate.selectMode(mode);
381
+ return { ok: true, mode };
327
382
  }
@@ -197,6 +197,16 @@ export class Gate {
197
197
  if (this.pi) syncModeTools(this.pi, mode);
198
198
  }
199
199
 
200
+ /** UNI-269: the app's mode chip picked a work mode with no prompt. Same
201
+ * sticky override as setExplicit (the next turn resolves to it, badge and
202
+ * all), but the display flips NOW so the footer and the app's chip show
203
+ * the pick before any turn runs. */
204
+ selectMode(mode: LhMode): void {
205
+ this.setExplicit(mode);
206
+ this.display = mode;
207
+ this.deps.onDisplayChanged?.();
208
+ }
209
+
200
210
  /** Pin the session to a mode (/unipi:regular, goal stop): every later turn resolves to it. */
201
211
  setSessionMode(mode: LhMode): void {
202
212
  this.sessionOverride = mode;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/mcp",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "MCP server management extension for Pi coding agent — browse, add, configure, and use MCP servers",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -30,7 +30,7 @@
30
30
  "test": "npx tsx --test tests/**/*.test.ts"
31
31
  },
32
32
  "dependencies": {
33
- "@pi-unipi/core": "3.0.0-alpha.38"
33
+ "@pi-unipi/core": "3.0.0-alpha.39"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/memory",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Persistent cross-session memory on MemPalace (auto-installed): daemon-routed writes, shared palace with other agents, for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -44,8 +44,8 @@
44
44
  "README.md"
45
45
  ],
46
46
  "dependencies": {
47
- "@pi-unipi/core": "3.0.0-alpha.38",
48
- "@pi-unipi/info-screen": "3.0.0-alpha.38",
47
+ "@pi-unipi/core": "3.0.0-alpha.39",
48
+ "@pi-unipi/info-screen": "3.0.0-alpha.39",
49
49
  "js-yaml": "^4.1.0"
50
50
  },
51
51
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/notify",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Cross-platform notification extension for Pi — native OS, Gotify, and Telegram notifications for agent lifecycle events",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "3.0.0-alpha.38",
37
+ "@pi-unipi/core": "3.0.0-alpha.39",
38
38
  "node-notifier": "^10.0.1"
39
39
  },
40
40
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/skill-registry",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Skill registry for pi — per-project skill on/off, a skill vault, and jev-judged skill exposure",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "main": "index.ts",
35
35
  "dependencies": {
36
- "@pi-unipi/core": "3.0.0-alpha.38"
36
+ "@pi-unipi/core": "3.0.0-alpha.39"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/subagents",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Subagents for UniPi — Devin-model independent child agents",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -9,8 +9,8 @@
9
9
  "test": "npx tsx --test src/__tests__/*.test.ts"
10
10
  },
11
11
  "dependencies": {
12
- "@pi-unipi/core": "3.0.0-alpha.38",
13
- "@pi-unipi/utility": "3.0.0-alpha.38",
12
+ "@pi-unipi/core": "3.0.0-alpha.39",
13
+ "@pi-unipi/utility": "3.0.0-alpha.39",
14
14
  "@earendil-works/pi-agent-core": "^0.87.1",
15
15
  "acorn": "8.18.0"
16
16
  },
@@ -16863,6 +16863,15 @@ var Gate = class {
16863
16863
  this.sessionOverride = mode;
16864
16864
  if (this.pi) syncModeTools(this.pi, mode);
16865
16865
  }
16866
+ /** UNI-269: the app's mode chip picked a work mode with no prompt. Same
16867
+ * sticky override as setExplicit (the next turn resolves to it, badge and
16868
+ * all), but the display flips NOW so the footer and the app's chip show
16869
+ * the pick before any turn runs. */
16870
+ selectMode(mode) {
16871
+ this.setExplicit(mode);
16872
+ this.display = mode;
16873
+ this.deps.onDisplayChanged?.();
16874
+ }
16866
16875
  /** Pin the session to a mode (/unipi:regular, goal stop): every later turn resolves to it. */
16867
16876
  setSessionMode(mode) {
16868
16877
  this.sessionOverride = mode;
@@ -17264,6 +17273,36 @@ Settings: ~/.pi/agent/settings.json \u2192 unipi.longHorizon`
17264
17273
  notify(ctx, "Regular mode.");
17265
17274
  }
17266
17275
  });
17276
+ registerCommandRunner(
17277
+ LH_MODE_RUNNER,
17278
+ async (_ctx, args) => selectSessionMode(gate, owner, String(args?.mode ?? ""), stopActiveOwnerFor, machine)
17279
+ );
17280
+ }
17281
+ var LH_MODE_RUNNER = "unipi:lh-mode";
17282
+ function selectSessionMode(gate, owner, mode, stopActive, machine) {
17283
+ if (!isLhMode(mode)) return { ok: false, reason: `unknown mode "${mode}"` };
17284
+ if (mode === "none") {
17285
+ stopActive();
17286
+ gate.setSessionMode("none");
17287
+ return { ok: true, mode };
17288
+ }
17289
+ const active = owner.getActive();
17290
+ if (active && modeForOwnerKind(active.kind) === mode) return { ok: true, mode };
17291
+ if (active) {
17292
+ if (active.kind === "goal") machine?.pause("paused(superseded)");
17293
+ const reason = `paused(superseded_by:${mode})`;
17294
+ const suspended = owner.suspend(reason);
17295
+ if (!suspended) {
17296
+ const parked = owner.getParked();
17297
+ return {
17298
+ ok: false,
17299
+ reason: parked ? `A ${parked.kind === "ralph-loop" ? "ralph loop" : parked.kind} ("${parked.label}") is already parked \u2014 resume or clear it first.` : "The running work could not be parked."
17300
+ };
17301
+ }
17302
+ bus.emit(UNIPI_EVENTS.LONG_HORIZON_OWNER_CHANGED, { event: "suspended", ownerId: suspended.ownerId, reason });
17303
+ }
17304
+ gate.selectMode(mode);
17305
+ return { ok: true, mode };
17267
17306
  }
17268
17307
 
17269
17308
  // packages/long-horizon/src/engine/goal-state.ts
@@ -57602,6 +57641,7 @@ function historyPage(branch, before, budget = ENTRIES_BUDGET) {
57602
57641
 
57603
57642
  // packages/app-bridge/src/wire.ts
57604
57643
  var BRIDGE_PROTOCOL = 1;
57644
+ var LH_MODE_IDS = ["goal", "ralph", "swarm", "graph", "none"];
57605
57645
  var IN_TYPES = /* @__PURE__ */ new Set([
57606
57646
  "prompt",
57607
57647
  "abort",
@@ -57636,6 +57676,7 @@ var IN_TYPES = /* @__PURE__ */ new Set([
57636
57676
  "work_rerun",
57637
57677
  "work_background",
57638
57678
  "lh_progress_get",
57679
+ "set_lh_mode",
57639
57680
  "dream_get",
57640
57681
  "dream_detail",
57641
57682
  "dream_action"
@@ -57763,6 +57804,11 @@ function parseIn(line) {
57763
57804
  return { t: "work_background", id: m.id, ref };
57764
57805
  case "lh_progress_get":
57765
57806
  return { t: "lh_progress_get", ref };
57807
+ case "set_lh_mode":
57808
+ if (typeof m.mode !== "string" || !LH_MODE_IDS.includes(m.mode)) {
57809
+ return { bad: "set_lh_mode.mode must be goal|ralph|swarm|graph|none", ref };
57810
+ }
57811
+ return { t: "set_lh_mode", mode: m.mode, ref };
57766
57812
  case "dream_get":
57767
57813
  return { t: "dream_get", ref };
57768
57814
  case "dream_detail":
@@ -58122,6 +58168,12 @@ init_core();
58122
58168
  init_core();
58123
58169
  var MEDIA_CHUNK_CHARS = 700 * 1024;
58124
58170
  var LH_PROGRESS_COALESCE_MS = 250;
58171
+ function recordLhMode(state2) {
58172
+ const mode = typeof state2?.mode === "string" && state2.mode && state2.mode !== "none" ? state2.mode : null;
58173
+ const paused = typeof state2?.paused === "string" && state2.paused && state2.paused !== "none" && state2.paused !== mode ? state2.paused : null;
58174
+ return { lhMode: mode, lhPaused: paused };
58175
+ }
58176
+ var LH_MODE_RUNNER2 = "unipi:lh-mode";
58125
58177
  var DREAM_COALESCE_MS = 250;
58126
58178
  var DREAM_API_KEY2 = /* @__PURE__ */ Symbol.for("unipi.dream.api");
58127
58179
  var getDreamApi = () => globalThis[DREAM_API_KEY2];
@@ -58498,6 +58550,7 @@ function createBridge(pi, deps = defaultDeps2) {
58498
58550
  }
58499
58551
  };
58500
58552
  const lhProgress = () => bus.get(UNIPI_EVENTS.LH_PROGRESS);
58553
+ const lhMode = () => bus.get(UNIPI_EVENTS.LH_STATE);
58501
58554
  const hello = () => {
58502
58555
  const c2 = ctx;
58503
58556
  const rest = {
@@ -58516,6 +58569,7 @@ function createBridge(pi, deps = defaultDeps2) {
58516
58569
  fusion: fusionPreset(),
58517
58570
  work: workItems(),
58518
58571
  ...lhProgress() ? { lhProgress: lhProgress() } : {},
58572
+ ...lhMode() ? { lhMode: lhMode() } : {},
58519
58573
  ...(() => {
58520
58574
  const dream = dreamStatus();
58521
58575
  return dream ? { dream } : {};
@@ -58591,7 +58645,10 @@ function createBridge(pi, deps = defaultDeps2) {
58591
58645
  // UNI-221: wake-capable work still pending (bg task with a wake, a
58592
58646
  // background subagent, a fusion handoff) — the host passes it into
58593
58647
  // chat_list so lists show "Working…" instead of idle/finished.
58594
- pendingWork: currentPendingWork()
58648
+ pendingWork: currentPendingWork(),
58649
+ // UNI-269: the working mode for the host's chat_list badge (null =
58650
+ // regular / long-horizon not loaded); a parked owner's mode apart.
58651
+ ...recordLhMode(lhMode())
58595
58652
  };
58596
58653
  try {
58597
58654
  const file = join89(dir, `${process.pid}.json`);
@@ -59208,6 +59265,20 @@ function createBridge(pi, deps = defaultDeps2) {
59208
59265
  case "lh_progress_get":
59209
59266
  write(sock, { t: "lh_progress", progress: lhProgress(), ref: msg.ref });
59210
59267
  return;
59268
+ case "set_lh_mode": {
59269
+ try {
59270
+ const out = await callCommandRunner(LH_MODE_RUNNER2, ctx, { mode: msg.mode });
59271
+ if (!out.found) return fail("Long-horizon modes need a newer unipi on this PC.");
59272
+ if (!out.result?.ok) return fail(out.result?.reason ?? "Could not switch the mode.");
59273
+ ack();
59274
+ lastLhMode = JSON.stringify(lhMode() ?? null);
59275
+ writeRecord();
59276
+ send({ t: "lh_mode", mode: lhMode() });
59277
+ } catch (error) {
59278
+ fail(error instanceof Error ? error.message : String(error));
59279
+ }
59280
+ return;
59281
+ }
59211
59282
  case "dream_get":
59212
59283
  write(sock, { t: "dream_status", status: dreamStatus(), ref: msg.ref });
59213
59284
  return;
@@ -59426,6 +59497,20 @@ function createBridge(pi, deps = defaultDeps2) {
59426
59497
  }, LH_PROGRESS_COALESCE_MS);
59427
59498
  lhTimer.unref?.();
59428
59499
  });
59500
+ let lhModeTimer;
59501
+ let lastLhMode = JSON.stringify(lhMode() ?? null);
59502
+ bus.on(pi, UNIPI_EVENTS.LH_STATE, () => {
59503
+ if (lhModeTimer) return;
59504
+ lhModeTimer = setTimeout(() => {
59505
+ lhModeTimer = void 0;
59506
+ const now2 = JSON.stringify(lhMode() ?? null);
59507
+ if (now2 === lastLhMode) return;
59508
+ lastLhMode = now2;
59509
+ writeRecord();
59510
+ send({ t: "lh_mode", mode: lhMode() });
59511
+ }, LH_PROGRESS_COALESCE_MS);
59512
+ lhModeTimer.unref?.();
59513
+ });
59429
59514
  let dreamTimer;
59430
59515
  let unsubDream;
59431
59516
  let lastDream = "";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/updater",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Auto-updater, changelog browser, and readme browser for Unipi — checks npm registry, renders CHANGELOG.md and README.md files in TUI overlays",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "3.0.0-alpha.38"
37
+ "@pi-unipi/core": "3.0.0-alpha.39"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/utility",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Utility commands and tools for Pi coding agent — lifecycle, diagnostics, cache, analytics, display, batch execution",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -36,7 +36,7 @@
36
36
  "access": "public"
37
37
  },
38
38
  "dependencies": {
39
- "@pi-unipi/core": "3.0.0-alpha.38"
39
+ "@pi-unipi/core": "3.0.0-alpha.39"
40
40
  },
41
41
  "devDependencies": {},
42
42
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/watchdog",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Jev watchdog for long-running tool calls and background tasks — judges stuck work via TypeSafe System One and kills or warns",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -32,8 +32,8 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/background-tasks": "3.0.0-alpha.38",
36
- "@pi-unipi/core": "3.0.0-alpha.38"
35
+ "@pi-unipi/background-tasks": "3.0.0-alpha.39",
36
+ "@pi-unipi/core": "3.0.0-alpha.39"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/web-api",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Web search, read, and summarize tools with provider-based backend selection for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -31,7 +31,7 @@
31
31
  "README.md"
32
32
  ],
33
33
  "dependencies": {
34
- "@pi-unipi/core": "3.0.0-alpha.38",
34
+ "@pi-unipi/core": "3.0.0-alpha.39",
35
35
  "defuddle": "^0.18.1",
36
36
  "linkedom": "^0.18.12",
37
37
  "wreq-js": "^2.3.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/workflow",
3
- "version": "3.0.0-alpha.38",
3
+ "version": "3.0.0-alpha.39",
4
4
  "description": "Plan mode and permission modes for the Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -27,7 +27,7 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@pi-unipi/core": "3.0.0-alpha.38"
30
+ "@pi-unipi/core": "3.0.0-alpha.39"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@earendil-works/pi-ai": "^0.87.1",