@oisheek_c/codeforge 1.0.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 (141) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +7 -0
  3. package/apps/cli/bin/codeforge.cmd +2 -0
  4. package/apps/cli/src/bootstrap.js +115 -0
  5. package/apps/cli/src/cli.js +189 -0
  6. package/apps/cli/src/dev/git.js +17 -0
  7. package/apps/cli/src/dev/index.js +68 -0
  8. package/apps/cli/src/dev/provider.js +48 -0
  9. package/apps/cli/src/dev/scanner.js +14 -0
  10. package/apps/cli/src/index.js +31 -0
  11. package/bin/codeforge.js +2 -0
  12. package/package.json +63 -0
  13. package/packages/agent/contextBuilder.js +234 -0
  14. package/packages/agent/executor.js +1729 -0
  15. package/packages/agent/fallback.js +129 -0
  16. package/packages/agent/index.js +26 -0
  17. package/packages/agent/intent.js +73 -0
  18. package/packages/agent/modelSelector.js +469 -0
  19. package/packages/agent/planner.js +379 -0
  20. package/packages/agent/rag.js +412 -0
  21. package/packages/agent/ragSelector.js +570 -0
  22. package/packages/agent/router.js +121 -0
  23. package/packages/agent/thinking.js +54 -0
  24. package/packages/agent/toolCalls.js +258 -0
  25. package/packages/config/config.js +391 -0
  26. package/packages/config/defaults.js +72 -0
  27. package/packages/config/index.js +2 -0
  28. package/packages/core/approvalPolicy.js +140 -0
  29. package/packages/core/context.js +0 -0
  30. package/packages/core/message.js +0 -0
  31. package/packages/core/plan.js +0 -0
  32. package/packages/core/reasoning.js +0 -0
  33. package/packages/core/result.js +0 -0
  34. package/packages/core/retrieval.js +0 -0
  35. package/packages/core/tool.js +536 -0
  36. package/packages/git/branch.js +7 -0
  37. package/packages/git/commit.js +16 -0
  38. package/packages/git/diff.js +15 -0
  39. package/packages/git/git.js +35 -0
  40. package/packages/git/index.js +6 -0
  41. package/packages/git/remote.js +9 -0
  42. package/packages/git/status.js +11 -0
  43. package/packages/memory/index.js +0 -0
  44. package/packages/memory/project.js +0 -0
  45. package/packages/memory/session.js +0 -0
  46. package/packages/prompts/builder.js +43 -0
  47. package/packages/prompts/coder.js +38 -0
  48. package/packages/prompts/index.js +5 -0
  49. package/packages/prompts/planner.js +49 -0
  50. package/packages/prompts/reviewer.js +38 -0
  51. package/packages/prompts/system.js +94 -0
  52. package/packages/providers/index.js +31 -0
  53. package/packages/providers/openrouter.js +380 -0
  54. package/packages/reasoning/budget.js +0 -0
  55. package/packages/reasoning/chain.js +0 -0
  56. package/packages/reasoning/coder.js +0 -0
  57. package/packages/reasoning/evaluator.js +0 -0
  58. package/packages/reasoning/index.js +8 -0
  59. package/packages/reasoning/planner.js +0 -0
  60. package/packages/reasoning/reflector.js +0 -0
  61. package/packages/reasoning/reviewer.js +0 -0
  62. package/packages/reasoning/router.js +0 -0
  63. package/packages/retrieval/budget.js +92 -0
  64. package/packages/retrieval/cache.js +84 -0
  65. package/packages/retrieval/embeddings.js +147 -0
  66. package/packages/retrieval/graph.js +151 -0
  67. package/packages/retrieval/imports.js +74 -0
  68. package/packages/retrieval/index.js +9 -0
  69. package/packages/retrieval/parser/extractors/calls.js +43 -0
  70. package/packages/retrieval/parser/extractors/comments.js +49 -0
  71. package/packages/retrieval/parser/extractors/diagnostics.js +21 -0
  72. package/packages/retrieval/parser/extractors/exports.js +71 -0
  73. package/packages/retrieval/parser/extractors/imports.js +40 -0
  74. package/packages/retrieval/parser/extractors/index.js +12 -0
  75. package/packages/retrieval/parser/extractors/metrics.js +78 -0
  76. package/packages/retrieval/parser/extractors/symbols.js +51 -0
  77. package/packages/retrieval/parser/extractors/todos.js +53 -0
  78. package/packages/retrieval/parser/helpers.js +138 -0
  79. package/packages/retrieval/parser/index.js +10 -0
  80. package/packages/retrieval/parser/languages/c.js +14 -0
  81. package/packages/retrieval/parser/languages/cpp.js +21 -0
  82. package/packages/retrieval/parser/languages/csharp.js +14 -0
  83. package/packages/retrieval/parser/languages/go.js +14 -0
  84. package/packages/retrieval/parser/languages/index.js +12 -0
  85. package/packages/retrieval/parser/languages/java.js +14 -0
  86. package/packages/retrieval/parser/languages/javascript.js +14 -0
  87. package/packages/retrieval/parser/languages/php.js +14 -0
  88. package/packages/retrieval/parser/languages/python.js +14 -0
  89. package/packages/retrieval/parser/languages/ruby.js +14 -0
  90. package/packages/retrieval/parser/languages/rust.js +14 -0
  91. package/packages/retrieval/parser/languages/swift.js +14 -0
  92. package/packages/retrieval/parser/languages/typescript.js +14 -0
  93. package/packages/retrieval/parser/languages.js +218 -0
  94. package/packages/retrieval/parser/parseFile.js +79 -0
  95. package/packages/retrieval/parser/parseRepository.js +78 -0
  96. package/packages/retrieval/parser/queries/c.js +148 -0
  97. package/packages/retrieval/parser/queries/cpp.js +198 -0
  98. package/packages/retrieval/parser/queries/csharp.js +151 -0
  99. package/packages/retrieval/parser/queries/go.js +124 -0
  100. package/packages/retrieval/parser/queries/index.js +35 -0
  101. package/packages/retrieval/parser/queries/java.js +128 -0
  102. package/packages/retrieval/parser/queries/javascript.js +181 -0
  103. package/packages/retrieval/parser/queries/php.js +140 -0
  104. package/packages/retrieval/parser/queries/python.js +110 -0
  105. package/packages/retrieval/parser/queries/ruby.js +105 -0
  106. package/packages/retrieval/parser/queries/rust.js +175 -0
  107. package/packages/retrieval/parser/queries/swift.js +134 -0
  108. package/packages/retrieval/parser/queries/typescript.js +202 -0
  109. package/packages/retrieval/parser/registry.js +107 -0
  110. package/packages/retrieval/parser/traverse.js +82 -0
  111. package/packages/retrieval/parser/types.js +239 -0
  112. package/packages/retrieval/parser.js +78 -0
  113. package/packages/retrieval/ranker.js +73 -0
  114. package/packages/retrieval/retriever.js +910 -0
  115. package/packages/retrieval/symbols.js +145 -0
  116. package/packages/scanner/detect.js +69 -0
  117. package/packages/scanner/ignore.js +12 -0
  118. package/packages/scanner/index.js +2 -0
  119. package/packages/scanner/root.js +21 -0
  120. package/packages/scanner/scanner.js +35 -0
  121. package/packages/scanner/tree.js +45 -0
  122. package/packages/terminal/activity.js +514 -0
  123. package/packages/terminal/banner.js +34 -0
  124. package/packages/terminal/colors.js +16 -0
  125. package/packages/terminal/dashboard.js +94 -0
  126. package/packages/terminal/index.js +19 -0
  127. package/packages/terminal/logger.js +43 -0
  128. package/packages/terminal/prompt.js +11 -0
  129. package/packages/terminal/renderer.js +1209 -0
  130. package/packages/terminal/spinner.js +9 -0
  131. package/packages/tools/editFile.js +261 -0
  132. package/packages/tools/filesystem.js +82 -0
  133. package/packages/tools/index.js +24 -0
  134. package/packages/tools/readFile.js +101 -0
  135. package/packages/tools/registry.js +227 -0
  136. package/packages/tools/searchFiles.js +322 -0
  137. package/packages/tools/shell.js +352 -0
  138. package/packages/tools/writeFile.js +212 -0
  139. package/packages/utils/constants.js +0 -0
  140. package/packages/utils/helpers.js +0 -0
  141. package/packages/utils/logger.js +0 -0
@@ -0,0 +1,514 @@
1
+ /**
2
+ * packages/terminal/activity.js
3
+ *
4
+ * Mutable presentation state for the live
5
+ * CodeForge terminal dashboard.
6
+ *
7
+ * The agent/executor owns execution.
8
+ * This module only translates execution events
9
+ * into UI state.
10
+ */
11
+
12
+ const STAGE_LABELS = Object.freeze({
13
+ intent: {
14
+ active: "Understanding request",
15
+ complete: "Understood request",
16
+ },
17
+
18
+ plan: {
19
+ active: "Planning approach",
20
+ complete: "Planned approach",
21
+ },
22
+
23
+ retrieve: {
24
+ active: "Searching repository",
25
+ complete: "Searched repository",
26
+ },
27
+
28
+ context: {
29
+ active: "Building context",
30
+ complete: "Built context",
31
+ },
32
+
33
+ route: {
34
+ active: "Selecting model",
35
+ complete: "Selected model",
36
+ },
37
+
38
+ thinking: {
39
+ active: "Preparing reasoning",
40
+ complete: "Reasoning configured",
41
+ },
42
+
43
+ generate: {
44
+ active: "Thinking",
45
+ complete: "Generated response",
46
+ },
47
+
48
+ tool_round: {
49
+ active: "Using tools",
50
+ complete: "Completed tool round",
51
+ },
52
+
53
+ tool: {
54
+ active: "Running tool",
55
+ complete: "Completed tool",
56
+ },
57
+
58
+ approval: {
59
+ active: "Waiting for approval",
60
+ complete: "Approval resolved",
61
+ },
62
+
63
+ fallback: {
64
+ active: "Selecting fallback",
65
+ complete: "Switched model",
66
+ },
67
+
68
+ complete: {
69
+ active: "Finishing",
70
+ complete: "Completed",
71
+ },
72
+ });
73
+
74
+ function createUsage() {
75
+ return {
76
+ promptTokens: 0,
77
+ completionTokens: 0,
78
+ reasoningTokens: 0,
79
+ totalTokens: 0,
80
+ cost: null,
81
+ };
82
+ }
83
+
84
+ export function createActivityState({
85
+ projectRoot = null,
86
+ } = {}) {
87
+ return {
88
+ projectRoot,
89
+
90
+ running: false,
91
+ completed: false,
92
+ failed: false,
93
+
94
+ startedAt: null,
95
+ completedAt: null,
96
+
97
+ activeStage: null,
98
+ activeLabel: "",
99
+ activeDetail: "",
100
+ activeStartedAt: null,
101
+
102
+ completedStages: [],
103
+
104
+ retrievedFiles: [],
105
+ retrievedResults: [],
106
+
107
+ contextMetrics: [],
108
+
109
+ provider: null,
110
+ modelRole: null,
111
+ model: null,
112
+
113
+ attempt: null,
114
+ maxAttempts: null,
115
+ attempts: null,
116
+
117
+ finishReason: null,
118
+
119
+ usage: createUsage(),
120
+
121
+ lastError: null,
122
+ };
123
+ }
124
+
125
+ export function resetActivityState(
126
+ state
127
+ ) {
128
+ const fresh =
129
+ createActivityState({
130
+ projectRoot:
131
+ state.projectRoot,
132
+ });
133
+
134
+ Object.assign(
135
+ state,
136
+ fresh
137
+ );
138
+
139
+ state.running = true;
140
+ state.startedAt =
141
+ Date.now();
142
+
143
+ return state;
144
+ }
145
+
146
+ function getStageLabel(
147
+ stage,
148
+ mode
149
+ ) {
150
+ return (
151
+ STAGE_LABELS[stage]?.[mode] ??
152
+ stage ??
153
+ "Working"
154
+ );
155
+ }
156
+
157
+ function updateTelemetry(
158
+ state,
159
+ event
160
+ ) {
161
+ const data =
162
+ event?.data;
163
+
164
+ if (!data) {
165
+ return;
166
+ }
167
+
168
+ if (
169
+ event.type ===
170
+ "context:metrics"
171
+ ) {
172
+ /*
173
+ * A fallback may measure the same model
174
+ * context again before another provider
175
+ * attempt.
176
+ *
177
+ * Preserve genuinely different tool rounds,
178
+ * but avoid visually duplicating an identical
179
+ * context measurement.
180
+ */
181
+ const metric = {
182
+ toolRound:
183
+ data.toolRound ?? 0,
184
+
185
+ messages:
186
+ data.messages ?? 0,
187
+
188
+ chars:
189
+ data.chars ?? {},
190
+
191
+ estimatedTokens:
192
+ data.estimatedTokens ?? {},
193
+ };
194
+
195
+ const previous =
196
+ state.contextMetrics[
197
+ state.contextMetrics.length - 1
198
+ ];
199
+
200
+ const duplicate =
201
+ previous &&
202
+ previous.toolRound ===
203
+ metric.toolRound &&
204
+ previous.messages ===
205
+ metric.messages &&
206
+ previous.estimatedTokens?.total ===
207
+ metric.estimatedTokens?.total;
208
+
209
+ if (!duplicate) {
210
+ state.contextMetrics.push(
211
+ metric
212
+ );
213
+ }
214
+
215
+ return;
216
+ }
217
+
218
+ if (
219
+ event.stage ===
220
+ "retrieve"
221
+ ) {
222
+ if (
223
+ Array.isArray(
224
+ data.files
225
+ )
226
+ ) {
227
+ state.retrievedFiles = [
228
+ ...data.files,
229
+ ];
230
+ }
231
+
232
+ if (
233
+ Array.isArray(
234
+ data.results
235
+ )
236
+ ) {
237
+ state.retrievedResults =
238
+ data.results.map(
239
+ (result) => ({
240
+ path:
241
+ result?.path ?? "",
242
+
243
+ score:
244
+ Number.isFinite(
245
+ result?.score
246
+ )
247
+ ? result.score
248
+ : null,
249
+
250
+ reason:
251
+ result?.reason ??
252
+ null,
253
+ })
254
+ );
255
+ }
256
+ }
257
+
258
+ if (data.provider) {
259
+ state.provider =
260
+ data.provider;
261
+ }
262
+
263
+ if (data.modelRole) {
264
+ state.modelRole =
265
+ data.modelRole;
266
+ }
267
+
268
+ if (data.model) {
269
+ state.model =
270
+ data.model;
271
+ }
272
+
273
+ if (
274
+ Number.isFinite(
275
+ data.attempt
276
+ )
277
+ ) {
278
+ state.attempt =
279
+ data.attempt;
280
+ }
281
+
282
+ if (
283
+ Number.isFinite(
284
+ data.maxAttempts
285
+ )
286
+ ) {
287
+ state.maxAttempts =
288
+ data.maxAttempts;
289
+ }
290
+
291
+ if (
292
+ Number.isFinite(
293
+ data.attempts
294
+ )
295
+ ) {
296
+ state.attempts =
297
+ data.attempts;
298
+ }
299
+
300
+ if (data.finishReason) {
301
+ state.finishReason =
302
+ data.finishReason;
303
+ }
304
+
305
+ if (data.usage) {
306
+ state.usage = {
307
+ ...state.usage,
308
+ ...data.usage,
309
+ };
310
+ }
311
+ }
312
+
313
+ function completeStage(
314
+ state,
315
+ event,
316
+ status
317
+ ) {
318
+ const stage =
319
+ event.stage;
320
+
321
+ const now =
322
+ Date.now();
323
+
324
+ let durationMs =
325
+ Number.isFinite(
326
+ event.durationMs
327
+ )
328
+ ? event.durationMs
329
+ : null;
330
+
331
+ if (
332
+ state.activeStage ===
333
+ stage &&
334
+ Number.isFinite(
335
+ state.activeStartedAt
336
+ )
337
+ ) {
338
+ durationMs =
339
+ now -
340
+ state.activeStartedAt;
341
+ }
342
+
343
+ const existingIndex =
344
+ state.completedStages.findIndex(
345
+ (item) =>
346
+ item.stage === stage
347
+ );
348
+
349
+ const item = {
350
+ stage,
351
+ status,
352
+
353
+ label:
354
+ getStageLabel(
355
+ stage,
356
+ "complete"
357
+ ),
358
+
359
+ detail:
360
+ event.detail ?? "",
361
+
362
+ durationMs,
363
+ };
364
+
365
+ if (
366
+ existingIndex >= 0
367
+ ) {
368
+ state.completedStages[
369
+ existingIndex
370
+ ] = item;
371
+ } else {
372
+ state.completedStages.push(
373
+ item
374
+ );
375
+ }
376
+
377
+ if (
378
+ state.activeStage ===
379
+ stage
380
+ ) {
381
+ state.activeStage =
382
+ null;
383
+
384
+ state.activeLabel =
385
+ "";
386
+
387
+ state.activeDetail =
388
+ "";
389
+
390
+ state.activeStartedAt =
391
+ null;
392
+ }
393
+ }
394
+
395
+ export function applyActivityEvent(
396
+ state,
397
+ event = {}
398
+ ) {
399
+ if (
400
+ event.type ===
401
+ "run:start"
402
+ ) {
403
+ resetActivityState(
404
+ state
405
+ );
406
+
407
+ return state;
408
+ }
409
+
410
+ updateTelemetry(
411
+ state,
412
+ event
413
+ );
414
+
415
+ if (
416
+ event.type ===
417
+ "context:metrics"
418
+ ) {
419
+ return state;
420
+ }
421
+
422
+ if (
423
+ event.type ===
424
+ "stage:start"
425
+ ) {
426
+ state.activeStage =
427
+ event.stage;
428
+
429
+ state.activeLabel =
430
+ getStageLabel(
431
+ event.stage,
432
+ "active"
433
+ );
434
+
435
+ state.activeDetail =
436
+ event.detail ?? "";
437
+
438
+ state.activeStartedAt =
439
+ Date.now();
440
+
441
+ return state;
442
+ }
443
+
444
+ if (
445
+ event.type ===
446
+ "stage:success"
447
+ ) {
448
+ completeStage(
449
+ state,
450
+ event,
451
+ "success"
452
+ );
453
+
454
+ if (
455
+ event.stage ===
456
+ "complete"
457
+ ) {
458
+ state.running =
459
+ false;
460
+
461
+ state.completed =
462
+ true;
463
+
464
+ state.completedAt =
465
+ Date.now();
466
+ }
467
+
468
+ return state;
469
+ }
470
+
471
+ if (
472
+ event.type ===
473
+ "stage:error"
474
+ ) {
475
+ completeStage(
476
+ state,
477
+ event,
478
+ "error"
479
+ );
480
+
481
+ state.lastError =
482
+ event.detail ??
483
+ "Execution failed";
484
+
485
+ if (
486
+ event.stage ===
487
+ "complete"
488
+ ) {
489
+ state.running =
490
+ false;
491
+
492
+ state.failed =
493
+ true;
494
+
495
+ state.completedAt =
496
+ Date.now();
497
+ }
498
+
499
+ return state;
500
+ }
501
+
502
+ if (
503
+ event.type ===
504
+ "stage:skipped"
505
+ ) {
506
+ completeStage(
507
+ state,
508
+ event,
509
+ "skipped"
510
+ );
511
+ }
512
+
513
+ return state;
514
+ }
@@ -0,0 +1,34 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { colors } from "./colors.js";
3
+
4
+ const packageJson = JSON.parse(
5
+ readFileSync(new URL("../../package.json", import.meta.url), "utf8")
6
+ );
7
+
8
+ const VERSION = packageJson.version;
9
+
10
+ export function showBanner() {
11
+ console.clear();
12
+
13
+ const logo = `
14
+ ██████╗ ██████╗ ██████╗ ███████╗███████╗ ██████╗ ██████╗ ██████╗ ███████╗
15
+ ██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔════╝
16
+ ██║ ██║ ██║██║ ██║█████╗ █████╗ ██║ ██║██████╔╝██║ ███╗█████╗
17
+ ██║ ██║ ██║██║ ██║██╔══╝ ██╔══╝ ██║ ██║██╔══██╗██║ ██║██╔══╝
18
+ ╚██████╗╚██████╔╝██████╔╝███████╗██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
19
+ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
20
+ `;
21
+
22
+ console.log(colors.primary(logo));
23
+
24
+ console.log(colors.bold(colors.text(`CodeForge AI v${VERSION}`)));
25
+ console.log(colors.muted("Terminal-Native AI Software Engineering Agent"));
26
+
27
+ console.log(
28
+ colors.primary(
29
+ "────────────────────────────────────────────────────────────"
30
+ )
31
+ );
32
+
33
+ console.log();
34
+ }
@@ -0,0 +1,16 @@
1
+ import chalk from "chalk";
2
+
3
+ export const colors = {
4
+ primary: chalk.cyanBright,
5
+ secondary: chalk.blueBright,
6
+
7
+ success: chalk.greenBright,
8
+ warning: chalk.yellowBright,
9
+ error: chalk.redBright,
10
+ info: chalk.blue,
11
+
12
+ text: chalk.white,
13
+ muted: chalk.gray,
14
+
15
+ bold: chalk.bold,
16
+ };
@@ -0,0 +1,94 @@
1
+ /**
2
+ * packages/terminal/dashboard.js
3
+ *
4
+ * Coordinates agent activity events with
5
+ * the live terminal renderer.
6
+ *
7
+ * Execution remains owned by packages/agent.
8
+ * Presentation remains owned by packages/terminal.
9
+ */
10
+
11
+ import {
12
+ applyActivityEvent,
13
+ createActivityState,
14
+ } from "./activity.js";
15
+
16
+ import {
17
+ createLiveRenderer,
18
+ } from "./renderer.js";
19
+
20
+ export function createAgentDashboard({
21
+ enabled = true,
22
+ projectRoot = null,
23
+ } = {}) {
24
+ const interactive =
25
+ Boolean(
26
+ enabled &&
27
+ process.stdout.isTTY
28
+ );
29
+
30
+ const state =
31
+ createActivityState({
32
+ projectRoot,
33
+ });
34
+
35
+ const renderer =
36
+ createLiveRenderer({
37
+ enabled:
38
+ interactive,
39
+ });
40
+
41
+ function handle(
42
+ event = {}
43
+ ) {
44
+ if (!interactive) {
45
+ return;
46
+ }
47
+
48
+ applyActivityEvent(
49
+ state,
50
+ event
51
+ );
52
+
53
+ renderer.setState(
54
+ state
55
+ );
56
+ }
57
+
58
+ function suspend() {
59
+ renderer.suspend();
60
+ }
61
+
62
+ function resume() {
63
+ renderer.resume();
64
+ }
65
+
66
+ function finish() {
67
+ if (!interactive) {
68
+ return;
69
+ }
70
+
71
+ renderer.setState(
72
+ state
73
+ );
74
+
75
+ renderer.finish();
76
+ }
77
+
78
+ function dispose() {
79
+ renderer.dispose();
80
+ }
81
+
82
+ return {
83
+ enabled:
84
+ interactive,
85
+
86
+ handle,
87
+
88
+ suspend,
89
+ resume,
90
+
91
+ finish,
92
+ dispose,
93
+ };
94
+ }
@@ -0,0 +1,19 @@
1
+ export * from "./banner.js";
2
+ export * from "./colors.js";
3
+ export * from "./logger.js";
4
+ export * from "./prompt.js";
5
+ export * from "./spinner.js";
6
+
7
+ export {
8
+ createActivityState,
9
+ resetActivityState,
10
+ applyActivityEvent,
11
+ } from "./activity.js";
12
+
13
+ export {
14
+ createLiveRenderer,
15
+ } from "./renderer.js";
16
+
17
+ export {
18
+ createAgentDashboard,
19
+ } from "./dashboard.js";
@@ -0,0 +1,43 @@
1
+ import { colors } from "./colors.js";
2
+
3
+ function print(symbol, color, message = "") {
4
+ console.log(
5
+ color(`${symbol} ${String(message)}`)
6
+ );
7
+ }
8
+
9
+ export const logger = {
10
+ info(message) {
11
+ print("ℹ", colors.info, message);
12
+ },
13
+
14
+ success(message) {
15
+ print("✔", colors.success, message);
16
+ },
17
+
18
+ warn(message) {
19
+ print("⚠", colors.warning, message);
20
+ },
21
+
22
+ error(message) {
23
+ print("✖", colors.error, message);
24
+ },
25
+
26
+ debug(message) {
27
+ if (process.env.DEBUG === "true") {
28
+ print("•", colors.secondary, message);
29
+ }
30
+ },
31
+
32
+ plain(message) {
33
+ console.log(colors.text(message));
34
+ },
35
+
36
+ line() {
37
+ console.log(
38
+ colors.muted(
39
+ "────────────────────────────────────────────────────────────────"
40
+ )
41
+ );
42
+ },
43
+ };
@@ -0,0 +1,11 @@
1
+ import readline from "node:readline";
2
+
3
+ export function createPrompt() {
4
+ return readline.createInterface({
5
+ input: process.stdin,
6
+ output: process.stdout,
7
+ prompt: "> ",
8
+ historySize: 1000,
9
+ terminal: true,
10
+ });
11
+ }