@groeponline/pi-wishcraft 1.4.0 → 1.4.5

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 (68) hide show
  1. package/AGENTS.md +28 -0
  2. package/CHANGELOG.md +36 -0
  3. package/README.md +22 -18
  4. package/ROADMAP.md +3 -3
  5. package/STRATEGY.md +54 -0
  6. package/bash-mode/editor-input.ts +3 -1
  7. package/bash-mode/editor.ts +44 -7
  8. package/bash-mode/forward.ts +64 -0
  9. package/bash-mode/pty-session.ts +356 -0
  10. package/bash-mode/ptyshell-managed.ts +145 -0
  11. package/bash-mode/session-factory.ts +64 -0
  12. package/bash-mode/transcript-v2.ts +77 -0
  13. package/bash-mode/transcript.ts +18 -0
  14. package/bash-mode/types.ts +27 -0
  15. package/docs/bash-mode.md +4 -0
  16. package/docs/configuration.md +45 -1
  17. package/docs/index.md +4 -1
  18. package/package.json +1 -1
  19. package/src/config/effective.ts +122 -0
  20. package/src/config/settings-registry.ts +2 -0
  21. package/src/config/structural-presets.ts +1 -1
  22. package/src/extension/commands/bash-mode-actions.ts +11 -10
  23. package/src/extension/commands/commands.ts +8 -0
  24. package/src/extension/core/state.ts +0 -1
  25. package/src/extension/core/types.ts +2 -2
  26. package/src/extension/session/session-lifecycle.ts +21 -0
  27. package/src/extension/skills/skill-templates.ts +12 -3
  28. package/src/extension/ui/custom-editor.ts +4 -0
  29. package/src/extension/ui/status-line-renderers.ts +12 -9
  30. package/src/extension/welcome/welcome-integration.ts +23 -1
  31. package/src/motion/catalog.ts +4 -0
  32. package/src/motion/frames.ts +19 -9
  33. package/src/motion/scheduler.ts +7 -0
  34. package/src/render/layout.ts +137 -0
  35. package/src/render/motion-candidates.ts +52 -0
  36. package/src/render/motion-rail.ts +99 -0
  37. package/src/render/paint.ts +64 -0
  38. package/src/render/v2-adapter.ts +70 -0
  39. package/src/render/v2-entry.ts +132 -0
  40. package/src/segments/pipeline.ts +164 -0
  41. package/src/segments/types.ts +36 -0
  42. package/src/segments/usage.ts +42 -3
  43. package/src/signal/controller.ts +37 -21
  44. package/src/studio/actions.ts +105 -0
  45. package/src/studio/advice-pane.ts +73 -0
  46. package/src/studio/advise/context.ts +89 -0
  47. package/src/studio/advise/engine.ts +117 -0
  48. package/src/studio/advise/prompts.ts +68 -0
  49. package/src/studio/component.ts +105 -0
  50. package/src/studio/deepwiki/cache.ts +74 -0
  51. package/src/studio/deepwiki/client.ts +73 -0
  52. package/src/studio/deepwiki/extract.ts +66 -0
  53. package/src/studio/inspect.ts +38 -0
  54. package/src/studio/list.ts +48 -0
  55. package/src/studio/open.ts +44 -0
  56. package/src/studio/state.ts +100 -0
  57. package/src/studio/types.ts +30 -0
  58. package/src/welcome/banner.ts +6 -0
  59. package/src/welcome/index.ts +7 -0
  60. package/src/welcome/overlay.ts +6 -0
  61. package/src/welcome/renderer.ts +6 -39
  62. package/src/welcome/types.ts +6 -0
  63. package/src/welcome/welcome-art.ts +148 -0
  64. package/src/working-vibes/frames.ts +25 -0
  65. package/src/working-vibes/index.ts +2 -0
  66. package/src/working-vibes/storage.ts +11 -0
  67. package/bash-mode/shell-session.ts +0 -294
  68. package/src/signal/render.ts +0 -221
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Pure studio state machine (U5). No TUI imports: tests drive this directly;
3
+ * component.ts maps raw input bytes onto StudioKeyEvent and re-renders.
4
+ */
5
+
6
+ import type { StudioKeyEvent, StudioPaneId, StudioState } from "./types.ts";
7
+
8
+ export const STUDIO_PANES: readonly StudioPaneId[] = [
9
+ "list",
10
+ "detail",
11
+ "actions",
12
+ "advice",
13
+ ];
14
+
15
+ export function createStudioState(): StudioState {
16
+ return {
17
+ mode: "normal",
18
+ focus: "list",
19
+ selectedIndex: 0,
20
+ filterQuery: "",
21
+ confirmText: null,
22
+ exitRequested: false,
23
+ };
24
+ }
25
+
26
+ export function handleStudioKey(
27
+ state: StudioState,
28
+ event: StudioKeyEvent,
29
+ ): StudioState {
30
+ switch (state.mode) {
31
+ case "help":
32
+ return handleHelpKey(state, event);
33
+ case "filter":
34
+ return handleFilterKey(state, event);
35
+ case "confirm":
36
+ return handleConfirmKey(state, event);
37
+ case "normal":
38
+ return handleNormalKey(state, event);
39
+ }
40
+ }
41
+
42
+ function handleHelpKey(state: StudioState, event: StudioKeyEvent): StudioState {
43
+ if (
44
+ event.key === "printable" && event.char === "q" ||
45
+ event.key === "escape" ||
46
+ event.key === "return"
47
+ ) {
48
+ return { ...state, mode: "normal" };
49
+ }
50
+ return state;
51
+ }
52
+
53
+ function handleFilterKey(state: StudioState, event: StudioKeyEvent): StudioState {
54
+ if (event.key === "escape") {
55
+ return { ...state, mode: "normal", filterQuery: "" };
56
+ }
57
+ if (event.key === "return") {
58
+ return { ...state, mode: "normal" };
59
+ }
60
+ if (event.key === "backspace") {
61
+ return { ...state, filterQuery: state.filterQuery.slice(0, -1) };
62
+ }
63
+ if (event.key === "printable" && event.char) {
64
+ return { ...state, filterQuery: state.filterQuery + event.char };
65
+ }
66
+ return state;
67
+ }
68
+
69
+ function handleConfirmKey(state: StudioState, event: StudioKeyEvent): StudioState {
70
+ // Confirmation resolution semantics arrive with the U7 action layer; for
71
+ // now any escape/return leaves confirm mode without changing selection.
72
+ if (event.key === "escape" || event.key === "return") {
73
+ return { ...state, mode: "normal", confirmText: null };
74
+ }
75
+ return state;
76
+ }
77
+
78
+ function handleNormalKey(state: StudioState, event: StudioKeyEvent): StudioState {
79
+ if (event.key === "escape" || (event.key === "printable" && event.char === "q")) {
80
+ return { ...state, exitRequested: true };
81
+ }
82
+ if (event.key === "printable" && event.char === "/") {
83
+ return { ...state, mode: "filter" };
84
+ }
85
+ if (event.key === "printable" && event.char === "?") {
86
+ return { ...state, mode: "help" };
87
+ }
88
+ if (event.key === "tab") {
89
+ const idx = STUDIO_PANES.indexOf(state.focus);
90
+ const next = STUDIO_PANES[(idx + 1) % STUDIO_PANES.length]!;
91
+ return { ...state, focus: next };
92
+ }
93
+ if (event.key === "down" || (event.key === "printable" && event.char === "j")) {
94
+ return { ...state, selectedIndex: state.selectedIndex + 1 };
95
+ }
96
+ if (event.key === "up" || (event.key === "printable" && event.char === "k")) {
97
+ return { ...state, selectedIndex: Math.max(0, state.selectedIndex - 1) };
98
+ }
99
+ return state;
100
+ }
@@ -0,0 +1,30 @@
1
+ /** Studio domain types (U5). Kept UI-free; state.ts is the pure reducer. */
2
+
3
+ export type StudioPaneId = "list" | "detail" | "actions" | "advice";
4
+
5
+ export type StudioMode = "normal" | "filter" | "confirm" | "help";
6
+
7
+ export interface StudioState {
8
+ mode: StudioMode;
9
+ focus: StudioPaneId;
10
+ selectedIndex: number;
11
+ filterQuery: string;
12
+ /** Pending destructive confirmation text (set by U7 actions). */
13
+ confirmText: string | null;
14
+ exitRequested: boolean;
15
+ }
16
+
17
+ export type StudioKeyKind =
18
+ | "escape"
19
+ | "return"
20
+ | "tab"
21
+ | "up"
22
+ | "down"
23
+ | "backspace"
24
+ | "printable"
25
+ | "other";
26
+
27
+ export interface StudioKeyEvent {
28
+ key: StudioKeyKind;
29
+ char?: string;
30
+ }
@@ -2,6 +2,7 @@ import type { Component } from "@earendil-works/pi-tui";
2
2
  import { dim, renderWelcomeBox } from "./renderer.ts";
3
3
  import type { WelcomeData } from "./types.ts";
4
4
  import type { LoadedCounts, RecentSession } from "./types.ts";
5
+ import type { WelcomeArtTheme } from "./welcome-art.ts";
5
6
 
6
7
  /**
7
8
  * Welcome header - same layout as overlay but persistent (no countdown).
@@ -39,6 +40,11 @@ export class WelcomeHeader implements Component {
39
40
  };
40
41
  }
41
42
 
43
+ setArt(art: WelcomeArtTheme, animate: boolean): void {
44
+ this.data.art = art;
45
+ this.data.animateArt = animate;
46
+ }
47
+
42
48
  invalidate(): void {}
43
49
 
44
50
  render(termWidth: number): string[] {
@@ -5,3 +5,10 @@ export { discoverLoadedCounts } from "./discover.ts";
5
5
  export { getRecentSessions } from "./sessions.ts";
6
6
  export { WhatsNewWidget } from "./widgets/whats-new-widget.ts";
7
7
  export { discoverWhatsNew, parseChangelogDelta } from "./whats-new.ts";
8
+ export {
9
+ DEFAULT_WELCOME_ART,
10
+ WELCOME_ART_THEMES,
11
+ normalizeWelcomeArt,
12
+ renderWelcomeArt,
13
+ type WelcomeArtTheme,
14
+ } from "./welcome-art.ts";
@@ -3,6 +3,7 @@ import { visibleWidth } from "@earendil-works/pi-tui";
3
3
  import { dim, renderWelcomeBox } from "./renderer.ts";
4
4
  import type { WelcomeData } from "./types.ts";
5
5
  import type { LoadedCounts, RecentSession } from "./types.ts";
6
+ import type { WelcomeArtTheme } from "./welcome-art.ts";
6
7
 
7
8
  // ═══════════════════════════════════════════════════════════════════════════
8
9
  // Welcome Components
@@ -49,6 +50,11 @@ export class WelcomeComponent implements Component {
49
50
  this.countdown = seconds;
50
51
  }
51
52
 
53
+ setArt(art: WelcomeArtTheme, animate: boolean): void {
54
+ this.data.art = art;
55
+ this.data.animateArt = animate;
56
+ }
57
+
52
58
  invalidate(): void {}
53
59
 
54
60
  render(termWidth: number): string[] {
@@ -2,6 +2,7 @@ import { visibleWidth } from "@earendil-works/pi-tui";
2
2
  import { ansi, colorEnabled, fgOnly, getFgAnsiCode } from "../theme/colors.ts";
3
3
  import { centerText, fitToWidth, getBoxLayout } from "./layout.ts";
4
4
  import type { WelcomeData, WelcomeWidget, WidgetRenderContext } from "./types.ts";
5
+ import { DEFAULT_WELCOME_ART, renderWelcomeArt } from "./welcome-art.ts";
5
6
 
6
7
  import { QueueWidget } from "./widgets/queue-widget.ts";
7
8
  import { SessionsWidget } from "./widgets/sessions-widget.ts";
@@ -9,24 +10,6 @@ import { ShortcutsWidget } from "./widgets/shortcuts-widget.ts";
9
10
  import { SystemWidget } from "./widgets/system-widget.ts";
10
11
  import { WhatsNewWidget } from "./widgets/whats-new-widget.ts";
11
12
 
12
- const PI_LOGO = [
13
- " . * ",
14
- " * ╭───╮ . ",
15
- " . │ │ * ",
16
- " │ │ ",
17
- " * ╰─┬─╯ . ",
18
- " . ┴ ",
19
- ];
20
-
21
- const GRADIENT_COLORS = [
22
- "\x1b[38;5;199m",
23
- "\x1b[38;5;171m",
24
- "\x1b[38;5;135m",
25
- "\x1b[38;5;99m",
26
- "\x1b[38;5;75m",
27
- "\x1b[38;5;51m",
28
- ];
29
-
30
13
  function bold(text: string): string {
31
14
  return `\x1b[1m${text}\x1b[22m`;
32
15
  }
@@ -35,31 +18,15 @@ export function dim(text: string): string {
35
18
  return getFgAnsiCode("sep") + text + (colorEnabled() ? ansi.reset : "");
36
19
  }
37
20
 
38
- function gradientLine(line: string): string {
39
- const reset = ansi.reset;
40
- let result = "";
41
- let colorIdx = 0;
42
- const step = Math.max(1, Math.floor(line.length / GRADIENT_COLORS.length));
43
-
44
- for (let i = 0; i < line.length; i++) {
45
- if (i > 0 && i % step === 0 && colorIdx < GRADIENT_COLORS.length - 1)
46
- colorIdx++;
47
- const char = line[i];
48
- if (char !== " ") {
49
- result += GRADIENT_COLORS[colorIdx] + char + reset;
50
- } else {
51
- result += char;
52
- }
53
- }
54
- return result;
55
- }
56
-
57
21
  function buildLeftColumn(ctx: WidgetRenderContext): string[] {
58
- const logoColored = PI_LOGO.map((line) => gradientLine(line));
22
+ const art = renderWelcomeArt(ctx.data.art ?? DEFAULT_WELCOME_ART, ctx.width, {
23
+ now: Date.now(),
24
+ animate: ctx.data.animateArt,
25
+ });
59
26
 
60
27
  return [
61
28
  "",
62
- ...logoColored.map((l) => centerText(l, ctx.width)),
29
+ ...art,
63
30
  "",
64
31
  centerText(fgOnly("model", ctx.data.modelName), ctx.width),
65
32
  centerText(dim(ctx.data.providerName), ctx.width),
@@ -1,3 +1,5 @@
1
+ import type { WelcomeArtTheme } from "./welcome-art.ts";
2
+
1
3
  export interface LoadedCounts {
2
4
  contextFiles: number;
3
5
  extensions: number;
@@ -20,6 +22,10 @@ export interface WelcomeData {
20
22
  hasStash?: boolean;
21
23
  nextIdeaText?: string;
22
24
  whatsNew?: string[];
25
+ /** Left-column art theme (lantern / balloon / normal). */
26
+ art?: WelcomeArtTheme;
27
+ /** Animate the lantern flame. */
28
+ animateArt?: boolean;
23
29
  }
24
30
 
25
31
  export interface WelcomeWidget {
@@ -0,0 +1,148 @@
1
+ /**
2
+ * welcome-art.ts
3
+ * ---------------------------------------------------------------------------
4
+ * The welcome overlay's left-column art, as selectable themes:
5
+ *
6
+ * - "lantern" — a Kongming wish-lantern (wenslantaarn): the detailed
7
+ * truecolor pixel art from lantern-art.ts, rendered with half-blocks.
8
+ * - "balloon" — a wish-balloon (wensballon): a hand-drawn hot-air balloon.
9
+ * - "normal" — the classic pi mark.
10
+ *
11
+ * `renderWelcomeArt` returns coloured, centred lines ready to drop into the
12
+ * welcome box. The lantern can flicker when `animate` is on.
13
+ * ---------------------------------------------------------------------------
14
+ */
15
+
16
+ import { ansi } from "../theme/colors.ts";
17
+ import { centerText } from "./layout.ts";
18
+ import { renderLantern, LANTERN_WIDTH } from "./lantern.ts";
19
+
20
+ export type WelcomeArtTheme = "lantern" | "balloon" | "normal";
21
+
22
+ export const WELCOME_ART_THEMES: readonly WelcomeArtTheme[] = [
23
+ "lantern",
24
+ "balloon",
25
+ "normal",
26
+ ];
27
+
28
+ export const DEFAULT_WELCOME_ART: WelcomeArtTheme = "lantern";
29
+
30
+ /** Coerce a settings value to a known theme, falling back to the default. */
31
+ export function normalizeWelcomeArt(value: unknown): WelcomeArtTheme {
32
+ return WELCOME_ART_THEMES.includes(value as WelcomeArtTheme)
33
+ ? (value as WelcomeArtTheme)
34
+ : DEFAULT_WELCOME_ART;
35
+ }
36
+
37
+ export interface WelcomeArtOptions {
38
+ /** Time source for the lantern flicker; Date.now() is fine. */
39
+ now?: number;
40
+ /** Animate the lantern flame (lantern theme only). */
41
+ animate?: boolean;
42
+ }
43
+
44
+ // --- Normal: the classic pi mark, warm→cool horizontal gradient -------------
45
+
46
+ const PI_LOGO = [
47
+ " . * ",
48
+ " * ╭───╮ . ",
49
+ " . │ π │ * ",
50
+ " │ │ ",
51
+ " * ╰─┬─╯ . ",
52
+ " . ┴ ",
53
+ ];
54
+
55
+ const PI_GRADIENT = [
56
+ "\x1b[38;5;199m",
57
+ "\x1b[38;5;171m",
58
+ "\x1b[38;5;135m",
59
+ "\x1b[38;5;99m",
60
+ "\x1b[38;5;75m",
61
+ "\x1b[38;5;51m",
62
+ ];
63
+
64
+ // --- Balloon: a wish-balloon (wensballon), warm→gold vertical gradient ------
65
+
66
+ const BALLOON_ART = [
67
+ " ╭───╮ ",
68
+ " ╱ ✦ ✦ ╲ ",
69
+ " ╱ ✦ ♥ ✦ ╲ ",
70
+ " │ ✦ ♥ ♥ ✦ │ ",
71
+ " │ ✦ ♥ ✦ │ ",
72
+ " ╲ ✦ ✦ ✦ ╱ ",
73
+ " ╲__ __╱ ",
74
+ " │╲ ╱│ ",
75
+ " │ ⌂ │ ",
76
+ " ╰───╯ ",
77
+ ];
78
+
79
+ const BALLOON_GRADIENT = [
80
+ "\x1b[38;5;213m",
81
+ "\x1b[38;5;212m",
82
+ "\x1b[38;5;205m",
83
+ "\x1b[38;5;204m",
84
+ "\x1b[38;5;209m",
85
+ "\x1b[38;5;215m",
86
+ "\x1b[38;5;221m",
87
+ "\x1b[38;5;179m",
88
+ "\x1b[38;5;137m",
89
+ "\x1b[38;5;95m",
90
+ ];
91
+
92
+ /** Colour a line left-to-right across a palette (non-space cells only). */
93
+ function horizontalGradient(line: string, palette: readonly string[]): string {
94
+ let result = "";
95
+ let colorIdx = 0;
96
+ const step = Math.max(1, Math.floor(line.length / palette.length));
97
+ for (let i = 0; i < line.length; i++) {
98
+ if (i > 0 && i % step === 0 && colorIdx < palette.length - 1) colorIdx++;
99
+ const char = line[i]!;
100
+ result += char !== " " ? palette[colorIdx] + char + ansi.reset : char;
101
+ }
102
+ return result;
103
+ }
104
+
105
+ /** Colour a whole row with the palette entry for that row index. */
106
+ function rowColor(
107
+ line: string,
108
+ rowIndex: number,
109
+ palette: readonly string[],
110
+ ): string {
111
+ const color = palette[Math.min(rowIndex, palette.length - 1)]!;
112
+ let result = "";
113
+ for (const char of line) {
114
+ result += char !== " " ? color + char + ansi.reset : char;
115
+ }
116
+ return result;
117
+ }
118
+
119
+ /**
120
+ * Render the chosen art as centred, coloured lines of the given width.
121
+ * Falls back to the pi mark when a themed art cannot fit the column.
122
+ */
123
+ export function renderWelcomeArt(
124
+ theme: WelcomeArtTheme,
125
+ width: number,
126
+ opts: WelcomeArtOptions = {},
127
+ ): string[] {
128
+ if (theme === "lantern") {
129
+ const lantern = renderLantern(
130
+ { now: opts.now ?? 0, still: !opts.animate },
131
+ width,
132
+ );
133
+ if (lantern.length > 0 && LANTERN_WIDTH <= width) {
134
+ return lantern.map((line) => centerText(line, width));
135
+ }
136
+ // too narrow for the pixel art: fall through to the pi mark
137
+ }
138
+
139
+ if (theme === "balloon") {
140
+ return BALLOON_ART.map((line, i) =>
141
+ centerText(rowColor(line, i, BALLOON_GRADIENT), width),
142
+ );
143
+ }
144
+
145
+ return PI_LOGO.map((line) =>
146
+ centerText(horizontalGradient(line, PI_GRADIENT), width),
147
+ );
148
+ }
@@ -0,0 +1,25 @@
1
+ /** Pure working-indicator frames shared by status renderers and tests. */
2
+
3
+ export type WorkingIndicatorStyle = "dots" | "pulse" | "bar" | "ascii";
4
+
5
+ const FRAMES: Record<WorkingIndicatorStyle, readonly string[]> = {
6
+ dots: ["· ", "·· ", "···", " ··", " ·", " ··"],
7
+ pulse: ["○", "◌", "●", "◌"],
8
+ bar: ["[= ]", "[== ]", "[===]", "[ ==]", "[ =]"],
9
+ ascii: ["-", "\\", "|", "/"],
10
+ };
11
+
12
+ export function workingIndicatorFrame(
13
+ style: WorkingIndicatorStyle = "dots",
14
+ tick = 0,
15
+ motion: "full" | "reduced" | "functional" | "off" = "full",
16
+ ): string {
17
+ const frames = FRAMES[style] ?? FRAMES.dots;
18
+ if (motion === "off" || motion === "reduced") return frames[0]!;
19
+ if (motion === "functional") return frames[tick % 2 === 0 ? 0 : Math.min(1, frames.length - 1)]!;
20
+ return frames[Math.abs(Math.floor(tick)) % frames.length]!;
21
+ }
22
+
23
+ export function workingIndicatorStyles(): WorkingIndicatorStyle[] {
24
+ return Object.keys(FRAMES) as WorkingIndicatorStyle[];
25
+ }
@@ -19,6 +19,8 @@ export {
19
19
  } from "./manager.ts";
20
20
 
21
21
  export type { VibeMode } from "./storage.ts";
22
+ export type { WorkingIndicatorStyle } from "./frames.ts";
23
+ export { workingIndicatorFrame, workingIndicatorStyles } from "./frames.ts";
22
24
 
23
25
  export type {
24
26
  GenerateVibesResult,
@@ -9,6 +9,7 @@ import { join, dirname } from "node:path";
9
9
  import { getAgentPath } from "../paths/agent-dirs.ts";
10
10
 
11
11
  export type VibeMode = "generate" | "file";
12
+ export type WorkingIndicatorStyle = "dots" | "pulse" | "bar" | "ascii";
12
13
 
13
14
  // ═══════════════════════════════════════════════════════════════════════════
14
15
  // Constants
@@ -51,6 +52,7 @@ export interface VibeConfig {
51
52
  refreshInterval: number; // default: 30000ms (30s)
52
53
  promptTemplate: string; // template with {theme}, {task}, {exclude} placeholders
53
54
  maxLength: number; // default: 65 chars
55
+ workingIndicatorStyle: WorkingIndicatorStyle;
54
56
  }
55
57
 
56
58
  // ═══════════════════════════════════════════════════════════════════════════
@@ -180,6 +182,14 @@ export function loadConfig(): VibeConfig {
180
182
  ? Math.max(0, settings.workingVibeRefreshInterval)
181
183
  : 30;
182
184
 
185
+ const rawIndicator = settings.wishcraft && isRecord(settings.wishcraft)
186
+ ? settings.wishcraft.workingIndicatorStyle
187
+ : settings.workingIndicatorStyle;
188
+ const workingIndicatorStyle: WorkingIndicatorStyle =
189
+ rawIndicator === "pulse" || rawIndicator === "bar" || rawIndicator === "ascii"
190
+ ? rawIndicator
191
+ : "dots";
192
+
183
193
  const maxLength =
184
194
  typeof settings.workingVibeMaxLength === "number" &&
185
195
  Number.isFinite(settings.workingVibeMaxLength)
@@ -204,6 +214,7 @@ export function loadConfig(): VibeConfig {
204
214
  ? settings.workingVibePrompt
205
215
  : DEFAULT_PROMPT,
206
216
  maxLength,
217
+ workingIndicatorStyle,
207
218
  };
208
219
  }
209
220