loopwork 0.3.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 (62) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +528 -0
  3. package/bin/loopwork +0 -0
  4. package/examples/README.md +70 -0
  5. package/examples/basic-json-backend/.specs/tasks/TASK-001.md +22 -0
  6. package/examples/basic-json-backend/.specs/tasks/TASK-002.md +23 -0
  7. package/examples/basic-json-backend/.specs/tasks/TASK-003.md +37 -0
  8. package/examples/basic-json-backend/.specs/tasks/tasks.json +19 -0
  9. package/examples/basic-json-backend/README.md +32 -0
  10. package/examples/basic-json-backend/TESTING.md +184 -0
  11. package/examples/basic-json-backend/hello.test.ts +9 -0
  12. package/examples/basic-json-backend/hello.ts +3 -0
  13. package/examples/basic-json-backend/loopwork.config.js +35 -0
  14. package/examples/basic-json-backend/math.test.ts +29 -0
  15. package/examples/basic-json-backend/math.ts +3 -0
  16. package/examples/basic-json-backend/package.json +15 -0
  17. package/examples/basic-json-backend/quick-start.sh +80 -0
  18. package/loopwork.config.ts +164 -0
  19. package/package.json +26 -0
  20. package/src/backends/github.ts +426 -0
  21. package/src/backends/index.ts +86 -0
  22. package/src/backends/json.ts +598 -0
  23. package/src/backends/plugin.ts +317 -0
  24. package/src/backends/types.ts +19 -0
  25. package/src/commands/init.ts +100 -0
  26. package/src/commands/run.ts +365 -0
  27. package/src/contracts/backend.ts +127 -0
  28. package/src/contracts/config.ts +129 -0
  29. package/src/contracts/index.ts +43 -0
  30. package/src/contracts/plugin.ts +82 -0
  31. package/src/contracts/task.ts +78 -0
  32. package/src/core/cli.ts +275 -0
  33. package/src/core/config.ts +165 -0
  34. package/src/core/state.ts +154 -0
  35. package/src/core/utils.ts +125 -0
  36. package/src/dashboard/cli.ts +449 -0
  37. package/src/dashboard/index.ts +6 -0
  38. package/src/dashboard/kanban.tsx +226 -0
  39. package/src/dashboard/tui.tsx +372 -0
  40. package/src/index.ts +19 -0
  41. package/src/mcp/server.ts +451 -0
  42. package/src/monitor/index.ts +420 -0
  43. package/src/plugins/asana.ts +192 -0
  44. package/src/plugins/cost-tracking.ts +402 -0
  45. package/src/plugins/discord.ts +269 -0
  46. package/src/plugins/everhour.ts +335 -0
  47. package/src/plugins/index.ts +253 -0
  48. package/src/plugins/telegram/bot.ts +517 -0
  49. package/src/plugins/telegram/index.ts +6 -0
  50. package/src/plugins/telegram/notifications.ts +198 -0
  51. package/src/plugins/todoist.ts +261 -0
  52. package/test/backends.test.ts +929 -0
  53. package/test/cli.test.ts +145 -0
  54. package/test/config.test.ts +90 -0
  55. package/test/e2e.test.ts +458 -0
  56. package/test/github-tasks.test.ts +191 -0
  57. package/test/loopwork-config-types.test.ts +288 -0
  58. package/test/monitor.test.ts +123 -0
  59. package/test/plugins.test.ts +1175 -0
  60. package/test/state.test.ts +295 -0
  61. package/test/utils.test.ts +60 -0
  62. package/tsconfig.json +20 -0
@@ -0,0 +1,37 @@
1
+ # TASK-003: Create README Documentation
2
+
3
+ ## Goal
4
+ Write a simple README.md file for the project
5
+
6
+ ## Requirements
7
+ - Create a `README.md` file in the project root
8
+ - Include a project title
9
+ - Add a brief description
10
+ - List the functions available
11
+ - Show usage examples
12
+
13
+ ## Example Structure
14
+ ```markdown
15
+ # My Project
16
+
17
+ A simple TypeScript project with basic utility functions.
18
+
19
+ ## Functions
20
+
21
+ ### sayHello()
22
+ Returns a greeting message.
23
+
24
+ ### sum(a, b)
25
+ Adds two numbers together.
26
+
27
+ ## Usage
28
+
29
+ `npm install`
30
+ `npm test`
31
+ ```
32
+
33
+ ## Success Criteria
34
+ - README.md exists
35
+ - Contains all required sections
36
+ - Examples are clear and accurate
37
+ - Proper markdown formatting
@@ -0,0 +1,19 @@
1
+ {
2
+ "tasks": [
3
+ {
4
+ "id": "TASK-001",
5
+ "status": "completed",
6
+ "priority": "high"
7
+ },
8
+ {
9
+ "id": "TASK-002",
10
+ "status": "completed",
11
+ "priority": "medium"
12
+ },
13
+ {
14
+ "id": "TASK-003",
15
+ "status": "completed",
16
+ "priority": "low"
17
+ }
18
+ ]
19
+ }
@@ -0,0 +1,32 @@
1
+ # Basic JSON Backend
2
+
3
+ A simple TypeScript project with basic utility functions.
4
+
5
+ ## Functions
6
+
7
+ ### sayHello()
8
+ Returns a greeting message.
9
+
10
+ ### sum(a, b)
11
+ Adds two numbers together.
12
+
13
+ ## Usage
14
+
15
+ ### Install dependencies
16
+ ```bash
17
+ bun install
18
+ ```
19
+
20
+ ### Run tests
21
+ ```bash
22
+ bun test
23
+ ```
24
+
25
+ ## Example
26
+ ```typescript
27
+ import { sayHello } from './hello'
28
+ import { sum } from './math'
29
+
30
+ console.log(sayHello()) // 'Hello, World!'
31
+ console.log(sum(2, 3)) // 5
32
+ ```
@@ -0,0 +1,184 @@
1
+ # Testing Guide
2
+
3
+ This document explains how to test the loopwork example.
4
+
5
+ ## Quick Start
6
+
7
+ ### Option 1: Interactive Menu
8
+
9
+ ```bash
10
+ ./quick-start.sh
11
+ ```
12
+
13
+ Choose from:
14
+ 1. **Dry Run** - Preview tasks without executing
15
+ 2. **Run Loopwork** - Execute tasks with AI
16
+ 3. **Reset tasks** - Reset all tasks to pending status
17
+ 4. **View task details** - See task descriptions
18
+
19
+ ### Option 2: Direct Commands
20
+
21
+ ```bash
22
+ # Dry run (preview)
23
+ bun run dry-run
24
+
25
+ # Actually execute
26
+ bun run start
27
+
28
+ # With explicit flags
29
+ bun ../../src/index.ts --dry-run
30
+ bun ../../src/index.ts --cli claude --timeout 600
31
+ ```
32
+
33
+ ## Testing Checklist
34
+
35
+ ### 1. Config Loading
36
+
37
+ ```bash
38
+ bun ../../src/index.ts --dry-run 2>&1 | grep "CLI:"
39
+ # Should show: CLI: claude (from config)
40
+
41
+ bun ../../src/index.ts --dry-run 2>&1 | grep "Max Iterations:"
42
+ # Should show: Max Iterations: 10 (from config)
43
+ ```
44
+
45
+ ### 2. Dry Run Mode
46
+
47
+ ```bash
48
+ bun ../../src/index.ts --dry-run 2>&1 | grep "Dry Run:"
49
+ # Should show: Dry Run: true
50
+
51
+ bun ../../src/index.ts 2>&1 | grep "Dry Run:"
52
+ # Should show: Dry Run: false
53
+ ```
54
+
55
+ ### 3. Task Priority
56
+
57
+ ```bash
58
+ bun ../../src/index.ts --dry-run 2>&1 | grep "Task:" | head -1
59
+ # Should show: Task: TASK-001 (high priority first)
60
+ ```
61
+
62
+ ### 4. Config Override
63
+
64
+ ```bash
65
+ bun ../../src/index.ts --cli opencode --dry-run 2>&1 | grep "CLI:"
66
+ # Should show: CLI: opencode (CLI arg overrides config)
67
+ ```
68
+
69
+ ## Manual Testing
70
+
71
+ ### Test 1: Complete Workflow
72
+
73
+ 1. Reset tasks: `echo "3" | ./quick-start.sh`
74
+ 2. Check status: `cat .specs/tasks/tasks.json`
75
+ 3. Run dry-run: `bun run dry-run`
76
+ 4. Verify output shows all 3 tasks
77
+
78
+ ### Test 2: Task Execution
79
+
80
+ āš ļø **Warning**: This will actually execute AI commands!
81
+
82
+ ```bash
83
+ # Make sure you want to run this
84
+ bun run start
85
+
86
+ # Monitor in another terminal
87
+ tail -f loopwork-runs/basic-example/*/logs/iteration-*.txt
88
+ ```
89
+
90
+ ### Test 3: State Management
91
+
92
+ ```bash
93
+ # Start execution
94
+ bun run start
95
+
96
+ # In another terminal, send SIGINT
97
+ kill -INT <pid>
98
+
99
+ # Should save state and show:
100
+ # "State saved. Resume with: --resume"
101
+
102
+ # Resume
103
+ bun ../../src/index.ts --resume
104
+ ```
105
+
106
+ ## Debugging
107
+
108
+ ### Enable Debug Mode
109
+
110
+ ```bash
111
+ # Method 1: Environment variable
112
+ LOOPWORK_DEBUG=true bun ../../src/index.ts --dry-run
113
+
114
+ # Method 2: CLI flag
115
+ bun ../../src/index.ts --debug --dry-run
116
+ ```
117
+
118
+ ### Check Command Being Executed
119
+
120
+ ```bash
121
+ bun ../../src/index.ts --debug --dry-run 2>&1 | grep "Executing:"
122
+ # Shows: [model-name] Executing: <command>
123
+ ```
124
+
125
+ ### Verify Config File Loading
126
+
127
+ ```bash
128
+ # Should NOT show warning about failed config load
129
+ bun ../../src/index.ts --dry-run 2>&1 | head -5
130
+ ```
131
+
132
+ ## Common Issues
133
+
134
+ ### "No pending tasks found"
135
+
136
+ Tasks have been completed. Reset them:
137
+ ```bash
138
+ echo "3" | ./quick-start.sh
139
+ ```
140
+
141
+ ### "Another loopwork is running"
142
+
143
+ Remove the lock file:
144
+ ```bash
145
+ rm -rf .loopwork-*.lock
146
+ ```
147
+
148
+ ### Config not loading
149
+
150
+ Make sure you're in the correct directory:
151
+ ```bash
152
+ pwd
153
+ # Should be: .../examples/basic-json-backend
154
+
155
+ ls loopwork.config.js
156
+ # Should exist
157
+ ```
158
+
159
+ ### --dry-run not working
160
+
161
+ This was a known issue that's now fixed. Update to latest code:
162
+ ```bash
163
+ git pull origin main
164
+ ```
165
+
166
+ ## Success Criteria
167
+
168
+ All of these should pass:
169
+
170
+ - āœ… `./quick-start.sh` shows interactive menu
171
+ - āœ… `bun run dry-run` shows 3 pending tasks
172
+ - āœ… Config values are loaded (claude CLI, 10 max iterations, 300s timeout)
173
+ - āœ… `--dry-run` flag shows "Dry Run: true"
174
+ - āœ… Tasks are shown in priority order (TASK-001 first)
175
+ - āœ… Command being executed is displayed
176
+
177
+ ## Next Steps
178
+
179
+ After testing the basic example:
180
+
181
+ 1. Try modifying the config (change CLI, timeouts, etc.)
182
+ 2. Create your own tasks in `.specs/tasks/`
183
+ 3. Experiment with task dependencies
184
+ 4. Add plugins (Telegram, cost tracking, etc.)
@@ -0,0 +1,9 @@
1
+ import { describe, it, expect } from 'bun:test'
2
+ import { sayHello } from './hello'
3
+
4
+ describe('sayHello', () => {
5
+ it('should return "Hello, World!"', () => {
6
+ const result = sayHello()
7
+ expect(result).toBe('Hello, World!')
8
+ })
9
+ })
@@ -0,0 +1,3 @@
1
+ export function sayHello(): string {
2
+ return 'Hello, World!'
3
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Basic Loopwork Configuration Example
3
+ *
4
+ * This is a minimal configuration for testing loopwork with JSON backend.
5
+ * Tasks are stored in .specs/tasks/tasks.json
6
+ */
7
+
8
+ export default {
9
+ // Backend configuration
10
+ backend: {
11
+ type: 'json',
12
+ tasksFile: '.specs/tasks/tasks.json',
13
+ tasksDir: '.specs/tasks',
14
+ },
15
+
16
+ // CLI tool to use: 'opencode' or 'claude'
17
+ cli: 'claude',
18
+
19
+ // Loop settings
20
+ maxIterations: 10,
21
+ timeout: 300, // 5 minutes per task
22
+
23
+ // Optional settings
24
+ // dryRun: false, // Set to true to test without executing (use --dry-run flag instead)
25
+ debug: true, // Enable debug logging
26
+ // autoConfirm: false, // Set to true to skip confirmations (use -y flag instead)
27
+
28
+ // Retry settings
29
+ maxRetries: 2,
30
+ retryDelay: 3000, // Wait 3 seconds before retry
31
+ taskDelay: 2000, // Wait 2 seconds between tasks
32
+
33
+ // Namespace for concurrent runs
34
+ namespace: 'basic-example',
35
+ }
@@ -0,0 +1,29 @@
1
+ import { describe, it, expect } from 'bun:test'
2
+ import { sum } from './math'
3
+
4
+ describe('sum', () => {
5
+ it('should add two positive integers', () => {
6
+ const result = sum(2, 3)
7
+ expect(result).toBe(5)
8
+ })
9
+
10
+ it('should add two negative integers', () => {
11
+ const result = sum(-2, -3)
12
+ expect(result).toBe(-5)
13
+ })
14
+
15
+ it('should add positive and negative integers', () => {
16
+ const result = sum(5, -3)
17
+ expect(result).toBe(2)
18
+ })
19
+
20
+ it('should handle decimal numbers', () => {
21
+ const result = sum(2.5, 3.7)
22
+ expect(result).toBe(6.2)
23
+ })
24
+
25
+ it('should handle zero', () => {
26
+ const result = sum(0, 5)
27
+ expect(result).toBe(5)
28
+ })
29
+ })
@@ -0,0 +1,3 @@
1
+ export function sum(a: number, b: number): number {
2
+ return a + b
3
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "loopwork-example-basic",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "description": "Basic example of using Loopwork with JSON backend",
7
+ "scripts": {
8
+ "start": "bun run ../../src/index.ts",
9
+ "dry-run": "bun run ../../src/index.ts --dry-run",
10
+ "build": "echo 'No build needed for example'"
11
+ },
12
+ "devDependencies": {
13
+ "@types/bun": "latest"
14
+ }
15
+ }
@@ -0,0 +1,80 @@
1
+ #!/bin/bash
2
+ # Quick Start Script for Basic JSON Backend Example
3
+
4
+ set -e
5
+
6
+ echo "šŸš€ Loopwork Basic Example - Quick Start"
7
+ echo "========================================"
8
+ echo ""
9
+
10
+ # Check if we're in the right directory
11
+ if [ ! -f "loopwork.config.js" ] && [ ! -f "loopwork.config.ts" ]; then
12
+ echo "āŒ Error: Please run this script from the examples/basic-json-backend directory"
13
+ exit 1
14
+ fi
15
+
16
+ echo "šŸ“‹ Current Tasks:"
17
+ cat .specs/tasks/tasks.json | grep -A 2 '"id"'
18
+ echo ""
19
+
20
+ echo "Choose an option:"
21
+ echo "1) Dry Run (preview without executing)"
22
+ echo "2) Run Loopwork (execute tasks)"
23
+ echo "3) Reset tasks to pending"
24
+ echo "4) View task details"
25
+ echo ""
26
+
27
+ read -p "Enter your choice (1-4): " choice
28
+
29
+ case $choice in
30
+ 1)
31
+ echo ""
32
+ echo "šŸ” Running dry-run..."
33
+ bun run ../../src/index.ts --dry-run
34
+ ;;
35
+ 2)
36
+ echo ""
37
+ echo "⚔ Running Loopwork..."
38
+ bun run ../../src/index.ts
39
+ ;;
40
+ 3)
41
+ echo ""
42
+ echo "šŸ”„ Resetting all tasks to pending..."
43
+ cat > .specs/tasks/tasks.json << 'EOF'
44
+ {
45
+ "tasks": [
46
+ {
47
+ "id": "TASK-001",
48
+ "status": "pending",
49
+ "priority": "high"
50
+ },
51
+ {
52
+ "id": "TASK-002",
53
+ "status": "pending",
54
+ "priority": "medium"
55
+ },
56
+ {
57
+ "id": "TASK-003",
58
+ "status": "pending",
59
+ "priority": "low"
60
+ }
61
+ ]
62
+ }
63
+ EOF
64
+ echo "āœ… Tasks reset!"
65
+ ;;
66
+ 4)
67
+ echo ""
68
+ echo "šŸ“„ Task Details:"
69
+ echo ""
70
+ for task in .specs/tasks/TASK-*.md; do
71
+ echo "----------------------------------------"
72
+ head -5 "$task"
73
+ echo ""
74
+ done
75
+ ;;
76
+ *)
77
+ echo "āŒ Invalid choice"
78
+ exit 1
79
+ ;;
80
+ esac
@@ -0,0 +1,164 @@
1
+ import {
2
+ defineConfig,
3
+ withTelegram,
4
+ withCostTracking,
5
+ withJSON,
6
+ withGitHub,
7
+ withPlugin,
8
+ withAsana,
9
+ withEverhour,
10
+ withTodoist,
11
+ withDiscord,
12
+ compose,
13
+ } from './src/loopwork-config-types'
14
+ import { withJSONBackend, withGitHubBackend } from './src/backend-plugin'
15
+
16
+ /**
17
+ * Loopwork Configuration
18
+ *
19
+ * This file configures the Loopwork task runner.
20
+ * Similar to next.config.js, you can use plugin wrappers to add functionality.
21
+ *
22
+ * Backends are now plugins:
23
+ * - withJSONBackend({ tasksFile: 'tasks.json' })
24
+ * - withGitHubBackend({ repo: 'owner/repo' })
25
+ */
26
+
27
+ // =============================================================================
28
+ // Full Example with All Plugins
29
+ // =============================================================================
30
+
31
+ export default compose(
32
+ // Backend plugins (choose one)
33
+ withJSONBackend({ tasksFile: '.specs/tasks/tasks.json' }),
34
+ // withGitHubBackend({ repo: 'owner/repo' }),
35
+
36
+ // Legacy backend config (still supported)
37
+ // withJSON({ tasksFile: '.specs/tasks/tasks.json' }),
38
+ // withGitHub({ repo: 'owner/repo' }),
39
+
40
+ // Telegram notifications on task events
41
+ withTelegram({
42
+ botToken: process.env.TELEGRAM_BOT_TOKEN,
43
+ chatId: process.env.TELEGRAM_CHAT_ID,
44
+ silent: false,
45
+ }),
46
+
47
+ // Asana integration: sync task status to Asana project
48
+ // Tasks should have metadata.asanaGid set in the tasks file
49
+ // withAsana({
50
+ // projectId: process.env.ASANA_PROJECT_ID,
51
+ // syncStatus: true,
52
+ // }),
53
+
54
+ // Everhour time tracking: auto-track time spent on tasks
55
+ // Uses metadata.everhourId or metadata.asanaGid (auto-prefixed with 'as:')
56
+ // withEverhour({
57
+ // autoStartTimer: true,
58
+ // autoStopTimer: true,
59
+ // }),
60
+
61
+ // Todoist integration: sync task status to Todoist
62
+ // Tasks should have metadata.todoistId set
63
+ // withTodoist({
64
+ // projectId: process.env.TODOIST_PROJECT_ID,
65
+ // syncStatus: true,
66
+ // addComments: true,
67
+ // }),
68
+
69
+ // Discord notifications via webhook
70
+ // withDiscord({
71
+ // webhookUrl: process.env.DISCORD_WEBHOOK_URL,
72
+ // username: 'Loopwork',
73
+ // notifyOnComplete: true,
74
+ // notifyOnFail: true,
75
+ // mentionOnFail: '<@&123456>', // mention role on failures
76
+ // }),
77
+
78
+ // Cost tracking for token usage
79
+ withCostTracking({
80
+ enabled: true,
81
+ defaultModel: 'claude-3.5-sonnet',
82
+ }),
83
+
84
+ // Dashboard TUI: live progress display
85
+ // Requires: bun add ink react @types/react
86
+ // withPlugin(createDashboardPlugin({ totalTasks: 10 })),
87
+
88
+ // Custom plugin: Log to console
89
+ withPlugin({
90
+ name: 'console-logger',
91
+ onLoopStart: (namespace) => {
92
+ console.log(`\nšŸš€ Loop starting in namespace: ${namespace}\n`)
93
+ },
94
+ onTaskStart: (task) => {
95
+ console.log(`šŸ“‹ Starting: ${task.id} - ${task.title}`)
96
+ },
97
+ onTaskComplete: (task, result) => {
98
+ console.log(`āœ… Completed: ${task.id} in ${result.duration}s`)
99
+ },
100
+ onTaskFailed: (task, error) => {
101
+ console.log(`āŒ Failed: ${task.id} - ${error}`)
102
+ },
103
+ onLoopEnd: (stats) => {
104
+ console.log(`\nšŸ“Š Loop finished: ${stats.completed} completed, ${stats.failed} failed\n`)
105
+ },
106
+ }),
107
+
108
+ // Custom plugin: Slack webhook (example)
109
+ // withPlugin({
110
+ // name: 'slack-notify',
111
+ // onTaskComplete: async (task) => {
112
+ // await fetch(process.env.SLACK_WEBHOOK_URL, {
113
+ // method: 'POST',
114
+ // headers: { 'Content-Type': 'application/json' },
115
+ // body: JSON.stringify({
116
+ // text: `āœ… Task completed: ${task.id} - ${task.title}`,
117
+ // }),
118
+ // })
119
+ // },
120
+ // }),
121
+ )(defineConfig({
122
+ // AI CLI tool: 'opencode', 'claude', or 'gemini'
123
+ cli: 'opencode',
124
+
125
+ // Loop settings
126
+ maxIterations: 50,
127
+ timeout: 600, // seconds per task
128
+ namespace: 'default', // for concurrent loops
129
+
130
+ // Behavior
131
+ autoConfirm: false, // -y flag
132
+ dryRun: false,
133
+ debug: false,
134
+
135
+ // Retry settings
136
+ maxRetries: 3,
137
+ circuitBreakerThreshold: 5,
138
+ taskDelay: 2000, // ms between tasks
139
+ retryDelay: 3000, // ms before retry
140
+ }))
141
+
142
+ // =============================================================================
143
+ // Alternative: Backend Plugins Pattern (recommended)
144
+ // =============================================================================
145
+
146
+ // export default compose(
147
+ // withJSONBackend({ tasksFile: 'tasks.json' }),
148
+ // withTelegram(),
149
+ // withAsana(),
150
+ // withEverhour(),
151
+ // )(defineConfig({ cli: 'opencode' }))
152
+
153
+ // =============================================================================
154
+ // Alternative: GitHub Backend Plugin
155
+ // =============================================================================
156
+
157
+ // export default compose(
158
+ // withGitHubBackend({ repo: 'myorg/myrepo' }),
159
+ // withTelegram(),
160
+ // withDiscord({ webhookUrl: process.env.DISCORD_WEBHOOK_URL }),
161
+ // )(defineConfig({
162
+ // cli: 'claude',
163
+ // feature: 'auth', // filter by feature label
164
+ // }))
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "loopwork",
3
+ "version": "0.3.0",
4
+ "description": "Loopwork - AI task runner with pluggable backends",
5
+ "main": "src/index.ts",
6
+ "bin": {
7
+ "loopwork": "bin/loopwork"
8
+ },
9
+ "scripts": {
10
+ "start": "bun run src/index.ts",
11
+ "build": "bun build ./src/index.ts --compile --outfile bin/loopwork",
12
+ "test": "bun test",
13
+ "setup-labels": "bun run src/setup-labels.ts"
14
+ },
15
+ "dependencies": {
16
+ "chalk": "^5.3.0",
17
+ "commander": "^12.0.0",
18
+ "ink": "^4.4.1",
19
+ "react": "^18.2.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/bun": "latest",
23
+ "@types/node": "^20.0.0",
24
+ "@types/react": "^18.2.0"
25
+ }
26
+ }