@chances-ai/tui 13.0.0 → 15.0.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.
Files changed (77) hide show
  1. package/dist/api-key-prompt.d.ts +8 -15
  2. package/dist/api-key-prompt.d.ts.map +1 -1
  3. package/dist/api-key-prompt.js +21 -31
  4. package/dist/api-key-prompt.js.map +1 -1
  5. package/dist/app.d.ts +15 -21
  6. package/dist/app.d.ts.map +1 -1
  7. package/dist/app.js +180 -151
  8. package/dist/app.js.map +1 -1
  9. package/dist/code-view.d.ts +9 -0
  10. package/dist/code-view.d.ts.map +1 -0
  11. package/dist/code-view.js +28 -0
  12. package/dist/code-view.js.map +1 -0
  13. package/dist/diff-model.d.ts +64 -0
  14. package/dist/diff-model.d.ts.map +1 -0
  15. package/dist/diff-model.js +156 -0
  16. package/dist/diff-model.js.map +1 -0
  17. package/dist/diff-view.d.ts +13 -0
  18. package/dist/diff-view.d.ts.map +1 -0
  19. package/dist/diff-view.js +60 -0
  20. package/dist/diff-view.js.map +1 -0
  21. package/dist/highlight-to-segments.d.ts +18 -0
  22. package/dist/highlight-to-segments.d.ts.map +1 -0
  23. package/dist/highlight-to-segments.js +224 -0
  24. package/dist/highlight-to-segments.js.map +1 -0
  25. package/dist/index.d.ts +15 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +13 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/markdown.d.ts +5 -0
  30. package/dist/markdown.d.ts.map +1 -0
  31. package/dist/markdown.js +117 -0
  32. package/dist/markdown.js.map +1 -0
  33. package/dist/modal.d.ts +3 -2
  34. package/dist/modal.d.ts.map +1 -1
  35. package/dist/modal.js +3 -2
  36. package/dist/modal.js.map +1 -1
  37. package/dist/model-picker.d.ts +7 -39
  38. package/dist/model-picker.d.ts.map +1 -1
  39. package/dist/model-picker.js +14 -65
  40. package/dist/model-picker.js.map +1 -1
  41. package/dist/progress.d.ts +41 -0
  42. package/dist/progress.d.ts.map +1 -0
  43. package/dist/progress.js +122 -0
  44. package/dist/progress.js.map +1 -0
  45. package/dist/select.d.ts +59 -0
  46. package/dist/select.d.ts.map +1 -0
  47. package/dist/select.js +114 -0
  48. package/dist/select.js.map +1 -0
  49. package/dist/session-picker.d.ts +7 -15
  50. package/dist/session-picker.d.ts.map +1 -1
  51. package/dist/session-picker.js +14 -40
  52. package/dist/session-picker.js.map +1 -1
  53. package/dist/slash-typeahead.d.ts +34 -0
  54. package/dist/slash-typeahead.d.ts.map +1 -0
  55. package/dist/slash-typeahead.js +78 -0
  56. package/dist/slash-typeahead.js.map +1 -0
  57. package/dist/theme-context.d.ts +25 -0
  58. package/dist/theme-context.d.ts.map +1 -0
  59. package/dist/theme-context.js +24 -0
  60. package/dist/theme-context.js.map +1 -0
  61. package/dist/theme.d.ts +106 -0
  62. package/dist/theme.d.ts.map +1 -0
  63. package/dist/theme.js +116 -0
  64. package/dist/theme.js.map +1 -0
  65. package/dist/tool-line.d.ts +33 -0
  66. package/dist/tool-line.d.ts.map +1 -0
  67. package/dist/tool-line.js +168 -0
  68. package/dist/tool-line.js.map +1 -0
  69. package/dist/tool-message.d.ts +18 -0
  70. package/dist/tool-message.d.ts.map +1 -0
  71. package/dist/tool-message.js +37 -0
  72. package/dist/tool-message.js.map +1 -0
  73. package/dist/view-model.d.ts +46 -1
  74. package/dist/view-model.d.ts.map +1 -1
  75. package/dist/view-model.js +109 -16
  76. package/dist/view-model.js.map +1 -1
  77. package/package.json +9 -4
package/dist/index.d.ts CHANGED
@@ -3,10 +3,24 @@ import type { ModalController } from "./modal.js";
3
3
  export { ChatViewModel } from "./view-model.js";
4
4
  export type { Line, LineKind } from "./view-model.js";
5
5
  export { ChatApp, suggestSlashCommands, suggestResourceMentions, type SlashSuggestion, type ResourceSuggestion, } from "./app.js";
6
+ export { SlashTypeahead } from "./slash-typeahead.js";
6
7
  export { ModalController, type OpenModal } from "./modal.js";
7
8
  export { ModelPicker, type PickableModel } from "./model-picker.js";
8
9
  export { SessionPicker, type PickableSession } from "./session-picker.js";
9
10
  export { ApiKeyPrompt } from "./api-key-prompt.js";
11
+ export { Select, type SelectOption, type SelectProps, filterOptions, moveCursor, pageCursor, visibleWindow, clampCursor, } from "./select.js";
12
+ export { ThemeProvider, useTheme } from "./theme-context.js";
13
+ export { resolveTheme, type Theme, type ThemeSetting, GLYPHS } from "./theme.js";
14
+ export { Markdown } from "./markdown.js";
15
+ export { CodeView } from "./code-view.js";
16
+ export { DiffView } from "./diff-view.js";
17
+ export { ToolMessage } from "./tool-message.js";
18
+ export { Progress } from "./progress.js";
19
+ /** (5.9) Rendering options forwarded into the chat's `ThemeProvider`. */
20
+ export interface ChatRenderOptions {
21
+ themeSetting?: import("./theme.js").ThemeSetting;
22
+ syntaxHighlight?: boolean;
23
+ }
10
24
  export interface ChatHandle {
11
25
  vm: ChatViewModel;
12
26
  waitUntilExit: () => Promise<void>;
@@ -20,5 +34,5 @@ export interface ChatHandle {
20
34
  * `modal` is the controller slash commands use to open pickers; pass the
21
35
  * same instance to `dispatchSlash(name, args, { openModal: modal.open })`.
22
36
  */
23
- export declare function renderChat(vm: ChatViewModel, onSubmit: (prompt: string) => Promise<void>, onSlash?: (line: string) => Promise<void>, modal?: ModalController, availableSlashCommands?: import("./app.js").SlashSuggestion[], availableResources?: import("./app.js").ResourceSuggestion[]): ChatHandle;
37
+ export declare function renderChat(vm: ChatViewModel, onSubmit: (prompt: string) => Promise<void>, onSlash?: (line: string) => Promise<void>, modal?: ModalController, availableSlashCommands?: import("./app.js").SlashSuggestion[], availableResources?: import("./app.js").ResourceSuggestion[], options?: ChatRenderOptions): ChatHandle;
24
38
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACL,OAAO,EACP,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,aAAa,CAAC;IAClB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,EAAE,EAAE,aAAa,EACjB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EAC3C,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EACzC,KAAK,CAAC,EAAE,eAAe,EACvB,sBAAsB,CAAC,EAAE,OAAO,UAAU,EAAE,eAAe,EAAE,EAC7D,kBAAkB,CAAC,EAAE,OAAO,UAAU,EAAE,kBAAkB,EAAE,GAC3D,UAAU,CAmBZ"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACL,OAAO,EACP,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EACL,MAAM,EACN,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,aAAa,EACb,UAAU,EACV,UAAU,EACV,aAAa,EACb,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,yEAAyE;AACzE,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,OAAO,YAAY,EAAE,YAAY,CAAC;IACjD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,aAAa,CAAC;IAClB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,EAAE,EAAE,aAAa,EACjB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EAC3C,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EACzC,KAAK,CAAC,EAAE,eAAe,EACvB,sBAAsB,CAAC,EAAE,OAAO,UAAU,EAAE,eAAe,EAAE,EAC7D,kBAAkB,CAAC,EAAE,OAAO,UAAU,EAAE,kBAAkB,EAAE,EAC5D,OAAO,CAAC,EAAE,iBAAiB,GAC1B,UAAU,CAqBZ"}
package/dist/index.js CHANGED
@@ -4,10 +4,21 @@ import { ChatApp } from "./app.js";
4
4
  import { ChatViewModel } from "./view-model.js";
5
5
  export { ChatViewModel } from "./view-model.js";
6
6
  export { ChatApp, suggestSlashCommands, suggestResourceMentions, } from "./app.js";
7
+ export { SlashTypeahead } from "./slash-typeahead.js";
7
8
  export { ModalController } from "./modal.js";
8
9
  export { ModelPicker } from "./model-picker.js";
9
10
  export { SessionPicker } from "./session-picker.js";
10
11
  export { ApiKeyPrompt } from "./api-key-prompt.js";
12
+ // (5.10 A2) The generic single-select primitive + its pure helpers.
13
+ export { Select, filterOptions, moveCursor, pageCursor, visibleWindow, clampCursor, } from "./select.js";
14
+ // (5.9) Visual-language surface — exported for reuse + focused testing.
15
+ export { ThemeProvider, useTheme } from "./theme-context.js";
16
+ export { resolveTheme, GLYPHS } from "./theme.js";
17
+ export { Markdown } from "./markdown.js";
18
+ export { CodeView } from "./code-view.js";
19
+ export { DiffView } from "./diff-view.js";
20
+ export { ToolMessage } from "./tool-message.js";
21
+ export { Progress } from "./progress.js";
11
22
  /**
12
23
  * Mounts the interactive chat. The caller owns the view-model so it can wire
13
24
  * `vm.requestPermission` into the PermissionGate before the engine is built.
@@ -16,8 +27,8 @@ export { ApiKeyPrompt } from "./api-key-prompt.js";
16
27
  * `modal` is the controller slash commands use to open pickers; pass the
17
28
  * same instance to `dispatchSlash(name, args, { openModal: modal.open })`.
18
29
  */
19
- export function renderChat(vm, onSubmit, onSlash, modal, availableSlashCommands, availableResources) {
20
- const instance = render(_jsx(ChatApp, { vm: vm, onSubmit: onSubmit, onSlash: onSlash, modal: modal, availableSlashCommands: availableSlashCommands, availableResources: availableResources }));
30
+ export function renderChat(vm, onSubmit, onSlash, modal, availableSlashCommands, availableResources, options) {
31
+ const instance = render(_jsx(ChatApp, { vm: vm, onSubmit: onSubmit, onSlash: onSlash, modal: modal, availableSlashCommands: availableSlashCommands, availableResources: availableResources, themeSetting: options?.themeSetting, syntaxHighlight: options?.syntaxHighlight }));
21
32
  return {
22
33
  vm,
23
34
  // Ink 7 widened `waitUntilExit()` to `Promise<unknown>` (Ink 5 was
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EACL,OAAO,EACP,oBAAoB,EACpB,uBAAuB,GAGxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,eAAe,EAAkB,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAwB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAQnD;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CACxB,EAAiB,EACjB,QAA2C,EAC3C,OAAyC,EACzC,KAAuB,EACvB,sBAA6D,EAC7D,kBAA4D;IAE5D,MAAM,QAAQ,GAAG,MAAM,CACrB,KAAC,OAAO,IACN,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,EACZ,sBAAsB,EAAE,sBAAsB,EAC9C,kBAAkB,EAAE,kBAAkB,GACtC,CACH,CAAC;IACF,OAAO;QACL,EAAE;QACF,mEAAmE;QACnE,yEAAyE;QACzE,sEAAsE;QACtE,aAAa,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;QACnE,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE;KAClC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EACL,OAAO,EACP,oBAAoB,EACpB,uBAAuB,GAGxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAkB,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAwB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,oEAAoE;AACpE,OAAO,EACL,MAAM,EAGN,aAAa,EACb,UAAU,EACV,UAAU,EACV,aAAa,EACb,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,wEAAwE;AACxE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAiC,MAAM,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAczC;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CACxB,EAAiB,EACjB,QAA2C,EAC3C,OAAyC,EACzC,KAAuB,EACvB,sBAA6D,EAC7D,kBAA4D,EAC5D,OAA2B;IAE3B,MAAM,QAAQ,GAAG,MAAM,CACrB,KAAC,OAAO,IACN,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,EACZ,sBAAsB,EAAE,sBAAsB,EAC9C,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,OAAO,EAAE,YAAY,EACnC,eAAe,EAAE,OAAO,EAAE,eAAe,GACzC,CACH,CAAC;IACF,OAAO;QACL,EAAE;QACF,mEAAmE;QACnE,yEAAyE;QACzE,sEAAsE;QACtE,aAAa,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;QACnE,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE;KAClC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { JSX } from "react";
2
+ export declare function Markdown({ text }: {
3
+ text: string;
4
+ }): JSX.Element;
5
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,GAAG,EAAa,MAAM,OAAO,CAAC;AAQ5C,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,CAAC,OAAO,CAehE"}
@@ -0,0 +1,117 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * (5.9 / v14) Render committed assistant text as terminal Markdown via marked's
4
+ * lexer → Ink nodes. NEVER throws: a bad lex falls back to the raw text, and
5
+ * each block is rendered under its own guard so one malformed token can't take
6
+ * down the turn.
7
+ *
8
+ * Streaming contract: this renders only on COMMITTED lines. The live (still
9
+ * streaming) assistant line is rendered as plain text by `app.tsx`, so
10
+ * half-finished Markdown never flickers (5.9 §4, builds on v13's committed/live
11
+ * split).
12
+ */
13
+ import { Box, Text } from "ink";
14
+ import { lexer } from "marked";
15
+ import { CodeView } from "./code-view.js";
16
+ import {} from "./theme.js";
17
+ import { useTheme } from "./theme-context.js";
18
+ const HR_WIDTH = 40;
19
+ export function Markdown({ text }) {
20
+ const { theme, glyphs } = useTheme();
21
+ let tokens;
22
+ try {
23
+ tokens = lexer(text);
24
+ }
25
+ catch {
26
+ return _jsx(Text, { children: text });
27
+ }
28
+ return (_jsx(Box, { flexDirection: "column", children: tokens.map((t, i) => (_jsx(Block, { token: t, theme: theme, glyphs: glyphs }, i))) }));
29
+ }
30
+ function Block({ token, theme, glyphs }) {
31
+ try {
32
+ return renderBlock(token, theme, glyphs);
33
+ }
34
+ catch {
35
+ return _jsx(Text, { children: "raw" in token ? token.raw : "" });
36
+ }
37
+ }
38
+ function renderBlock(token, theme, glyphs) {
39
+ switch (token.type) {
40
+ case "space":
41
+ return _jsx(Text, { children: " " });
42
+ case "heading": {
43
+ const h = token;
44
+ return (_jsx(Text, { bold: true, color: h.depth === 1 ? theme.accent : undefined, children: renderInline(h.tokens, theme) }));
45
+ }
46
+ case "paragraph": {
47
+ const p = token;
48
+ return _jsx(Text, { children: renderInline(p.tokens, theme) });
49
+ }
50
+ case "text": {
51
+ const t = token;
52
+ return _jsx(Text, { children: t.tokens ? renderInline(t.tokens, theme) : t.text });
53
+ }
54
+ case "code": {
55
+ const c = token;
56
+ return _jsx(CodeView, { code: c.text, lang: c.lang });
57
+ }
58
+ case "blockquote": {
59
+ const bq = token;
60
+ const lines = bq.text.split("\n");
61
+ return (_jsx(Box, { flexDirection: "column", children: lines.map((line, i) => (_jsxs(Text, { dimColor: true, children: [glyphs.blockquote, " ", line] }, i))) }));
62
+ }
63
+ case "list": {
64
+ const list = token;
65
+ return (_jsx(Box, { flexDirection: "column", children: list.items.map((item, i) => {
66
+ const marker = list.ordered ? `${(Number(list.start) || 1) + i}.` : glyphs.bullet;
67
+ return (_jsxs(Text, { children: [marker, " ", renderInline(item.tokens, theme)] }, i));
68
+ }) }));
69
+ }
70
+ case "hr":
71
+ return _jsx(Text, { dimColor: true, children: glyphs.hr.repeat(HR_WIDTH) });
72
+ case "table": {
73
+ const table = token;
74
+ const header = table.header.map((c) => c.text).join(" ");
75
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: header }), table.rows.map((row, i) => (_jsx(Text, { children: row.map((c) => c.text).join(" ") }, i)))] }));
76
+ }
77
+ default: {
78
+ const raw = "raw" in token ? token.raw : "text" in token ? token.text : "";
79
+ return raw ? _jsx(Text, { children: raw }) : null;
80
+ }
81
+ }
82
+ }
83
+ /** Render inline tokens (within a paragraph/heading/list item) into Ink Text
84
+ * runs. Unknown inline types fall back to their raw text. */
85
+ function renderInline(tokens, theme) {
86
+ if (!tokens)
87
+ return [];
88
+ return tokens.map((t, i) => {
89
+ switch (t.type) {
90
+ case "text": {
91
+ const tt = t;
92
+ return tt.tokens ? _jsx(Text, { children: renderInline(tt.tokens, theme) }, i) : tt.text;
93
+ }
94
+ case "strong":
95
+ return (_jsx(Text, { bold: true, children: renderInline(t.tokens, theme) }, i));
96
+ case "em":
97
+ return (_jsx(Text, { italic: true, children: renderInline(t.tokens, theme) }, i));
98
+ case "del":
99
+ return (_jsx(Text, { strikethrough: true, children: renderInline(t.tokens, theme) }, i));
100
+ case "codespan":
101
+ return (_jsx(Text, { color: theme.synString, children: t.text }, i));
102
+ case "link": {
103
+ const link = t;
104
+ const label = renderInline(link.tokens, theme);
105
+ const showUrl = link.href && link.href !== link.text;
106
+ return (_jsxs(Text, { children: [_jsx(Text, { color: theme.accent, children: label }), showUrl ? _jsxs(Text, { dimColor: true, children: [" (", link.href, ")"] }) : null] }, i));
107
+ }
108
+ case "br":
109
+ return "\n";
110
+ case "escape":
111
+ return t.text;
112
+ default:
113
+ return "raw" in t ? t.raw : "text" in t ? t.text : "";
114
+ }
115
+ });
116
+ }
117
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.tsx"],"names":[],"mappings":"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"}
package/dist/modal.d.ts CHANGED
@@ -24,8 +24,9 @@ export declare class ModalController {
24
24
  */
25
25
  attach(setter: (node: ReactNode) => void): () => void;
26
26
  open: <T>(render: (resolve: (value: T | null) => void) => unknown) => Promise<T | null>;
27
- /** True when a modal is currently displayed. Used by ChatApp.useInput to
28
- * suppress chat input handling while the modal owns the keystrokes. */
27
+ /** True when a modal is currently displayed. (Since 5.10 the modal's own
28
+ * `Select`/`Modal` keybinding context masks chat input structurally, so this
29
+ * is no longer needed to gate input — it remains a small status accessor.) */
29
30
  isActive(): boolean;
30
31
  }
31
32
  export type { OpenModal };
@@ -1 +1 @@
1
- {"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../src/modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAA4C;IAC3D,OAAO,CAAC,MAAM,CAAqD;IAEnE;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI;IAcrD,IAAI,GAAI,CAAC,EAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,KAAK,OAAO,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAmBrF;IAEF;2EACuE;IACvE,QAAQ,IAAI,OAAO;CAGpB;AAED,YAAY,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../src/modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAA4C;IAC3D,OAAO,CAAC,MAAM,CAAqD;IAEnE;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI;IAcrD,IAAI,GAAI,CAAC,EAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,KAAK,OAAO,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAmBrF;IAEF;;kFAE8E;IAC9E,QAAQ,IAAI,OAAO;CAGpB;AAED,YAAY,EAAE,SAAS,EAAE,CAAC"}
package/dist/modal.js CHANGED
@@ -54,8 +54,9 @@ export class ModalController {
54
54
  this.setNode?.(node);
55
55
  });
56
56
  };
57
- /** True when a modal is currently displayed. Used by ChatApp.useInput to
58
- * suppress chat input handling while the modal owns the keystrokes. */
57
+ /** True when a modal is currently displayed. (Since 5.10 the modal's own
58
+ * `Select`/`Modal` keybinding context masks chat input structurally, so this
59
+ * is no longer needed to gate input — it remains a small status accessor.) */
59
60
  isActive() {
60
61
  return this.active !== null;
61
62
  }
package/dist/modal.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"modal.js","sourceRoot":"","sources":["../src/modal.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,eAAe;IAClB,OAAO,GAAuC,IAAI,CAAC;IACnD,MAAM,GAAgD,IAAI,CAAC;IAEnE;;;OAGG;IACH,MAAM,CAAC,MAAiC;QACtC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,OAAO,GAAG,EAAE;YACV,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM;gBAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACjD,gEAAgE;YAChE,mEAAmE;YACnE,6BAA6B;YAC7B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;gBAChC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACrB,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAK,MAAuD,EAAqB,EAAE;QACxF,OAAO,IAAI,OAAO,CAAW,CAAC,cAAc,EAAE,EAAE;YAC9C,uEAAuE;YACvE,IAAI,IAAI,CAAC,MAAM;gBAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YAEjD,MAAM,WAAW,GAAG,CAAC,KAAe,EAAQ,EAAE;gBAC5C,iEAAiE;gBACjE,+DAA+D;gBAC/D,gDAAgD;gBAChD,IAAI,IAAI,CAAC,MAAM,EAAE,aAAa,KAAM,WAAiC,EAAE,CAAC;oBACtE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;gBACrB,CAAC;gBACD,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;gBACrB,cAAc,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC,CAAC;YACF,IAAI,CAAC,MAAM,GAAG,EAAE,aAAa,EAAE,WAAgC,EAAE,CAAC;YAClE,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAc,CAAC;YAC9C,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF;2EACuE;IACvE,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC;IAC9B,CAAC;CACF"}
1
+ {"version":3,"file":"modal.js","sourceRoot":"","sources":["../src/modal.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,eAAe;IAClB,OAAO,GAAuC,IAAI,CAAC;IACnD,MAAM,GAAgD,IAAI,CAAC;IAEnE;;;OAGG;IACH,MAAM,CAAC,MAAiC;QACtC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,OAAO,GAAG,EAAE;YACV,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM;gBAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACjD,gEAAgE;YAChE,mEAAmE;YACnE,6BAA6B;YAC7B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;gBAChC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACrB,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAK,MAAuD,EAAqB,EAAE;QACxF,OAAO,IAAI,OAAO,CAAW,CAAC,cAAc,EAAE,EAAE;YAC9C,uEAAuE;YACvE,IAAI,IAAI,CAAC,MAAM;gBAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YAEjD,MAAM,WAAW,GAAG,CAAC,KAAe,EAAQ,EAAE;gBAC5C,iEAAiE;gBACjE,+DAA+D;gBAC/D,gDAAgD;gBAChD,IAAI,IAAI,CAAC,MAAM,EAAE,aAAa,KAAM,WAAiC,EAAE,CAAC;oBACtE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;gBACrB,CAAC;gBACD,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;gBACrB,cAAc,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC,CAAC;YACF,IAAI,CAAC,MAAM,GAAG,EAAE,aAAa,EAAE,WAAgC,EAAE,CAAC;YAClE,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAc,CAAC;YAC9C,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF;;kFAE8E;IAC9E,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC;IAC9B,CAAC;CACF"}
@@ -1,4 +1,4 @@
1
- import { type JSX } from "react";
1
+ import type { JSX } from "react";
2
2
  export interface PickableModel {
3
3
  /** Display id, e.g. "claude-opus-4-7". */
4
4
  id: string;
@@ -7,45 +7,13 @@ export interface PickableModel {
7
7
  /** True for the currently-active model, rendered with a marker. */
8
8
  current?: boolean;
9
9
  }
10
- export interface ModelPickerState {
11
- filter: string;
12
- cursor: number;
13
- }
14
- /** Subset of Ink's Key shape that the reducer cares about. Defined locally so
15
- * the reducer has no dependency on Ink at all — unit tests can drive it as
16
- * plain data without needing a TTY. */
17
- export interface PickerKey {
18
- return?: boolean;
19
- escape?: boolean;
20
- upArrow?: boolean;
21
- downArrow?: boolean;
22
- backspace?: boolean;
23
- delete?: boolean;
24
- ctrl?: boolean;
25
- meta?: boolean;
26
- }
27
- /** Subset of the active match list the reducer needs — kept as a generic
28
- * function over PickableModel for ergonomics. */
29
- export declare function filterModels(models: PickableModel[], filter: string): PickableModel[];
30
- /**
31
- * Pure reducer for the ModelPicker. Returns the next state plus an optional
32
- * `resolved` value: a `PickableModel` when the user picked, `null` when they
33
- * cancelled (Esc or Enter on empty matches), `undefined` when the keystroke
34
- * was a navigation/filter edit and the picker should stay open.
35
- *
36
- * The component just plumbs Ink's useInput into this function — extracted so
37
- * the keystroke logic is testable without ink-testing-library's stdin
38
- * limitations.
39
- */
40
- export declare function reduceModelPicker(state: ModelPickerState, char: string, key: PickerKey, models: PickableModel[]): {
41
- state: ModelPickerState;
42
- resolved?: PickableModel | null;
43
- };
44
10
  /**
45
- * Fuzzy-filter model picker modeled on oh-my-pi's `model-selector.ts`. Arrow
46
- * keys move the cursor, Enter selects, Esc cancels (resolves null). All
47
- * keystroke logic lives in {@link reduceModelPicker} so it's testable as a
48
- * pure function this component is just glue to Ink's useInput.
11
+ * (5.10 A4) Fuzzy-filter model picker now a thin wrapper over the generic
12
+ * {@link Select} (which owns all keystroke logic via the ink-ext `Select`
13
+ * context). The old per-component `useInput` + `reduceModelPicker` reducer are
14
+ * gone; their behavior (filter, ↑↓ clamp, Enter/Esc) is the Select's, covered by
15
+ * `select.test`. Signature is unchanged so `apps/cli/src/slash/model.ts` still
16
+ * renders `<ModelPicker models onChoose/>` verbatim.
49
17
  */
50
18
  export declare function ModelPicker({ models, onChoose, }: {
51
19
  models: PickableModel[];
@@ -1 +1 @@
1
- {"version":3,"file":"model-picker.d.ts","sourceRoot":"","sources":["../src/model-picker.tsx"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;uCAEuC;AACvC,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;iDACiD;AACjD,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAIrF;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,aAAa,EAAE,GACtB;IAAE,KAAK,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,IAAI,CAAA;CAAE,CAsB9D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD,GAAG,GAAG,CAAC,OAAO,CA4Cd"}
1
+ {"version":3,"file":"model-picker.d.ts","sourceRoot":"","sources":["../src/model-picker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAGjC,MAAM,WAAW,aAAa;IAC5B,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD,GAAG,GAAG,CAAC,OAAO,CAed"}
@@ -1,70 +1,19 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text, useInput } from "ink";
3
- import { useState } from "react";
4
- /** Subset of the active match list the reducer needs — kept as a generic
5
- * function over PickableModel for ergonomics. */
6
- export function filterModels(models, filter) {
7
- const lower = filter.toLowerCase();
8
- if (!lower)
9
- return models;
10
- return models.filter((m) => `${m.provider}/${m.id}`.toLowerCase().includes(lower));
11
- }
12
- /**
13
- * Pure reducer for the ModelPicker. Returns the next state plus an optional
14
- * `resolved` value: a `PickableModel` when the user picked, `null` when they
15
- * cancelled (Esc or Enter on empty matches), `undefined` when the keystroke
16
- * was a navigation/filter edit and the picker should stay open.
17
- *
18
- * The component just plumbs Ink's useInput into this function — extracted so
19
- * the keystroke logic is testable without ink-testing-library's stdin
20
- * limitations.
21
- */
22
- export function reduceModelPicker(state, char, key, models) {
23
- const matches = filterModels(models, state.filter);
24
- const safeCursor = Math.min(state.cursor, Math.max(0, matches.length - 1));
25
- if (key.escape)
26
- return { state, resolved: null };
27
- if (key.return) {
28
- const choice = matches[safeCursor];
29
- return { state, resolved: choice ?? null };
30
- }
31
- if (key.upArrow) {
32
- return { state: { ...state, cursor: Math.max(0, safeCursor - 1) } };
33
- }
34
- if (key.downArrow) {
35
- return { state: { ...state, cursor: Math.min(matches.length - 1, safeCursor + 1) } };
36
- }
37
- if (key.backspace || key.delete) {
38
- return { state: { filter: state.filter.slice(0, -1), cursor: 0 } };
39
- }
40
- if (char && !key.ctrl && !key.meta) {
41
- return { state: { filter: state.filter + char, cursor: 0 } };
42
- }
43
- return { state };
44
- }
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Select } from "./select.js";
45
3
  /**
46
- * Fuzzy-filter model picker modeled on oh-my-pi's `model-selector.ts`. Arrow
47
- * keys move the cursor, Enter selects, Esc cancels (resolves null). All
48
- * keystroke logic lives in {@link reduceModelPicker} so it's testable as a
49
- * pure function this component is just glue to Ink's useInput.
4
+ * (5.10 A4) Fuzzy-filter model picker now a thin wrapper over the generic
5
+ * {@link Select} (which owns all keystroke logic via the ink-ext `Select`
6
+ * context). The old per-component `useInput` + `reduceModelPicker` reducer are
7
+ * gone; their behavior (filter, ↑↓ clamp, Enter/Esc) is the Select's, covered by
8
+ * `select.test`. Signature is unchanged so `apps/cli/src/slash/model.ts` still
9
+ * renders `<ModelPicker models onChoose/>` verbatim.
50
10
  */
51
11
  export function ModelPicker({ models, onChoose, }) {
52
- const [state, setState] = useState({ filter: "", cursor: 0 });
53
- useInput((char, key) => {
54
- const { state: next, resolved } = reduceModelPicker(state, char, key, models);
55
- if (resolved !== undefined) {
56
- onChoose(resolved);
57
- return;
58
- }
59
- if (next !== state)
60
- setState(next);
61
- });
62
- const matches = filterModels(models, state.filter);
63
- const safeCursor = Math.min(state.cursor, Math.max(0, matches.length - 1));
64
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsx(Text, { color: "cyan", children: "Pick a model \u00B7 type to filter \u00B7 \u2191\u2193 \u00B7 Enter \u00B7 Esc" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { children: "filter: " }), _jsx(Text, { color: "yellow", children: state.filter || "(any)" })] }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [matches.length === 0 ? (_jsx(Text, { dimColor: true, children: "no models match" })) : (matches.slice(0, 10).map((m, i) => {
65
- const selected = i === safeCursor;
66
- const marker = m.current ? "●" : " ";
67
- return (_jsxs(Text, { color: selected ? "cyan" : undefined, children: [selected ? "▸ " : " ", marker, " ", _jsxs(Text, { dimColor: true, children: [m.provider, "/"] }), m.id] }, `${m.provider}/${m.id}`));
68
- })), matches.length > 10 ? (_jsxs(Text, { dimColor: true, children: ["\u2026 ", matches.length - 10, " more (type to narrow)"] })) : null] })] }));
12
+ const options = models.map((m) => ({
13
+ label: `${m.provider}/${m.id}`,
14
+ value: m,
15
+ current: m.current,
16
+ }));
17
+ return (_jsx(Select, { heading: "Pick a model \u00B7 type to filter \u00B7 \u2191\u2193 \u00B7 Enter \u00B7 Esc", options: options, filterable: true, onSelect: onChoose, onCancel: () => onChoose(null) }));
69
18
  }
70
19
  //# sourceMappingURL=model-picker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-picker.js","sourceRoot":"","sources":["../src/model-picker.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAY,MAAM,OAAO,CAAC;AA8B3C;iDACiD;AACjD,MAAM,UAAU,YAAY,CAAC,MAAuB,EAAE,MAAc;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,IAAI,CAAC,KAAK;QAAE,OAAO,MAAM,CAAC;IAC1B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACrF,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAuB,EACvB,IAAY,EACZ,GAAc,EACd,MAAuB;IAEvB,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAE3E,IAAI,GAAG,CAAC,MAAM;QAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjD,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QACnC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,IAAI,EAAE,CAAC;IAC7C,CAAC;IACD,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QAChB,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC;IACtE,CAAC;IACD,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QAClB,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC;IACvF,CAAC;IACD,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAChC,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;IACrE,CAAC;IACD,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,GAIT;IACC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAmB,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAEhF,QAAQ,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACrB,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAgB,EAAE,MAAM,CAAC,CAAC;QAC3F,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACnB,OAAO;QACT,CAAC;QACD,IAAI,IAAI,KAAK,KAAK;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAE3E,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAC,OAAO,EAAC,WAAW,EAAC,MAAM,EAAC,QAAQ,EAAE,CAAC,aAC5E,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,+FAAwD,EAC1E,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,aACf,KAAC,IAAI,2BAAgB,EACrB,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,YAAE,KAAK,CAAC,MAAM,IAAI,OAAO,GAAQ,IACjD,EACN,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,SAAS,EAAE,CAAC,aACrC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACtB,KAAC,IAAI,IAAC,QAAQ,sCAAuB,CACtC,CAAC,CAAC,CAAC,CACF,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;wBAChC,MAAM,QAAQ,GAAG,CAAC,KAAK,UAAU,CAAC;wBAClC,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;wBACrC,OAAO,CACL,MAAC,IAAI,IAA+B,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,aACrE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EACtB,MAAM,OAAE,MAAC,IAAI,IAAC,QAAQ,mBAAE,CAAC,CAAC,QAAQ,SAAS,EAC3C,CAAC,CAAC,EAAE,KAHI,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,EAAE,CAI3B,CACR,CAAC;oBACJ,CAAC,CAAC,CACH,EACA,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CACrB,MAAC,IAAI,IAAC,QAAQ,8BAAI,OAAO,CAAC,MAAM,GAAG,EAAE,8BAA8B,CACpE,CAAC,CAAC,CAAC,IAAI,IACJ,IACF,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"model-picker.js","sourceRoot":"","sources":["../src/model-picker.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAqB,MAAM,aAAa,CAAC;AAWxD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,GAIT;IACC,MAAM,OAAO,GAAkC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChE,KAAK,EAAE,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,EAAE;QAC9B,KAAK,EAAE,CAAC;QACR,OAAO,EAAE,CAAC,CAAC,OAAO;KACnB,CAAC,CAAC,CAAC;IACJ,OAAO,CACL,KAAC,MAAM,IACL,OAAO,EAAC,gFAAkD,EAC1D,OAAO,EAAE,OAAO,EAChB,UAAU,QACV,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAC9B,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { type JSX } from "react";
2
+ /** Our own small set of lively progress verbs (user decision D3 — not
3
+ * claude-code's whimsical brand list, not a bare static "Thinking…"). */
4
+ export declare const DEFAULT_VERBS: readonly ["Thinking", "Working", "Crunching", "Wrangling", "Plotting", "Cooking", "Pondering", "Tinkering", "Computing", "Noodling"];
5
+ /** Pick a verb by index (deterministic; callers vary the index per turn). */
6
+ export declare function pickVerb(index: number): string;
7
+ /** Human token count: `1234 → "1.2k"`, `980 → "980"`. */
8
+ export declare function formatTokenCount(n: number): string;
9
+ /** Human elapsed: `<60s → "8s"`, else `"2m 5s"`. */
10
+ export declare function formatElapsed(ms: number): string;
11
+ export interface ProgressInfo {
12
+ verb: string;
13
+ elapsedMs: number;
14
+ tokens: number;
15
+ /** Width budget for the text (excluding the leading glyph + space). */
16
+ width: number;
17
+ arrowDown: string;
18
+ }
19
+ /**
20
+ * Build the progress text after the glyph. Segments are appended in display
21
+ * order `esc · elapsed · tokens` but dropped from the TAIL (tokens, then
22
+ * elapsed, then esc) so the most useful hint — how to interrupt — survives
23
+ * longest. The `verb…` head is always kept (it's never dropped).
24
+ */
25
+ export declare function formatProgress({ verb, elapsedMs, tokens, width, arrowDown }: ProgressInfo): string;
26
+ export interface ProgressProps {
27
+ active: boolean;
28
+ /** Verb to display. Omitted ⇒ a lively verb is picked once on mount (varies
29
+ * per turn because the component is mounted only while busy). */
30
+ verb?: string;
31
+ /** Estimated tokens streamed this turn (≈ chars / 4). */
32
+ tokens: number;
33
+ reducedMotion?: boolean;
34
+ width?: number;
35
+ /** Test seam: fixed elapsed ms (skips the wall clock). */
36
+ elapsedMsOverride?: number;
37
+ /** Test seam: fixed frame index (skips the interval). */
38
+ frameOverride?: number;
39
+ }
40
+ export declare function Progress({ active, verb, tokens, reducedMotion, width, elapsedMsOverride, frameOverride, }: ProgressProps): JSX.Element | null;
41
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../src/progress.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAE,KAAK,GAAG,EAA+B,MAAM,OAAO,CAAC;AAQ9D;0EAC0E;AAC1E,eAAO,MAAM,aAAa,sIAWhB,CAAC;AAEX,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,yDAAyD;AACzD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,YAAY,GAAG,MAAM,CAYlG;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB;sEACkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAOD,wBAAgB,QAAQ,CAAC,EACvB,MAAM,EACN,IAAI,EACJ,MAAM,EACN,aAAqB,EACrB,KAAK,EACL,iBAAiB,EACjB,aAAa,GACd,EAAE,aAAa,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAoDpC"}
@@ -0,0 +1,122 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * (5.9 / v14) The progress / "thinking" line shown above the input while a turn
4
+ * streams: `✻ Crunching… (esc to interrupt · 8s · ↓ 1.2k tokens)`.
5
+ *
6
+ * - `formatProgress` is a pure, width-aware formatter (segments drop as the
7
+ * terminal narrows, keeping `esc to interrupt` longest). Tested without a clock.
8
+ * - The component owns a single `setInterval` for the 12-step pulse glyph,
9
+ * created in a `useEffect` keyed on `active` and cleared on unmount / when the
10
+ * turn ends (codex R1 SHOULD-2). It holds ONLY local frame state — it never
11
+ * touches the view-model, so it can't race the v13 FrameScheduler.
12
+ * - Glyph color is the accent, shifting to `stall` red after ~3s with no new
13
+ * tokens. Reduced-motion / NO_COLOR → a static dot.
14
+ */
15
+ import { Box, Text } from "ink";
16
+ import { useEffect, useRef, useState } from "react";
17
+ import stringWidth from "string-width";
18
+ import { SPINNER_FRAMES, SPINNER_STATIC } from "./theme.js";
19
+ import { useTheme } from "./theme-context.js";
20
+ const TICK_MS = 120;
21
+ const STALL_MS = 3000;
22
+ /** Our own small set of lively progress verbs (user decision D3 — not
23
+ * claude-code's whimsical brand list, not a bare static "Thinking…"). */
24
+ export const DEFAULT_VERBS = [
25
+ "Thinking",
26
+ "Working",
27
+ "Crunching",
28
+ "Wrangling",
29
+ "Plotting",
30
+ "Cooking",
31
+ "Pondering",
32
+ "Tinkering",
33
+ "Computing",
34
+ "Noodling",
35
+ ];
36
+ /** Pick a verb by index (deterministic; callers vary the index per turn). */
37
+ export function pickVerb(index) {
38
+ return DEFAULT_VERBS[Math.abs(index) % DEFAULT_VERBS.length];
39
+ }
40
+ /** Human token count: `1234 → "1.2k"`, `980 → "980"`. */
41
+ export function formatTokenCount(n) {
42
+ if (n >= 1000)
43
+ return `${(n / 1000).toFixed(1)}k`;
44
+ return String(Math.max(0, Math.round(n)));
45
+ }
46
+ /** Human elapsed: `<60s → "8s"`, else `"2m 5s"`. */
47
+ export function formatElapsed(ms) {
48
+ const s = Math.floor(ms / 1000);
49
+ if (s < 60)
50
+ return `${s}s`;
51
+ const m = Math.floor(s / 60);
52
+ const rem = s % 60;
53
+ return rem === 0 ? `${m}m` : `${m}m ${rem}s`;
54
+ }
55
+ /**
56
+ * Build the progress text after the glyph. Segments are appended in display
57
+ * order `esc · elapsed · tokens` but dropped from the TAIL (tokens, then
58
+ * elapsed, then esc) so the most useful hint — how to interrupt — survives
59
+ * longest. The `verb…` head is always kept (it's never dropped).
60
+ */
61
+ export function formatProgress({ verb, elapsedMs, tokens, width, arrowDown }) {
62
+ const head = `${verb}…`;
63
+ const segs = ["esc to interrupt", formatElapsed(elapsedMs)];
64
+ if (tokens > 0)
65
+ segs.push(`${arrowDown} ${formatTokenCount(tokens)} tokens`);
66
+ // Drop from the tail until the whole line fits the width budget.
67
+ for (let keep = segs.length; keep >= 0; keep--) {
68
+ const kept = segs.slice(0, keep);
69
+ const text = kept.length > 0 ? `${head} (${kept.join(" · ")})` : head;
70
+ if (stringWidth(text) <= width || keep === 0)
71
+ return text;
72
+ }
73
+ return head;
74
+ }
75
+ function termWidth() {
76
+ const cols = process.stdout?.columns;
77
+ return typeof cols === "number" && cols > 0 ? cols : 80;
78
+ }
79
+ export function Progress({ active, verb, tokens, reducedMotion = false, width, elapsedMsOverride, frameOverride, }) {
80
+ const { theme, glyphs } = useTheme();
81
+ const [frame, setFrame] = useState(0);
82
+ const [autoVerb] = useState(() => pickVerb(Math.floor(Math.random() * DEFAULT_VERBS.length)));
83
+ const shownVerb = verb ?? autoVerb;
84
+ const startRef = useRef(Date.now());
85
+ const lastTokenRef = useRef({ tokens, at: Date.now() });
86
+ // Reset the turn clock on each activation. `tokens` is intentionally NOT a
87
+ // dependency — we seed it once when the turn begins; live movement is read
88
+ // through `lastTokenRef` below.
89
+ useEffect(() => {
90
+ if (active) {
91
+ startRef.current = Date.now();
92
+ lastTokenRef.current = { tokens, at: Date.now() };
93
+ }
94
+ }, [active]);
95
+ // Single pulse interval, cleared on unmount / when inactive (R1 SHOULD-2).
96
+ useEffect(() => {
97
+ if (!active || reducedMotion || frameOverride !== undefined)
98
+ return;
99
+ const id = setInterval(() => setFrame((f) => (f + 1) % SPINNER_FRAMES.length), TICK_MS);
100
+ return () => clearInterval(id);
101
+ }, [active, reducedMotion, frameOverride]);
102
+ // Track token movement for stall detection.
103
+ if (tokens !== lastTokenRef.current.tokens) {
104
+ lastTokenRef.current = { tokens, at: Date.now() };
105
+ }
106
+ if (!active)
107
+ return null;
108
+ const elapsedMs = elapsedMsOverride ?? Date.now() - startRef.current;
109
+ const stalled = Date.now() - lastTokenRef.current.at > STALL_MS;
110
+ const glyphIndex = frameOverride ?? frame;
111
+ const glyph = reducedMotion ? SPINNER_STATIC : (SPINNER_FRAMES[glyphIndex % SPINNER_FRAMES.length] ?? glyphs.thinking);
112
+ const glyphColor = stalled ? theme.stall : theme.accent;
113
+ const text = formatProgress({
114
+ verb: shownVerb,
115
+ elapsedMs,
116
+ tokens,
117
+ width: Math.max(8, (width ?? termWidth()) - 2),
118
+ arrowDown: glyphs.arrowDown,
119
+ });
120
+ return (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: glyphColor, children: glyph }), _jsxs(Text, { dimColor: true, children: [" ", text] })] }));
121
+ }
122
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.tsx"],"names":[],"mappings":"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"}