@yandy0725/pi-ask-user 0.1.0 → 0.2.0
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.md +28 -2
- package/README.zh.md +28 -2
- package/index.ts +63 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,17 +97,43 @@ Effective order:
|
|
|
97
97
|
|
|
98
98
|
1. Per-call `displayMode` parameter (if provided)
|
|
99
99
|
2. `PI_ASK_USER_DISPLAY_MODE` (if set to `"overlay"` or `"inline"`)
|
|
100
|
-
3.
|
|
100
|
+
3. Project config file `.pi/ask-user.json` `displayMode` field (if exists)
|
|
101
|
+
4. User config file `~/.pi/agent/ask-user.json` `displayMode` field (if exists)
|
|
102
|
+
5. Fallback default: `"overlay"`
|
|
101
103
|
|
|
102
104
|
Unrecognised values are silently ignored and fall back to `"overlay"`.
|
|
103
105
|
|
|
106
|
+
## Personal preferences via config files
|
|
107
|
+
|
|
108
|
+
In addition to environment variables, you can use JSON config files:
|
|
109
|
+
|
|
110
|
+
**Locations:**
|
|
111
|
+
- User-level (global): `~/.pi/agent/ask-user.json`
|
|
112
|
+
- Project-level: `.pi/ask-user.json`
|
|
113
|
+
|
|
114
|
+
Fields in the project-level file override same-named fields in the user-level file. Priority: call param > env var > project config > user config > default.
|
|
115
|
+
|
|
116
|
+
**Example `~/.pi/agent/ask-user.json`:**
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"displayMode": "inline",
|
|
121
|
+
"overlayToggleKey": "alt+h",
|
|
122
|
+
"commentToggleKey": "alt+c"
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
All fields are optional. Missing files or malformed JSON are silently ignored, equivalent to no configuration.
|
|
127
|
+
|
|
104
128
|
### Shortcuts
|
|
105
129
|
|
|
106
130
|
Effective order for both `overlayToggleKey` and `commentToggleKey`:
|
|
107
131
|
|
|
108
132
|
1. Per-call parameter (if provided)
|
|
109
133
|
2. Matching env var (`PI_ASK_USER_OVERLAY_TOGGLE_KEY` / `PI_ASK_USER_COMMENT_TOGGLE_KEY`)
|
|
110
|
-
3.
|
|
134
|
+
3. Project config file `.pi/ask-user.json` (if exists)
|
|
135
|
+
4. User config file `~/.pi/agent/ask-user.json` (if exists)
|
|
136
|
+
5. Built-in defaults: `alt+o` and `ctrl+g`
|
|
111
137
|
|
|
112
138
|
Pass `"off"`, `"none"`, or `"disabled"` (at any level) to disable the shortcut entirely. Invalid specs are silently dropped and the next source is used. Specs follow the Pi-TUI [`KeyId`](https://github.com/earendil-works/pi-mono/blob/main/packages/tui/src/keys.ts) format: `[mod+]...key` where modifiers are `ctrl`, `shift`, `alt`, `super`, in any order, joined by `+` (e.g. `ctrl+g`, `alt+shift+x`, `escape`, `tab`).
|
|
113
139
|
|
package/README.zh.md
CHANGED
|
@@ -80,17 +80,43 @@ export PI_ASK_USER_COMMENT_TOGGLE_KEY=alt+c
|
|
|
80
80
|
|
|
81
81
|
1. 每次调用时的 `displayMode` 参数(如提供)
|
|
82
82
|
2. `PI_ASK_USER_DISPLAY_MODE`(如设置为 `"overlay"` 或 `"inline"`)
|
|
83
|
-
3.
|
|
83
|
+
3. 项目配置文件 `.pi/ask-user.json`(如存在)中的 `displayMode`
|
|
84
|
+
4. 用户配置文件 `~/.pi/agent/ask-user.json`(如存在)中的 `displayMode`
|
|
85
|
+
5. 回退默认值:`"overlay"`
|
|
84
86
|
|
|
85
87
|
无法识别的值会被静默忽略并回退到 `"overlay"`。
|
|
86
88
|
|
|
89
|
+
## 通过配置文件设置个人偏好
|
|
90
|
+
|
|
91
|
+
除了环境变量,也可以通过 JSON 配置文件设置:
|
|
92
|
+
|
|
93
|
+
**文件位置:**
|
|
94
|
+
- 用户级(全局):`~/.pi/agent/ask-user.json`
|
|
95
|
+
- 项目级:`.pi/ask-user.json`
|
|
96
|
+
|
|
97
|
+
项目级文件中的字段会覆盖用户级文件中同名字段。配置优先级:调用参数 > 环境变量 > 项目配置 > 用户配置 > 默认值。
|
|
98
|
+
|
|
99
|
+
**示例 `~/.pi/agent/ask-user.json`:**
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"displayMode": "inline",
|
|
104
|
+
"overlayToggleKey": "alt+h",
|
|
105
|
+
"commentToggleKey": "alt+c"
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
所有字段可选。文件不存在或 JSON 格式错误时静默忽略,等效于未配置。
|
|
110
|
+
|
|
87
111
|
### 快捷键
|
|
88
112
|
|
|
89
113
|
`overlayToggleKey` 和 `commentToggleKey` 的生效优先级:
|
|
90
114
|
|
|
91
115
|
1. 每次调用时的参数(如提供)
|
|
92
116
|
2. 对应的环境变量(`PI_ASK_USER_OVERLAY_TOGGLE_KEY` / `PI_ASK_USER_COMMENT_TOGGLE_KEY`)
|
|
93
|
-
3.
|
|
117
|
+
3. 项目配置文件 `.pi/ask-user.json`(如存在)
|
|
118
|
+
4. 用户配置文件 `~/.pi/agent/ask-user.json`(如存在)
|
|
119
|
+
5. 内置默认值:`alt+o` 和 `ctrl+g`
|
|
94
120
|
|
|
95
121
|
传入 `"off"`、`"none"` 或 `"disabled"`(任意级别)可以完全禁用快捷键。无效的键位格式会被静默丢弃,使用下一个来源。键位格式遵循 Pi-TUI 的 [`KeyId`](https://github.com/earendil-works/pi-mono/blob/main/packages/tui/src/keys.ts) 格式:`[mod+]...key`,修饰键为 `ctrl`、`shift`、`alt`、`super`,可任意顺序用 `+` 连接(如 `ctrl+g`、`alt+shift+x`、`escape`、`tab`)。
|
|
96
122
|
|
package/index.ts
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* and a custom box border instead of manual ANSI box drawing.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
9
|
import { createRequire } from "node:module";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
9
12
|
import type { ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
|
|
10
13
|
import { getMarkdownTheme } from "@earendil-works/pi-coding-agent";
|
|
11
14
|
import {
|
|
@@ -15,6 +18,7 @@ import {
|
|
|
15
18
|
Editor,
|
|
16
19
|
type EditorTheme,
|
|
17
20
|
fuzzyFilter,
|
|
21
|
+
isKeyRelease,
|
|
18
22
|
Key,
|
|
19
23
|
type Keybinding,
|
|
20
24
|
type KeybindingsManager,
|
|
@@ -317,12 +321,58 @@ function buildShortcut(spec: string): ResolvedShortcut {
|
|
|
317
321
|
};
|
|
318
322
|
}
|
|
319
323
|
|
|
324
|
+
interface AskUserConfig {
|
|
325
|
+
displayMode?: string;
|
|
326
|
+
overlayToggleKey?: string;
|
|
327
|
+
commentToggleKey?: string;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function filterConfigFields(raw: Record<string, unknown>): Partial<AskUserConfig> {
|
|
331
|
+
const str = (v: unknown): string | undefined => (typeof v === "string" ? v : undefined);
|
|
332
|
+
return {
|
|
333
|
+
displayMode: typeof raw.displayMode === "string" ? raw.displayMode : undefined,
|
|
334
|
+
overlayToggleKey: str(raw.overlayToggleKey),
|
|
335
|
+
commentToggleKey: str(raw.commentToggleKey),
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function loadAskUserConfig(cwd?: string): Partial<AskUserConfig> {
|
|
340
|
+
const homeDir = homedir();
|
|
341
|
+
const userConfigPath = join(homeDir, ".pi", "agent", "ask-user.json");
|
|
342
|
+
|
|
343
|
+
let config: Partial<AskUserConfig> = {};
|
|
344
|
+
try {
|
|
345
|
+
if (existsSync(userConfigPath)) {
|
|
346
|
+
const raw = readFileSync(userConfigPath, "utf-8");
|
|
347
|
+
config = filterConfigFields(JSON.parse(raw));
|
|
348
|
+
}
|
|
349
|
+
} catch {
|
|
350
|
+
// User config file missing or invalid — silently ignore.
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (cwd) {
|
|
354
|
+
const projectConfigPath = join(cwd, ".pi", "ask-user.json");
|
|
355
|
+
try {
|
|
356
|
+
if (existsSync(projectConfigPath)) {
|
|
357
|
+
const raw = readFileSync(projectConfigPath, "utf-8");
|
|
358
|
+
const projectConfig = filterConfigFields(JSON.parse(raw));
|
|
359
|
+
config = { ...config, ...projectConfig };
|
|
360
|
+
}
|
|
361
|
+
} catch {
|
|
362
|
+
// Project config file missing or invalid — silently ignore.
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return config;
|
|
367
|
+
}
|
|
368
|
+
|
|
320
369
|
function resolveShortcut(
|
|
321
370
|
paramValue: string | null | undefined,
|
|
322
371
|
envValue: string | undefined,
|
|
372
|
+
configValue: string | null | undefined,
|
|
323
373
|
defaultSpec: string,
|
|
324
374
|
): ResolvedShortcut {
|
|
325
|
-
const candidates: Array<string | null | undefined> = [paramValue, envValue, defaultSpec];
|
|
375
|
+
const candidates: Array<string | null | undefined> = [paramValue, envValue, configValue, defaultSpec];
|
|
326
376
|
for (const raw of candidates) {
|
|
327
377
|
const normalized = normalizeShortcutSpec(raw);
|
|
328
378
|
if (normalized === undefined) continue; // not provided, fall through
|
|
@@ -1565,19 +1615,24 @@ export default function (pi: ExtensionAPI) {
|
|
|
1565
1615
|
commentToggleKey,
|
|
1566
1616
|
timeout,
|
|
1567
1617
|
} = params as AskParams;
|
|
1618
|
+
const config = loadAskUserConfig(ctx.cwd);
|
|
1619
|
+
const configDisplayMode: AskDisplayMode | undefined =
|
|
1620
|
+
config.displayMode === "overlay" || config.displayMode === "inline" ? config.displayMode : undefined;
|
|
1568
1621
|
const envMode = process.env.PI_ASK_USER_DISPLAY_MODE;
|
|
1569
1622
|
const envDisplayMode: AskDisplayMode | undefined =
|
|
1570
1623
|
envMode === "overlay" || envMode === "inline" ? envMode : undefined;
|
|
1571
|
-
const effectiveDisplayMode: AskDisplayMode = displayMode ?? envDisplayMode ?? "overlay";
|
|
1624
|
+
const effectiveDisplayMode: AskDisplayMode = displayMode ?? envDisplayMode ?? configDisplayMode ?? "overlay";
|
|
1572
1625
|
const shortcuts: ResolvedAskShortcuts = {
|
|
1573
1626
|
overlayToggle: resolveShortcut(
|
|
1574
1627
|
overlayToggleKey,
|
|
1575
1628
|
process.env.PI_ASK_USER_OVERLAY_TOGGLE_KEY,
|
|
1629
|
+
config.overlayToggleKey,
|
|
1576
1630
|
DEFAULT_OVERLAY_TOGGLE_KEY,
|
|
1577
1631
|
),
|
|
1578
1632
|
commentToggle: resolveShortcut(
|
|
1579
1633
|
commentToggleKey,
|
|
1580
1634
|
process.env.PI_ASK_USER_COMMENT_TOGGLE_KEY,
|
|
1635
|
+
config.commentToggleKey,
|
|
1581
1636
|
DEFAULT_COMMENT_TOGGLE_KEY,
|
|
1582
1637
|
),
|
|
1583
1638
|
};
|
|
@@ -1669,6 +1724,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
1669
1724
|
if (effectiveDisplayMode === "overlay" && !overlayToggle.disabled && typeof ctx.ui.onTerminalInput === "function") {
|
|
1670
1725
|
removeOverlayInputListener = ctx.ui.onTerminalInput((data) => {
|
|
1671
1726
|
if (!overlayToggle.matches(data) || !overlayHandle) return undefined;
|
|
1727
|
+
// Ignore Kitty keyboard protocol key release events.
|
|
1728
|
+
// matchesKittySequence ignores event type, so both press (:1u)
|
|
1729
|
+
// and release (:3u) events match the same key binding. Without
|
|
1730
|
+
// this filter, releasing the toggle key chord would immediately
|
|
1731
|
+
// re-show a just-hidden overlay, causing a visible flicker.
|
|
1732
|
+
if (isKeyRelease(data)) return undefined;
|
|
1672
1733
|
const nextHidden = !overlayHandle.isHidden();
|
|
1673
1734
|
overlayHandle.setHidden(nextHidden);
|
|
1674
1735
|
if (nextHidden && !hasAnnouncedHide) {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.2.0",
|
|
7
7
|
"description": "Interactive ask_user tool for pi-coding-agent with searchable split-pane selection UI, multi-select, and freeform input",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"repository": {
|