@selesai/code 0.5.21 → 0.5.22

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.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/dist/core/agent-session-skill-block.test.d.ts +2 -0
  3. package/dist/core/agent-session-skill-block.test.d.ts.map +1 -0
  4. package/dist/core/agent-session-skill-block.test.js +20 -0
  5. package/dist/core/agent-session-skill-block.test.js.map +1 -0
  6. package/dist/core/agent-session.d.ts +7 -4
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +22 -12
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/skills.d.ts.map +1 -1
  11. package/dist/core/skills.js +1 -1
  12. package/dist/core/skills.js.map +1 -1
  13. package/dist/extensions/inline-skills.test.ts +96 -0
  14. package/dist/extensions/inline-skills.ts +92 -0
  15. package/dist/extensions/package.json +1 -0
  16. package/dist/extensions/pi-powerline-footer/tests/tps.test.ts +39 -0
  17. package/dist/extensions/pi-powerline-footer/tps.ts +172 -113
  18. package/dist/extensions/question/batch.ts +89 -25
  19. package/dist/extensions/question/constants.ts +1 -1
  20. package/dist/extensions/question/helpers.ts +34 -78
  21. package/dist/extensions/question/index.ts +327 -564
  22. package/dist/extensions/question/package.json +2 -1
  23. package/dist/extensions/question/question-list.ts +21 -14
  24. package/dist/extensions/question/row-layout.ts +2 -2
  25. package/dist/extensions/question/schemas.ts +33 -47
  26. package/dist/extensions/question/selection-mode.ts +5 -7
  27. package/dist/extensions/question/tests/batch.test.ts +65 -16
  28. package/dist/extensions/question/tests/helpers.test.ts +31 -156
  29. package/dist/extensions/question/tests/question-list.test.ts +17 -3
  30. package/dist/extensions/question/tests/row-layout.test.ts +4 -4
  31. package/dist/extensions/question/tests/schemas.test.ts +30 -0
  32. package/dist/extensions/question/tests/wizard.test.ts +99 -0
  33. package/dist/extensions/question/types.ts +65 -66
  34. package/dist/extensions/workflow/adapter.ts +4 -76
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  40. package/dist/modes/interactive/interactive-mode.js +10 -10
  41. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  42. package/dist/skills/workflow-creation/SKILL.md +2 -2
  43. package/docs/skills.md +8 -0
  44. package/docs/workflows.md +4 -4
  45. package/package.json +1 -1
@@ -1,102 +1,58 @@
1
1
  // Pure helper functions for the question extension.
2
2
 
3
- import type { MarkdownTheme } from "@selesai/code";
3
+ import type { PreparedQuestion, QuestionOption, QuestionResponse } from "./types.ts";
4
4
 
5
- import type { QuestionOption, QuestionResponse, RawOption } from "./types.ts";
6
-
7
- export function getOptionsFormatError(options: RawOption[] | undefined): string | null {
8
- for (const option of options ?? []) {
9
- if (typeof option !== "string") continue;
10
- const text = option.trim();
11
- if (!text.startsWith("[") && !text.startsWith("{")) continue;
12
- try {
13
- const parsed = JSON.parse(text);
14
- const jsonOption = (value: unknown) => !!value && typeof value === "object" && typeof (value as { label?: unknown }).label === "string";
15
- if (jsonOption(parsed) || (Array.isArray(parsed) && parsed.some(jsonOption))) {
16
- return 'Invalid question.options: pass an array of strings or {label, description} objects, not a JSON-encoded string. Example: {"options":[{"label":"Yes","description":"..."}]}, not {"options":["[{\\"label\\":\\"Yes\\"}]"]}.';
17
- }
18
- } catch {}
19
- }
20
- return null;
21
- }
22
-
23
- export function normalizeOptions(options: RawOption[] | undefined): QuestionOption[] {
24
- return (options ?? [])
25
- .map((option) =>
26
- typeof option === "string"
27
- ? { label: option }
28
- : { label: option.label, description: option.description },
29
- )
30
- .filter((option) => option.label.trim().length > 0);
5
+ export function trimText(value: string | null | undefined): string | undefined {
6
+ const trimmed = value?.trim();
7
+ return trimmed || undefined;
31
8
  }
32
9
 
33
10
  export function oneLine(value: unknown, max = 100): string {
34
11
  const text = String(value ?? "").replace(/\s+/g, " ").trim();
35
- return text.length > max ? `${text.slice(0, max - 1)}…` : text;
12
+ return text.length > max ? `${text.slice(0, Math.max(0, max - 1))}…` : text;
36
13
  }
37
14
 
38
- // ponytail: lazy import avoids hard dependency on pi-coding-agent at module load
39
- // time (it may not be resolvable in dev/test environments). The function is
40
- // only called at runtime when the TUI is active.
41
- let _getMarkdownTheme: (() => MarkdownTheme) | null | undefined;
42
- export function safeMarkdownTheme(): MarkdownTheme | undefined {
43
- try {
44
- if (_getMarkdownTheme === undefined) {
45
- // Dynamic require avoids breaking module load when package is absent.
46
- _getMarkdownTheme = (globalThis as any).require
47
- ? (globalThis as any).require("@selesai/code").getMarkdownTheme
48
- : null;
49
- }
50
- if (!_getMarkdownTheme) return undefined;
51
- const md = _getMarkdownTheme();
52
- if (!md) return undefined;
53
- md.bold("");
54
- return md;
55
- } catch {
56
- return undefined;
57
- }
15
+ export function previewText(value: unknown, max = 160, maxLines = 2): string {
16
+ const lines = String(value ?? "").trim().split(/\r?\n/);
17
+ const limited = lines.slice(0, maxLines).join("\n");
18
+ const wasCut = lines.length > maxLines || limited.length > max;
19
+ const text = limited.length > max ? limited.slice(0, Math.max(0, max - 1)) : limited;
20
+ return wasCut ? `${text}…` : text;
58
21
  }
59
22
 
60
- export function createFreeformResponse(text: string | null | undefined): QuestionResponse | null {
61
- const trimmed = text?.trim();
62
- return trimmed ? { kind: "freeform", text: trimmed } : null;
23
+ export function createTextResponse(text: string | null | undefined): QuestionResponse | null {
24
+ const normalized = trimText(text);
25
+ return normalized ? { kind: "text", text: normalized } : null;
63
26
  }
64
27
 
65
- export function createSelectionResponse(selections: string[], comment?: string | null): QuestionResponse | null {
66
- const norm = selections.map((s) => s.trim()).filter(Boolean);
67
- if (norm.length === 0) return null;
68
- const c = comment?.trim();
69
- return c ? { kind: "selection", selections: norm, comment: c } : { kind: "selection", selections: norm };
28
+ export function createSelectionResponse(values: string[], otherText?: string | null): QuestionResponse | null {
29
+ const normalizedValues = values.map((value) => value.trim()).filter(Boolean);
30
+ const normalizedOther = trimText(otherText);
31
+ if (normalizedValues.length === 0 && !normalizedOther) return null;
32
+ return normalizedOther
33
+ ? { kind: "selection", values: normalizedValues, otherText: normalizedOther }
34
+ : { kind: "selection", values: normalizedValues };
70
35
  }
71
36
 
72
37
  export function formatResponseSummary(response: QuestionResponse): string {
73
- if (response.kind === "freeform") return response.text;
74
- const selections = response.selections.join(", ");
75
- return response.comment ? `${selections} — ${response.comment}` : selections;
38
+ if (response.kind === "text") return response.text;
39
+ return [...response.values, ...(response.otherText ? [response.otherText] : [])].join(", ");
40
+ }
41
+
42
+ export function formatQuestionResponse(question: PreparedQuestion, response: QuestionResponse): string {
43
+ if (response.kind === "text") return response.text;
44
+ const labels = response.values.map(
45
+ (value) => question.options.find((option) => option.value === value)?.label ?? value,
46
+ );
47
+ if (response.otherText) labels.push(`Other: ${response.otherText}`);
48
+ return labels.join(", ");
76
49
  }
77
50
 
78
51
  export function formatOptionsForMessage(options: QuestionOption[]): string {
79
52
  return options
80
53
  .map((option, index) => {
81
- const desc = option.description ? ` — ${option.description}` : "";
82
- return `${index + 1}. ${option.label}${desc}`;
54
+ const description = option.description ? ` — ${option.description}` : "";
55
+ return `${index + 1}. ${option.label}${description}`;
83
56
  })
84
57
  .join("\n");
85
58
  }
86
-
87
- export function buildCommentPrompt(prompt: string, selections: string[]): string {
88
- const label = selections.length === 1 ? "Selected option" : "Selected options";
89
- const lines = selections.map((selection) => `- ${selection}`).join("\n");
90
- return `${prompt}\n\n${label}:\n${lines}`;
91
- }
92
-
93
- export function parseDialogSelections(input: string): string[] {
94
- return input
95
- .split(",")
96
- .map((selection) => selection.trim())
97
- .filter(Boolean);
98
- }
99
-
100
- export function isCancelled(value: unknown): value is null | undefined {
101
- return value === null || value === undefined;
102
- }