pi-cc-extensions 0.8.72 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -48,7 +48,7 @@ Run `/reload` after installation.
48
48
 
49
49
  ## Configuration
50
50
 
51
- `/ccstyle` behavior is configured through `~/.pi/agent/claude-code-style.json`:
51
+ `/ccstyle` behavior is configured through `~/.pi/agent/pi-cc-extensions.json`:
52
52
 
53
53
  ```js
54
54
  {
package/README.md CHANGED
@@ -48,7 +48,7 @@ pi install git:github.com/minuque/pi-cc-extensions
48
48
 
49
49
  ## 配置
50
50
 
51
- `/ccstyle` 的行为由 `~/.pi/agent/claude-code-style.json` 配置:
51
+ `/ccstyle` 的行为由 `~/.pi/agent/pi-cc-extensions.json` 配置:
52
52
 
53
53
  ```js
54
54
  {
@@ -1,5 +1,5 @@
1
1
  import type { CompactThinkingConfig } from "../feature/compact-thinking.ts";
2
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { join } from "node:path";
5
5
 
@@ -68,7 +68,8 @@ export type Config = {
68
68
  };
69
69
 
70
70
  const AGENT_DIR = process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent");
71
- const CONFIG_PATH = join(AGENT_DIR, "claude-code-style.json");
71
+ export const CONFIG_PATH = join(AGENT_DIR, "pi-cc-extensions.json");
72
+ const LEGACY_CONFIG_PATH = join(AGENT_DIR, "claude-code-style.json");
72
73
 
73
74
  export const DIFF_VIEW_MODES: DiffViewMode[] = ["auto", "split", "unified"];
74
75
  export const DIFF_INDICATOR_MODES: DiffIndicatorMode[] = ["bars", "classic", "none"];
@@ -288,10 +289,21 @@ export const config: Config = loadConfig();
288
289
 
289
290
  function loadConfig(): Config {
290
291
  try {
291
- const source = existsSync(CONFIG_PATH)
292
- ? (JSON.parse(readFileSync(CONFIG_PATH, "utf8")) as Record<string, unknown>)
292
+ const fromLegacy = !existsSync(CONFIG_PATH) && existsSync(LEGACY_CONFIG_PATH);
293
+ const rawPath = existsSync(CONFIG_PATH) ? CONFIG_PATH : fromLegacy ? LEGACY_CONFIG_PATH : null;
294
+ const source = rawPath
295
+ ? (JSON.parse(readFileSync(rawPath, "utf8")) as Record<string, unknown>)
293
296
  : {};
294
- return normalizeConfig(source);
297
+ const next = normalizeConfig(source);
298
+ if (fromLegacy) {
299
+ try {
300
+ writeFileSync(CONFIG_PATH, JSON.stringify(next, null, 2));
301
+ rmSync(LEGACY_CONFIG_PATH, { force: true });
302
+ } catch {
303
+ // 新路径写失败时仍使用已读到的旧配置,旧文件保留。
304
+ }
305
+ }
306
+ return next;
295
307
  } catch {
296
308
  // Ignore bad config and fall back to defaults.
297
309
  }
@@ -7,8 +7,8 @@
7
7
  import { getSettingsListTheme } from "@earendil-works/pi-coding-agent";
8
8
  import { Input, SettingsList, matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
9
9
  import type { CompactThinkingController } from "../feature/compact-thinking.ts";
10
- import { applyCustomFooter } from "../feature/shell/footer.ts";
11
- import { applyStartupHeader } from "../feature/shell/startup-header.ts";
10
+ import { applyCustomFooter, clearCustomFooter } from "../feature/shell/footer.ts";
11
+ import { applyStartupHeader, clearStartupHeader } from "../feature/shell/startup-header.ts";
12
12
  import type { ToolGroupingHooks } from "../renderer/tool/grouping.ts";
13
13
  import {
14
14
  config,
@@ -474,9 +474,11 @@ export async function showCcstylePanel(
474
474
 
475
475
  const onSettingChange = (id: string, value: string) => {
476
476
  if (id === "enableCustomFooter") {
477
- updateConfig({ enableCustomFooter: value === "on" });
478
- customFooterToggle.apply(value === "on");
479
- applyCustomFooter(ctx);
477
+ const enabled = value === "on";
478
+ updateConfig({ enableCustomFooter: enabled });
479
+ customFooterToggle.apply(enabled);
480
+ if (enabled) applyCustomFooter(ctx);
481
+ else clearCustomFooter(ctx);
480
482
  ctx.ui.notify(`Updated ${id}: ${value}`, "info");
481
483
  return;
482
484
  }
@@ -601,14 +603,16 @@ export async function showCcstylePanel(
601
603
  ? "Thinking text uses the theme's dim color."
602
604
  : "Keep the default thinking text color.";
603
605
  break;
604
- case "showStartupHeader":
605
- updateConfig({ showStartupHeader: value === "on" });
606
+ case "showStartupHeader": {
607
+ const enabled = value === "on";
608
+ updateConfig({ showStartupHeader: enabled });
606
609
  startupHeaderSetting.description = config.showStartupHeader
607
610
  ? "Show the custom startup header (logo + tips) on new sessions."
608
611
  : "Use Pi's native startup header instead.";
609
- // 实时切换:on → 自定义 header;off → 官方默认 header。
610
- applyStartupHeader(ctx);
612
+ if (enabled) applyStartupHeader(ctx);
613
+ else clearStartupHeader(ctx);
611
614
  break;
615
+ }
612
616
  case "scrollStepLines":
613
617
  updateConfig({
614
618
  scrollStepLines: pickPositiveInt(value, DEFAULT_CONFIG.scrollStepLines, 1, 50),
@@ -14,6 +14,10 @@
14
14
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
15
15
  import { truncateToWidth } from "@earendil-works/pi-tui";
16
16
  import { execFile } from "node:child_process";
17
+ import { existsSync } from "node:fs";
18
+ import { homedir } from "node:os";
19
+ import { join } from "node:path";
20
+ import { pathToFileURL } from "node:url";
17
21
  import { config } from "../../config/config.ts";
18
22
  import { stripAnsi } from "../../utils/ansi-text.ts";
19
23
 
@@ -95,14 +99,26 @@ export function pickFooterUsageText(
95
99
 
96
100
  let piUsageMod: any | null | undefined;
97
101
 
102
+ function piUsageImportSpecs(): string[] {
103
+ const agentDir = process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent");
104
+ const dist = join(agentDir, "npm", "node_modules", "@narumitw", "pi-usage", "dist", "index.ts");
105
+ const specs: string[] = [];
106
+ if (existsSync(dist)) specs.push(pathToFileURL(dist).href);
107
+ specs.push("@narumitw/pi-usage");
108
+ return specs;
109
+ }
110
+
98
111
  async function getPiUsage(): Promise<any | null> {
99
112
  if (piUsageMod !== undefined) return piUsageMod;
100
- try {
101
- const spec = "@narumitw/pi-usage";
102
- piUsageMod = await import(spec);
103
- } catch {
104
- piUsageMod = null;
113
+ for (const spec of piUsageImportSpecs()) {
114
+ try {
115
+ piUsageMod = await import(spec);
116
+ return piUsageMod;
117
+ } catch {
118
+ // 下一候选:本机 Pi npm 目录,或包名(与本包同 node_modules 时)
119
+ }
105
120
  }
121
+ piUsageMod = null;
106
122
  return piUsageMod;
107
123
  }
108
124
 
@@ -379,16 +395,9 @@ const createCustomFooterFactory =
379
395
  };
380
396
  };
381
397
 
382
- /**
383
- * 按配置应用底栏:on → 自定义 footer;off → 恢复官方默认 footer。
384
- * 导出供 /ccstyle 面板在切换开关时实时重应用。
385
- */
398
+ /** Apply the configured custom footer without disturbing another extension's footer when disabled. */
386
399
  export function applyCustomFooter(ctx: ExtensionContext): void {
387
- if (!ctx?.hasUI || typeof ctx.ui?.setFooter !== "function") return;
388
- if (!config.enableCustomFooter) {
389
- ctx.ui.setFooter(undefined);
390
- return;
391
- }
400
+ if (!ctx?.hasUI || typeof ctx.ui?.setFooter !== "function" || !config.enableCustomFooter) return;
392
401
  try {
393
402
  ctx.ui.setFooter(createCustomFooterFactory(ctx));
394
403
  } catch (err) {
@@ -396,6 +405,12 @@ export function applyCustomFooter(ctx: ExtensionContext): void {
396
405
  }
397
406
  }
398
407
 
408
+ /** Restore Pi's native footer when the user explicitly disables this extension's active footer. */
409
+ export function clearCustomFooter(ctx: ExtensionContext): void {
410
+ if (!ctx?.hasUI || typeof ctx.ui?.setFooter !== "function") return;
411
+ ctx.ui.setFooter(undefined);
412
+ }
413
+
399
414
  export default function (pi: ExtensionAPI) {
400
415
  // 模型/思考级别变化时强制重渲染(自定义 footer 不会被内置 invalidate() 触达)
401
416
  pi.on("model_select", () => {
@@ -279,15 +279,9 @@ export function renderHeaderLines(
279
279
  );
280
280
  }
281
281
 
282
- /**
283
- * 按配置应用启动头:on → 自定义 header;off → 恢复官方默认 header。
284
- * 导出供 /ccstyle 面板在切换开关时实时重应用。
285
- */
282
+ /** 按配置安装启动头。禁用时不碰槽位,避免清掉其他扩展的 header。 */
286
283
  export function applyStartupHeader(ctx: any): void {
287
- if (!ctx?.hasUI || typeof ctx.ui?.setHeader !== "function") return;
288
- if (!config.showStartupHeader) {
289
- // 恢复官方内置 header(logo + 快捷键提示 + onboarding)。
290
- ctx.ui.setHeader(undefined);
284
+ if (!ctx?.hasUI || typeof ctx.ui?.setHeader !== "function" || !config.showStartupHeader) {
291
285
  return;
292
286
  }
293
287
  ctx.ui.setHeader((_tui: unknown, theme: any) => ({
@@ -298,6 +292,12 @@ export function applyStartupHeader(ctx: any): void {
298
292
  }));
299
293
  }
300
294
 
295
+ /** 用户从 /ccstyle 关掉本扩展启动头时,恢复官方 header。 */
296
+ export function clearStartupHeader(ctx: any): void {
297
+ if (!ctx?.hasUI || typeof ctx.ui?.setHeader !== "function") return;
298
+ ctx.ui.setHeader(undefined);
299
+ }
300
+
301
301
  export default function piStartupHeader(pi: ExtensionAPI) {
302
302
  pi.on("session_start", async (_event, ctx) => {
303
303
  applyStartupHeader(ctx);
@@ -11,11 +11,11 @@ export function toolViewportWidth(width: number): number {
11
11
  return Math.max(1, Math.floor(width * TOOL_VIEWPORT_WIDTH_RATIO));
12
12
  }
13
13
 
14
- /** 与默认工具结果相同的一级缩进包装。 */
14
+ /** 与默认工具结果相同的一级缩进包装。子组件只扣始终加上的 1 列;↳ 行多出的 2 列由 truncateToWidth 吃掉。 */
15
15
  export function insetComponent(component: any): any {
16
16
  return {
17
17
  render: (width: number) =>
18
- component.render(Math.max(1, width - 3)).map((line: string) => {
18
+ component.render(Math.max(1, width - 1)).map((line: string) => {
19
19
  const nestedMarker = line.replace(/^((?:\x1b\[[0-?]*[ -/]*[@-~])*)↳/, "$1 ↳");
20
20
  return truncateToWidth(` ${nestedMarker}`, Math.max(0, width), "");
21
21
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cc-extensions",
3
- "version": "0.8.72",
3
+ "version": "0.9.1",
4
4
  "license": "MIT",
5
5
  "description": "A Pi productivity suite with Claude Code-style UI, context inspection, and agent/session references",
6
6
  "type": "module",