@sheepbun/yips 0.1.1

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 (99) hide show
  1. package/dist/agent/commands/command-catalog.js +243 -0
  2. package/dist/agent/commands/commands.js +418 -0
  3. package/dist/agent/conductor.js +118 -0
  4. package/dist/agent/context/code-context.js +68 -0
  5. package/dist/agent/context/memory-store.js +159 -0
  6. package/dist/agent/context/session-store.js +211 -0
  7. package/dist/agent/protocol/tool-protocol.js +160 -0
  8. package/dist/agent/skills/skills.js +327 -0
  9. package/dist/agent/tools/tool-executor.js +415 -0
  10. package/dist/agent/tools/tool-safety.js +52 -0
  11. package/dist/app/index.js +35 -0
  12. package/dist/app/repl.js +105 -0
  13. package/dist/app/update-check.js +132 -0
  14. package/dist/app/version.js +51 -0
  15. package/dist/code-context.js +68 -0
  16. package/dist/colors.js +204 -0
  17. package/dist/command-catalog.js +242 -0
  18. package/dist/commands.js +350 -0
  19. package/dist/conductor.js +94 -0
  20. package/dist/config/config.js +335 -0
  21. package/dist/config/hooks.js +187 -0
  22. package/dist/config.js +335 -0
  23. package/dist/downloader-state.js +302 -0
  24. package/dist/downloader-ui.js +289 -0
  25. package/dist/gateway/adapters/discord.js +108 -0
  26. package/dist/gateway/adapters/formatting.js +96 -0
  27. package/dist/gateway/adapters/telegram.js +106 -0
  28. package/dist/gateway/adapters/types.js +2 -0
  29. package/dist/gateway/adapters/whatsapp.js +124 -0
  30. package/dist/gateway/auth-policy.js +66 -0
  31. package/dist/gateway/core.js +87 -0
  32. package/dist/gateway/headless-conductor.js +328 -0
  33. package/dist/gateway/message-router.js +23 -0
  34. package/dist/gateway/rate-limiter.js +48 -0
  35. package/dist/gateway/runtime/backend-policy.js +18 -0
  36. package/dist/gateway/runtime/discord-bot.js +104 -0
  37. package/dist/gateway/runtime/discord-main.js +69 -0
  38. package/dist/gateway/session-manager.js +77 -0
  39. package/dist/gateway/types.js +2 -0
  40. package/dist/hardware.js +92 -0
  41. package/dist/hooks.js +187 -0
  42. package/dist/index.js +34 -0
  43. package/dist/input-engine.js +250 -0
  44. package/dist/llama-client.js +227 -0
  45. package/dist/llama-server.js +620 -0
  46. package/dist/llm/llama-client.js +227 -0
  47. package/dist/llm/llama-server.js +620 -0
  48. package/dist/llm/token-counter.js +47 -0
  49. package/dist/memory-store.js +159 -0
  50. package/dist/messages.js +59 -0
  51. package/dist/model-downloader.js +382 -0
  52. package/dist/model-manager-state.js +118 -0
  53. package/dist/model-manager-ui.js +194 -0
  54. package/dist/model-manager.js +190 -0
  55. package/dist/models/hardware.js +92 -0
  56. package/dist/models/model-downloader.js +382 -0
  57. package/dist/models/model-manager.js +190 -0
  58. package/dist/prompt-box.js +78 -0
  59. package/dist/prompt-composer.js +498 -0
  60. package/dist/repl.js +105 -0
  61. package/dist/session-store.js +211 -0
  62. package/dist/spinner.js +76 -0
  63. package/dist/title-box.js +388 -0
  64. package/dist/token-counter.js +47 -0
  65. package/dist/tool-executor.js +415 -0
  66. package/dist/tool-protocol.js +121 -0
  67. package/dist/tool-safety.js +52 -0
  68. package/dist/tui/app.js +2553 -0
  69. package/dist/tui/startup.js +56 -0
  70. package/dist/tui-input-routing.js +53 -0
  71. package/dist/tui.js +51 -0
  72. package/dist/types/app-types.js +2 -0
  73. package/dist/types.js +2 -0
  74. package/dist/ui/colors.js +204 -0
  75. package/dist/ui/downloader/downloader-state.js +302 -0
  76. package/dist/ui/downloader/downloader-ui.js +289 -0
  77. package/dist/ui/input/input-engine.js +250 -0
  78. package/dist/ui/input/tui-input-routing.js +53 -0
  79. package/dist/ui/input/vt-session.js +168 -0
  80. package/dist/ui/messages.js +59 -0
  81. package/dist/ui/model-manager/model-manager-state.js +118 -0
  82. package/dist/ui/model-manager/model-manager-ui.js +194 -0
  83. package/dist/ui/prompt/prompt-box.js +78 -0
  84. package/dist/ui/prompt/prompt-composer.js +498 -0
  85. package/dist/ui/spinner.js +76 -0
  86. package/dist/ui/title-box.js +388 -0
  87. package/dist/ui/tui/app.js +6 -0
  88. package/dist/ui/tui/autocomplete.js +85 -0
  89. package/dist/ui/tui/constants.js +18 -0
  90. package/dist/ui/tui/history.js +29 -0
  91. package/dist/ui/tui/layout.js +341 -0
  92. package/dist/ui/tui/runtime-core.js +2584 -0
  93. package/dist/ui/tui/runtime-utils.js +53 -0
  94. package/dist/ui/tui/start-tui.js +54 -0
  95. package/dist/ui/tui/startup.js +56 -0
  96. package/dist/version.js +51 -0
  97. package/dist/vt-session.js +168 -0
  98. package/install.sh +457 -0
  99. package/package.json +128 -0
@@ -0,0 +1,388 @@
1
+ "use strict";
2
+ /** Responsive title box using the yips-cli visual contract. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.stripMarkup = stripMarkup;
5
+ exports.renderTitleBox = renderTitleBox;
6
+ exports.getLayoutMode = getLayoutMode;
7
+ const colors_1 = require("#ui/colors");
8
+ const YIPS_LOGO = [
9
+ "██╗ ██╗██╗██████╗ ███████╗",
10
+ "╚██╗ ██╔╝██║██╔══██╗██╔════╝",
11
+ " ╚████╔╝ ██║██████╔╝███████╗",
12
+ " ╚██╔╝ ██║██╔═══╝ ╚════██║",
13
+ " ██║ ██║██║ ███████║",
14
+ " ╚═╝ ╚═╝╚═╝ ╚══════╝"
15
+ ];
16
+ const LOGO_WIDTH = 28;
17
+ const TOP_TITLE = "Yips";
18
+ const TOP_TITLE_FALLBACK = "Yips";
19
+ const TOP_BORDER_MIN_WIDTH = 25;
20
+ function getLayoutMode(width) {
21
+ if (width >= 80)
22
+ return "full";
23
+ if (width >= 60)
24
+ return "single";
25
+ if (width >= 45)
26
+ return "compact";
27
+ return "minimal";
28
+ }
29
+ function centerText(text, width) {
30
+ if (width <= 0)
31
+ return "";
32
+ if (text.length >= width)
33
+ return text.slice(0, width);
34
+ const leftPadding = Math.floor((width - text.length) / 2);
35
+ const rightPadding = width - text.length - leftPadding;
36
+ return `${" ".repeat(leftPadding)}${text}${" ".repeat(rightPadding)}`;
37
+ }
38
+ function fitText(text, width) {
39
+ if (width <= 0)
40
+ return "";
41
+ if (text.length >= width)
42
+ return text.slice(0, width);
43
+ return text.padEnd(width, " ");
44
+ }
45
+ function toSingleColor(char, progress) {
46
+ return (0, colors_1.colorChar)(char, (0, colors_1.interpolateColor)(colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW, progress));
47
+ }
48
+ function makeTopBorder(version, width) {
49
+ if (width <= 0)
50
+ return "";
51
+ const fallback = `╭${"─".repeat(Math.max(0, width - 2))}╮`;
52
+ if (width < TOP_BORDER_MIN_WIDTH) {
53
+ return (0, colors_1.horizontalGradient)(fallback, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW);
54
+ }
55
+ let title = TOP_TITLE;
56
+ let titleLength = title.length + 1 + version.length;
57
+ let borderAvailable = width - titleLength - 7;
58
+ if (borderAvailable < 0) {
59
+ title = TOP_TITLE_FALLBACK;
60
+ titleLength = title.length + 1 + version.length;
61
+ borderAvailable = width - titleLength - 7;
62
+ if (borderAvailable < 0) {
63
+ return (0, colors_1.horizontalGradient)(fallback, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW);
64
+ }
65
+ }
66
+ const pieces = [];
67
+ let position = 0;
68
+ const appendBorder = (segment) => {
69
+ for (const char of segment) {
70
+ const progress = position / Math.max(width - 1, 1);
71
+ pieces.push(toSingleColor(char, progress));
72
+ position += 1;
73
+ }
74
+ };
75
+ appendBorder("╭─── ");
76
+ pieces.push("\u001b[1m");
77
+ for (let i = 0; i < title.length; i++) {
78
+ const progress = i / Math.max(title.length - 1, 1);
79
+ pieces.push(toSingleColor(title[i], progress));
80
+ position += 1;
81
+ }
82
+ pieces.push(" ");
83
+ position += 1;
84
+ pieces.push((0, colors_1.colorText)(version, colors_1.GRADIENT_BLUE));
85
+ position += version.length;
86
+ pieces.push("\u001b[22m");
87
+ const closing = ` ${"─".repeat(Math.max(0, borderAvailable))}╮`;
88
+ appendBorder(closing);
89
+ return pieces.join("");
90
+ }
91
+ /** Strip ANSI and legacy terminal-kit markup sequences for test/plain rendering. */
92
+ function stripMarkup(text) {
93
+ return (0, colors_1.stripAnsi)(text).replace(/\^\[#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})\]|\^#[0-9a-fA-F]{6}|\^:/g, "");
94
+ }
95
+ function makeBottomBorder(sessionName, width) {
96
+ if (width <= 0)
97
+ return "";
98
+ const borderChars = Array.from({ length: Math.max(0, width - 2) }, () => "─");
99
+ const trimmedSessionName = sessionName.trim();
100
+ if (trimmedSessionName.length === 0) {
101
+ return (0, colors_1.horizontalGradient)(`╰${borderChars.join("")}╯`, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW);
102
+ }
103
+ const displayName = ` ${trimmedSessionName.replace(/_/g, " ")} `;
104
+ if (displayName.length <= borderChars.length) {
105
+ const start = Math.floor((borderChars.length - displayName.length) / 2);
106
+ for (let i = 0; i < displayName.length; i++) {
107
+ borderChars[start + i] = displayName[i];
108
+ }
109
+ }
110
+ return (0, colors_1.horizontalGradient)(`╰${borderChars.join("")}╯`, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW);
111
+ }
112
+ function buildModelInfo(backend, model, tokenUsage) {
113
+ const trimmedModel = model.trim();
114
+ if (trimmedModel.length === 0) {
115
+ return backend;
116
+ }
117
+ const parts = [backend, trimmedModel];
118
+ const usage = tokenUsage.trim();
119
+ if (usage.length > 0) {
120
+ parts.push(usage);
121
+ }
122
+ return parts.join(" · ");
123
+ }
124
+ function padLine(markup, plain, width) {
125
+ const clippedPlain = fitText(plain, width);
126
+ if (plain.length > width) {
127
+ return clippedPlain;
128
+ }
129
+ const padding = " ".repeat(Math.max(0, width - plain.length));
130
+ return `${markup}${padding}`;
131
+ }
132
+ function makeSingleRow(contentMarkup, contentPlain, width) {
133
+ const innerWidth = Math.max(0, width - 2);
134
+ const leftBorder = (0, colors_1.horizontalGradient)("│", colors_1.GRADIENT_PINK, colors_1.GRADIENT_PINK);
135
+ const rightBorder = (0, colors_1.horizontalGradient)("│", colors_1.GRADIENT_YELLOW, colors_1.GRADIENT_YELLOW);
136
+ return `${leftBorder}${padLine(contentMarkup, contentPlain, innerWidth)}${rightBorder}`;
137
+ }
138
+ function styleCenteredText(text, width, style) {
139
+ const centered = centerText(text, width);
140
+ switch (style) {
141
+ case "gradient":
142
+ return {
143
+ markup: (0, colors_1.horizontalGradient)(centered, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW),
144
+ plain: centered
145
+ };
146
+ case "blue":
147
+ return { markup: (0, colors_1.colorText)(centered, colors_1.GRADIENT_BLUE), plain: centered };
148
+ case "pink":
149
+ return { markup: (0, colors_1.colorText)(centered, colors_1.INPUT_PINK), plain: centered };
150
+ case "dim":
151
+ return { markup: (0, colors_1.colorText)(centered, colors_1.DIM_GRAY), plain: centered };
152
+ case "plain":
153
+ return { markup: centered, plain: centered };
154
+ }
155
+ }
156
+ function styleCenteredTextWithGradientSpan(text, width) {
157
+ if (width <= 0)
158
+ return { markup: "", plain: "" };
159
+ const clipped = text.slice(0, width);
160
+ if (clipped.length >= width) {
161
+ return {
162
+ markup: (0, colors_1.horizontalGradient)(clipped, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW),
163
+ plain: clipped
164
+ };
165
+ }
166
+ const leftPadding = Math.floor((width - clipped.length) / 2);
167
+ const rightPadding = width - clipped.length - leftPadding;
168
+ return {
169
+ markup: `${" ".repeat(leftPadding)}${(0, colors_1.horizontalGradient)(clipped, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW)}${" ".repeat(rightPadding)}`,
170
+ plain: `${" ".repeat(leftPadding)}${clipped}${" ".repeat(rightPadding)}`
171
+ };
172
+ }
173
+ function withBold(row) {
174
+ if (row.markup.length === 0)
175
+ return row;
176
+ return { markup: `\u001b[1m${row.markup}\u001b[22m`, plain: row.plain };
177
+ }
178
+ function styleLeftText(text, width, style) {
179
+ const clipped = text.slice(0, Math.max(0, width));
180
+ const padded = fitText(clipped, width);
181
+ switch (style) {
182
+ case "gradient":
183
+ if (clipped.length === 0)
184
+ return { markup: padded, plain: padded };
185
+ return {
186
+ markup: `${(0, colors_1.horizontalGradient)(clipped, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW)}${" ".repeat(Math.max(0, width - clipped.length))}`,
187
+ plain: padded
188
+ };
189
+ case "blue":
190
+ if (clipped.length === 0)
191
+ return { markup: padded, plain: padded };
192
+ return {
193
+ markup: `${(0, colors_1.colorText)(clipped, colors_1.GRADIENT_BLUE)}${" ".repeat(Math.max(0, width - clipped.length))}`,
194
+ plain: padded
195
+ };
196
+ case "white":
197
+ if (clipped.length === 0)
198
+ return { markup: padded, plain: padded };
199
+ return {
200
+ markup: `${(0, colors_1.colorText)(clipped, { r: 255, g: 255, b: 255 })}${" ".repeat(Math.max(0, width - clipped.length))}`,
201
+ plain: padded
202
+ };
203
+ case "dim":
204
+ if (clipped.length === 0)
205
+ return { markup: padded, plain: padded };
206
+ return {
207
+ markup: `${(0, colors_1.colorText)(clipped, colors_1.DIM_GRAY)}${" ".repeat(Math.max(0, width - clipped.length))}`,
208
+ plain: padded
209
+ };
210
+ case "plain":
211
+ return { markup: padded, plain: padded };
212
+ }
213
+ }
214
+ function styleHighlightedText(text, width) {
215
+ const clipped = text.slice(0, Math.max(0, width));
216
+ const padded = fitText(clipped, width);
217
+ if (clipped.length === 0)
218
+ return { markup: padded, plain: padded };
219
+ return {
220
+ markup: `\u001b[1m${(0, colors_1.colorText)(clipped, colors_1.INPUT_PINK)}\u001b[22m${" ".repeat(Math.max(0, width - clipped.length))}`,
221
+ plain: padded
222
+ };
223
+ }
224
+ function styleLeftTextGlobalGradient(text, width, totalWidth, startColumn) {
225
+ const clipped = text.slice(0, Math.max(0, width));
226
+ const padded = fitText(clipped, width);
227
+ if (clipped.length === 0)
228
+ return { markup: padded, plain: padded };
229
+ const maxColumn = Math.max(totalWidth - 1, 1);
230
+ const startColor = (0, colors_1.interpolateColor)(colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW, Math.max(0, Math.min(1, startColumn / maxColumn)));
231
+ const endColumn = startColumn + Math.max(clipped.length - 1, 0);
232
+ const endColor = (0, colors_1.interpolateColor)(colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW, Math.max(0, Math.min(1, endColumn / maxColumn)));
233
+ return {
234
+ markup: `${(0, colors_1.horizontalGradient)(clipped, startColor, endColor)}${" ".repeat(Math.max(0, width - clipped.length))}`,
235
+ plain: padded
236
+ };
237
+ }
238
+ function centerLogoLine(logoMarkup, logoPlain, width) {
239
+ const paddingLeft = Math.max(0, Math.floor((width - logoPlain.length) / 2));
240
+ const paddingRight = Math.max(0, width - logoPlain.length - paddingLeft);
241
+ return {
242
+ markup: `${" ".repeat(paddingLeft)}${logoMarkup}${" ".repeat(paddingRight)}`,
243
+ plain: `${" ".repeat(paddingLeft)}${logoPlain}${" ".repeat(paddingRight)}`
244
+ };
245
+ }
246
+ function renderSingleColumn(options, mode) {
247
+ const { width, version, username, backend, model, tokenUsage, cwd, sessionName } = options;
248
+ const innerWidth = Math.max(0, width - 2);
249
+ const lines = [];
250
+ const modelInfo = buildModelInfo(backend, model, tokenUsage);
251
+ const gradientLogo = (0, colors_1.rowMajorGradient)(YIPS_LOGO, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW);
252
+ const showLogo = innerWidth >= LOGO_WIDTH;
253
+ lines.push(makeTopBorder(version, width));
254
+ if (mode === "minimal") {
255
+ const minimalRows = [];
256
+ minimalRows.push(styleCenteredText("", innerWidth, "plain"));
257
+ if (showLogo) {
258
+ for (let i = 0; i < YIPS_LOGO.length; i++) {
259
+ minimalRows.push(centerLogoLine(gradientLogo[i] ?? "", YIPS_LOGO[i] ?? "", innerWidth));
260
+ }
261
+ }
262
+ else {
263
+ minimalRows.push(styleCenteredText("YIPS", innerWidth, "gradient"));
264
+ }
265
+ minimalRows.push(styleCenteredText(modelInfo, innerWidth, "blue"));
266
+ minimalRows.push(styleCenteredText("", innerWidth, "plain"));
267
+ for (const row of minimalRows) {
268
+ lines.push(makeSingleRow(row.markup, row.plain, width));
269
+ }
270
+ lines.push(makeBottomBorder(sessionName, width));
271
+ return lines;
272
+ }
273
+ const rows = [];
274
+ rows.push(styleCenteredText("", innerWidth, "plain"));
275
+ rows.push(mode === "single"
276
+ ? withBold(styleCenteredTextWithGradientSpan(`Welcome back ${username}!`, innerWidth))
277
+ : styleCenteredTextWithGradientSpan(`Hi ${username}!`, innerWidth));
278
+ rows.push(styleCenteredText("", innerWidth, "plain"));
279
+ if (showLogo) {
280
+ for (let i = 0; i < YIPS_LOGO.length; i++) {
281
+ rows.push(centerLogoLine(gradientLogo[i] ?? "", YIPS_LOGO[i] ?? "", innerWidth));
282
+ }
283
+ }
284
+ else {
285
+ rows.push(styleCenteredText("YIPS", innerWidth, "gradient"));
286
+ }
287
+ rows.push(styleCenteredText(modelInfo, innerWidth, "blue"));
288
+ if (mode === "single") {
289
+ rows.push(styleCenteredTextWithGradientSpan(cwd, innerWidth));
290
+ }
291
+ rows.push(styleCenteredText("", innerWidth, "plain"));
292
+ for (const row of rows) {
293
+ lines.push(makeSingleRow(row.markup, row.plain, width));
294
+ }
295
+ lines.push(makeBottomBorder(sessionName, width));
296
+ return lines;
297
+ }
298
+ function renderFull(options) {
299
+ const { width, version, username, backend, model, tokenUsage, cwd, sessionName, recentActivity = [], sessionSelection } = options;
300
+ const lines = [];
301
+ const modelInfo = buildModelInfo(backend, model, tokenUsage);
302
+ const availableWidth = Math.max(0, width - 3);
303
+ const leftWidth = Math.max(Math.floor(availableWidth * 0.45), 30);
304
+ const rightWidth = Math.max(0, availableWidth - leftWidth);
305
+ const middleProgress = (leftWidth + 1) / Math.max(width - 1, 1);
306
+ const middleBorderColor = (0, colors_1.interpolateColor)(colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW, middleProgress);
307
+ const leftBorder = (0, colors_1.horizontalGradient)("│", colors_1.GRADIENT_PINK, colors_1.GRADIENT_PINK);
308
+ const middleBorder = (0, colors_1.colorText)("│", middleBorderColor);
309
+ const rightBorder = (0, colors_1.horizontalGradient)("│", colors_1.GRADIENT_YELLOW, colors_1.GRADIENT_YELLOW);
310
+ const gradientLogo = (0, colors_1.rowMajorGradient)(YIPS_LOGO, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW);
311
+ const rightStartColumn = leftWidth + 2;
312
+ const leftRows = [
313
+ styleCenteredText("", leftWidth, "plain"),
314
+ withBold(styleCenteredTextWithGradientSpan(`Welcome back ${username}!`, leftWidth)),
315
+ styleCenteredText("", leftWidth, "plain")
316
+ ];
317
+ for (let i = 0; i < YIPS_LOGO.length; i++) {
318
+ leftRows.push(centerLogoLine(gradientLogo[i] ?? "", YIPS_LOGO[i] ?? "", leftWidth));
319
+ }
320
+ leftRows.push(styleCenteredText(modelInfo, leftWidth, "blue"));
321
+ leftRows.push(styleCenteredTextWithGradientSpan(cwd, leftWidth));
322
+ leftRows.push(styleCenteredText("", leftWidth, "plain"));
323
+ const rightRows = [
324
+ withBold(styleLeftTextGlobalGradient("Tips for getting started:", rightWidth, width, rightStartColumn)),
325
+ styleLeftTextGlobalGradient("- Ask questions, edit files, or run commands.", rightWidth, width, rightStartColumn),
326
+ styleLeftTextGlobalGradient("- Be specific for the best results.", rightWidth, width, rightStartColumn),
327
+ styleLeftTextGlobalGradient("- /help for more information.", rightWidth, width, rightStartColumn),
328
+ styleLeftText("", rightWidth, "plain"),
329
+ styleLeftTextGlobalGradient("─".repeat(Math.max(0, rightWidth)), rightWidth, width, rightStartColumn),
330
+ withBold(styleLeftText("Recent activity", rightWidth, "white"))
331
+ ];
332
+ const activityItems = recentActivity.length > 0 ? recentActivity : ["No recent activity yet."];
333
+ if (sessionSelection?.active) {
334
+ const maxSlots = 5;
335
+ const safeSelected = Math.max(0, Math.min(sessionSelection.selectedIndex, activityItems.length - 1));
336
+ const start = Math.max(0, Math.min(safeSelected - Math.floor(maxSlots / 2), Math.max(0, activityItems.length - maxSlots)));
337
+ const visible = activityItems.slice(start, start + maxSlots);
338
+ for (let i = 0; i < visible.length; i++) {
339
+ const actualIndex = start + i;
340
+ const item = visible[i] ?? "";
341
+ if (actualIndex === safeSelected) {
342
+ rightRows.push(styleHighlightedText(`> ${item}`, rightWidth));
343
+ }
344
+ else {
345
+ rightRows.push(styleLeftText(` ${item}`, rightWidth, "dim"));
346
+ }
347
+ }
348
+ }
349
+ else {
350
+ for (const item of activityItems.slice(0, 5)) {
351
+ rightRows.push(styleLeftText(item, rightWidth, "dim"));
352
+ }
353
+ }
354
+ while (rightRows.length < leftRows.length) {
355
+ rightRows.push(styleLeftText("", rightWidth, "plain"));
356
+ }
357
+ lines.push(makeTopBorder(version, width));
358
+ const maxRows = Math.max(leftRows.length, rightRows.length);
359
+ for (let row = 0; row < maxRows; row++) {
360
+ const left = leftRows[row] ?? styleLeftText("", leftWidth, "plain");
361
+ const right = rightRows[row] ?? styleLeftText("", rightWidth, "plain");
362
+ lines.push(`${leftBorder}${padLine(left.markup, left.plain, leftWidth)}${middleBorder}${padLine(right.markup, right.plain, rightWidth)}${rightBorder}`);
363
+ }
364
+ lines.push(makeBottomBorder(sessionName, width));
365
+ return lines;
366
+ }
367
+ function renderCompact(options) {
368
+ return renderSingleColumn(options, "compact");
369
+ }
370
+ function renderMinimal(options) {
371
+ return renderSingleColumn(options, "minimal");
372
+ }
373
+ function renderSingle(options) {
374
+ return renderSingleColumn(options, "single");
375
+ }
376
+ function renderTitleBox(options) {
377
+ const mode = getLayoutMode(options.width);
378
+ switch (mode) {
379
+ case "full":
380
+ return renderFull(options);
381
+ case "single":
382
+ return renderSingle(options);
383
+ case "compact":
384
+ return renderCompact(options);
385
+ case "minimal":
386
+ return renderMinimal(options);
387
+ }
388
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /** Thin facade for the Ink app runtime implementation. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.createInkApp = void 0;
5
+ var runtime_core_1 = require("#ui/tui/runtime-core");
6
+ Object.defineProperty(exports, "createInkApp", { enumerable: true, get: function () { return runtime_core_1.createInkApp; } });
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildModelAutocompleteCandidates = buildModelAutocompleteCandidates;
4
+ exports.shouldConsumeSubmitForAutocomplete = shouldConsumeSubmitForAutocomplete;
5
+ exports.buildAutocompleteOverlayLines = buildAutocompleteOverlayLines;
6
+ const node_path_1 = require("node:path");
7
+ const colors_1 = require("#ui/colors");
8
+ const constants_1 = require("#ui/tui/constants");
9
+ function charLength(text) {
10
+ return Array.from(text).length;
11
+ }
12
+ function withReverseHighlight(text) {
13
+ return `${constants_1.ANSI_REVERSE_ON}${text}${constants_1.ANSI_RESET_ALL}`;
14
+ }
15
+ function buildModelAutocompleteCandidates(modelIds) {
16
+ const candidates = [];
17
+ const seenValues = new Set();
18
+ for (const rawModelId of modelIds) {
19
+ const value = rawModelId.trim();
20
+ if (value.length === 0 || seenValues.has(value)) {
21
+ continue;
22
+ }
23
+ seenValues.add(value);
24
+ const aliases = [];
25
+ const parentPath = value.includes("/") ? value.slice(0, value.lastIndexOf("/")) : "";
26
+ if (parentPath.length > 0) {
27
+ aliases.push(parentPath);
28
+ }
29
+ const segments = value.split("/").filter((segment) => segment.length > 0);
30
+ if (segments.length >= 2) {
31
+ aliases.push(`${segments[0]}/${segments[1]}`);
32
+ }
33
+ const filename = (0, node_path_1.basename)(value);
34
+ if (filename.length > 0) {
35
+ aliases.push(filename);
36
+ if (filename.toLowerCase().endsWith(".gguf")) {
37
+ aliases.push(filename.slice(0, -5));
38
+ }
39
+ }
40
+ const dedupedAliases = [
41
+ ...new Set(aliases.filter((alias) => alias.length > 0 && alias !== value))
42
+ ];
43
+ candidates.push({
44
+ value,
45
+ aliases: dedupedAliases
46
+ });
47
+ }
48
+ return candidates;
49
+ }
50
+ function shouldConsumeSubmitForAutocomplete(menu) {
51
+ if (!menu) {
52
+ return false;
53
+ }
54
+ const selected = menu.options[menu.selectedIndex];
55
+ if (!selected) {
56
+ return false;
57
+ }
58
+ return selected !== menu.token;
59
+ }
60
+ function buildAutocompleteOverlayLines(composer, registry) {
61
+ const menu = composer.getAutocompleteMenuState();
62
+ if (!menu) {
63
+ return [];
64
+ }
65
+ const descriptorBySlashName = new Map(registry.listCommands().map((descriptor) => [`/${descriptor.name}`, descriptor]));
66
+ const lines = [];
67
+ const windowSize = Math.min(constants_1.MAX_AUTOCOMPLETE_PREVIEW, menu.options.length);
68
+ const startIndex = Math.max(0, Math.min(menu.selectedIndex - Math.floor(windowSize / 2), menu.options.length - windowSize));
69
+ const visibleOptions = menu.options.slice(startIndex, startIndex + windowSize);
70
+ const commandColumnWidth = Math.max(10, ...visibleOptions.map((option) => charLength(option)));
71
+ const leftPadding = " ".repeat(1 + charLength(constants_1.PROMPT_PREFIX));
72
+ for (let rowIndex = 0; rowIndex < visibleOptions.length; rowIndex++) {
73
+ const option = visibleOptions[rowIndex] ?? "";
74
+ const descriptor = descriptorBySlashName.get(option);
75
+ const description = descriptor?.description ?? (option.startsWith("/") ? "Command" : "Local model");
76
+ const commandColor = descriptor?.kind === "skill" ? colors_1.INPUT_PINK : colors_1.GRADIENT_BLUE;
77
+ const selected = startIndex + rowIndex === menu.selectedIndex;
78
+ const paddedCommand = option.padEnd(commandColumnWidth, " ");
79
+ const styledCommand = (0, colors_1.colorText)(paddedCommand, commandColor);
80
+ const styledDescription = (0, colors_1.horizontalGradient)(description, colors_1.GRADIENT_PINK, colors_1.GRADIENT_YELLOW);
81
+ const rowText = `${leftPadding}${styledCommand} ${styledDescription}`;
82
+ lines.push(selected ? withReverseHighlight(rowText) : rowText);
83
+ }
84
+ return lines;
85
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_AUTOCOMPLETE_PREVIEW = exports.TITLE_OUTPUT_GAP_ROWS = exports.ANSI_SGR_PATTERN = exports.DISABLE_MOUSE_REPORTING = exports.ENABLE_MOUSE_REPORTING = exports.MOUSE_SCROLL_LINE_STEP = exports.BUSY_SPINNER_RENDER_INTERVAL_MS = exports.DOWNLOADER_PROGRESS_RENDER_INTERVAL_MS = exports.DOWNLOADER_SEARCH_DEBOUNCE_MS = exports.DOWNLOADER_MIN_SEARCH_CHARS = exports.ANSI_RESET_ALL = exports.ANSI_REVERSE_ON = exports.KEY_DEBUG_ENABLED = exports.CURSOR_MARKER = exports.PROMPT_PREFIX = void 0;
4
+ exports.PROMPT_PREFIX = ">>> ";
5
+ exports.CURSOR_MARKER = "▌";
6
+ exports.KEY_DEBUG_ENABLED = process.env["YIPS_DEBUG_KEYS"] === "1";
7
+ exports.ANSI_REVERSE_ON = "\u001b[7m";
8
+ exports.ANSI_RESET_ALL = "\u001b[0m";
9
+ exports.DOWNLOADER_MIN_SEARCH_CHARS = 3;
10
+ exports.DOWNLOADER_SEARCH_DEBOUNCE_MS = 400;
11
+ exports.DOWNLOADER_PROGRESS_RENDER_INTERVAL_MS = 200;
12
+ exports.BUSY_SPINNER_RENDER_INTERVAL_MS = 16;
13
+ exports.MOUSE_SCROLL_LINE_STEP = 3;
14
+ exports.ENABLE_MOUSE_REPORTING = "\u001b[?1000h\u001b[?1006h";
15
+ exports.DISABLE_MOUSE_REPORTING = "\u001b[?1000l\u001b[?1006l";
16
+ exports.ANSI_SGR_PATTERN = new RegExp(String.raw `\u001b\[[0-9;]*m`, "g");
17
+ exports.TITLE_OUTPUT_GAP_ROWS = 1;
18
+ exports.MAX_AUTOCOMPLETE_PREVIEW = 8;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderHistoryLines = renderHistoryLines;
4
+ exports.composeChatRequestMessages = composeChatRequestMessages;
5
+ const messages_1 = require("#ui/messages");
6
+ function renderHistoryLines(history) {
7
+ const lines = [];
8
+ let userCount = 0;
9
+ for (const entry of history) {
10
+ if (entry.role === "user") {
11
+ userCount += 1;
12
+ lines.push(...(0, messages_1.formatUserMessage)(entry.content).split("\n"));
13
+ continue;
14
+ }
15
+ if (entry.role === "assistant") {
16
+ lines.push(...(0, messages_1.formatAssistantMessage)(entry.content).split("\n"));
17
+ lines.push("");
18
+ continue;
19
+ }
20
+ lines.push(...(0, messages_1.formatDimMessage)(`[system] ${entry.content}`).split("\n"));
21
+ }
22
+ return { lines, userCount };
23
+ }
24
+ function composeChatRequestMessages(history, codeContextMessage) {
25
+ if (!codeContextMessage) {
26
+ return history;
27
+ }
28
+ return [{ role: "system", content: codeContextMessage }, ...history];
29
+ }