pi-cc-extensions 0.8.41 → 0.8.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/README.en.md +11 -4
- package/README.md +11 -4
- package/extensions/claude-code-style.ts +39 -49
- package/extensions/compact-thinking.ts +14 -2
- package/extensions/fixed-editor.ts +20 -0
- package/extensions/fullscreen-detect.ts +38 -0
- package/package.json +4 -4
package/README.en.md
CHANGED
|
@@ -22,11 +22,9 @@
|
|
|
22
22
|
## Preview
|
|
23
23
|
|
|
24
24
|
<table>
|
|
25
|
-
<img
|
|
25
|
+
<img width="2788" height="1846" alt="demo_new" src="https://github.com/user-attachments/assets/d4f9bb51-a49a-4a34-aa60-006514d37b09" />
|
|
26
26
|
</table>
|
|
27
27
|
|
|
28
|
-
https://github.com/user-attachments/assets/4ae094d2-7480-484b-a0c8-6e782495ce9f
|
|
29
|
-
|
|
30
28
|
## Quick start
|
|
31
29
|
|
|
32
30
|
```bash
|
|
@@ -113,9 +111,18 @@ Run `/reload` after changing extensions.
|
|
|
113
111
|
## Compatibility
|
|
114
112
|
|
|
115
113
|
- Node.js `>=22.19.0`
|
|
116
|
-
-
|
|
114
|
+
- Pi `^0.84.0` (loaded through `pi.extensions` and `pi.themes` in the root `package.json`)
|
|
115
|
+
- For Pi 0.80.x and earlier, use an older release of this package (peerDependencies are now `^0.84.0`)
|
|
117
116
|
- If a Pi, TUI, or `@tifan/pi-fixed-editor` update causes display issues, try `/reload` first
|
|
118
117
|
|
|
118
|
+
### Fullscreen mode & sunset features
|
|
119
|
+
|
|
120
|
+
- Official `--tui-mode fullscreen` (and runtime switching via `/settings`) is reused as-is: when `tui.mode === "fullscreen"`, the extension stands down and installs no rendering layer (tool styling, compact mode, tool grouping, and the fixed editor are all skipped), leaving fullscreen entirely to the official TUI. Data features (context, session references, autocomplete, etc.) are unaffected.
|
|
121
|
+
- Capabilities that overlap with the official fullscreen TUI are sunset (frozen, kept working only): fixed-editor layout, independently scrollable transcript, etc. — no second implementation.
|
|
122
|
+
- Known boundary: when switching from regular to fullscreen at runtime, per-TUI rendering patches are automatically abandoned with the old TUI instance, but component-level style patches remain active (they do not affect the official layout); for full isolation, start the session in fullscreen mode.
|
|
123
|
+
- Pi 0.84+ wraps the TUI reference in a lazy Proxy (`createInteractiveTuiReference`): capturing `doRender`/`render`/`handleInput` through it resolves to the wrapper itself and recurses infinitely. The extension detects the lazy Proxy and skips line-level rendering patches; `@tifan/pi-fixed-editor`'s compositor is likewise disabled on 0.84+ (Fixed editor interactions are temporarily unavailable; rendering is handled by the official pipeline).
|
|
124
|
+
- The `compact-thinking.json` config file is sunset (no longer read or maintained); compact-thinking settings are managed exclusively by `claude-code-style.json`.
|
|
125
|
+
|
|
119
126
|
## Recommended companions
|
|
120
127
|
|
|
121
128
|
|
package/README.md
CHANGED
|
@@ -22,11 +22,9 @@
|
|
|
22
22
|
## 界面预览
|
|
23
23
|
|
|
24
24
|
<table>
|
|
25
|
-
|
|
25
|
+
<img width="2788" height="1846" alt="demo_new" src="https://github.com/user-attachments/assets/d4f9bb51-a49a-4a34-aa60-006514d37b09" />
|
|
26
26
|
</table>
|
|
27
27
|
|
|
28
|
-
https://github.com/user-attachments/assets/4ae094d2-7480-484b-a0c8-6e782495ce9f
|
|
29
|
-
|
|
30
28
|
## 快速开始
|
|
31
29
|
|
|
32
30
|
```bash
|
|
@@ -61,9 +59,18 @@ pi -e .
|
|
|
61
59
|
## 兼容性
|
|
62
60
|
|
|
63
61
|
- Node.js `>=22.19.0`
|
|
64
|
-
-
|
|
62
|
+
- Pi `^0.84.0`(通过根目录 `package.json` 的 `pi.extensions` 和 `pi.themes` 加载)
|
|
63
|
+
- 0.80.x 及更早版本请使用本包的旧版本(peerDependencies 已收紧为 `^0.84.0`)
|
|
65
64
|
- `@tifan/pi-fixed-editor`、Pi 或 TUI 内部实现升级后若显示异常,先执行 `/reload`
|
|
66
65
|
|
|
66
|
+
### Fullscreen 模式与日落功能
|
|
67
|
+
|
|
68
|
+
- 官方 `--tui-mode fullscreen`(及 `/settings` 运行时切换)复用官方布局:插件在 `tui.mode === "fullscreen"` 时自动让位,不安装任何渲染层(工具样式、紧凑模式、工具分组、固定编辑器均跳过),fullscreen 完全由官方 TUI 提供。数据类功能(context、session 引用、自动补全等)不受影响。
|
|
69
|
+
- 与官方 fullscreen 重叠的能力已日落(冻结开发、仅维持可用):固定编辑器布局、独立滚动 transcript 等不再二次实现。
|
|
70
|
+
- 已知边界:运行时从 regular 切换到 fullscreen 时,插件行级渲染 patch 随旧 TUI 实例自动失效,但组件级样式 patch 仍生效(不影响官方布局);如需完全隔离,建议以 fullscreen 模式启动会话。
|
|
71
|
+
- Pi 0.84+ 的 TUI 引用是惰性 Proxy(`createInteractiveTuiReference`),通过它捕获 `doRender`/`render`/`handleInput` 会解析到包装自身形成无限递归。插件检测到惰性 Proxy 后跳过行级渲染 patch;`@tifan/pi-fixed-editor` 的 compositor 因同样原因在 0.84+ 下停用(Fixed editor 交互功能暂时不可用,渲染由官方管线接管)。
|
|
72
|
+
- `compact-thinking.json` 配置文件已日落(不再读取、不再兼容),compact-thinking 的配置统一由 `claude-code-style.json` 管控。
|
|
73
|
+
|
|
67
74
|
## 推荐搭配
|
|
68
75
|
|
|
69
76
|
| 扩展 | 用途 |
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { getSettingsListTheme, ToolExecutionComponent } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { isFullscreenUi, isLazyProxyTui } from "./fullscreen-detect.ts";
|
|
3
4
|
import {
|
|
4
5
|
installCompactStyle,
|
|
5
6
|
type CompactStyleHooks,
|
|
@@ -227,7 +228,6 @@ function formatExcludeRenderers(names: readonly string[]): string {
|
|
|
227
228
|
export function formatConfigStatus(source: Config = config): string {
|
|
228
229
|
return [
|
|
229
230
|
`mode=${source.mode}`,
|
|
230
|
-
`fixedEditor=${source.fixedEditorFeatures ? "on" : "off"}`,
|
|
231
231
|
`exclude=[${source.excludeRenderers.join(", ") || "none"}]`,
|
|
232
232
|
`diffView=${source.diffViewMode}`,
|
|
233
233
|
`diffIndicator=${source.diffIndicatorMode}`,
|
|
@@ -1515,6 +1515,8 @@ function renderScrollButton(width: number, theme: any): string[] {
|
|
|
1515
1515
|
*/
|
|
1516
1516
|
function patchToolMouseInputCapture(tui: any): void {
|
|
1517
1517
|
if (toolMouseInputPatchTui === tui) return;
|
|
1518
|
+
// 0.84+ 惰性 Proxy:捕获 handleInput 会解析到 wrapper 自身(无限递归),跳过。
|
|
1519
|
+
if (isLazyProxyTui(tui)) return;
|
|
1518
1520
|
|
|
1519
1521
|
restoreToolMouseInputCapture();
|
|
1520
1522
|
const originalHandle = tui?.handleInput;
|
|
@@ -1722,6 +1724,8 @@ function patchToolMouseMotionAfterRender(tui: any): void {
|
|
|
1722
1724
|
) {
|
|
1723
1725
|
return;
|
|
1724
1726
|
}
|
|
1727
|
+
// 0.84+ 惰性 Proxy:捕获 doRender 会解析到 wrapper 自身(无限递归),跳过。
|
|
1728
|
+
if (isLazyProxyTui(tui)) return;
|
|
1725
1729
|
restoreToolMouseRenderPatch();
|
|
1726
1730
|
const original = tui?.doRender;
|
|
1727
1731
|
const terminal = tui?.terminal;
|
|
@@ -1947,8 +1951,16 @@ export function installToolMouseInteraction(
|
|
|
1947
1951
|
|
|
1948
1952
|
toolMouseUi = ctx.ui;
|
|
1949
1953
|
toolMouseFixedFeaturesEnabled = fixedEditorFeatures;
|
|
1954
|
+
// 0.84+ 的 tui 是惰性 Proxy:行级 patch(doRender/handleInput)无法安全捕获,
|
|
1955
|
+
// fixed-editor compositor 亦停用 —— 整个工具鼠标交互体系(hover/点击/滚动按钮)
|
|
1956
|
+
// 让位给官方,连 onTerminalInput 监听都不注册。
|
|
1957
|
+
let proxyTui = false;
|
|
1950
1958
|
ctx.ui.setWidget(TOOL_MOUSE_WIDGET_KEY, (tui: any, theme: any) => {
|
|
1951
1959
|
toolMouseTui = tui;
|
|
1960
|
+
if (isLazyProxyTui(tui)) {
|
|
1961
|
+
proxyTui = true;
|
|
1962
|
+
return { render: () => 0, invalidate() {} };
|
|
1963
|
+
}
|
|
1952
1964
|
// Root input capture follows the live compositor; onRebuild re-applies it
|
|
1953
1965
|
// once the fixed-editor compositor actually owns the terminal.
|
|
1954
1966
|
if (useFixedEditorFeatures(tui)) patchToolMouseInputCapture(tui);
|
|
@@ -1967,6 +1979,10 @@ export function installToolMouseInteraction(
|
|
|
1967
1979
|
scrollButtonWidget = widget;
|
|
1968
1980
|
return widget;
|
|
1969
1981
|
});
|
|
1982
|
+
if (proxyTui) {
|
|
1983
|
+
teardownToolMouseInteraction(fixedEditorFeatures);
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1970
1986
|
toolMouseInputUnsubscribe = ctx.ui.onTerminalInput(handleToolMouseInput);
|
|
1971
1987
|
}
|
|
1972
1988
|
|
|
@@ -2040,18 +2056,12 @@ function applyStyleMode(
|
|
|
2040
2056
|
|
|
2041
2057
|
function modeSettingDescription(mode: CompactStyleMode): string {
|
|
2042
2058
|
if (mode === "compact") {
|
|
2043
|
-
return "Compact transcript summaries.
|
|
2059
|
+
return "Compact transcript summaries. Diff options below still apply independently.";
|
|
2044
2060
|
}
|
|
2045
2061
|
if (mode === "off") {
|
|
2046
|
-
return "Pi native tool rendering.
|
|
2062
|
+
return "Pi native tool rendering. Diff options below still apply independently.";
|
|
2047
2063
|
}
|
|
2048
|
-
return "Claude Code style with rich edit/write diffs. Tune
|
|
2049
|
-
}
|
|
2050
|
-
|
|
2051
|
-
function fixedEditorSettingDescription(enabled: boolean): string {
|
|
2052
|
-
return enabled
|
|
2053
|
-
? "Pinned editor via @tifan/pi-fixed-editor. Mouse capture, 5-row wheel, tool clicks, back-to-bottom button, message count, and Ctrl+End."
|
|
2054
|
-
: "Native scrolling editor; mouse hover/click and wheel reporting off. Ctrl+End remains enabled.";
|
|
2064
|
+
return "Claude Code style with rich edit/write diffs. Tune diff options below.";
|
|
2055
2065
|
}
|
|
2056
2066
|
|
|
2057
2067
|
function excludeRenderersDescription(names: readonly string[]): string {
|
|
@@ -2162,7 +2172,6 @@ function renderSectionTabBar(
|
|
|
2162
2172
|
async function showCcstylePanel(
|
|
2163
2173
|
ctx: any,
|
|
2164
2174
|
compactStyle: CompactStyleHooks,
|
|
2165
|
-
fixedEditorController: FixedEditorController,
|
|
2166
2175
|
toolGrouping?: ToolGroupingHooks,
|
|
2167
2176
|
compactThinking?: CompactThinkingController,
|
|
2168
2177
|
): Promise<void> {
|
|
@@ -2179,13 +2188,6 @@ async function showCcstylePanel(
|
|
|
2179
2188
|
currentValue: config.mode,
|
|
2180
2189
|
values: ["on", "off", "compact"],
|
|
2181
2190
|
};
|
|
2182
|
-
const fixedEditorSetting = {
|
|
2183
|
-
id: "fixedEditorFeatures",
|
|
2184
|
-
label: "Fixed editor",
|
|
2185
|
-
description: fixedEditorSettingDescription(config.fixedEditorFeatures),
|
|
2186
|
-
currentValue: config.fixedEditorFeatures ? "on" : "off",
|
|
2187
|
-
values: ["on", "off"],
|
|
2188
|
-
};
|
|
2189
2191
|
// Tracks whether the Exclude-tools submenu is open so Tab switches sections
|
|
2190
2192
|
// only at the top level (mirrors Zentui settings: Tab = switch sections).
|
|
2191
2193
|
let excludeSubmenuOpen = false;
|
|
@@ -2287,17 +2289,6 @@ async function showCcstylePanel(
|
|
|
2287
2289
|
modeSetting.description = modeSettingDescription(value as CompactStyleMode);
|
|
2288
2290
|
applyStyleMode(value as CompactStyleMode, ctx, compactStyle, toolGrouping);
|
|
2289
2291
|
return;
|
|
2290
|
-
case "fixedEditorFeatures":
|
|
2291
|
-
config.fixedEditorFeatures = value === "on";
|
|
2292
|
-
fixedEditorSetting.description = fixedEditorSettingDescription(
|
|
2293
|
-
config.fixedEditorFeatures,
|
|
2294
|
-
);
|
|
2295
|
-
saveConfig();
|
|
2296
|
-
fixedEditorController.setEnabled(config.fixedEditorFeatures);
|
|
2297
|
-
installToolMouseInteraction(ctx);
|
|
2298
|
-
refreshCurrentTranscript(compactStyle, ctx);
|
|
2299
|
-
ctx.ui.notify(`Fixed editor: ${value}`, "info");
|
|
2300
|
-
return;
|
|
2301
2292
|
case "excludeRenderers":
|
|
2302
2293
|
excludeSetting.currentValue = formatExcludeRenderers(config.excludeRenderers);
|
|
2303
2294
|
excludeSetting.description = excludeRenderersDescription(config.excludeRenderers);
|
|
@@ -2367,11 +2358,6 @@ async function showCcstylePanel(
|
|
|
2367
2358
|
label: "Style",
|
|
2368
2359
|
items: [modeSetting, excludeSetting],
|
|
2369
2360
|
},
|
|
2370
|
-
{
|
|
2371
|
-
id: "editor",
|
|
2372
|
-
label: "Editor",
|
|
2373
|
-
items: [fixedEditorSetting],
|
|
2374
|
-
},
|
|
2375
2361
|
{
|
|
2376
2362
|
id: "diff",
|
|
2377
2363
|
label: "Diff",
|
|
@@ -3189,6 +3175,8 @@ export default function (
|
|
|
3189
3175
|
| undefined;
|
|
3190
3176
|
const ensureTuiInstallation = (ctx: any) => {
|
|
3191
3177
|
if (ctx?.mode !== "tui" || !ctx?.hasUI) return undefined;
|
|
3178
|
+
// fullscreen 复用官方布局,插件渲染层(工具样式/紧凑模式/分组)让位
|
|
3179
|
+
if (isFullscreenUi(ctx)) return undefined;
|
|
3192
3180
|
if (installation) return installation;
|
|
3193
3181
|
const globalToolRendering = installGlobalToolRendering(writeExecutionMetadata);
|
|
3194
3182
|
const toolGrouping = installToolGrouping(() => config.mode === "on");
|
|
@@ -3215,23 +3203,25 @@ export default function (
|
|
|
3215
3203
|
},
|
|
3216
3204
|
handler: async (args, ctx) => {
|
|
3217
3205
|
const arg = args.trim().toLowerCase();
|
|
3218
|
-
if (!arg || arg === "panel") {
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3206
|
+
if (!arg || arg === "panel" || arg === "on" || arg === "off" || arg === "compact") {
|
|
3207
|
+
if (ctx?.mode !== "tui" || !ctx?.hasUI) {
|
|
3208
|
+
ctx.ui?.notify?.("/ccstyle requires TUI mode", "warning");
|
|
3209
|
+
return;
|
|
3210
|
+
}
|
|
3211
|
+
if (isFullscreenUi(ctx)) {
|
|
3212
|
+
ctx.ui.notify(
|
|
3213
|
+
"ccstyle 渲染已在 fullscreen 模式下让位给官方 TUI;请切换到 regular 模式后使用 /ccstyle",
|
|
3214
|
+
"warning",
|
|
3227
3215
|
);
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
}
|
|
3231
|
-
if (arg === "on" || arg === "off" || arg === "compact") {
|
|
3216
|
+
return;
|
|
3217
|
+
}
|
|
3232
3218
|
const hooks = ensureTuiInstallation(ctx);
|
|
3233
|
-
if (hooks)
|
|
3234
|
-
|
|
3219
|
+
if (!hooks) return;
|
|
3220
|
+
if (!arg || arg === "panel") {
|
|
3221
|
+
await showCcstylePanel(ctx, hooks.compactStyle, hooks.toolGrouping, compactThinking);
|
|
3222
|
+
} else {
|
|
3223
|
+
applyStyleMode(arg, ctx, hooks.compactStyle, hooks.toolGrouping);
|
|
3224
|
+
}
|
|
3235
3225
|
return;
|
|
3236
3226
|
}
|
|
3237
3227
|
if (arg === "status") {
|
|
@@ -2,8 +2,10 @@ import * as piAi from "@earendil-works/pi-ai";
|
|
|
2
2
|
import * as piCodingAgent from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import * as piTui from "@earendil-works/pi-tui";
|
|
5
|
-
import { readFileSync } from "node:fs";
|
|
5
|
+
import { readFileSync, rmSync } from "node:fs";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
7
9
|
import { createJiti } from "jiti";
|
|
8
10
|
|
|
9
11
|
export type CompactThinkingConfig = {
|
|
@@ -186,7 +188,17 @@ export function installCompactThinking(
|
|
|
186
188
|
host[COMPACT_THINKING_OWNER]?.stop(event, ctx);
|
|
187
189
|
session = { event, ctx };
|
|
188
190
|
|
|
189
|
-
|
|
191
|
+
// compact-thinking.json 已日落:不预写、不读取,配置统一由
|
|
192
|
+
// claude-code-style.json 管控(下方 Object.assign 覆盖库默认值)。
|
|
193
|
+
// 库首次加载会在 .pi/agent 下自建默认文件,加载完成后立即删除,不留残留。
|
|
194
|
+
const agentDir = process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent");
|
|
195
|
+
const configPath = join(agentDir, "compact-thinking.json");
|
|
196
|
+
let loaded: ReturnType<typeof loadPatchedUpstream>;
|
|
197
|
+
try {
|
|
198
|
+
loaded = loadPatchedUpstream();
|
|
199
|
+
} finally {
|
|
200
|
+
rmSync(configPath, { force: true });
|
|
201
|
+
}
|
|
190
202
|
upstreamConfig = loaded.config;
|
|
191
203
|
Object.assign(upstreamConfig, initialConfig);
|
|
192
204
|
delegates.clear();
|
|
@@ -2,6 +2,7 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
|
2
2
|
import * as piCodingAgent from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import * as piTui from "@earendil-works/pi-tui";
|
|
4
4
|
import { visibleWidth } from "@earendil-works/pi-tui";
|
|
5
|
+
import { isFullscreenUi, isLazyProxyTui } from "./fullscreen-detect.ts";
|
|
5
6
|
import { createJiti } from "jiti";
|
|
6
7
|
|
|
7
8
|
type LifecycleHandler = (event: any, ctx: any) => void;
|
|
@@ -196,8 +197,25 @@ export function installFixedEditorImePatch(compositorClass: {
|
|
|
196
197
|
}
|
|
197
198
|
}
|
|
198
199
|
|
|
200
|
+
const COMPOSITOR_PROXY_GUARD = Symbol.for("pi.ccstyle.compositor-proxy-guard");
|
|
201
|
+
|
|
199
202
|
if (terminalSplit.TerminalSplitCompositor) {
|
|
200
203
|
installFixedEditorImePatch(terminalSplit.TerminalSplitCompositor);
|
|
204
|
+
// 0.84+ 的 tui 是惰性 Proxy:compositor 构造时捕获的 doRender/render 是
|
|
205
|
+
// 每次重新解析的包装,install 后执行会解析到 compositor 自身(无限递归)。
|
|
206
|
+
// 检测到惰性 Proxy 时跳过安装,渲染管线完全交给官方。
|
|
207
|
+
installProxyGuard(terminalSplit.TerminalSplitCompositor);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function installProxyGuard(compositorClass: { prototype: Record<PropertyKey, any> }): void {
|
|
211
|
+
const prototype = compositorClass.prototype;
|
|
212
|
+
const originalInstall = prototype.install;
|
|
213
|
+
if (typeof originalInstall !== "function" || prototype[COMPOSITOR_PROXY_GUARD]) return;
|
|
214
|
+
prototype[COMPOSITOR_PROXY_GUARD] = true;
|
|
215
|
+
prototype.install = function (this: any, ...args: any[]) {
|
|
216
|
+
if (isLazyProxyTui(this.tui)) return;
|
|
217
|
+
return Reflect.apply(originalInstall, this, args);
|
|
218
|
+
};
|
|
201
219
|
}
|
|
202
220
|
|
|
203
221
|
export type FixedEditorController = {
|
|
@@ -320,6 +338,8 @@ export function installFixedEditor(
|
|
|
320
338
|
}
|
|
321
339
|
function activate() {
|
|
322
340
|
if (!session || session.ctx?.mode !== "tui" || active) return;
|
|
341
|
+
// fullscreen 复用官方的 sticky editor,固定编辑器让位
|
|
342
|
+
if (isFullscreenUi(session.ctx)) return;
|
|
323
343
|
const previous = (globalThis as any)[FIXED_EDITOR_OWNER] as FixedEditorOwner | undefined;
|
|
324
344
|
if (previous?.owner !== owner) previous?.stop();
|
|
325
345
|
const currentSession = session;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// fullscreen 模式探测:官方 fullscreen TUI(TuiAltScreen)由官方独占布局,
|
|
2
|
+
// 插件渲染层应让位。检测方式是瞬时 setWidget 拿 tui 实例检查 mode。
|
|
3
|
+
const PROBE_KEY = "cc-fullscreen-probe";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 官方 0.84+ 的 tui 引用是惰性 Proxy(createInteractiveTuiReference):
|
|
7
|
+
* 函数属性每次 get 都返回新包装,执行时才解析到当前实现。
|
|
8
|
+
* 通过它捕获 doRender/render/handleInput 会解析到自身形成无限递归,
|
|
9
|
+
* 因此检测到惰性 Proxy 时必须跳过所有"捕获后包装"类 patch。
|
|
10
|
+
*/
|
|
11
|
+
export function isLazyProxyTui(tui: any): boolean {
|
|
12
|
+
if (!tui || typeof tui !== "object") return false;
|
|
13
|
+
const probe = tui.requestRender;
|
|
14
|
+
return typeof probe === "function" && probe !== tui.requestRender;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 探测当前会话的 TUI 是否运行在官方 fullscreen 模式。
|
|
19
|
+
* 无 setWidget 的环境(测试 mock)视为 regular。
|
|
20
|
+
*/
|
|
21
|
+
export function isFullscreenUi(ctx: { ui?: any }): boolean {
|
|
22
|
+
if (typeof ctx?.ui?.setWidget !== "function") return false;
|
|
23
|
+
let fullscreen = false;
|
|
24
|
+
try {
|
|
25
|
+
ctx.ui.setWidget(PROBE_KEY, (tui: any) => {
|
|
26
|
+
fullscreen = tui?.mode === "fullscreen";
|
|
27
|
+
return { render: () => 0, invalidate() {} };
|
|
28
|
+
});
|
|
29
|
+
} catch {
|
|
30
|
+
// 探测失败按 regular 处理,避免误伤
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
ctx.ui.setWidget(PROBE_KEY, undefined);
|
|
34
|
+
} catch {
|
|
35
|
+
// 忽略
|
|
36
|
+
}
|
|
37
|
+
return fullscreen;
|
|
38
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-cc-extensions",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.43",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "A Pi productivity suite with Claude Code-style UI, fixed editor, context inspection, and agent/session references",
|
|
6
6
|
"type": "module",
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
"@tifan/pi-fixed-editor"
|
|
56
56
|
],
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@earendil-works/pi-ai": "
|
|
59
|
-
"@earendil-works/pi-coding-agent": "
|
|
60
|
-
"@earendil-works/pi-tui": "
|
|
58
|
+
"@earendil-works/pi-ai": "^0.84.0",
|
|
59
|
+
"@earendil-works/pi-coding-agent": "^0.84.0",
|
|
60
|
+
"@earendil-works/pi-tui": "^0.84.0"
|
|
61
61
|
},
|
|
62
62
|
"engines": {
|
|
63
63
|
"node": ">=22.19.0"
|