@pi-unipi/unipi 3.0.0-alpha.42 → 3.0.0-alpha.43
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 +26 -24
- package/packages/app-bridge/package.json +2 -2
- package/packages/app-bridge/src/bridge.ts +66 -4
- package/packages/app-bridge/src/wire.ts +9 -0
- package/packages/ask-user/package.json +2 -2
- package/packages/autocomplete/package.json +1 -1
- package/packages/autocomplete/src/constants.ts +2 -0
- 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/command-echo.ts +47 -1
- package/packages/core/constants.ts +1 -0
- package/packages/core/package.json +1 -1
- package/packages/dream/package.json +2 -2
- 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/mcp/package.json +2 -2
- package/packages/memory/package.json +3 -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 +531 -85
- package/packages/updater/package.json +2 -2
- package/packages/utility/package.json +2 -2
- package/packages/utility/skills/cron/SKILL.md +131 -0
- package/packages/utility/src/cron/index.ts +323 -0
- package/packages/utility/src/cron/settings.ts +185 -0
- package/packages/utility/src/index.ts +18 -1
- 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.43] — 2026-10-16
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- Cron: scheduled, unattended pi runs on your PC, run by the UniPi host (needs UniPi host 0.5.1). `skill:cron` sets jobs up from a plain request ("every weekday at 18:30 summarize my inbox"), with plain-language schedules, per-job notifications (ntfy, Gotify, Telegram) and an optional wake-up message to the session that set it. `/unipi:cron` lists jobs, their runs and results, and runs, stops, enables or pauses them. Cron settings are in `/unipi:settings`. (UNI-288, UNI-314–318)
|
|
13
|
+
- `/skill:craft-skill` and `/skill:web` are listed as normal skills. (UNI-307)
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- The UniPi app now gets argument suggestions for every extension's commands (e.g. `/usage `), not only UniPi's own. (UNI-304)
|
|
17
|
+
- The app's model list stayed partial (only openrouter) when a provider such as OmniRoute registered after the app connected; the list is now pushed again when it changes.
|
|
18
|
+
- Removing a steered message from the app no longer stops the run. (UNI-305)
|
|
19
|
+
- `/reload` from the app reloads pi instead of being sent as a message. (UNI-308)
|
|
20
|
+
|
|
9
21
|
## [3.0.0-alpha.42] — 2026-10-16
|
|
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.43",
|
|
4
4
|
"description": "All-in-one extension suite for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -70,7 +70,9 @@
|
|
|
70
70
|
"packages/notify/skills",
|
|
71
71
|
"packages/kanboard/skills",
|
|
72
72
|
"packages/updater/skills",
|
|
73
|
-
"packages/subagents/skills"
|
|
73
|
+
"packages/subagents/skills",
|
|
74
|
+
"packages/web-api/skills",
|
|
75
|
+
"packages/dream/skills"
|
|
74
76
|
]
|
|
75
77
|
},
|
|
76
78
|
"peerDependencies": {
|
|
@@ -80,28 +82,28 @@
|
|
|
80
82
|
"typebox": "^1.1.38"
|
|
81
83
|
},
|
|
82
84
|
"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.
|
|
85
|
+
"@pi-unipi/app-bridge": "3.0.0-alpha.43",
|
|
86
|
+
"@pi-unipi/ask-user": "3.0.0-alpha.43",
|
|
87
|
+
"@pi-unipi/background-tasks": "3.0.0-alpha.43",
|
|
88
|
+
"@pi-unipi/btw": "3.0.0-alpha.43",
|
|
89
|
+
"@pi-unipi/command-enchantment": "3.0.0-alpha.43",
|
|
90
|
+
"@pi-unipi/compactor": "3.0.0-alpha.43",
|
|
91
|
+
"@pi-unipi/core": "3.0.0-alpha.43",
|
|
92
|
+
"@pi-unipi/dream": "3.0.0-alpha.43",
|
|
93
|
+
"@pi-unipi/footer": "3.0.0-alpha.43",
|
|
94
|
+
"@pi-unipi/fusion": "3.0.0-alpha.43",
|
|
95
|
+
"@pi-unipi/info-screen": "3.0.0-alpha.43",
|
|
96
|
+
"@pi-unipi/input-shortcuts": "3.0.0-alpha.43",
|
|
97
|
+
"@pi-unipi/kanboard": "3.0.0-alpha.43",
|
|
98
|
+
"@pi-unipi/mcp": "3.0.0-alpha.43",
|
|
99
|
+
"@pi-unipi/memory": "3.0.0-alpha.43",
|
|
100
|
+
"@pi-unipi/notify": "3.0.0-alpha.43",
|
|
101
|
+
"@pi-unipi/skill-registry": "3.0.0-alpha.43",
|
|
102
|
+
"@pi-unipi/subagents": "3.0.0-alpha.43",
|
|
103
|
+
"@pi-unipi/updater": "3.0.0-alpha.43",
|
|
104
|
+
"@pi-unipi/utility": "3.0.0-alpha.43",
|
|
105
|
+
"@pi-unipi/web-api": "3.0.0-alpha.43",
|
|
106
|
+
"@pi-unipi/workflow": "3.0.0-alpha.43",
|
|
105
107
|
"@resvg/resvg-wasm": "^2.6.2",
|
|
106
108
|
"beautiful-mermaid": "^1.1.3"
|
|
107
109
|
},
|
|
@@ -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.43",
|
|
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.43"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -658,6 +658,23 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
|
|
|
658
658
|
}
|
|
659
659
|
};
|
|
660
660
|
|
|
661
|
+
// The model list changes after `hello`: providers that register late
|
|
662
|
+
// (pi-omniroute-bridge refreshes its provider in session_start, after this
|
|
663
|
+
// bridge's hello) or a /model in the TUI that loads more. A phone that
|
|
664
|
+
// connected early kept the first, partial list (only openrouter) until
|
|
665
|
+
// something forced a new hello. Push a `models` line whenever the list
|
|
666
|
+
// differs from the last one sent, and check a few times after start.
|
|
667
|
+
let lastModelsKey = "";
|
|
668
|
+
const modelsKey = (list: ModelInfo[]) => list.map((m) => `${m.provider}/${m.id}`).join("\n");
|
|
669
|
+
const pushModelsIfChanged = () => {
|
|
670
|
+
if (!ctx || clients.size === 0) return;
|
|
671
|
+
const list = models();
|
|
672
|
+
const key = modelsKey(list);
|
|
673
|
+
if (key === lastModelsKey) return;
|
|
674
|
+
lastModelsKey = key;
|
|
675
|
+
send({ t: "models", models: list } as OutMsg);
|
|
676
|
+
};
|
|
677
|
+
|
|
661
678
|
// UNI-222: long-horizon progress (sticky LH_PROGRESS on the core bus).
|
|
662
679
|
const lhProgress = (): LhProgressInfo | undefined => bus.get(UNIPI_EVENTS.LH_PROGRESS) as LhProgressInfo | undefined;
|
|
663
680
|
// UNI-269: the working mode (sticky LH_STATE — the footer's "Graph Mode").
|
|
@@ -675,7 +692,11 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
|
|
|
675
692
|
streaming: streaming ? { id: streaming.id, role: "assistant" as const, content: phoneSafe(streaming.content) as unknown[] } : undefined,
|
|
676
693
|
tools: [...tools.values()].map((t) => ({ ...t, text: t.text ? clipText(t.text, 8 * 1024) : t.text })),
|
|
677
694
|
commands: commands().map((x) => ({ ...x, description: x.description ? clipText(x.description, 160) : x.description })),
|
|
678
|
-
models:
|
|
695
|
+
models: (() => {
|
|
696
|
+
const list = models();
|
|
697
|
+
lastModelsKey = modelsKey(list);
|
|
698
|
+
return list;
|
|
699
|
+
})(),
|
|
679
700
|
dialogs: hub.list(),
|
|
680
701
|
queue: queueView(),
|
|
681
702
|
fusion: fusionPreset(),
|
|
@@ -1121,12 +1142,32 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
|
|
|
1121
1142
|
if (!c) return fail("pi is gone.");
|
|
1122
1143
|
const i = tuiQueue.findIndex((q) => q.id === id);
|
|
1123
1144
|
if (i < 0) return fail("That queued message is gone.");
|
|
1124
|
-
|
|
1145
|
+
// UNI-305: pi has no API to drop ONE item from its own live steer/followUp
|
|
1146
|
+
// queue — the only way to edit it is to abort the whole run and re-send
|
|
1147
|
+
// what's left (see the class comment above `tuiQueue`). That's fine
|
|
1148
|
+
// between tool calls (there is nothing running to lose), but aborting
|
|
1149
|
+
// WHILE a tool is executing kills it mid-flight — real, unsaved work —
|
|
1150
|
+
// and if the removed item was the queue's only entry nothing is left to
|
|
1151
|
+
// re-send: the run just dies instead of continuing. So this waits a
|
|
1152
|
+
// short beat for the in-flight tool to reach its own end (the next safe
|
|
1153
|
+
// boundary) before touching the queue; a tool still running past that
|
|
1154
|
+
// is left alone and the edit is refused instead of destroying it.
|
|
1155
|
+
if (tools.size > 0) {
|
|
1156
|
+
const deadline = Date.now() + 4_000;
|
|
1157
|
+
while (tools.size > 0 && Date.now() < deadline) await sleep(100);
|
|
1158
|
+
if (tools.size > 0) return fail("That message was already handed to pi — it can't be taken back while a tool is running.");
|
|
1159
|
+
}
|
|
1160
|
+
// The wait above may have let pi drain this very item into a real turn
|
|
1161
|
+
// (the message_start handler below removes it from tuiQueue once pi
|
|
1162
|
+
// actually sends it) — re-check instead of operating on a stale index.
|
|
1163
|
+
const liveIndex = tuiQueue.findIndex((q) => q.id === id);
|
|
1164
|
+
if (liveIndex < 0) return fail("That message was already handed to pi — it can't be taken back now.");
|
|
1165
|
+
const [target] = tuiQueue.splice(liveIndex, 1);
|
|
1125
1166
|
const action = apply(target!) ?? undefined;
|
|
1126
1167
|
// Keep the edited/kept target in its original slot (promote: first).
|
|
1127
1168
|
const rest = tuiQueue.splice(0, tuiQueue.length);
|
|
1128
1169
|
if (action === "promote") rest.unshift(target!);
|
|
1129
|
-
else if (action !== "drop") rest.splice(
|
|
1170
|
+
else if (action !== "drop") rest.splice(liveIndex, 0, target!);
|
|
1130
1171
|
if (!c.isIdle()) {
|
|
1131
1172
|
await abortKeepingEditor(c);
|
|
1132
1173
|
const deadline = Date.now() + 10_000;
|
|
@@ -1507,6 +1548,21 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
|
|
|
1507
1548
|
}
|
|
1508
1549
|
return;
|
|
1509
1550
|
}
|
|
1551
|
+
case "reload": {
|
|
1552
|
+
// UNI-308: `/reload` must work from the app, not fall through to a plain
|
|
1553
|
+
// prompt. `ctx.reload()` (ExtensionCommandContext) is the same call the
|
|
1554
|
+
// terminal's built-in `/reload` makes.
|
|
1555
|
+
if (!(await ensureIdle(msg.force))) return write(sock, { t: "error", message: "pi is busy. Stop the current run first.", code: "busy", ref: msg.ref });
|
|
1556
|
+
try {
|
|
1557
|
+
await runCommandOp(async (cctx) => {
|
|
1558
|
+
await cctx.reload();
|
|
1559
|
+
});
|
|
1560
|
+
ack();
|
|
1561
|
+
} catch (error) {
|
|
1562
|
+
fail(error instanceof Error ? error.message : String(error));
|
|
1563
|
+
}
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1510
1566
|
case "tree_go": {
|
|
1511
1567
|
if (!(await ensureIdle(msg.force))) return write(sock, { t: "error", message: "pi is busy. Stop the current run first.", code: "busy", ref: msg.ref });
|
|
1512
1568
|
try {
|
|
@@ -1822,6 +1878,8 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
|
|
|
1822
1878
|
setRemoteDialogs(hub);
|
|
1823
1879
|
listen();
|
|
1824
1880
|
writeRecord();
|
|
1881
|
+
// Late providers (registered after this hello): re-check the model list.
|
|
1882
|
+
for (const ms of [1500, 5000, 15000]) setTimeout(() => safe(pushModelsIfChanged)(), ms).unref?.();
|
|
1825
1883
|
if (event?.reason && event.reason !== "startup") {
|
|
1826
1884
|
streaming = undefined;
|
|
1827
1885
|
tools.clear();
|
|
@@ -1988,6 +2046,7 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
|
|
|
1988
2046
|
});
|
|
1989
2047
|
|
|
1990
2048
|
on("agent_start", safe(() => {
|
|
2049
|
+
pushModelsIfChanged();
|
|
1991
2050
|
// A fresh run after a phone Stop: the queue delivers after THIS one.
|
|
1992
2051
|
releaseHold();
|
|
1993
2052
|
running = true;
|
|
@@ -2155,7 +2214,10 @@ export function createBridge(pi: ExtensionAPI, deps: BridgeDeps = defaultDeps) {
|
|
|
2155
2214
|
|
|
2156
2215
|
// The preset's `active` changes with the model (Fusion leaves fusion mode
|
|
2157
2216
|
// on a /model switch), so it rides along (UNI-212).
|
|
2158
|
-
on("model_select", safe(() =>
|
|
2217
|
+
on("model_select", safe(() => {
|
|
2218
|
+
stateWithFusion();
|
|
2219
|
+
pushModelsIfChanged();
|
|
2220
|
+
}));
|
|
2159
2221
|
on("thinking_level_select", safe(() => send({ t: "state", ...runState() })));
|
|
2160
2222
|
on("session_compact", safe(() => {
|
|
2161
2223
|
if (!ctx) return;
|
|
@@ -251,6 +251,8 @@ export type OutMsg =
|
|
|
251
251
|
dream?: DreamStatusInfo;
|
|
252
252
|
}
|
|
253
253
|
| ({ t: "state" } & Partial<RunState>)
|
|
254
|
+
/** The model list changed after `hello` (a late provider, a /model in the TUI). */
|
|
255
|
+
| { t: "models"; models: ModelInfo[] }
|
|
254
256
|
| ({ t: "session"; reason: string } & SessionInfo)
|
|
255
257
|
| { t: "entry"; entry: unknown }
|
|
256
258
|
| { t: "msg_start"; id: string; role: string }
|
|
@@ -413,6 +415,10 @@ export type InMsg =
|
|
|
413
415
|
| { t: "tree"; ref?: string }
|
|
414
416
|
/** Navigate to a different point in the tree. `force`: abort the current run first. */
|
|
415
417
|
| { t: "tree_go"; id: string; summarize?: boolean; force?: boolean; ref?: string }
|
|
418
|
+
/** UNI-308: `/reload` sent from the app — re-reads extensions, skills, prompts, context files
|
|
419
|
+
* via `ctx.reload()` (the same thing the terminal's `/reload` built-in does). `force`: abort
|
|
420
|
+
* the current run first, like the other session ops. */
|
|
421
|
+
| { t: "reload"; force?: boolean; ref?: string }
|
|
416
422
|
/** Fetches the full bytes behind an image `mediaRef` the bridge sent in a
|
|
417
423
|
* `media`-omitted placeholder (see `phoneSafe`): replies with one or more
|
|
418
424
|
* `media_chunk` (≤ 700 KB of base64 per chunk) ending in `done:true`, or a
|
|
@@ -501,6 +507,7 @@ const IN_TYPES = new Set([
|
|
|
501
507
|
"session_fork",
|
|
502
508
|
"tree",
|
|
503
509
|
"tree_go",
|
|
510
|
+
"reload",
|
|
504
511
|
"session_rename",
|
|
505
512
|
"media",
|
|
506
513
|
"file_share",
|
|
@@ -594,6 +601,8 @@ export function parseIn(line: string): InMsg | { bad: string; ref?: string } | u
|
|
|
594
601
|
case "tree_go":
|
|
595
602
|
if (typeof m.id !== "string" || !m.id) return { bad: "tree_go.id must be a string", ref };
|
|
596
603
|
return { t: "tree_go", id: m.id, summarize: m.summarize === true, force: m.force === true, ref };
|
|
604
|
+
case "reload":
|
|
605
|
+
return { t: "reload", force: m.force === true, ref };
|
|
597
606
|
case "session_rename":
|
|
598
607
|
if (typeof m.name !== "string") return { bad: "session_rename.name must be a string", ref };
|
|
599
608
|
return { t: "session_rename", name: m.name.slice(0, 200), ref };
|
|
@@ -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.43",
|
|
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.
|
|
45
|
+
"@pi-unipi/core": "3.0.0-alpha.43"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -77,6 +77,7 @@ export const COMMAND_REGISTRY: Record<string, string> = {
|
|
|
77
77
|
"unipi:dream": "utility",
|
|
78
78
|
"unipi:answer": "utility",
|
|
79
79
|
"unipi:summarize": "utility",
|
|
80
|
+
"unipi:cron": "utility",
|
|
80
81
|
"unipi:move": "utility",
|
|
81
82
|
|
|
82
83
|
// skill-registry
|
|
@@ -165,6 +166,7 @@ export const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
|
165
166
|
"unipi:doctor": "Check UniPi's runtime: config, model cache, Decision Model, skills",
|
|
166
167
|
"unipi:answer": "Answer the last reply — fixed input under the scrollable reply, per question, or web form",
|
|
167
168
|
"unipi:summarize": "Summarize your last reply again (answer first, then findings, open items, questions). Add text to ask about it",
|
|
169
|
+
"unipi:cron": "Scheduled pi runs on this PC — jobs, next runs, results; run, stop, enable, pause",
|
|
168
170
|
"unipi:skills": "Manage skills — on/off per project, listed or not, the skill vault",
|
|
169
171
|
"unipi:move": "Re-link sessions, trust, worktrees, boards and memories after moving this project",
|
|
170
172
|
|
|
@@ -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.43",
|
|
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.43",
|
|
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.43",
|
|
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.43"
|
|
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.43",
|
|
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.43",
|
|
37
|
+
"@pi-unipi/info-screen": "3.0.0-alpha.43",
|
|
38
38
|
"@earendil-works/pi-agent-core": "^0.87.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* failures never block the command itself.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import type
|
|
15
|
+
import { ExtensionRunner, type ExtensionAPI, type ExtensionCommandContext, type RegisteredCommand } from "@earendil-works/pi-coding-agent";
|
|
16
16
|
import { Text } from "@earendil-works/pi-tui";
|
|
17
17
|
|
|
18
18
|
export const COMMAND_ECHO_TYPE = "unipi-command-echo";
|
|
@@ -96,6 +96,48 @@ export function commandArgCompleters(): Map<string, ArgCompleter> {
|
|
|
96
96
|
return (g[COMPLETERS_KEY] ??= new Map<string, ArgCompleter>());
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/**
|
|
100
|
+
* UNI-304: `commandArgCompleters()` used to only ever hold the commands
|
|
101
|
+
* this module's own `withCommandEcho` wrapper saw (UniPi's commands). Other
|
|
102
|
+
* extensions' commands — pi-omniroute-bridge's `/usage`, a future `/skill:*`
|
|
103
|
+
* completer, anything not registered through `withCommandEcho` — never got
|
|
104
|
+
* an entry, so the app (which can only ask the bridge, never pi's live
|
|
105
|
+
* in-memory command registry) got nothing for them.
|
|
106
|
+
*
|
|
107
|
+
* `ExtensionRunner.resolveRegisteredCommands()` is where pi itself resolves
|
|
108
|
+
* every extension's registered command (with its real `getArgumentCompletions`,
|
|
109
|
+
* see `RegisteredCommand`) into the de-duplicated list the TUI's own
|
|
110
|
+
* autocomplete reads (`interactive-mode.js` calls `getRegisteredCommands()`,
|
|
111
|
+
* which calls this). It runs on every keystroke in a command's argument area,
|
|
112
|
+
* so it is already a safe, repeatedly-called hook. Patching it here — once,
|
|
113
|
+
* idempotently, on the shared class — is the least invasive way to see every
|
|
114
|
+
* extension's completer: no extension author needs to go through
|
|
115
|
+
* `withCommandEcho`, and pi needs no API change. UniPi's `unipi/index.ts`
|
|
116
|
+
* calls `withCommandEcho` (which calls this) before any other module loads,
|
|
117
|
+
* so the patch is in place before any extension — ours or a third party's —
|
|
118
|
+
* registers a single command.
|
|
119
|
+
*/
|
|
120
|
+
let runnerPatched = false;
|
|
121
|
+
export function patchExtensionRunnerCommandCompleters(): void {
|
|
122
|
+
if (runnerPatched) return;
|
|
123
|
+
runnerPatched = true;
|
|
124
|
+
const proto = ExtensionRunner.prototype as unknown as {
|
|
125
|
+
resolveRegisteredCommands: () => Array<{ invocationName: string; name: string; getArgumentCompletions?: ArgCompleter }>;
|
|
126
|
+
};
|
|
127
|
+
const original = proto.resolveRegisteredCommands;
|
|
128
|
+
if (typeof original !== "function") return; // Unknown/future pi build: no-op rather than throw.
|
|
129
|
+
proto.resolveRegisteredCommands = function (this: unknown, ...args: unknown[]) {
|
|
130
|
+
const resolved = original.apply(this, args as []);
|
|
131
|
+
const map = commandArgCompleters();
|
|
132
|
+
for (const command of resolved) {
|
|
133
|
+
if (typeof command.getArgumentCompletions === "function") {
|
|
134
|
+
map.set(command.invocationName, command.getArgumentCompletions.bind(command));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return resolved;
|
|
138
|
+
} as typeof original;
|
|
139
|
+
}
|
|
140
|
+
|
|
99
141
|
/** Never echo `/name` (internal, programmatic commands). Call before or after registering. */
|
|
100
142
|
export function silenceCommandEcho(name: string): void {
|
|
101
143
|
silentSet().add(name.replace(/^\//, ""));
|
|
@@ -114,6 +156,10 @@ export function isSilentEcho(text: unknown): boolean {
|
|
|
114
156
|
}
|
|
115
157
|
|
|
116
158
|
export function withCommandEcho(pi: ExtensionAPI): ExtensionAPI {
|
|
159
|
+
// UNI-304: patch once, before any command is registered, so every
|
|
160
|
+
// extension's own completer (not just ones that happen to go through this
|
|
161
|
+
// wrapper) ends up in commandArgCompleters().
|
|
162
|
+
patchExtensionRunnerCommandCompleters();
|
|
117
163
|
try {
|
|
118
164
|
pi.registerEntryRenderer<{ text?: string }>(
|
|
119
165
|
COMMAND_ECHO_TYPE,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/dream",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.43",
|
|
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.43"
|
|
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.
|
|
3
|
+
"version": "3.0.0-alpha.43",
|
|
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.43",
|
|
36
|
+
"@pi-unipi/background-tasks": "3.0.0-alpha.43"
|
|
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.43",
|
|
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.43",
|
|
36
|
+
"@pi-unipi/subagents": "3.0.0-alpha.43",
|
|
37
|
+
"@pi-unipi/utility": "3.0.0-alpha.43"
|
|
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.43",
|
|
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.43"
|
|
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.43",
|
|
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.43"
|
|
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.43",
|
|
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.43"
|
|
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.43",
|
|
52
|
+
"@pi-unipi/kanboard-linux-arm64": "3.0.0-alpha.43",
|
|
53
|
+
"@pi-unipi/kanboard-darwin-x64": "3.0.0-alpha.43",
|
|
54
|
+
"@pi-unipi/kanboard-darwin-arm64": "3.0.0-alpha.43",
|
|
55
|
+
"@pi-unipi/kanboard-win32-x64": "3.0.0-alpha.43"
|
|
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.43",
|
|
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.43",
|
|
41
41
|
"@resvg/resvg-wasm": "^2.6.2",
|
|
42
42
|
"beautiful-mermaid": "^1.1.3"
|
|
43
43
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/mcp",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.43",
|
|
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.43"
|
|
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.43",
|
|
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.
|
|
48
|
-
"@pi-unipi/info-screen": "3.0.0-alpha.
|
|
47
|
+
"@pi-unipi/core": "3.0.0-alpha.43",
|
|
48
|
+
"@pi-unipi/info-screen": "3.0.0-alpha.43",
|
|
49
49
|
"js-yaml": "^4.1.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|