@hflin/cclin 0.1.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 (200) hide show
  1. package/README.md +124 -0
  2. package/dist/index.d.ts +10 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +165 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/llm/client.d.ts +32 -0
  7. package/dist/llm/client.d.ts.map +1 -0
  8. package/dist/llm/client.js +280 -0
  9. package/dist/llm/client.js.map +1 -0
  10. package/dist/runtime/compaction.d.ts +49 -0
  11. package/dist/runtime/compaction.d.ts.map +1 -0
  12. package/dist/runtime/compaction.js +118 -0
  13. package/dist/runtime/compaction.js.map +1 -0
  14. package/dist/runtime/compaction.test.d.ts +7 -0
  15. package/dist/runtime/compaction.test.d.ts.map +1 -0
  16. package/dist/runtime/compaction.test.js +70 -0
  17. package/dist/runtime/compaction.test.js.map +1 -0
  18. package/dist/runtime/history.d.ts +34 -0
  19. package/dist/runtime/history.d.ts.map +1 -0
  20. package/dist/runtime/history.js +63 -0
  21. package/dist/runtime/history.js.map +1 -0
  22. package/dist/runtime/hooks.d.ts +54 -0
  23. package/dist/runtime/hooks.d.ts.map +1 -0
  24. package/dist/runtime/hooks.js +113 -0
  25. package/dist/runtime/hooks.js.map +1 -0
  26. package/dist/runtime/hooks.test.d.ts +7 -0
  27. package/dist/runtime/hooks.test.d.ts.map +1 -0
  28. package/dist/runtime/hooks.test.js +73 -0
  29. package/dist/runtime/hooks.test.js.map +1 -0
  30. package/dist/runtime/model-profile.d.ts +42 -0
  31. package/dist/runtime/model-profile.d.ts.map +1 -0
  32. package/dist/runtime/model-profile.js +84 -0
  33. package/dist/runtime/model-profile.js.map +1 -0
  34. package/dist/runtime/prompt.d.ts +38 -0
  35. package/dist/runtime/prompt.d.ts.map +1 -0
  36. package/dist/runtime/prompt.js +152 -0
  37. package/dist/runtime/prompt.js.map +1 -0
  38. package/dist/runtime/prompt.md +64 -0
  39. package/dist/runtime/prompt.test.d.ts +7 -0
  40. package/dist/runtime/prompt.test.d.ts.map +1 -0
  41. package/dist/runtime/prompt.test.js +38 -0
  42. package/dist/runtime/prompt.test.js.map +1 -0
  43. package/dist/runtime/react-loop.d.ts +82 -0
  44. package/dist/runtime/react-loop.d.ts.map +1 -0
  45. package/dist/runtime/react-loop.js +311 -0
  46. package/dist/runtime/react-loop.js.map +1 -0
  47. package/dist/runtime/react-loop.test.d.ts +7 -0
  48. package/dist/runtime/react-loop.test.d.ts.map +1 -0
  49. package/dist/runtime/react-loop.test.js +78 -0
  50. package/dist/runtime/react-loop.test.js.map +1 -0
  51. package/dist/runtime/session.d.ts +109 -0
  52. package/dist/runtime/session.d.ts.map +1 -0
  53. package/dist/runtime/session.js +252 -0
  54. package/dist/runtime/session.js.map +1 -0
  55. package/dist/runtime/skills.d.ts +36 -0
  56. package/dist/runtime/skills.d.ts.map +1 -0
  57. package/dist/runtime/skills.js +187 -0
  58. package/dist/runtime/skills.js.map +1 -0
  59. package/dist/runtime/skills.test.d.ts +7 -0
  60. package/dist/runtime/skills.test.d.ts.map +1 -0
  61. package/dist/runtime/skills.test.js +92 -0
  62. package/dist/runtime/skills.test.js.map +1 -0
  63. package/dist/tools/approval.d.ts +61 -0
  64. package/dist/tools/approval.d.ts.map +1 -0
  65. package/dist/tools/approval.js +119 -0
  66. package/dist/tools/approval.js.map +1 -0
  67. package/dist/tools/approval.test.d.ts +9 -0
  68. package/dist/tools/approval.test.d.ts.map +1 -0
  69. package/dist/tools/approval.test.js +112 -0
  70. package/dist/tools/approval.test.js.map +1 -0
  71. package/dist/tools/bash.d.ts +6 -0
  72. package/dist/tools/bash.d.ts.map +1 -0
  73. package/dist/tools/bash.js +58 -0
  74. package/dist/tools/bash.js.map +1 -0
  75. package/dist/tools/edit-file.d.ts +6 -0
  76. package/dist/tools/edit-file.d.ts.map +1 -0
  77. package/dist/tools/edit-file.js +58 -0
  78. package/dist/tools/edit-file.js.map +1 -0
  79. package/dist/tools/get-memory.d.ts +9 -0
  80. package/dist/tools/get-memory.d.ts.map +1 -0
  81. package/dist/tools/get-memory.js +56 -0
  82. package/dist/tools/get-memory.js.map +1 -0
  83. package/dist/tools/list-directory.d.ts +6 -0
  84. package/dist/tools/list-directory.d.ts.map +1 -0
  85. package/dist/tools/list-directory.js +68 -0
  86. package/dist/tools/list-directory.js.map +1 -0
  87. package/dist/tools/mcp-client.d.ts +74 -0
  88. package/dist/tools/mcp-client.d.ts.map +1 -0
  89. package/dist/tools/mcp-client.js +129 -0
  90. package/dist/tools/mcp-client.js.map +1 -0
  91. package/dist/tools/mcp-config.d.ts +31 -0
  92. package/dist/tools/mcp-config.d.ts.map +1 -0
  93. package/dist/tools/mcp-config.js +55 -0
  94. package/dist/tools/mcp-config.js.map +1 -0
  95. package/dist/tools/mcp-registry.d.ts +39 -0
  96. package/dist/tools/mcp-registry.d.ts.map +1 -0
  97. package/dist/tools/mcp-registry.js +88 -0
  98. package/dist/tools/mcp-registry.js.map +1 -0
  99. package/dist/tools/orchestrator.d.ts +52 -0
  100. package/dist/tools/orchestrator.d.ts.map +1 -0
  101. package/dist/tools/orchestrator.js +190 -0
  102. package/dist/tools/orchestrator.js.map +1 -0
  103. package/dist/tools/orchestrator.test.d.ts +8 -0
  104. package/dist/tools/orchestrator.test.d.ts.map +1 -0
  105. package/dist/tools/orchestrator.test.js +122 -0
  106. package/dist/tools/orchestrator.test.js.map +1 -0
  107. package/dist/tools/read-file.d.ts +6 -0
  108. package/dist/tools/read-file.d.ts.map +1 -0
  109. package/dist/tools/read-file.js +50 -0
  110. package/dist/tools/read-file.js.map +1 -0
  111. package/dist/tools/registry.d.ts +55 -0
  112. package/dist/tools/registry.d.ts.map +1 -0
  113. package/dist/tools/registry.js +75 -0
  114. package/dist/tools/registry.js.map +1 -0
  115. package/dist/tools/registry.test.d.ts +8 -0
  116. package/dist/tools/registry.test.d.ts.map +1 -0
  117. package/dist/tools/registry.test.js +100 -0
  118. package/dist/tools/registry.test.js.map +1 -0
  119. package/dist/tools/router.d.ts +62 -0
  120. package/dist/tools/router.d.ts.map +1 -0
  121. package/dist/tools/router.js +119 -0
  122. package/dist/tools/router.js.map +1 -0
  123. package/dist/tools/router.test.d.ts +7 -0
  124. package/dist/tools/router.test.d.ts.map +1 -0
  125. package/dist/tools/router.test.js +102 -0
  126. package/dist/tools/router.test.js.map +1 -0
  127. package/dist/tools/safety.d.ts +16 -0
  128. package/dist/tools/safety.d.ts.map +1 -0
  129. package/dist/tools/safety.js +81 -0
  130. package/dist/tools/safety.js.map +1 -0
  131. package/dist/tools/safety.test.d.ts +7 -0
  132. package/dist/tools/safety.test.d.ts.map +1 -0
  133. package/dist/tools/safety.test.js +104 -0
  134. package/dist/tools/safety.test.js.map +1 -0
  135. package/dist/tools/search-files.d.ts +9 -0
  136. package/dist/tools/search-files.d.ts.map +1 -0
  137. package/dist/tools/search-files.js +114 -0
  138. package/dist/tools/search-files.js.map +1 -0
  139. package/dist/tools/update-plan.d.ts +9 -0
  140. package/dist/tools/update-plan.d.ts.map +1 -0
  141. package/dist/tools/update-plan.js +99 -0
  142. package/dist/tools/update-plan.js.map +1 -0
  143. package/dist/tools/write-file.d.ts +6 -0
  144. package/dist/tools/write-file.d.ts.map +1 -0
  145. package/dist/tools/write-file.js +41 -0
  146. package/dist/tools/write-file.js.map +1 -0
  147. package/dist/tui/app.d.ts +31 -0
  148. package/dist/tui/app.d.ts.map +1 -0
  149. package/dist/tui/app.js +121 -0
  150. package/dist/tui/app.js.map +1 -0
  151. package/dist/tui/chatwidget/markdown_renderer.d.ts +20 -0
  152. package/dist/tui/chatwidget/markdown_renderer.d.ts.map +1 -0
  153. package/dist/tui/chatwidget/markdown_renderer.js +188 -0
  154. package/dist/tui/chatwidget/markdown_renderer.js.map +1 -0
  155. package/dist/tui/cjk_text.d.ts +25 -0
  156. package/dist/tui/cjk_text.d.ts.map +1 -0
  157. package/dist/tui/cjk_text.js +84 -0
  158. package/dist/tui/cjk_text.js.map +1 -0
  159. package/dist/tui/cjk_text.test.d.ts +2 -0
  160. package/dist/tui/cjk_text.test.d.ts.map +1 -0
  161. package/dist/tui/cjk_text.test.js +62 -0
  162. package/dist/tui/cjk_text.test.js.map +1 -0
  163. package/dist/tui/composer_input.d.ts +31 -0
  164. package/dist/tui/composer_input.d.ts.map +1 -0
  165. package/dist/tui/composer_input.js +184 -0
  166. package/dist/tui/composer_input.js.map +1 -0
  167. package/dist/tui/composer_input.test.d.ts +2 -0
  168. package/dist/tui/composer_input.test.d.ts.map +1 -0
  169. package/dist/tui/composer_input.test.js +87 -0
  170. package/dist/tui/composer_input.test.js.map +1 -0
  171. package/dist/tui/input.d.ts +21 -0
  172. package/dist/tui/input.d.ts.map +1 -0
  173. package/dist/tui/input.js +166 -0
  174. package/dist/tui/input.js.map +1 -0
  175. package/dist/tui/output.d.ts +17 -0
  176. package/dist/tui/output.d.ts.map +1 -0
  177. package/dist/tui/output.js +104 -0
  178. package/dist/tui/output.js.map +1 -0
  179. package/dist/tui/state/chat_timeline.d.ts +50 -0
  180. package/dist/tui/state/chat_timeline.d.ts.map +1 -0
  181. package/dist/tui/state/chat_timeline.js +129 -0
  182. package/dist/tui/state/chat_timeline.js.map +1 -0
  183. package/dist/tui/types.d.ts +45 -0
  184. package/dist/tui/types.d.ts.map +1 -0
  185. package/dist/tui/types.js +14 -0
  186. package/dist/tui/types.js.map +1 -0
  187. package/dist/types.d.ts +435 -0
  188. package/dist/types.d.ts.map +1 -0
  189. package/dist/types.js +8 -0
  190. package/dist/types.js.map +1 -0
  191. package/dist/utils/tokenizer.d.ts +21 -0
  192. package/dist/utils/tokenizer.d.ts.map +1 -0
  193. package/dist/utils/tokenizer.js +71 -0
  194. package/dist/utils/tokenizer.js.map +1 -0
  195. package/dist/utils/tokenizer.test.d.ts +7 -0
  196. package/dist/utils/tokenizer.test.d.ts.map +1 -0
  197. package/dist/utils/tokenizer.test.js +51 -0
  198. package/dist/utils/tokenizer.test.js.map +1 -0
  199. package/package.json +41 -0
  200. package/src/runtime/prompt.md +64 -0
@@ -0,0 +1,188 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * @file Markdown 渲染器 — 将 Markdown 文本解析为 Ink 组件。
4
+ *
5
+ * 自写 parser(正则逐行解析),不依赖外部库。
6
+ * 参考 memo-code/packages/tui/src/chatwidget/MarkdownRenderer.tsx
7
+ *
8
+ * 支持:
9
+ * - heading (# ## ###)
10
+ * - paragraph
11
+ * - code block (```)
12
+ * - list (- * •)
13
+ * - blockquote (>)
14
+ * - horizontal rule (---)
15
+ * - inline: **bold**, *italic*, `code`, [link](url)
16
+ */
17
+ import { memo } from 'react';
18
+ import { Box, Text } from 'ink';
19
+ function parseBlocks(raw) {
20
+ const lines = raw.split('\n');
21
+ const blocks = [];
22
+ let i = 0;
23
+ while (i < lines.length) {
24
+ const line = lines[i] ?? '';
25
+ // Code block
26
+ if (line.trimStart().startsWith('```')) {
27
+ const lang = line.trimStart().slice(3).trim();
28
+ const codeLines = [];
29
+ i++;
30
+ while (i < lines.length) {
31
+ const cl = lines[i] ?? '';
32
+ if (cl.trimStart().startsWith('```')) {
33
+ i++;
34
+ break;
35
+ }
36
+ codeLines.push(cl);
37
+ i++;
38
+ }
39
+ blocks.push({ type: 'code_block', lang, code: codeLines.join('\n') });
40
+ continue;
41
+ }
42
+ // Horizontal rule
43
+ if (/^-{3,}$/.test(line.trim()) || /^\*{3,}$/.test(line.trim())) {
44
+ blocks.push({ type: 'hr' });
45
+ i++;
46
+ continue;
47
+ }
48
+ // Heading
49
+ const headingMatch = /^(#{1,3})\s+(.+)/.exec(line);
50
+ if (headingMatch) {
51
+ blocks.push({
52
+ type: 'heading',
53
+ level: (headingMatch[1] ?? '#').length,
54
+ text: headingMatch[2] ?? '',
55
+ });
56
+ i++;
57
+ continue;
58
+ }
59
+ // Blockquote
60
+ if (line.trimStart().startsWith('> ')) {
61
+ blocks.push({ type: 'blockquote', text: line.replace(/^\s*>\s?/, '') });
62
+ i++;
63
+ continue;
64
+ }
65
+ // List item
66
+ const listMatch = /^(\s*)[-*•]\s+(.+)/.exec(line);
67
+ if (listMatch) {
68
+ blocks.push({
69
+ type: 'list_item',
70
+ indent: (listMatch[1] ?? '').length,
71
+ text: listMatch[2] ?? '',
72
+ });
73
+ i++;
74
+ continue;
75
+ }
76
+ // Table (lines starting with |)
77
+ if (/^\s*\|/.test(line)) {
78
+ const tableLines = [];
79
+ while (i < lines.length && /^\s*\|/.test(lines[i] ?? '')) {
80
+ tableLines.push(lines[i]);
81
+ i++;
82
+ }
83
+ // Parse cells: split by |, trim, filter empty
84
+ const dataRows = tableLines
85
+ .filter(l => !/^\s*\|[\s-:|]+\|\s*$/.test(l)) // skip separator rows
86
+ .map(l => l.split('|').map(c => c.trim()).filter(Boolean));
87
+ if (dataRows.length > 0) {
88
+ blocks.push({
89
+ type: 'table',
90
+ headers: dataRows[0],
91
+ rows: dataRows.slice(1),
92
+ });
93
+ }
94
+ continue;
95
+ }
96
+ // Empty line → skip
97
+ if (line.trim() === '') {
98
+ i++;
99
+ continue;
100
+ }
101
+ // Paragraph (collect consecutive non-empty lines)
102
+ const paraLines = [line];
103
+ i++;
104
+ while (i < lines.length) {
105
+ const pl = lines[i] ?? '';
106
+ if (pl.trim() === '' || pl.trimStart().startsWith('#') ||
107
+ pl.trimStart().startsWith('```') || pl.trimStart().startsWith('> ') ||
108
+ /^(\s*)[-*•]\s+/.test(pl) || /^-{3,}$/.test(pl.trim()))
109
+ break;
110
+ paraLines.push(pl);
111
+ i++;
112
+ }
113
+ blocks.push({ type: 'paragraph', text: paraLines.join(' ') });
114
+ }
115
+ return blocks;
116
+ }
117
+ function parseInline(raw) {
118
+ const nodes = [];
119
+ // Combined regex: **bold**, *italic*, `code`, [text](url)
120
+ const re = /\*\*(.+?)\*\*|\*(.+?)\*|`([^`]+)`|\[([^\]]+)\]\(([^)]+)\)/g;
121
+ let lastIndex = 0;
122
+ let m;
123
+ while ((m = re.exec(raw)) !== null) {
124
+ if (m.index > lastIndex) {
125
+ nodes.push({ type: 'text', text: raw.slice(lastIndex, m.index) });
126
+ }
127
+ if (m[1] !== undefined)
128
+ nodes.push({ type: 'bold', text: m[1] });
129
+ else if (m[2] !== undefined)
130
+ nodes.push({ type: 'italic', text: m[2] });
131
+ else if (m[3] !== undefined)
132
+ nodes.push({ type: 'code', text: m[3] });
133
+ else if (m[4] !== undefined && m[5] !== undefined) {
134
+ nodes.push({ type: 'link', text: m[4], url: m[5] });
135
+ }
136
+ lastIndex = m.index + m[0].length;
137
+ }
138
+ if (lastIndex < raw.length) {
139
+ nodes.push({ type: 'text', text: raw.slice(lastIndex) });
140
+ }
141
+ return nodes.length > 0 ? nodes : [{ type: 'text', text: raw }];
142
+ }
143
+ // ─── Ink 渲染组件 ────────────────────────────────────────────────────────
144
+ function InlineText({ text }) {
145
+ const nodes = parseInline(text);
146
+ return (_jsx(Text, { children: nodes.map((n, i) => {
147
+ switch (n.type) {
148
+ case 'bold': return _jsx(Text, { bold: true, children: n.text }, i);
149
+ case 'italic': return _jsx(Text, { italic: true, children: n.text }, i);
150
+ case 'code': return _jsxs(Text, { color: "cyan", children: ["`", n.text, "`"] }, i);
151
+ case 'link': return _jsx(Text, { color: "blue", children: n.text }, i);
152
+ default: return _jsx(Text, { children: n.text }, i);
153
+ }
154
+ }) }));
155
+ }
156
+ function BlockRenderer({ block }) {
157
+ switch (block.type) {
158
+ case 'heading':
159
+ return (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { bold: true, color: block.level === 1 ? 'white' : 'gray', children: ['#'.repeat(block.level), " ", block.text] }) }));
160
+ case 'code_block':
161
+ return (_jsxs(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, marginY: 0, flexDirection: "column", children: [block.lang ? _jsx(Text, { color: "gray", children: block.lang }) : null, _jsx(Text, { color: "green", children: block.code })] }));
162
+ case 'list_item': {
163
+ const pad = ' '.repeat(Math.floor(block.indent / 2));
164
+ return (_jsxs(Box, { children: [_jsxs(Text, { children: [pad, "\u2022 "] }), _jsx(InlineText, { text: block.text })] }));
165
+ }
166
+ case 'blockquote':
167
+ return (_jsxs(Box, { children: [_jsx(Text, { color: "gray", children: "\u2502 " }), _jsx(InlineText, { text: block.text })] }));
168
+ case 'table': {
169
+ const allRows = [block.headers, ...block.rows];
170
+ const colCount = block.headers.length;
171
+ // Calculate column widths
172
+ const colWidths = Array.from({ length: colCount }, (_, ci) => Math.max(3, ...allRows.map(r => (r[ci] ?? '').length)));
173
+ const sep = '┼' + colWidths.map(w => '─'.repeat(w + 2)).join('┼') + '┼';
174
+ const fmtRow = (cells, bold) => (_jsxs(Text, { ...(bold ? { bold: true } : {}), children: ['│', cells.map((c, ci) => ` ${(c ?? '').padEnd(colWidths[ci] ?? 3)} │`).join('')] }));
175
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "gray", children: sep }), fmtRow(block.headers, true), _jsx(Text, { color: "gray", children: sep }), block.rows.map((row, ri) => (_jsx(Box, { flexDirection: "column", children: fmtRow(row, false) }, ri))), _jsx(Text, { color: "gray", children: sep })] }));
176
+ }
177
+ case 'hr':
178
+ return _jsx(Text, { color: "gray", children: '─'.repeat(40) });
179
+ case 'paragraph':
180
+ return _jsx(InlineText, { text: block.text });
181
+ }
182
+ }
183
+ // ─── 导出组件 ─────────────────────────────────────────────────────────────
184
+ export const MarkdownRenderer = memo(function MarkdownRenderer({ content, }) {
185
+ const blocks = parseBlocks(content);
186
+ return (_jsx(Box, { flexDirection: "column", children: blocks.map((block, i) => (_jsx(BlockRenderer, { block: block }, i))) }));
187
+ });
188
+ //# sourceMappingURL=markdown_renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown_renderer.js","sourceRoot":"","sources":["../../../src/tui/chatwidget/markdown_renderer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @file CJK-aware text utilities — character width + word wrap.
3
+ *
4
+ * Provides `charWidth()` for terminal cell width of any character,
5
+ * and `wrapTextCJK()` for column-aware soft wrapping that prevents
6
+ * CJK double-width chars from overflowing the terminal edge.
7
+ */
8
+ /**
9
+ * Returns the display width of a character in a terminal.
10
+ * CJK ideographs and fullwidth forms → 2, control chars → 0, others → 1.
11
+ */
12
+ export declare function charWidth(char: string): number;
13
+ /**
14
+ * Returns the display width of a string in terminal cells.
15
+ */
16
+ export declare function stringWidth(str: string): number;
17
+ /**
18
+ * Wraps text into lines that fit within `columns` terminal cells.
19
+ *
20
+ * Unlike Ink's built-in wrapping, this correctly accounts for
21
+ * CJK double-width characters, preventing the "floating char" bug
22
+ * where a 2-cell char overflows onto the next line.
23
+ */
24
+ export declare function wrapTextCJK(text: string, columns: number): string[];
25
+ //# sourceMappingURL=cjk_text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cjk_text.d.ts","sourceRoot":"","sources":["../../src/tui/cjk_text.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuB9C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM/C;AAID;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAmCnE"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @file CJK-aware text utilities — character width + word wrap.
3
+ *
4
+ * Provides `charWidth()` for terminal cell width of any character,
5
+ * and `wrapTextCJK()` for column-aware soft wrapping that prevents
6
+ * CJK double-width chars from overflowing the terminal edge.
7
+ */
8
+ // ─── Character Width ──────────────────────────────────────────────────────
9
+ /**
10
+ * Returns the display width of a character in a terminal.
11
+ * CJK ideographs and fullwidth forms → 2, control chars → 0, others → 1.
12
+ */
13
+ export function charWidth(char) {
14
+ const cp = char.codePointAt(0);
15
+ if (cp === undefined)
16
+ return 0;
17
+ if (cp < 0x20)
18
+ return 0; // control chars
19
+ // CJK Unified Ideographs, Extension A/B
20
+ if ((cp >= 0x4e00 && cp <= 0x9fff) ||
21
+ (cp >= 0x3400 && cp <= 0x4dbf) ||
22
+ (cp >= 0x20000 && cp <= 0x2a6df) ||
23
+ (cp >= 0xf900 && cp <= 0xfaff) ||
24
+ // Fullwidth Forms
25
+ (cp >= 0xff01 && cp <= 0xff60) ||
26
+ (cp >= 0xffe0 && cp <= 0xffe6) ||
27
+ // CJK Radicals, Kangxi, Ideographic Description
28
+ (cp >= 0x2e80 && cp <= 0x303e) ||
29
+ // Hangul Syllables
30
+ (cp >= 0xac00 && cp <= 0xd7a3) ||
31
+ // CJK Compatibility Ideographs Supplement
32
+ (cp >= 0x2f800 && cp <= 0x2fa1f)) {
33
+ return 2;
34
+ }
35
+ return 1;
36
+ }
37
+ /**
38
+ * Returns the display width of a string in terminal cells.
39
+ */
40
+ export function stringWidth(str) {
41
+ let w = 0;
42
+ for (const ch of str) {
43
+ w += charWidth(ch);
44
+ }
45
+ return w;
46
+ }
47
+ // ─── CJK-Aware Wrapping ──────────────────────────────────────────────────
48
+ /**
49
+ * Wraps text into lines that fit within `columns` terminal cells.
50
+ *
51
+ * Unlike Ink's built-in wrapping, this correctly accounts for
52
+ * CJK double-width characters, preventing the "floating char" bug
53
+ * where a 2-cell char overflows onto the next line.
54
+ */
55
+ export function wrapTextCJK(text, columns) {
56
+ if (columns < 1)
57
+ columns = 1;
58
+ const result = [];
59
+ // Split on explicit newlines first
60
+ const paragraphs = text.split('\n');
61
+ for (const para of paragraphs) {
62
+ if (para === '') {
63
+ result.push('');
64
+ continue;
65
+ }
66
+ let line = '';
67
+ let lineWidth = 0;
68
+ for (const ch of para) {
69
+ const cw = charWidth(ch);
70
+ // If adding this char would exceed columns, start a new line
71
+ if (lineWidth + cw > columns && line.length > 0) {
72
+ result.push(line);
73
+ line = '';
74
+ lineWidth = 0;
75
+ }
76
+ line += ch;
77
+ lineWidth += cw;
78
+ }
79
+ // Push remaining content
80
+ result.push(line);
81
+ }
82
+ return result;
83
+ }
84
+ //# sourceMappingURL=cjk_text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cjk_text.js","sourceRoot":"","sources":["../../src/tui/cjk_text.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,6EAA6E;AAE7E;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IAClC,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;IAC9B,IAAI,EAAE,KAAK,SAAS;QAAE,OAAO,CAAC,CAAA;IAC9B,IAAI,EAAE,GAAG,IAAI;QAAE,OAAO,CAAC,CAAA,CAAC,gBAAgB;IACxC,wCAAwC;IACxC,IACI,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,OAAO,IAAI,EAAE,IAAI,OAAO,CAAC;QAChC,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,kBAAkB;QAClB,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,gDAAgD;QAChD,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,mBAAmB;QACnB,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,0CAA0C;QAC1C,CAAC,EAAE,IAAI,OAAO,IAAI,EAAE,IAAI,OAAO,CAAC,EAClC,CAAC;QACC,OAAO,CAAC,CAAA;IACZ,CAAC;IACD,OAAO,CAAC,CAAA;AACZ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACnC,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACnB,CAAC,IAAI,SAAS,CAAC,EAAE,CAAC,CAAA;IACtB,CAAC;IACD,OAAO,CAAC,CAAA;AACZ,CAAC;AAED,4EAA4E;AAE5E;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,OAAe;IACrD,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,CAAA;IAC5B,MAAM,MAAM,GAAa,EAAE,CAAA;IAE3B,mCAAmC;IACnC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAEnC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC5B,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACf,SAAQ;QACZ,CAAC;QAED,IAAI,IAAI,GAAG,EAAE,CAAA;QACb,IAAI,SAAS,GAAG,CAAC,CAAA;QAEjB,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;YACpB,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,CAAA;YAExB,6DAA6D;YAC7D,IAAI,SAAS,GAAG,EAAE,GAAG,OAAO,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACjB,IAAI,GAAG,EAAE,CAAA;gBACT,SAAS,GAAG,CAAC,CAAA;YACjB,CAAC;YAED,IAAI,IAAI,EAAE,CAAA;YACV,SAAS,IAAI,EAAE,CAAA;QACnB,CAAC;QAED,yBAAyB;QACzB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrB,CAAC;IAED,OAAO,MAAM,CAAA;AACjB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cjk_text.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cjk_text.test.d.ts","sourceRoot":"","sources":["../../src/tui/cjk_text.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,62 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { charWidth, stringWidth, wrapTextCJK } from './cjk_text.js';
3
+ describe('charWidth', () => {
4
+ it('returns 1 for ASCII', () => {
5
+ expect(charWidth('a')).toBe(1);
6
+ expect(charWidth('Z')).toBe(1);
7
+ expect(charWidth('!')).toBe(1);
8
+ });
9
+ it('returns 2 for CJK ideographs', () => {
10
+ expect(charWidth('中')).toBe(2);
11
+ expect(charWidth('可')).toBe(2);
12
+ expect(charWidth('你')).toBe(2);
13
+ });
14
+ it('returns 2 for fullwidth forms', () => {
15
+ expect(charWidth('A')).toBe(2); // U+FF21
16
+ });
17
+ it('returns 0 for control chars', () => {
18
+ expect(charWidth('\t')).toBe(0);
19
+ expect(charWidth('\x00')).toBe(0);
20
+ });
21
+ });
22
+ describe('stringWidth', () => {
23
+ it('counts ASCII correctly', () => {
24
+ expect(stringWidth('hello')).toBe(5);
25
+ });
26
+ it('counts CJK correctly', () => {
27
+ expect(stringWidth('你好')).toBe(4);
28
+ });
29
+ it('counts mixed text correctly', () => {
30
+ expect(stringWidth('hi你好')).toBe(6);
31
+ });
32
+ });
33
+ describe('wrapTextCJK', () => {
34
+ it('no wrapping needed for short ASCII', () => {
35
+ expect(wrapTextCJK('hello', 80)).toEqual(['hello']);
36
+ });
37
+ it('wraps ASCII at column boundary', () => {
38
+ expect(wrapTextCJK('abcdef', 3)).toEqual(['abc', 'def']);
39
+ });
40
+ it('wraps CJK text respecting double width', () => {
41
+ // 3 CJK chars = 6 cells. columns=5 → first line fits 2 chars (4 cells), 3rd on next
42
+ expect(wrapTextCJK('你好吗', 5)).toEqual(['你好', '吗']);
43
+ });
44
+ it('prevents CJK char from overflowing', () => {
45
+ // "abc" = 3 cells, "可" = 2 cells. columns=4 → "abc" fits, "可" doesn't (3+2=5>4), wraps
46
+ expect(wrapTextCJK('abc可', 4)).toEqual(['abc', '可']);
47
+ });
48
+ it('handles mixed ASCII and CJK', () => {
49
+ // "hi你" = 2+2=4 cells, "好" = 2 cells. columns=5 → "hi你" fits (4), "好" fits too (4+2=6>5)
50
+ expect(wrapTextCJK('hi你好', 5)).toEqual(['hi你', '好']);
51
+ });
52
+ it('preserves explicit newlines', () => {
53
+ expect(wrapTextCJK('a\nb', 80)).toEqual(['a', 'b']);
54
+ });
55
+ it('handles empty lines from newlines', () => {
56
+ expect(wrapTextCJK('a\n\nb', 80)).toEqual(['a', '', 'b']);
57
+ });
58
+ it('handles empty string', () => {
59
+ expect(wrapTextCJK('', 80)).toEqual(['']);
60
+ });
61
+ });
62
+ //# sourceMappingURL=cjk_text.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cjk_text.test.js","sourceRoot":"","sources":["../../src/tui/cjk_text.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @file Editor buffer utilities for TUI input.
3
+ *
4
+ * Ported from memo-code's composer_input.ts — provides:
5
+ * - Surrogate-pair-safe cursor clamping
6
+ * - Character-aware cursor movement
7
+ * - Terminal-width-aware wrapped cursor layout
8
+ */
9
+ export type EditorBuffer = {
10
+ value: string;
11
+ cursor: number;
12
+ };
13
+ export type WrappedCursorLine = {
14
+ text: string;
15
+ start: number;
16
+ end: number;
17
+ };
18
+ export type WrappedCursorLayout = {
19
+ lines: WrappedCursorLine[];
20
+ row: number;
21
+ cursorInRow: number;
22
+ };
23
+ export declare function clampCursorToBoundary(value: string, cursor: number): number;
24
+ export declare function nextCursorIndex(value: string, cursor: number): number;
25
+ export declare function previousCursorIndex(value: string, cursor: number): number;
26
+ export declare function moveCursorLeft(value: string, cursor: number): number;
27
+ export declare function moveCursorRight(value: string, cursor: number): number;
28
+ export declare function insertAtCursor(value: string, cursor: number, input: string): EditorBuffer;
29
+ export declare function backspaceAtCursor(value: string, cursor: number): EditorBuffer;
30
+ export declare function getWrappedCursorLayout(value: string, cursor: number, columns: number): WrappedCursorLayout;
31
+ //# sourceMappingURL=composer_input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer_input.d.ts","sourceRoot":"","sources":["../../src/tui/composer_input.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,YAAY,GAAG;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAC9B,KAAK,EAAE,iBAAiB,EAAE,CAAA;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;CACtB,CAAA;AAkDD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAkB3E;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAMrE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAWzE;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAErE;AAID,wBAAgB,cAAc,CAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACd,YAAY,CAUd;AAED,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACf,YAAY,CAMd;AAID,wBAAgB,sBAAsB,CAClC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GAChB,mBAAmB,CAqErB"}
@@ -0,0 +1,184 @@
1
+ /**
2
+ * @file Editor buffer utilities for TUI input.
3
+ *
4
+ * Ported from memo-code's composer_input.ts — provides:
5
+ * - Surrogate-pair-safe cursor clamping
6
+ * - Character-aware cursor movement
7
+ * - Terminal-width-aware wrapped cursor layout
8
+ */
9
+ // ─── Surrogate pair helpers ───────────────────────────────────────────────
10
+ const SURROGATE_HIGH_MIN = 0xd800;
11
+ const SURROGATE_HIGH_MAX = 0xdbff;
12
+ const SURROGATE_LOW_MIN = 0xdc00;
13
+ const SURROGATE_LOW_MAX = 0xdfff;
14
+ function isHighSurrogate(v) {
15
+ return v >= SURROGATE_HIGH_MIN && v <= SURROGATE_HIGH_MAX;
16
+ }
17
+ function isLowSurrogate(v) {
18
+ return v >= SURROGATE_LOW_MIN && v <= SURROGATE_LOW_MAX;
19
+ }
20
+ // ─── Character width (lightweight, no external dep) ───────────────────────
21
+ /**
22
+ * Returns the display width of a character in a terminal.
23
+ * CJK ideographs and fullwidth forms → 2, control chars → 0, others → 1.
24
+ */
25
+ function charWidth(char) {
26
+ const cp = char.codePointAt(0);
27
+ if (cp === undefined)
28
+ return 0;
29
+ if (cp < 0x20)
30
+ return 0; // control chars
31
+ // CJK Unified Ideographs, CJK Extension A/B, CJK Compatibility
32
+ if ((cp >= 0x4e00 && cp <= 0x9fff) ||
33
+ (cp >= 0x3400 && cp <= 0x4dbf) ||
34
+ (cp >= 0x20000 && cp <= 0x2a6df) ||
35
+ (cp >= 0xf900 && cp <= 0xfaff) ||
36
+ // Fullwidth Forms
37
+ (cp >= 0xff01 && cp <= 0xff60) ||
38
+ (cp >= 0xffe0 && cp <= 0xffe6) ||
39
+ // CJK Radicals, Kangxi, Ideographic Description
40
+ (cp >= 0x2e80 && cp <= 0x303e) ||
41
+ // Hangul Syllables
42
+ (cp >= 0xac00 && cp <= 0xd7a3) ||
43
+ // CJK Compatibility Ideographs Supplement
44
+ (cp >= 0x2f800 && cp <= 0x2fa1f)) {
45
+ return 2;
46
+ }
47
+ return 1;
48
+ }
49
+ // ─── Cursor boundary helpers ──────────────────────────────────────────────
50
+ export function clampCursorToBoundary(value, cursor) {
51
+ if (!Number.isFinite(cursor))
52
+ return 0;
53
+ if (cursor <= 0)
54
+ return 0;
55
+ if (cursor >= value.length)
56
+ return value.length;
57
+ if (value.length === 0)
58
+ return 0;
59
+ const normalized = Math.floor(cursor);
60
+ if (normalized <= 0)
61
+ return 0;
62
+ if (normalized >= value.length)
63
+ return value.length;
64
+ const current = value.charCodeAt(normalized);
65
+ const previous = value.charCodeAt(normalized - 1);
66
+ if (isLowSurrogate(current) && isHighSurrogate(previous)) {
67
+ return normalized - 1;
68
+ }
69
+ return normalized;
70
+ }
71
+ export function nextCursorIndex(value, cursor) {
72
+ const safe = clampCursorToBoundary(value, cursor);
73
+ if (safe >= value.length)
74
+ return value.length;
75
+ const cp = value.codePointAt(safe);
76
+ if (cp === undefined)
77
+ return Math.min(value.length, safe + 1);
78
+ return Math.min(value.length, safe + (cp > 0xffff ? 2 : 1));
79
+ }
80
+ export function previousCursorIndex(value, cursor) {
81
+ const safe = clampCursorToBoundary(value, cursor);
82
+ if (safe <= 0)
83
+ return 0;
84
+ const prev = safe - 1;
85
+ if (prev <= 0)
86
+ return prev;
87
+ const currentCode = value.charCodeAt(prev);
88
+ const beforeCode = value.charCodeAt(prev - 1);
89
+ if (isLowSurrogate(currentCode) && isHighSurrogate(beforeCode)) {
90
+ return prev - 1;
91
+ }
92
+ return prev;
93
+ }
94
+ // ─── Cursor movement ──────────────────────────────────────────────────────
95
+ export function moveCursorLeft(value, cursor) {
96
+ return previousCursorIndex(value, cursor);
97
+ }
98
+ export function moveCursorRight(value, cursor) {
99
+ return nextCursorIndex(value, cursor);
100
+ }
101
+ // ─── Editor operations ────────────────────────────────────────────────────
102
+ export function insertAtCursor(value, cursor, input) {
103
+ const safe = clampCursorToBoundary(value, cursor);
104
+ if (!input)
105
+ return { value, cursor: safe };
106
+ // Normalize pasted line endings: \r\n → \n, lone \r → \n
107
+ const normalized = input.replace(/\r\n?/g, '\n');
108
+ if (!normalized)
109
+ return { value, cursor: safe };
110
+ const next = `${value.slice(0, safe)}${normalized}${value.slice(safe)}`;
111
+ return { value: next, cursor: safe + normalized.length };
112
+ }
113
+ export function backspaceAtCursor(value, cursor) {
114
+ const safe = clampCursorToBoundary(value, cursor);
115
+ if (safe <= 0)
116
+ return { value, cursor: safe };
117
+ const start = previousCursorIndex(value, safe);
118
+ const next = `${value.slice(0, start)}${value.slice(safe)}`;
119
+ return { value: next, cursor: start };
120
+ }
121
+ // ─── Wrapped cursor layout ────────────────────────────────────────────────
122
+ export function getWrappedCursorLayout(value, cursor, columns) {
123
+ const safe = clampCursorToBoundary(value, cursor);
124
+ const wrapCols = Number.isFinite(columns)
125
+ ? Math.max(1, Math.floor(columns))
126
+ : 1;
127
+ const lines = [];
128
+ let segStart = 0;
129
+ let segEnd = 0;
130
+ let segText = '';
131
+ let segWidth = 0;
132
+ const pushSeg = () => {
133
+ lines.push({ text: segText, start: segStart, end: segEnd });
134
+ };
135
+ let index = 0;
136
+ for (const char of value) {
137
+ const charStart = index;
138
+ index += char.length;
139
+ if (char === '\n') {
140
+ segEnd = charStart;
141
+ pushSeg();
142
+ segStart = index;
143
+ segEnd = index;
144
+ segText = '';
145
+ segWidth = 0;
146
+ continue;
147
+ }
148
+ const cw = Math.max(0, charWidth(char));
149
+ if (segText.length > 0 && segWidth + cw > wrapCols) {
150
+ pushSeg();
151
+ segStart = charStart;
152
+ segEnd = charStart;
153
+ segText = '';
154
+ segWidth = 0;
155
+ }
156
+ segText += char;
157
+ segEnd = index;
158
+ segWidth += cw;
159
+ }
160
+ pushSeg();
161
+ if (lines.length === 0) {
162
+ return {
163
+ lines: [{ text: '', start: 0, end: 0 }],
164
+ row: 0,
165
+ cursorInRow: 0,
166
+ };
167
+ }
168
+ let row = Math.max(0, lines.length - 1);
169
+ let cursorInRow = (lines[row]?.text ?? '').length;
170
+ for (let i = 0; i < lines.length; i++) {
171
+ const line = lines[i];
172
+ if (!line)
173
+ continue;
174
+ if (safe < line.start)
175
+ continue;
176
+ if (safe <= line.end) {
177
+ row = i;
178
+ cursorInRow = safe - line.start;
179
+ break;
180
+ }
181
+ }
182
+ return { lines, row, cursorInRow };
183
+ }
184
+ //# sourceMappingURL=composer_input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer_input.js","sourceRoot":"","sources":["../../src/tui/composer_input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=composer_input.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer_input.test.d.ts","sourceRoot":"","sources":["../../src/tui/composer_input.test.ts"],"names":[],"mappings":""}