@ikuma.cloud/pix-mcp 0.0.10 → 0.0.12

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 CHANGED
@@ -301,8 +301,9 @@ commands behind:
301
301
 
302
302
  In TUI mode, `/mcp-prompt` without arguments opens a native prompt selector
303
303
  that shows the focused prompt's title and description, followed by native input
304
- dialogs. Required and optional arguments are requested in declaration order;
305
- leaving an optional input empty omits it. The rendered prompt is placed in Pi's
304
+ dialogs. Each dialog shows the argument description when the server provides
305
+ one. Required and optional arguments are requested in declaration order; leaving
306
+ an optional input empty omits it. The rendered prompt is placed in Pi's
306
307
  editor so you can review or modify it before sending. Image blocks are stored in
307
308
  private temporary files and inserted as `@` references. Escape cancels without
308
309
  retrieving the prompt. The explicit `list` and `run` forms remain available in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikuma.cloud/pix-mcp",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/index.ts CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  formatResult,
26
26
  removeEditablePromptGuard,
27
27
  } from "./output.ts";
28
+ import { inputPromptArgument } from "./prompt-argument-input.ts";
28
29
  import { pickPrompt } from "./prompt-picker.ts";
29
30
  import { pickResource } from "./resource-picker.ts";
30
31
  import {
@@ -457,14 +458,14 @@ export default function mcp(pi: ExtensionAPI) {
457
458
  };
458
459
  ensureCurrent();
459
460
 
460
- const dialogOptions = ctx.signal ? { signal: ctx.signal } : undefined;
461
461
  const argumentTokens: PromptArgumentToken[] = [];
462
462
  for (const argument of item.prompt.arguments ?? []) {
463
- const value = await ctx.ui.input(
464
- `${argument.name} (${argument.required ? "required" : "optional"})`,
465
- argument.required ? "Enter a value" : "Leave empty to omit",
466
- dialogOptions,
467
- );
463
+ const description = compact(argument.description ?? "", 160);
464
+ const value = await inputPromptArgument(ctx, {
465
+ label: `${argument.name} (${argument.required ? "required" : "optional"})`,
466
+ ...(description ? { description } : {}),
467
+ guidance: argument.required ? "Enter a value" : "Leave empty to omit",
468
+ });
468
469
  if (value === undefined) return;
469
470
  ctx.signal?.throwIfAborted();
470
471
  ensureCurrent();
@@ -0,0 +1,83 @@
1
+ import {
2
+ ExtensionInputComponent,
3
+ type ExtensionCommandContext,
4
+ type Theme,
5
+ } from "@earendil-works/pi-coding-agent";
6
+ import type { TUI } from "@earendil-works/pi-tui";
7
+
8
+ export interface PromptArgumentInputOptions {
9
+ label: string;
10
+ description?: string;
11
+ guidance: string;
12
+ signal?: AbortSignal;
13
+ }
14
+
15
+ class PromptArgumentInputComponent extends ExtensionInputComponent {
16
+ readonly #tui: TUI;
17
+ readonly #signal: AbortSignal | undefined;
18
+ readonly #onAbort: () => void;
19
+
20
+ constructor(
21
+ tui: TUI,
22
+ theme: Theme,
23
+ done: (value: string | undefined) => void,
24
+ options: PromptArgumentInputOptions,
25
+ ) {
26
+ let finished = false;
27
+ const finish = (value: string | undefined) => {
28
+ if (finished) return;
29
+ finished = true;
30
+ done(value);
31
+ };
32
+ const details = [
33
+ ...(options.description ? [theme.fg("dim", options.description)] : []),
34
+ theme.fg("muted", options.guidance),
35
+ ].join("\n");
36
+ super(
37
+ options.label,
38
+ undefined,
39
+ (value) => finish(value),
40
+ () => finish(undefined),
41
+ { tui, description: details },
42
+ );
43
+ this.#tui = tui;
44
+ this.#signal = options.signal;
45
+ this.#onAbort = () => finish(undefined);
46
+ options.signal?.addEventListener("abort", this.#onAbort, { once: true });
47
+ if (options.signal?.aborted) this.#onAbort();
48
+ }
49
+
50
+ override handleInput(data: string): void {
51
+ super.handleInput(data);
52
+ this.#tui.requestRender();
53
+ }
54
+
55
+ override dispose(): void {
56
+ this.#signal?.removeEventListener("abort", this.#onAbort);
57
+ super.dispose();
58
+ }
59
+ }
60
+
61
+ export function createPromptArgumentInput(
62
+ tui: TUI,
63
+ theme: Theme,
64
+ done: (value: string | undefined) => void,
65
+ options: PromptArgumentInputOptions,
66
+ ): ExtensionInputComponent {
67
+ return new PromptArgumentInputComponent(tui, theme, done, options);
68
+ }
69
+
70
+ // Pi 0.87.1's ctx.ui.input renders every title line as accent and ignores its
71
+ // placeholder. Reuse its native component through custom UI to style details.
72
+ export async function inputPromptArgument(
73
+ ctx: ExtensionCommandContext,
74
+ options: Omit<PromptArgumentInputOptions, "signal">,
75
+ ): Promise<string | undefined> {
76
+ if (ctx.signal?.aborted) return;
77
+ return ctx.ui.custom<string | undefined>((tui, theme, _keybindings, done) =>
78
+ createPromptArgumentInput(tui, theme, done, {
79
+ ...options,
80
+ ...(ctx.signal ? { signal: ctx.signal } : {}),
81
+ }),
82
+ );
83
+ }