@alexleekt/pi-ask-user-glimpse 0.3.0 → 0.3.2

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/index.ts CHANGED
@@ -284,6 +284,45 @@ function buildDebugParams(mode: string): AskUserParams | null {
284
284
  ],
285
285
  allowComment: true,
286
286
  };
287
+ case "long-question":
288
+ return {
289
+ question: "This is a very long question that exceeds one hundred and twenty characters so it should trigger the auto-split behavior. The first sentence becomes the dialog title, and the rest flows to the context panel.",
290
+ options: [
291
+ { title: "Split worked", description: "Title is short, context has the rest" },
292
+ { title: "Not split", description: "Everything is still in the title" },
293
+ ],
294
+ allowComment: true,
295
+ };
296
+ case "mermaid":
297
+ return {
298
+ question: "Test: Mermaid Diagrams",
299
+ context: `This prompt includes Mermaid diagrams to test rendering in the left context panel.
300
+
301
+ \`\`\`mermaid
302
+ graph TD
303
+ A[User asks question] --> B{Has context?}
304
+ B -->|Yes| C[Show left panel]
305
+ B -->|No| D[Single panel]
306
+ C --> E[Render markdown + diagrams]
307
+ D --> E
308
+ \`\`\`
309
+
310
+ The diagram above should render as an SVG. Below is a sequence diagram:
311
+
312
+ \`\`\`mermaid
313
+ sequenceDiagram
314
+ participant Agent
315
+ participant User
316
+ Agent->>User: Ask question
317
+ User->>Agent: Submit answer
318
+ \`\`\`
319
+ `,
320
+ options: [
321
+ { title: "Looks good", description: "Diagrams render correctly" },
322
+ { title: "Broken", description: "Something is wrong" },
323
+ ],
324
+ allowComment: true,
325
+ };
287
326
  default:
288
327
  return null;
289
328
  }
@@ -293,21 +332,23 @@ const askUserTool = defineTool({
293
332
  name: "ask_user",
294
333
  label: "Ask User",
295
334
  description:
296
- "Ask the user a question with optional multiple-choice answers. Use this to gather information interactively. Ask exactly one focused question per call. Before calling, gather context with tools (read/web/ref) and pass a short summary via the context field.",
335
+ "Ask the user a question with optional multiple-choice answers. Use this to gather information interactively. Ask exactly one focused question per call. Before calling, gather context with tools (read/web/ref) and pass a short summary via the context field. The context panel supports Mermaid diagrams (flowcharts, sequence diagrams, etc.) — include them when visualizing architecture, flows, or relationships would aid understanding.",
297
336
  promptSnippet:
298
337
  "Ask the user one focused question with optional multiple-choice answers to gather information interactively",
299
338
  promptGuidelines: [
300
339
  "Always use ask_user instead of guessing when user input would improve the answer.",
340
+ "Keep the question field short and focused (ideally one sentence). Put background, examples, or elaboration in the context field.",
341
+ "Include Mermaid diagrams in the context field when visualizing architecture, data flows, or decision trees would help the user understand the question.",
301
342
  "Pass a concise question and, when applicable, a list of options with short titles and optional longer descriptions.",
302
343
  "Set allowMultiple: true when more than one choice is valid.",
303
344
  "Set allowFreeform: true (default) when the user might want to answer in their own words.",
304
345
  ],
305
346
  parameters: Type.Object({
306
- question: Type.String({ description: "The question to ask the user" }),
347
+ question: Type.String({ description: "A short, focused question (ideally one sentence). Put background detail in context." }),
307
348
  context: Type.Optional(
308
349
  Type.String({
309
350
  description:
310
- "Additional context to help the user understand the question",
351
+ "Background, examples, or elaboration that helps the user understand the question. Shown in a side panel, so keep the question itself concise. Supports Mermaid diagrams (flowcharts, sequence diagrams, etc.) — wrap them in ```mermaid code blocks.",
311
352
  }),
312
353
  ),
313
354
  options: Type.Optional(
@@ -542,6 +583,8 @@ export default function (pi: ExtensionAPI) {
542
583
  "multi-select",
543
584
  "freeform",
544
585
  "questionnaire",
586
+ "long-question",
587
+ "mermaid",
545
588
  ]);
546
589
  if (!mode) return;
547
590
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexleekt/pi-ask-user-glimpse",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Pi extension that replaces ask_user with rich native WebView dialogs via glimpseui and shadcn/ui",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -61,6 +61,7 @@
61
61
  "@vitejs/plugin-react": "^4.3.0",
62
62
  "autoprefixer": "^10.4.20",
63
63
  "marked": "^15.0.12",
64
+ "mermaid": "^11.15.0",
64
65
  "playwright": "^1.60.0",
65
66
  "postcss": "^8.4.47",
66
67
  "react": "^18.3.1",
@@ -71,8 +72,8 @@
71
72
  "vite-plugin-singlefile": "^2.0.0"
72
73
  },
73
74
  "peerDependencies": {
74
- "@earendil-works/pi-coding-agent": "*",
75
- "@earendil-works/pi-ai": "*"
75
+ "@earendil-works/pi-ai": "*",
76
+ "@earendil-works/pi-coding-agent": "*"
76
77
  },
77
78
  "engines": {
78
79
  "node": ">=18.0.0"
package/tool/ask-user.ts CHANGED
@@ -397,10 +397,22 @@ export async function askUserHandler(
397
397
  payloadType = "single-select";
398
398
  }
399
399
 
400
+ // If the question is long and no separate context was provided, auto-split
401
+ // the first sentence into the question and the rest into context.
402
+ let question = params.question;
403
+ let context = params.context;
404
+ if (!context && params.question.length > 120) {
405
+ const match = params.question.match(/^(.+?[.?!])(\s+|$)/);
406
+ if (match && match[0].length < params.question.length) {
407
+ question = match[1].trim();
408
+ context = params.question.slice(match[0].length).trim();
409
+ }
410
+ }
411
+
400
412
  const payload: AskUserPayload = {
401
413
  type: payloadType,
402
- question: params.question,
403
- context: params.context,
414
+ question,
415
+ context,
404
416
  options: normalizedOptions,
405
417
  questions: params.questions,
406
418
  allowMultiple,
@@ -11,6 +11,7 @@ export interface AskResponse {
11
11
  kind: "selection" | "freeform";
12
12
  comment?: string;
13
13
  }[];
14
+ additionalComments?: string;
14
15
  }
15
16
 
16
17
  export interface AskToolDetails {
@@ -22,6 +23,10 @@ export interface AskToolDetails {
22
23
  error?: string;
23
24
  }
24
25
 
26
+ function pickString(raw: unknown): string | undefined {
27
+ return raw ? String(raw) : undefined;
28
+ }
29
+
25
30
  function normalizeKind(raw: unknown): AskResponse["kind"] {
26
31
  if (raw === "freeform" || raw === "questionnaire") return raw;
27
32
  return "selection";
@@ -51,9 +56,7 @@ function buildResponse(
51
56
  entry.kind === "freeform"
52
57
  ? "freeform"
53
58
  : "selection",
54
- comment: entry.comment
55
- ? String(entry.comment)
56
- : undefined,
59
+ comment: pickString(entry.comment),
57
60
  };
58
61
  })
59
62
  : [],
@@ -69,7 +72,8 @@ function buildResponse(
69
72
  return {
70
73
  kind,
71
74
  selections,
72
- comment: result.comment ? String(result.comment) : undefined,
75
+ comment: pickString(result.comment),
76
+ additionalComments: pickString(result.additionalComments),
73
77
  };
74
78
  }
75
79
 
@@ -77,12 +81,12 @@ function responseToText(response: AskResponse): string {
77
81
  if (response.kind === "freeform") {
78
82
  return response.text ?? "";
79
83
  }
84
+ const lines: string[] = [];
80
85
  const selections = response.selections ?? [];
81
- let text = selections.join(", ");
82
- if (response.comment) {
83
- text += `\n\nComment: ${response.comment}`;
84
- }
85
- return text;
86
+ if (selections.length > 0) lines.push(selections.join(", "));
87
+ if (response.comment) lines.push(`Comment: ${response.comment}`);
88
+ if (response.additionalComments) lines.push(`Additional Comments: ${response.additionalComments}`);
89
+ return lines.join("\n\n");
86
90
  }
87
91
 
88
92
  export function formatResponse(