@pi-unipi/unipi 3.0.0-alpha.37 → 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 +12 -0
- package/package.json +23 -23
- package/packages/app-bridge/package.json +2 -2
- package/packages/app-bridge/src/bridge.ts +51 -1
- package/packages/app-bridge/src/wire.ts +27 -0
- package/packages/ask-user/package.json +4 -2
- package/packages/autocomplete/package.json +1 -1
- package/packages/background-tasks/package.json +2 -2
- package/packages/btw/package.json +2 -2
- package/packages/compactor/package.json +3 -3
- package/packages/core/package.json +1 -1
- package/packages/dream/package.json +2 -2
- package/packages/dream/src/runs.ts +27 -1
- package/packages/footer/package.json +3 -3
- package/packages/fusion/package.json +4 -4
- package/packages/info-screen/package.json +2 -2
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/kanboard/package.json +7 -7
- package/packages/long-horizon/package.json +2 -2
- package/packages/long-horizon/src/commands.ts +57 -2
- package/packages/long-horizon/src/gate.ts +10 -0
- package/packages/mcp/package.json +2 -2
- package/packages/memory/package.json +4 -3
- package/packages/notify/package.json +2 -2
- package/packages/skill-registry/package.json +2 -2
- package/packages/subagents/package.json +3 -3
- package/packages/unipi/bundled.js +110 -3
- package/packages/updater/package.json +2 -2
- package/packages/utility/package.json +2 -2
- package/packages/watchdog/package.json +3 -3
- package/packages/web-api/package.json +2 -2
- package/packages/workflow/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,18 @@ 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
|
+
|
|
15
|
+
## [3.0.0-alpha.38] — 2026-10-11
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- Dream: "Run now" (`/unipi:dream run`) failed instantly. The published `memory` and `ask-user` packages were missing files, so Dream's background run could not load. Both packages now ship complete, and a failed Dream run shows the actual error.
|
|
19
|
+
- Release check added: a package is not released if one of its files imports a file the package does not ship.
|
|
20
|
+
|
|
9
21
|
## [3.0.0-alpha.37] — 2026-10-11
|
|
10
22
|
|
|
11
23
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/unipi",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
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.
|
|
84
|
-
"@pi-unipi/ask-user": "3.0.0-alpha.
|
|
85
|
-
"@pi-unipi/background-tasks": "3.0.0-alpha.
|
|
86
|
-
"@pi-unipi/btw": "3.0.0-alpha.
|
|
87
|
-
"@pi-unipi/command-enchantment": "3.0.0-alpha.
|
|
88
|
-
"@pi-unipi/compactor": "3.0.0-alpha.
|
|
89
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
90
|
-
"@pi-unipi/dream": "3.0.0-alpha.
|
|
91
|
-
"@pi-unipi/footer": "3.0.0-alpha.
|
|
92
|
-
"@pi-unipi/fusion": "3.0.0-alpha.
|
|
93
|
-
"@pi-unipi/info-screen": "3.0.0-alpha.
|
|
94
|
-
"@pi-unipi/input-shortcuts": "3.0.0-alpha.
|
|
95
|
-
"@pi-unipi/kanboard": "3.0.0-alpha.
|
|
96
|
-
"@pi-unipi/mcp": "3.0.0-alpha.
|
|
97
|
-
"@pi-unipi/memory": "3.0.0-alpha.
|
|
98
|
-
"@pi-unipi/notify": "3.0.0-alpha.
|
|
99
|
-
"@pi-unipi/skill-registry": "3.0.0-alpha.
|
|
100
|
-
"@pi-unipi/subagents": "3.0.0-alpha.
|
|
101
|
-
"@pi-unipi/updater": "3.0.0-alpha.
|
|
102
|
-
"@pi-unipi/utility": "3.0.0-alpha.
|
|
103
|
-
"@pi-unipi/web-api": "3.0.0-alpha.
|
|
104
|
-
"@pi-unipi/workflow": "3.0.0-alpha.
|
|
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.
|
|
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.
|
|
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.
|
|
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",
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
"user-input"
|
|
22
22
|
],
|
|
23
23
|
"files": [
|
|
24
|
+
"clipboard.ts",
|
|
25
|
+
"questions.ts",
|
|
24
26
|
"index.ts",
|
|
25
27
|
"types.ts",
|
|
26
28
|
"tools.ts",
|
|
@@ -40,7 +42,7 @@
|
|
|
40
42
|
"access": "public"
|
|
41
43
|
},
|
|
42
44
|
"dependencies": {
|
|
43
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
45
|
+
"@pi-unipi/core": "3.0.0-alpha.39"
|
|
44
46
|
},
|
|
45
47
|
"peerDependencies": {
|
|
46
48
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/background-tasks",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
37
|
-
"@pi-unipi/info-screen": "3.0.0-alpha.
|
|
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/dream",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
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.
|
|
42
|
+
"@pi-unipi/core": "3.0.0-alpha.39"
|
|
43
43
|
},
|
|
44
44
|
"pi": {
|
|
45
45
|
"extensions": [
|
|
@@ -127,7 +127,10 @@ export function runFromStaging(staging: string, decisions: DreamState["decisions
|
|
|
127
127
|
let error: string | undefined;
|
|
128
128
|
if (status === "failed") {
|
|
129
129
|
if (meta?.exitCode === 124) error = "timed out (max runtime)";
|
|
130
|
-
else if (typeof meta?.exitCode === "number")
|
|
130
|
+
else if (typeof meta?.exitCode === "number") {
|
|
131
|
+
const why = logErrorLine(path.join(staging, "trajectory.log"));
|
|
132
|
+
error = why ? `exit ${String(meta.exitCode)}: ${why}` : `exit ${String(meta.exitCode)} without a report`;
|
|
133
|
+
}
|
|
131
134
|
else if (meta?.signal) error = `killed by ${meta.signal}`;
|
|
132
135
|
else error = "ended without a report";
|
|
133
136
|
}
|
|
@@ -328,3 +331,26 @@ export function summarizeReport(report: string): string[] {
|
|
|
328
331
|
export function reportSummary(staging: string): string[] {
|
|
329
332
|
return summarizeReport(readReport(staging));
|
|
330
333
|
}
|
|
334
|
+
|
|
335
|
+
/** The child's own reason for failing: the last `Error:` line of its log
|
|
336
|
+
* (pi prints "Error: Failed to load extension …" and exits 1), clipped. */
|
|
337
|
+
export function logErrorLine(logFile: string): string | undefined {
|
|
338
|
+
try {
|
|
339
|
+
const fd = fs.openSync(logFile, "r");
|
|
340
|
+
try {
|
|
341
|
+
const size = fs.fstatSync(fd).size;
|
|
342
|
+
const len = Math.min(size, 16 * 1024);
|
|
343
|
+
const buf = Buffer.alloc(len);
|
|
344
|
+
fs.readSync(fd, buf, 0, len, size - len);
|
|
345
|
+
const lines = buf.toString("utf8").split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
346
|
+
const hit = [...lines].reverse().find((l) => /^(Error|TypeError|SyntaxError|ReferenceError)\b/.test(l));
|
|
347
|
+
if (!hit) return undefined;
|
|
348
|
+
const msg = hit.replace(/^Error:\s*/, "");
|
|
349
|
+
return msg.length > 240 ? `${msg.slice(0, 239)}…` : msg;
|
|
350
|
+
} finally {
|
|
351
|
+
fs.closeSync(fd);
|
|
352
|
+
}
|
|
353
|
+
} catch {
|
|
354
|
+
return undefined;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/footer",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
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.
|
|
36
|
-
"@pi-unipi/background-tasks": "3.0.0-alpha.
|
|
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.
|
|
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.
|
|
36
|
-
"@pi-unipi/subagents": "3.0.0-alpha.
|
|
37
|
-
"@pi-unipi/utility": "3.0.0-alpha.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
52
|
-
"@pi-unipi/kanboard-linux-arm64": "3.0.0-alpha.
|
|
53
|
-
"@pi-unipi/kanboard-darwin-x64": "3.0.0-alpha.
|
|
54
|
-
"@pi-unipi/kanboard-darwin-arm64": "3.0.0-alpha.
|
|
55
|
-
"@pi-unipi/kanboard-win32-x64": "3.0.0-alpha.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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",
|
|
@@ -37,14 +37,15 @@
|
|
|
37
37
|
"settings.ts",
|
|
38
38
|
"tools.ts",
|
|
39
39
|
"commands.ts",
|
|
40
|
+
"save-session.ts",
|
|
40
41
|
"index.ts",
|
|
41
42
|
"tui/**/*",
|
|
42
43
|
"skills/**/*",
|
|
43
44
|
"README.md"
|
|
44
45
|
],
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
47
|
-
"@pi-unipi/info-screen": "3.0.0-alpha.
|
|
47
|
+
"@pi-unipi/core": "3.0.0-alpha.39",
|
|
48
|
+
"@pi-unipi/info-screen": "3.0.0-alpha.39",
|
|
48
49
|
"js-yaml": "^4.1.0"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/notify",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
13
|
-
"@pi-unipi/utility": "3.0.0-alpha.
|
|
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
|
|
@@ -24535,8 +24574,10 @@ function runFromStaging(staging, decisions = {}, now2 = Date.now(), alive2 = pid
|
|
|
24535
24574
|
let error;
|
|
24536
24575
|
if (status2 === "failed") {
|
|
24537
24576
|
if (meta2?.exitCode === 124) error = "timed out (max runtime)";
|
|
24538
|
-
else if (typeof meta2?.exitCode === "number")
|
|
24539
|
-
|
|
24577
|
+
else if (typeof meta2?.exitCode === "number") {
|
|
24578
|
+
const why = logErrorLine(path20.join(staging, "trajectory.log"));
|
|
24579
|
+
error = why ? `exit ${String(meta2.exitCode)}: ${why}` : `exit ${String(meta2.exitCode)} without a report`;
|
|
24580
|
+
} else if (meta2?.signal) error = `killed by ${meta2.signal}`;
|
|
24540
24581
|
else error = "ended without a report";
|
|
24541
24582
|
}
|
|
24542
24583
|
return {
|
|
@@ -24701,6 +24742,26 @@ function summarizeReport(report) {
|
|
|
24701
24742
|
function reportSummary(staging) {
|
|
24702
24743
|
return summarizeReport(readReport(staging));
|
|
24703
24744
|
}
|
|
24745
|
+
function logErrorLine(logFile) {
|
|
24746
|
+
try {
|
|
24747
|
+
const fd = fs19.openSync(logFile, "r");
|
|
24748
|
+
try {
|
|
24749
|
+
const size = fs19.fstatSync(fd).size;
|
|
24750
|
+
const len = Math.min(size, 16 * 1024);
|
|
24751
|
+
const buf = Buffer.alloc(len);
|
|
24752
|
+
fs19.readSync(fd, buf, 0, len, size - len);
|
|
24753
|
+
const lines4 = buf.toString("utf8").split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
24754
|
+
const hit = [...lines4].reverse().find((l) => /^(Error|TypeError|SyntaxError|ReferenceError)\b/.test(l));
|
|
24755
|
+
if (!hit) return void 0;
|
|
24756
|
+
const msg = hit.replace(/^Error:\s*/, "");
|
|
24757
|
+
return msg.length > 240 ? `${msg.slice(0, 239)}\u2026` : msg;
|
|
24758
|
+
} finally {
|
|
24759
|
+
fs19.closeSync(fd);
|
|
24760
|
+
}
|
|
24761
|
+
} catch {
|
|
24762
|
+
return void 0;
|
|
24763
|
+
}
|
|
24764
|
+
}
|
|
24704
24765
|
|
|
24705
24766
|
// packages/dream/src/runner.ts
|
|
24706
24767
|
var require_ = createRequire2(import.meta.url);
|
|
@@ -57580,6 +57641,7 @@ function historyPage(branch, before, budget = ENTRIES_BUDGET) {
|
|
|
57580
57641
|
|
|
57581
57642
|
// packages/app-bridge/src/wire.ts
|
|
57582
57643
|
var BRIDGE_PROTOCOL = 1;
|
|
57644
|
+
var LH_MODE_IDS = ["goal", "ralph", "swarm", "graph", "none"];
|
|
57583
57645
|
var IN_TYPES = /* @__PURE__ */ new Set([
|
|
57584
57646
|
"prompt",
|
|
57585
57647
|
"abort",
|
|
@@ -57614,6 +57676,7 @@ var IN_TYPES = /* @__PURE__ */ new Set([
|
|
|
57614
57676
|
"work_rerun",
|
|
57615
57677
|
"work_background",
|
|
57616
57678
|
"lh_progress_get",
|
|
57679
|
+
"set_lh_mode",
|
|
57617
57680
|
"dream_get",
|
|
57618
57681
|
"dream_detail",
|
|
57619
57682
|
"dream_action"
|
|
@@ -57741,6 +57804,11 @@ function parseIn(line) {
|
|
|
57741
57804
|
return { t: "work_background", id: m.id, ref };
|
|
57742
57805
|
case "lh_progress_get":
|
|
57743
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 };
|
|
57744
57812
|
case "dream_get":
|
|
57745
57813
|
return { t: "dream_get", ref };
|
|
57746
57814
|
case "dream_detail":
|
|
@@ -58100,6 +58168,12 @@ init_core();
|
|
|
58100
58168
|
init_core();
|
|
58101
58169
|
var MEDIA_CHUNK_CHARS = 700 * 1024;
|
|
58102
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";
|
|
58103
58177
|
var DREAM_COALESCE_MS = 250;
|
|
58104
58178
|
var DREAM_API_KEY2 = /* @__PURE__ */ Symbol.for("unipi.dream.api");
|
|
58105
58179
|
var getDreamApi = () => globalThis[DREAM_API_KEY2];
|
|
@@ -58476,6 +58550,7 @@ function createBridge(pi, deps = defaultDeps2) {
|
|
|
58476
58550
|
}
|
|
58477
58551
|
};
|
|
58478
58552
|
const lhProgress = () => bus.get(UNIPI_EVENTS.LH_PROGRESS);
|
|
58553
|
+
const lhMode = () => bus.get(UNIPI_EVENTS.LH_STATE);
|
|
58479
58554
|
const hello = () => {
|
|
58480
58555
|
const c2 = ctx;
|
|
58481
58556
|
const rest = {
|
|
@@ -58494,6 +58569,7 @@ function createBridge(pi, deps = defaultDeps2) {
|
|
|
58494
58569
|
fusion: fusionPreset(),
|
|
58495
58570
|
work: workItems(),
|
|
58496
58571
|
...lhProgress() ? { lhProgress: lhProgress() } : {},
|
|
58572
|
+
...lhMode() ? { lhMode: lhMode() } : {},
|
|
58497
58573
|
...(() => {
|
|
58498
58574
|
const dream = dreamStatus();
|
|
58499
58575
|
return dream ? { dream } : {};
|
|
@@ -58569,7 +58645,10 @@ function createBridge(pi, deps = defaultDeps2) {
|
|
|
58569
58645
|
// UNI-221: wake-capable work still pending (bg task with a wake, a
|
|
58570
58646
|
// background subagent, a fusion handoff) — the host passes it into
|
|
58571
58647
|
// chat_list so lists show "Working…" instead of idle/finished.
|
|
58572
|
-
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())
|
|
58573
58652
|
};
|
|
58574
58653
|
try {
|
|
58575
58654
|
const file = join89(dir, `${process.pid}.json`);
|
|
@@ -59186,6 +59265,20 @@ function createBridge(pi, deps = defaultDeps2) {
|
|
|
59186
59265
|
case "lh_progress_get":
|
|
59187
59266
|
write(sock, { t: "lh_progress", progress: lhProgress(), ref: msg.ref });
|
|
59188
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
|
+
}
|
|
59189
59282
|
case "dream_get":
|
|
59190
59283
|
write(sock, { t: "dream_status", status: dreamStatus(), ref: msg.ref });
|
|
59191
59284
|
return;
|
|
@@ -59404,6 +59497,20 @@ function createBridge(pi, deps = defaultDeps2) {
|
|
|
59404
59497
|
}, LH_PROGRESS_COALESCE_MS);
|
|
59405
59498
|
lhTimer.unref?.();
|
|
59406
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
|
+
});
|
|
59407
59514
|
let dreamTimer;
|
|
59408
59515
|
let unsubDream;
|
|
59409
59516
|
let lastDream = "";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/updater",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
36
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
30
|
+
"@pi-unipi/core": "3.0.0-alpha.39"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@earendil-works/pi-ai": "^0.87.1",
|