ralphctl 0.5.0 → 0.6.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 (58) hide show
  1. package/README.md +29 -16
  2. package/dist/absolute-path-WUTZQ37D.mjs +8 -0
  3. package/dist/chunk-6RDMCLWU.mjs +108 -0
  4. package/dist/chunk-HIU74KTO.mjs +1046 -0
  5. package/dist/chunk-S3PTDH57.mjs +78 -0
  6. package/dist/chunk-WV4D2CPG.mjs +26 -0
  7. package/dist/cli.mjs +22413 -717
  8. package/dist/manifest.json +24 -0
  9. package/dist/prompt-adapter-JQICGVX7.mjs +7 -0
  10. package/dist/prompts/ideate.md +3 -1
  11. package/dist/prompts/plan-auto.md +23 -8
  12. package/dist/prompts/plan-common-examples.md +3 -3
  13. package/dist/prompts/plan-common.md +6 -5
  14. package/dist/prompts/plan-interactive.md +30 -7
  15. package/dist/prompts/repo-onboard.md +154 -64
  16. package/dist/prompts/signals-task.md +3 -0
  17. package/dist/prompts/sprint-feedback.md +3 -0
  18. package/dist/prompts/task-evaluation.md +74 -53
  19. package/dist/prompts/task-execution.md +65 -21
  20. package/dist/prompts/ticket-refine.md +11 -8
  21. package/dist/prompts/validation-checklist.md +3 -2
  22. package/dist/skills/default/abstraction-first/SKILL.md +45 -0
  23. package/dist/skills/default/alignment/SKILL.md +46 -0
  24. package/dist/skills/default/iterative-review/SKILL.md +48 -0
  25. package/dist/skills/exec/.gitkeep +0 -0
  26. package/dist/skills/plan/.gitkeep +0 -0
  27. package/dist/skills/refine/.gitkeep +0 -0
  28. package/dist/storage-paths-IPNZZM5D.mjs +15 -0
  29. package/dist/validation-error-QT6Q7FYU.mjs +7 -0
  30. package/package.json +9 -4
  31. package/dist/add-67UFUI54.mjs +0 -17
  32. package/dist/add-DVPVHENV.mjs +0 -18
  33. package/dist/bootstrap-FMHG6DRY.mjs +0 -11
  34. package/dist/chunk-62HYDA7L.mjs +0 -1128
  35. package/dist/chunk-747KW2RW.mjs +0 -24
  36. package/dist/chunk-BSB4EDGR.mjs +0 -260
  37. package/dist/chunk-BT5FKIZX.mjs +0 -787
  38. package/dist/chunk-CBMFRQ4Y.mjs +0 -441
  39. package/dist/chunk-CFUVE2BP.mjs +0 -16
  40. package/dist/chunk-D6QZNEYN.mjs +0 -5520
  41. package/dist/chunk-FNAAA32W.mjs +0 -103
  42. package/dist/chunk-GQ2WFKBN.mjs +0 -269
  43. package/dist/chunk-IWXBJD2D.mjs +0 -27
  44. package/dist/chunk-OGEXYSFS.mjs +0 -228
  45. package/dist/chunk-VAZ3LJBI.mjs +0 -179
  46. package/dist/chunk-WDMLPXOD.mjs +0 -363
  47. package/dist/chunk-XN2UIHBY.mjs +0 -589
  48. package/dist/chunk-ZE2BRQA2.mjs +0 -5542
  49. package/dist/create-Z635FQKO.mjs +0 -15
  50. package/dist/handle-23EFF3BE.mjs +0 -22
  51. package/dist/mount-NCYR22SN.mjs +0 -7434
  52. package/dist/project-DQHF4ISP.mjs +0 -34
  53. package/dist/prompts/check-script-discover.md +0 -69
  54. package/dist/prompts/ideate-auto.md +0 -195
  55. package/dist/prompts/task-evaluation-resume.md +0 -41
  56. package/dist/resolver-OVPYVW6Q.mjs +0 -163
  57. package/dist/sprint-4E26AB5F.mjs +0 -38
  58. package/dist/start-T34NI3LF.mjs +0 -19
@@ -1,589 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- unwrapOrThrow
4
- } from "./chunk-IWXBJD2D.mjs";
5
- import {
6
- ConfigSchema,
7
- fileExists,
8
- getConfigPath,
9
- readValidatedJson,
10
- writeValidatedJson
11
- } from "./chunk-WDMLPXOD.mjs";
12
-
13
- // src/integration/ui/theme/theme.ts
14
- import { bold, cyan, gray, green, red, yellow } from "colorette";
15
- import gradient from "gradient-string";
16
- import { isColorSupported } from "colorette";
17
- var emoji = {
18
- donut: "\u{1F369}"
19
- };
20
- var colors = {
21
- // Semantic colors
22
- success: green,
23
- error: red,
24
- warning: yellow,
25
- info: cyan,
26
- muted: gray,
27
- highlight: yellow,
28
- accent: bold
29
- };
30
- var success = (text) => colors.success(text);
31
- var error = (text) => colors.error(text);
32
- var muted = (text) => colors.muted(text);
33
- var gradients = {
34
- /** Gold → Orange → Hot Pink → Orchid → Violet (Ralph's signature donut warmth) */
35
- donut: gradient(["#FFD700", "#FFA500", "#FF69B4", "#DA70D6", "#9400D3"], {
36
- interpolation: "hsv",
37
- hsvSpin: "short"
38
- }),
39
- /** Green → Dark Cyan (success/completion) */
40
- success: gradient(["#00FF00", "#00CED1"]),
41
- /** Orange Red → Gold (warning/attention) */
42
- warning: gradient(["#FF4500", "#FFD700"])
43
- };
44
- var BANNER = `
45
- \u{1F369} \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u{1F369}
46
- \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551
47
- \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
48
- \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
49
- \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
50
- \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D
51
- `;
52
- var banner = {
53
- art: BANNER,
54
- tagline: "I'm helping with your sprints!"
55
- };
56
- var RALPH_QUOTES = [
57
- "I'm helping!",
58
- "Me fail English? That's unpossible!",
59
- "Go banana!",
60
- "Hi, Super Nintendo Chalmers!",
61
- "I bent my wookie.",
62
- "My cat's breath smells like cat food.",
63
- "I'm learnding!",
64
- "The doctor said I wouldn't have so many nose bleeds if I kept my finger outta there.",
65
- "I found a moonrock in my nose!",
66
- "That's where I saw the leprechaun. He told me to burn things.",
67
- "My daddy's gonna put you in jail!",
68
- "I'm a unitard!",
69
- "I ate the purple berries...",
70
- "Tastes like burning!",
71
- "My parents won't let me use scissors.",
72
- "I dress myself!",
73
- "Principal Skinner, I got carsick in your office.",
74
- "I'm Idaho!",
75
- "Mrs. Krabappel and Principal Skinner were in the closet making babies!",
76
- "Even my boogers are spicy!",
77
- "It smells like hot dogs.",
78
- "I sleep in a drawer!",
79
- "I picked the red one!",
80
- "The pointy kitty took it!",
81
- "When I grow up, I want to be a principal or a caterpillar."
82
- ];
83
- function getRandomQuote() {
84
- const index = Math.floor(Math.random() * RALPH_QUOTES.length);
85
- return RALPH_QUOTES[index] ?? "";
86
- }
87
- var QUOTES_BY_CATEGORY = {
88
- error: [
89
- "My tummy hurts!",
90
- "Tastes like burning!",
91
- "I ate the purple berries...",
92
- "The doctor said I wouldn't have so many nose bleeds if I kept my finger outta there.",
93
- "My parents won't let me use scissors.",
94
- "Principal Skinner, I got carsick in your office.",
95
- "I eated the purple berries. They taste like... burning."
96
- ],
97
- success: [
98
- "I'm helping!",
99
- "Go banana!",
100
- "I'm learnding!",
101
- "I'm a unitard!",
102
- "I dress myself!",
103
- "I picked the red one!",
104
- "I found a moonrock in my nose!",
105
- "Yay! I'm a helper!"
106
- ],
107
- farewell: [
108
- "Bye bye! My cat's breath smells like cat food!",
109
- "When I grow up, I want to be a principal or a caterpillar.",
110
- "I sleep in a drawer!",
111
- "I'm Idaho!",
112
- "The pointy kitty took it!"
113
- ],
114
- idle: [
115
- "Hi, Super Nintendo Chalmers!",
116
- "I bent my wookie.",
117
- "My cat's breath smells like cat food.",
118
- "It smells like hot dogs.",
119
- "That's where I saw the leprechaun. He told me to burn things.",
120
- "Me fail English? That's unpossible!",
121
- "Even my boogers are spicy!",
122
- "Mrs. Krabappel and Principal Skinner were in the closet making babies!"
123
- ]
124
- };
125
- function getQuoteForContext(category) {
126
- const quotes = QUOTES_BY_CATEGORY[category];
127
- const index = Math.floor(Math.random() * quotes.length);
128
- return quotes[index] ?? "";
129
- }
130
- var statusEmoji = {
131
- todo: "\u{1F4DD}",
132
- in_progress: "\u{1F3C3}",
133
- done: "\u2705",
134
- blocked: "\u{1F6AB}",
135
- draft: "\u{1F4CB}",
136
- active: "\u{1F3AF}",
137
- closed: "\u{1F389}"
138
- };
139
- function getStatusEmoji(status) {
140
- if (status in statusEmoji) {
141
- return statusEmoji[status];
142
- }
143
- return status;
144
- }
145
-
146
- // src/integration/ui/theme/ui.ts
147
- var icons = {
148
- sprint: ">",
149
- ticket: "#",
150
- task: "*",
151
- project: "@",
152
- edit: ">",
153
- success: "+",
154
- error: "x",
155
- warning: "!",
156
- info: "i",
157
- tip: "?",
158
- active: "*",
159
- inactive: "o",
160
- bullet: "-"
161
- };
162
- var INDENT = " ";
163
- var log = {
164
- info(message) {
165
- console.log(`${INDENT}${colors.info(icons.info)} ${message}`);
166
- },
167
- success(message) {
168
- console.log(`${INDENT}${colors.success(icons.success)} ${message}`);
169
- },
170
- warn(message) {
171
- console.log(`${INDENT}${colors.warning(icons.warning)} ${message}`);
172
- },
173
- error(message) {
174
- console.log(`${INDENT}${colors.error(icons.error)} ${message}`);
175
- },
176
- dim(message) {
177
- console.log(`${INDENT}${colors.muted(message)}`);
178
- },
179
- item(message) {
180
- console.log(`${INDENT}${INDENT}${colors.muted(icons.bullet)} ${message}`);
181
- },
182
- itemSuccess(message) {
183
- console.log(`${INDENT}${INDENT}${colors.success(icons.success)} ${message}`);
184
- },
185
- itemError(message, detail) {
186
- console.log(`${INDENT}${INDENT}${colors.error(icons.error)} ${message}`);
187
- if (detail) console.log(`${INDENT}${INDENT} ${colors.muted(detail)}`);
188
- },
189
- raw(message, indentLevel = 1) {
190
- console.log(`${INDENT.repeat(indentLevel)}${message}`);
191
- },
192
- newline() {
193
- console.log("");
194
- }
195
- };
196
- function printHeader(title, icon) {
197
- const displayIcon = icon ?? emoji.donut;
198
- console.log("");
199
- console.log(` ${displayIcon} ${colors.highlight(title)}`);
200
- console.log(colors.muted(` ${"\u2500".repeat(40)}`));
201
- console.log("");
202
- }
203
- function printSeparator(width = 40) {
204
- console.log(`${INDENT}${colors.muted("\u2500".repeat(width))}`);
205
- }
206
- function showSuccess(message, details) {
207
- console.log(`
208
- ${INDENT}${colors.success(icons.success)} ${colors.success(message)}`);
209
- if (details) {
210
- console.log(details.map(([label, value]) => field(label, value)).join("\n"));
211
- }
212
- }
213
- function showError(message) {
214
- console.log(`
215
- ${INDENT}${colors.error(icons.error)} ${colors.error(message)}`);
216
- }
217
- function showWarning(message) {
218
- console.log(`${INDENT}${colors.warning(icons.warning)} ${colors.warning(message)}`);
219
- }
220
- function showTip(message) {
221
- console.log(`${INDENT}${colors.muted(icons.tip + " " + message)}`);
222
- }
223
- function showEmpty(what, hint) {
224
- console.log(`
225
- ${INDENT}${colors.muted(icons.inactive)} ${colors.muted(`No ${what} yet.`)}`);
226
- if (hint) {
227
- console.log(`${INDENT} ${colors.muted(icons.tip + " " + hint)}
228
- `);
229
- }
230
- }
231
- function showNextStep(command, description) {
232
- const desc = description ? ` ${colors.muted("- " + description)}` : "";
233
- console.log(`${INDENT}${colors.muted("\u2192")} ${colors.highlight(command)}${desc}`);
234
- }
235
- function showNextSteps(steps) {
236
- for (const [command, description] of steps) showNextStep(command, description);
237
- }
238
- function showRandomQuote() {
239
- console.log(colors.muted(` "${getRandomQuote()}"`));
240
- }
241
- function printCountSummary(label, done, total) {
242
- const percent = total > 0 ? Math.round(done / total * 100) : 0;
243
- const color = percent === 100 ? colors.success : percent > 50 ? colors.warning : colors.muted;
244
- printSeparator();
245
- console.log(`${INDENT}${label} ${color(`${String(done)}/${String(total)} (${String(percent)}%)`)}`);
246
- }
247
- function getBannerText() {
248
- const art = isColorSupported ? gradients.donut.multiline(banner.art) : banner.art;
249
- const quote = getRandomQuote();
250
- return `${art}
251
- ${colors.muted(`"${quote}"`)}
252
- `;
253
- }
254
- function printBanner() {
255
- console.log(getBannerText());
256
- }
257
- function isTTY() {
258
- if (!process.stdout.isTTY || process.env["NO_COLOR"]) return false;
259
- return true;
260
- }
261
- function terminalBell() {
262
- if (isTTY()) process.stdout.write("\x07");
263
- }
264
- function createSpinner(text) {
265
- let started = false;
266
- const shim = {
267
- text,
268
- start() {
269
- if (!started && isTTY()) {
270
- console.log(`${INDENT}${colors.muted("\u2022")} ${shim.text}`);
271
- }
272
- started = true;
273
- return shim;
274
- },
275
- stop() {
276
- return shim;
277
- },
278
- succeed(msg) {
279
- console.log(`${INDENT}${colors.success("+")} ${msg ?? shim.text}`);
280
- return shim;
281
- },
282
- fail(msg) {
283
- console.error(`${INDENT}${colors.error("x")} ${msg ?? shim.text}`);
284
- return shim;
285
- }
286
- };
287
- return shim;
288
- }
289
- function field(label, value, labelWidth = 12) {
290
- const paddedLabel = (label + ":").padEnd(labelWidth);
291
- return `${INDENT}${colors.muted(paddedLabel)} ${value}`;
292
- }
293
- function fieldMultiline(label, value, labelWidth = 12) {
294
- const lines = value.split("\n");
295
- const paddedLabel = (label + ":").padEnd(labelWidth);
296
- const indent = INDENT + " ".repeat(labelWidth + 1);
297
- if (lines.length === 1) return `${INDENT}${colors.muted(paddedLabel)} ${value}`;
298
- const firstLine = lines[0] ?? "";
299
- const result = [`${INDENT}${colors.muted(paddedLabel)} ${firstLine}`];
300
- for (let i = 1; i < lines.length; i++) result.push(`${indent}${lines[i] ?? ""}`);
301
- return result.join("\n");
302
- }
303
- function labelValue(label, value, labelWidth = DETAIL_LABEL_WIDTH) {
304
- return field(label, value, labelWidth).trimStart();
305
- }
306
- function formatTaskStatus(status) {
307
- const e = getStatusEmoji(status);
308
- const labels = {
309
- todo: "To Do",
310
- in_progress: "In Progress",
311
- done: "Done",
312
- cancelled: "Cancelled"
313
- };
314
- const statusColors = {
315
- todo: colors.muted,
316
- in_progress: colors.warning,
317
- done: colors.success,
318
- cancelled: colors.muted
319
- };
320
- return (statusColors[status] ?? colors.muted)(`${e} ${labels[status] ?? status}`);
321
- }
322
- function formatSprintStatus(status) {
323
- const e = getStatusEmoji(status);
324
- const labels = { draft: "Draft", active: "Active", closed: "Closed" };
325
- const statusColors = {
326
- draft: colors.warning,
327
- active: colors.success,
328
- closed: colors.muted
329
- };
330
- return (statusColors[status] ?? colors.muted)(`${e} ${labels[status] ?? status}`);
331
- }
332
- function badge(text, type = "muted") {
333
- return colors[type](`[${text}]`);
334
- }
335
- var boxChars = {
336
- light: {
337
- topLeft: "\u250C",
338
- topRight: "\u2510",
339
- bottomLeft: "\u2514",
340
- bottomRight: "\u2518",
341
- horizontal: "\u2500",
342
- vertical: "\u2502",
343
- teeRight: "\u251C",
344
- teeLeft: "\u2524",
345
- teeDown: "\u252C",
346
- teeUp: "\u2534",
347
- cross: "\u253C"
348
- },
349
- rounded: {
350
- topLeft: "\u256D",
351
- topRight: "\u256E",
352
- bottomLeft: "\u2570",
353
- bottomRight: "\u256F",
354
- horizontal: "\u2500",
355
- vertical: "\u2502",
356
- teeRight: "\u251C",
357
- teeLeft: "\u2524",
358
- teeDown: "\u252C",
359
- teeUp: "\u2534",
360
- cross: "\u253C"
361
- },
362
- heavy: {
363
- topLeft: "\u250F",
364
- topRight: "\u2513",
365
- bottomLeft: "\u2517",
366
- bottomRight: "\u251B",
367
- horizontal: "\u2501",
368
- vertical: "\u2503",
369
- teeRight: "\u2523",
370
- teeLeft: "\u252B",
371
- teeDown: "\u2533",
372
- teeUp: "\u253B",
373
- cross: "\u254B"
374
- }
375
- };
376
- var ANSI_REGEX = /\x1B(?:\[[0-9;]*[A-Za-z]|\][^\x07]*\x07|\([A-Z])/g;
377
- function stripAnsi(s) {
378
- return s.replace(ANSI_REGEX, "");
379
- }
380
- function sanitizeForDisplay(s) {
381
- return s.replace(ANSI_REGEX, "");
382
- }
383
- var MIN_BOX_WIDTH = 20;
384
- var DEFAULT_TERMINAL_WIDTH = 80;
385
- var DETAIL_LABEL_WIDTH = 14;
386
- function getTerminalWidth() {
387
- return process.stdout.columns || DEFAULT_TERMINAL_WIDTH;
388
- }
389
- function wrapLine(line, maxWidth) {
390
- const visible = stripAnsi(line);
391
- if (visible.length <= maxWidth) return [line];
392
- const indentMatch = /^(\s*)/.exec(visible);
393
- const indent = indentMatch?.[1] ?? "";
394
- const indentLen = indent.length;
395
- const wrapWidth = maxWidth - indentLen;
396
- if (wrapWidth <= 0) return [line];
397
- const words = visible.trimStart().split(/(\s+)/);
398
- const wrapped = [];
399
- let current = "";
400
- for (const word of words) {
401
- if (current.length + word.length <= wrapWidth) {
402
- current += word;
403
- } else if (current.length === 0) {
404
- for (let i = 0; i < word.length; i += wrapWidth) wrapped.push(indent + word.slice(i, i + wrapWidth));
405
- } else {
406
- wrapped.push(indent + current.trimEnd());
407
- current = word.trimStart();
408
- }
409
- }
410
- if (current.trimEnd().length > 0) wrapped.push(indent + current.trimEnd());
411
- return wrapped.length > 0 ? wrapped : [line];
412
- }
413
- function horizontalLine(width, style = "light") {
414
- return boxChars[style].horizontal.repeat(width);
415
- }
416
- function renderCard(title, lines, options = {}) {
417
- const { style = "rounded", colorFn = colors.muted } = options;
418
- const chars = boxChars[style];
419
- const termWidth = getTerminalWidth();
420
- const maxInnerWidth = Math.max(MIN_BOX_WIDTH, termWidth - 4);
421
- const safeTitle = sanitizeForDisplay(title);
422
- const titleWidth = Math.min(safeTitle.length, maxInnerWidth - 2);
423
- const wrappedLines = lines.flatMap((l) => wrapLine(l, maxInnerWidth - 2));
424
- const contentWidths = wrappedLines.map((l) => stripAnsi(l).length);
425
- const innerWidth = Math.min(Math.max(...contentWidths, titleWidth, MIN_BOX_WIDTH) + 2, maxInnerWidth);
426
- const result = [];
427
- result.push(colorFn(chars.topLeft + chars.horizontal.repeat(innerWidth) + chars.topRight));
428
- const titlePad = " ".repeat(Math.max(0, innerWidth - titleWidth - 2));
429
- result.push(colorFn(chars.vertical) + " " + colors.highlight(safeTitle) + titlePad + " " + colorFn(chars.vertical));
430
- result.push(colorFn(chars.teeRight + chars.horizontal.repeat(innerWidth) + chars.teeLeft));
431
- for (const line of wrappedLines) {
432
- const visibleLen = stripAnsi(line).length;
433
- const rightPad = " ".repeat(Math.max(0, innerWidth - visibleLen - 2));
434
- result.push(colorFn(chars.vertical) + " " + line + rightPad + " " + colorFn(chars.vertical));
435
- }
436
- result.push(colorFn(chars.bottomLeft + chars.horizontal.repeat(innerWidth) + chars.bottomRight));
437
- return result.join("\n");
438
- }
439
- function progressBar(done, total, options = {}) {
440
- const { width = 20, filled = "\u2588", empty = "\u2591", showPercent = true } = options;
441
- if (total === 0 || width <= 0) return colors.muted("\u2500".repeat(Math.max(0, width)));
442
- const filledCount = Math.round(done / total * width);
443
- const emptyCount = width - filledCount;
444
- const percent = Math.round(done / total * 100);
445
- const bar = colors.success(filled.repeat(filledCount)) + colors.muted(empty.repeat(emptyCount));
446
- if (!showPercent) return bar;
447
- const label = percent === 100 ? colors.success(`${String(percent)}%`) : colors.muted(`${String(percent)}%`);
448
- return `${bar} ${label}`;
449
- }
450
- function renderTable(columns, rows, options = {}) {
451
- const { style = "rounded", indent = 2, colorFn = colors.muted } = options;
452
- const chars = boxChars[style];
453
- const pad = " ".repeat(indent);
454
- const colWidths = columns.map((col, i) => {
455
- const headerWidth = col.header.length;
456
- const dataWidth = Math.max(0, ...rows.map((row) => stripAnsi(row[i] ?? "").length));
457
- return Math.max(headerWidth, dataWidth, col.minWidth ?? 0);
458
- });
459
- const result = [];
460
- const topLine = colWidths.map((w) => chars.horizontal.repeat(w + 2)).join(chars.teeDown);
461
- result.push(pad + colorFn(chars.topLeft + topLine + chars.topRight));
462
- const headerCells = columns.map((col, i) => {
463
- const w = colWidths[i] ?? 0;
464
- return " " + colors.highlight(col.header.padEnd(w)) + " ";
465
- });
466
- result.push(pad + colorFn(chars.vertical) + headerCells.join(colorFn(chars.vertical)) + colorFn(chars.vertical));
467
- const sepLine = colWidths.map((w) => chars.horizontal.repeat(w + 2)).join(chars.cross);
468
- result.push(pad + colorFn(chars.teeRight + sepLine + chars.teeLeft));
469
- for (const row of rows) {
470
- const cells = columns.map((col, i) => {
471
- const w = colWidths[i] ?? 0;
472
- const cell = row[i] ?? "";
473
- const visibleLen = stripAnsi(cell).length;
474
- const padding = Math.max(0, w - visibleLen);
475
- const coloredCell = col.color ? col.color(cell) : cell;
476
- if (col.align === "right") return " " + " ".repeat(padding) + coloredCell + " ";
477
- return " " + coloredCell + " ".repeat(padding) + " ";
478
- });
479
- result.push(pad + colorFn(chars.vertical) + cells.join(colorFn(chars.vertical)) + colorFn(chars.vertical));
480
- }
481
- const bottomLine = colWidths.map((w) => chars.horizontal.repeat(w + 2)).join(chars.teeUp);
482
- result.push(pad + colorFn(chars.bottomLeft + bottomLine + chars.bottomRight));
483
- return result.join("\n");
484
- }
485
-
486
- // src/integration/persistence/config.ts
487
- var DEFAULT_EVALUATION_ITERATIONS = 1;
488
- var DEFAULT_CONFIG = {
489
- currentSprint: null,
490
- aiProvider: null,
491
- editor: null
492
- };
493
- async function getConfig() {
494
- const configPath = getConfigPath();
495
- if (!await fileExists(configPath)) {
496
- return DEFAULT_CONFIG;
497
- }
498
- return unwrapOrThrow(await readValidatedJson(configPath, ConfigSchema));
499
- }
500
- async function saveConfig(config) {
501
- unwrapOrThrow(await writeValidatedJson(getConfigPath(), config, ConfigSchema));
502
- }
503
- async function getCurrentSprint() {
504
- const config = await getConfig();
505
- return config.currentSprint;
506
- }
507
- async function setCurrentSprint(sprintId) {
508
- const config = await getConfig();
509
- config.currentSprint = sprintId;
510
- await saveConfig(config);
511
- }
512
- async function getAiProvider() {
513
- const config = await getConfig();
514
- return config.aiProvider ?? null;
515
- }
516
- async function setAiProvider(provider) {
517
- const config = await getConfig();
518
- config.aiProvider = provider;
519
- await saveConfig(config);
520
- }
521
- async function getEditor() {
522
- const config = await getConfig();
523
- return config.editor ?? null;
524
- }
525
- async function setEditor(editor) {
526
- const config = await getConfig();
527
- config.editor = editor;
528
- await saveConfig(config);
529
- }
530
- async function getEvaluationIterations() {
531
- const config = await getConfig();
532
- return config.evaluationIterations ?? DEFAULT_EVALUATION_ITERATIONS;
533
- }
534
- async function setEvaluationIterations(iterations) {
535
- const config = await getConfig();
536
- config.evaluationIterations = iterations;
537
- await saveConfig(config);
538
- }
539
-
540
- export {
541
- emoji,
542
- colors,
543
- success,
544
- error,
545
- muted,
546
- gradients,
547
- banner,
548
- getRandomQuote,
549
- getQuoteForContext,
550
- icons,
551
- log,
552
- printHeader,
553
- printSeparator,
554
- showSuccess,
555
- showError,
556
- showWarning,
557
- showTip,
558
- showEmpty,
559
- showNextStep,
560
- showNextSteps,
561
- showRandomQuote,
562
- printCountSummary,
563
- printBanner,
564
- isTTY,
565
- terminalBell,
566
- createSpinner,
567
- field,
568
- fieldMultiline,
569
- labelValue,
570
- formatTaskStatus,
571
- formatSprintStatus,
572
- badge,
573
- boxChars,
574
- DETAIL_LABEL_WIDTH,
575
- horizontalLine,
576
- renderCard,
577
- progressBar,
578
- renderTable,
579
- getConfig,
580
- saveConfig,
581
- getCurrentSprint,
582
- setCurrentSprint,
583
- getAiProvider,
584
- setAiProvider,
585
- getEditor,
586
- setEditor,
587
- getEvaluationIterations,
588
- setEvaluationIterations
589
- };