loopwork 0.3.0 → 0.3.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 (46) hide show
  1. package/bin/loopwork +0 -0
  2. package/package.json +48 -4
  3. package/src/backends/github.ts +6 -3
  4. package/src/backends/json.ts +28 -10
  5. package/src/commands/run.ts +2 -2
  6. package/src/contracts/config.ts +3 -75
  7. package/src/contracts/index.ts +0 -6
  8. package/src/core/cli.ts +25 -16
  9. package/src/core/state.ts +10 -4
  10. package/src/core/utils.ts +10 -4
  11. package/src/monitor/index.ts +56 -34
  12. package/src/plugins/index.ts +9 -131
  13. package/examples/README.md +0 -70
  14. package/examples/basic-json-backend/.specs/tasks/TASK-001.md +0 -22
  15. package/examples/basic-json-backend/.specs/tasks/TASK-002.md +0 -23
  16. package/examples/basic-json-backend/.specs/tasks/TASK-003.md +0 -37
  17. package/examples/basic-json-backend/.specs/tasks/tasks.json +0 -19
  18. package/examples/basic-json-backend/README.md +0 -32
  19. package/examples/basic-json-backend/TESTING.md +0 -184
  20. package/examples/basic-json-backend/hello.test.ts +0 -9
  21. package/examples/basic-json-backend/hello.ts +0 -3
  22. package/examples/basic-json-backend/loopwork.config.js +0 -35
  23. package/examples/basic-json-backend/math.test.ts +0 -29
  24. package/examples/basic-json-backend/math.ts +0 -3
  25. package/examples/basic-json-backend/package.json +0 -15
  26. package/examples/basic-json-backend/quick-start.sh +0 -80
  27. package/loopwork.config.ts +0 -164
  28. package/src/plugins/asana.ts +0 -192
  29. package/src/plugins/cost-tracking.ts +0 -402
  30. package/src/plugins/discord.ts +0 -269
  31. package/src/plugins/everhour.ts +0 -335
  32. package/src/plugins/telegram/bot.ts +0 -517
  33. package/src/plugins/telegram/index.ts +0 -6
  34. package/src/plugins/telegram/notifications.ts +0 -198
  35. package/src/plugins/todoist.ts +0 -261
  36. package/test/backends.test.ts +0 -929
  37. package/test/cli.test.ts +0 -145
  38. package/test/config.test.ts +0 -90
  39. package/test/e2e.test.ts +0 -458
  40. package/test/github-tasks.test.ts +0 -191
  41. package/test/loopwork-config-types.test.ts +0 -288
  42. package/test/monitor.test.ts +0 -123
  43. package/test/plugins.test.ts +0 -1175
  44. package/test/state.test.ts +0 -295
  45. package/test/utils.test.ts +0 -60
  46. package/tsconfig.json +0 -20
@@ -8,14 +8,15 @@ import type {
8
8
  LoopworkConfig,
9
9
  LoopworkPlugin,
10
10
  ConfigWrapper,
11
- TelegramConfig,
12
- DiscordConfig,
13
- AsanaConfig,
14
- EverhourConfig,
15
- TodoistConfig,
16
- CostTrackingConfig,
17
11
  } from '../contracts'
18
12
  import { DEFAULT_CONFIG } from '../contracts'
13
+ import { withJSONBackend, withGitHubBackend } from '../backends/plugin'
14
+
15
+ // ============================================================================
16
+ // Re-exports from backends
17
+ // ============================================================================
18
+
19
+ export { withJSONBackend, withGitHubBackend }
19
20
 
20
21
  // ============================================================================
21
22
  // Config Helpers
@@ -49,8 +50,8 @@ export function defineConfigAsync(
49
50
  *
50
51
  * @example
51
52
  * export default compose(
52
- * withTelegram(),
53
- * withCostTracking(),
53
+ * withPlugin(myPlugin),
54
+ * withJSONBackend(),
54
55
  * )(defineConfig({ ... }))
55
56
  */
56
57
  export function compose(...wrappers: ConfigWrapper[]): ConfigWrapper {
@@ -71,129 +72,6 @@ export function withPlugin(plugin: LoopworkPlugin): ConfigWrapper {
71
72
  })
72
73
  }
73
74
 
74
- /**
75
- * Add Telegram notifications
76
- */
77
- export function withTelegram(options: TelegramConfig = {}): ConfigWrapper {
78
- return (config) => ({
79
- ...config,
80
- telegram: {
81
- notifications: true,
82
- silent: false,
83
- ...options,
84
- botToken: options.botToken || process.env.TELEGRAM_BOT_TOKEN,
85
- chatId: options.chatId || process.env.TELEGRAM_CHAT_ID,
86
- },
87
- })
88
- }
89
-
90
- /**
91
- * Add Discord notifications
92
- */
93
- export function withDiscord(options: DiscordConfig = {}): ConfigWrapper {
94
- return (config) => ({
95
- ...config,
96
- discord: {
97
- webhookUrl: options.webhookUrl || process.env.DISCORD_WEBHOOK_URL,
98
- username: options.username || 'Loopwork',
99
- avatarUrl: options.avatarUrl,
100
- notifyOnStart: options.notifyOnStart ?? false,
101
- notifyOnComplete: options.notifyOnComplete ?? true,
102
- notifyOnFail: options.notifyOnFail ?? true,
103
- notifyOnLoopEnd: options.notifyOnLoopEnd ?? true,
104
- mentionOnFail: options.mentionOnFail,
105
- },
106
- })
107
- }
108
-
109
- /**
110
- * Add Asana integration
111
- */
112
- export function withAsana(options: AsanaConfig = {}): ConfigWrapper {
113
- return (config) => ({
114
- ...config,
115
- asana: {
116
- accessToken: options.accessToken || process.env.ASANA_ACCESS_TOKEN,
117
- projectId: options.projectId || process.env.ASANA_PROJECT_ID,
118
- workspaceId: options.workspaceId,
119
- autoCreate: options.autoCreate ?? false,
120
- syncStatus: options.syncStatus ?? true,
121
- },
122
- })
123
- }
124
-
125
- /**
126
- * Add Everhour time tracking
127
- */
128
- export function withEverhour(options: EverhourConfig = {}): ConfigWrapper {
129
- return (config) => ({
130
- ...config,
131
- everhour: {
132
- apiKey: options.apiKey || process.env.EVERHOUR_API_KEY,
133
- autoStartTimer: options.autoStartTimer ?? true,
134
- autoStopTimer: options.autoStopTimer ?? true,
135
- projectId: options.projectId,
136
- dailyLimit: options.dailyLimit ?? 8,
137
- },
138
- })
139
- }
140
-
141
- /**
142
- * Add Todoist integration
143
- */
144
- export function withTodoist(options: TodoistConfig = {}): ConfigWrapper {
145
- return (config) => ({
146
- ...config,
147
- todoist: {
148
- apiToken: options.apiToken || process.env.TODOIST_API_TOKEN,
149
- projectId: options.projectId || process.env.TODOIST_PROJECT_ID,
150
- syncStatus: options.syncStatus ?? true,
151
- addComments: options.addComments ?? true,
152
- },
153
- })
154
- }
155
-
156
- /**
157
- * Add cost tracking
158
- */
159
- export function withCostTracking(options: CostTrackingConfig = {}): ConfigWrapper {
160
- return (config) => ({
161
- ...config,
162
- costTracking: {
163
- enabled: true,
164
- defaultModel: 'claude-3.5-sonnet',
165
- ...options,
166
- },
167
- })
168
- }
169
-
170
- /**
171
- * Use GitHub Issues as backend
172
- */
173
- export function withGitHub(options: { repo?: string } = {}): ConfigWrapper {
174
- return (config) => ({
175
- ...config,
176
- backend: {
177
- type: 'github',
178
- repo: options.repo,
179
- },
180
- })
181
- }
182
-
183
- /**
184
- * Use JSON files as backend
185
- */
186
- export function withJSON(options: { tasksFile?: string; tasksDir?: string } = {}): ConfigWrapper {
187
- return (config) => ({
188
- ...config,
189
- backend: {
190
- type: 'json',
191
- tasksFile: options.tasksFile || '.specs/tasks/tasks.json',
192
- tasksDir: options.tasksDir,
193
- },
194
- })
195
- }
196
-
197
75
  // ============================================================================
198
76
  // Plugin Registry
199
77
  // ============================================================================
@@ -1,70 +0,0 @@
1
- # Loopwork Examples
2
-
3
- This directory contains example projects demonstrating different ways to use Loopwork.
4
-
5
- ## Available Examples
6
-
7
- ### 1. Basic JSON Backend
8
- **Directory**: `basic-json-backend/`
9
-
10
- A simple example using the JSON backend with 3 basic coding tasks:
11
- - Create a Hello World function
12
- - Add a sum function
13
- - Write README documentation
14
-
15
- **Best for**: Learning the basics, local development, small projects
16
-
17
- **Key Features**:
18
- - Simple task structure
19
- - Local file-based task management
20
- - Easy to understand and modify
21
-
22
- [View Example →](./basic-json-backend/)
23
-
24
- ---
25
-
26
- ## Coming Soon
27
-
28
- ### GitHub Backend Example
29
- Using GitHub Issues as a task backend with labels and milestones.
30
-
31
- ### Advanced Plugins Example
32
- Demonstrating Telegram notifications, cost tracking, and custom plugins.
33
-
34
- ### Multi-Feature Project
35
- Complex project with multiple features, sub-tasks, and dependencies.
36
-
37
- ---
38
-
39
- ## Quick Start
40
-
41
- 1. Choose an example directory
42
- 2. Read the README in that directory
43
- 3. Run the example:
44
-
45
- ```bash
46
- cd basic-json-backend
47
- bun run start
48
- ```
49
-
50
- ## Example Structure
51
-
52
- Each example includes:
53
- - `README.md` - Detailed instructions
54
- - `loopwork.config.ts` - Configuration file
55
- - `.specs/tasks/` - Task definitions (for JSON backend)
56
- - Sample tasks and PRDs
57
-
58
- ## Learning Path
59
-
60
- We recommend following this order:
61
-
62
- 1. **Start here**: `basic-json-backend/` - Learn core concepts
63
- 2. **Next**: GitHub backend example - Learn backend integration
64
- 3. **Advanced**: Plugins example - Learn extensibility
65
-
66
- ## Need Help?
67
-
68
- - Read the [main documentation](../README.md)
69
- - Check [troubleshooting guide](../docs/troubleshooting.md)
70
- - Open an issue on GitHub
@@ -1,22 +0,0 @@
1
- # TASK-001: Create Hello World Function
2
-
3
- ## Goal
4
- Create a simple function that returns "Hello, World!"
5
-
6
- ## Requirements
7
- - Create a file called `hello.ts`
8
- - Export a function named `sayHello`
9
- - The function should return the string "Hello, World!"
10
- - Add a simple test to verify it works
11
-
12
- ## Example
13
- ```typescript
14
- export function sayHello(): string {
15
- return "Hello, World!"
16
- }
17
- ```
18
-
19
- ## Success Criteria
20
- - File `hello.ts` exists
21
- - Function returns correct string
22
- - Test passes
@@ -1,23 +0,0 @@
1
- # TASK-002: Add a Sum Function
2
-
3
- ## Goal
4
- Create a function that adds two numbers together
5
-
6
- ## Requirements
7
- - Create a file called `math.ts`
8
- - Export a function named `sum`
9
- - The function should take two numbers and return their sum
10
- - Add tests for the function
11
-
12
- ## Example
13
- ```typescript
14
- export function sum(a: number, b: number): number {
15
- return a + b
16
- }
17
- ```
18
-
19
- ## Success Criteria
20
- - File `math.ts` exists
21
- - Function correctly adds two numbers
22
- - Tests pass
23
- - Function handles decimal numbers
@@ -1,37 +0,0 @@
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
@@ -1,19 +0,0 @@
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
- }
@@ -1,32 +0,0 @@
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
- ```
@@ -1,184 +0,0 @@
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.)
@@ -1,9 +0,0 @@
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
- })
@@ -1,3 +0,0 @@
1
- export function sayHello(): string {
2
- return 'Hello, World!'
3
- }
@@ -1,35 +0,0 @@
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
- }
@@ -1,29 +0,0 @@
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
- })
@@ -1,3 +0,0 @@
1
- export function sum(a: number, b: number): number {
2
- return a + b
3
- }
@@ -1,15 +0,0 @@
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
- }