olly-molly 0.1.0 → 0.1.3

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 (77) hide show
  1. package/README.md +3 -3
  2. package/bin/cli.js +137 -52
  3. package/package.json +4 -15
  4. package/app/api/agent/execute/route.ts +0 -157
  5. package/app/api/agent/status/route.ts +0 -38
  6. package/app/api/check-api-key/route.ts +0 -12
  7. package/app/api/conversations/[id]/route.ts +0 -35
  8. package/app/api/conversations/route.ts +0 -24
  9. package/app/api/members/[id]/route.ts +0 -37
  10. package/app/api/members/route.ts +0 -12
  11. package/app/api/pm/breakdown/route.ts +0 -142
  12. package/app/api/pm/tickets/route.ts +0 -147
  13. package/app/api/projects/[id]/route.ts +0 -56
  14. package/app/api/projects/active/route.ts +0 -15
  15. package/app/api/projects/route.ts +0 -53
  16. package/app/api/tickets/[id]/logs/route.ts +0 -16
  17. package/app/api/tickets/[id]/route.ts +0 -60
  18. package/app/api/tickets/[id]/work-logs/route.ts +0 -16
  19. package/app/api/tickets/route.ts +0 -37
  20. package/app/design-system/page.tsx +0 -242
  21. package/app/favicon.ico +0 -0
  22. package/app/globals.css +0 -318
  23. package/app/layout.tsx +0 -37
  24. package/app/page.tsx +0 -331
  25. package/components/ThemeProvider.tsx +0 -56
  26. package/components/ThemeToggle.tsx +0 -31
  27. package/components/activity/ActivityLog.tsx +0 -96
  28. package/components/activity/index.ts +0 -1
  29. package/components/kanban/ConversationList.tsx +0 -75
  30. package/components/kanban/ConversationView.tsx +0 -132
  31. package/components/kanban/KanbanBoard.tsx +0 -179
  32. package/components/kanban/KanbanColumn.tsx +0 -80
  33. package/components/kanban/SortableTicket.tsx +0 -58
  34. package/components/kanban/TicketCard.tsx +0 -98
  35. package/components/kanban/TicketModal.tsx +0 -510
  36. package/components/kanban/TicketSidebar.tsx +0 -448
  37. package/components/kanban/index.ts +0 -8
  38. package/components/pm/PMRequestModal.tsx +0 -196
  39. package/components/pm/index.ts +0 -1
  40. package/components/project/ProjectSelector.tsx +0 -211
  41. package/components/project/index.ts +0 -1
  42. package/components/team/MemberCard.tsx +0 -147
  43. package/components/team/TeamPanel.tsx +0 -57
  44. package/components/team/index.ts +0 -2
  45. package/components/ui/ApiKeyModal.tsx +0 -101
  46. package/components/ui/Avatar.tsx +0 -95
  47. package/components/ui/Badge.tsx +0 -59
  48. package/components/ui/Button.tsx +0 -60
  49. package/components/ui/Card.tsx +0 -64
  50. package/components/ui/Input.tsx +0 -41
  51. package/components/ui/Modal.tsx +0 -76
  52. package/components/ui/ResizablePane.tsx +0 -97
  53. package/components/ui/Select.tsx +0 -45
  54. package/components/ui/Textarea.tsx +0 -41
  55. package/components/ui/index.ts +0 -8
  56. package/db/dev.sqlite +0 -0
  57. package/db/dev.sqlite-shm +0 -0
  58. package/db/dev.sqlite-wal +0 -0
  59. package/db/schema-conversations.sql +0 -26
  60. package/db/schema-projects.sql +0 -29
  61. package/db/schema.sql +0 -94
  62. package/lib/agent-jobs.ts +0 -232
  63. package/lib/db.ts +0 -564
  64. package/next.config.ts +0 -10
  65. package/postcss.config.mjs +0 -7
  66. package/public/app-icon.png +0 -0
  67. package/public/file.svg +0 -1
  68. package/public/globe.svg +0 -1
  69. package/public/next.svg +0 -1
  70. package/public/profiles/designer.png +0 -0
  71. package/public/profiles/dev-backend.png +0 -0
  72. package/public/profiles/dev-frontend.png +0 -0
  73. package/public/profiles/pm.png +0 -0
  74. package/public/profiles/qa.png +0 -0
  75. package/public/vercel.svg +0 -1
  76. package/public/window.svg +0 -1
  77. package/tsconfig.json +0 -34
package/lib/agent-jobs.ts DELETED
@@ -1,232 +0,0 @@
1
- import { spawn, ChildProcess } from 'child_process';
2
- import { conversationService, conversationMessageService, activityService, ticketService } from './db';
3
-
4
- export type AgentProvider = 'claude' | 'opencode';
5
-
6
- const CLAUDE_PATH = '/opt/homebrew/bin/claude';
7
- const OPENCODE_PATH = '/opt/homebrew/bin/opencode';
8
-
9
- interface RunningJob {
10
- id: string;
11
- conversationId: string;
12
- ticketId: string;
13
- agentId: string;
14
- agentName: string;
15
- projectPath: string;
16
- provider: AgentProvider;
17
- startedAt: Date;
18
- process: ChildProcess;
19
- output: string;
20
- status: 'running' | 'completed' | 'failed';
21
- }
22
-
23
- // Store running jobs in memory
24
- const runningJobs = new Map<string, RunningJob>();
25
-
26
- export function getRunningJobs(): Omit<RunningJob, 'process'>[] {
27
- return Array.from(runningJobs.values()).map(job => ({
28
- id: job.id,
29
- conversationId: job.conversationId,
30
- ticketId: job.ticketId,
31
- agentId: job.agentId,
32
- agentName: job.agentName,
33
- projectPath: job.projectPath,
34
- provider: job.provider,
35
- startedAt: job.startedAt,
36
- output: job.output,
37
- status: job.status,
38
- }));
39
- }
40
-
41
- export function getJobByTicketId(ticketId: string): Omit<RunningJob, 'process'> | null {
42
- for (const job of runningJobs.values()) {
43
- if (job.ticketId === ticketId) {
44
- return {
45
- id: job.id,
46
- conversationId: job.conversationId,
47
- ticketId: job.ticketId,
48
- agentId: job.agentId,
49
- agentName: job.agentName,
50
- projectPath: job.projectPath,
51
- provider: job.provider,
52
- startedAt: job.startedAt,
53
- output: job.output,
54
- status: job.status,
55
- };
56
- }
57
- }
58
- return null;
59
- }
60
-
61
- export function getJobOutput(jobId: string): string | null {
62
- const job = runningJobs.get(jobId);
63
- return job?.output || null;
64
- }
65
-
66
- interface StartJobParams {
67
- jobId: string;
68
- conversationId: string;
69
- ticketId: string;
70
- agentId: string;
71
- agentName: string;
72
- projectPath: string;
73
- prompt: string;
74
- provider: AgentProvider;
75
- }
76
-
77
- export function startBackgroundJob(params: StartJobParams): void {
78
- const { jobId, conversationId, ticketId, agentId, agentName, projectPath, prompt, provider } = params;
79
-
80
- // Configure command and args based on provider
81
- let execPath: string;
82
- let args: string[];
83
- let startMessage: string;
84
-
85
- if (provider === 'opencode') {
86
- execPath = OPENCODE_PATH;
87
- args = ['run', prompt];
88
- startMessage = `🚀 Starting OpenCode in ${projectPath}...\n\n`;
89
- } else {
90
- execPath = CLAUDE_PATH;
91
- args = ['--print', '--dangerously-skip-permissions', prompt];
92
- startMessage = `🚀 Starting Claude Code in ${projectPath}...\n\n`;
93
- }
94
-
95
- const agentProcess = spawn(execPath, args, {
96
- cwd: projectPath,
97
- env: { ...process.env, PORT: '3001' },
98
- detached: false,
99
- stdio: ['ignore', 'pipe', 'pipe'],
100
- });
101
-
102
- const job: RunningJob = {
103
- id: jobId,
104
- conversationId,
105
- ticketId,
106
- agentId,
107
- agentName,
108
- projectPath,
109
- provider,
110
- startedAt: new Date(),
111
- process: agentProcess,
112
- output: startMessage,
113
- status: 'running',
114
- };
115
-
116
- runningJobs.set(jobId, job);
117
-
118
- // Log start message to conversation
119
- conversationMessageService.create(conversationId, startMessage, 'system');
120
-
121
- // Capture stdout
122
- agentProcess.stdout?.on('data', (data: Buffer) => {
123
- const text = data.toString('utf-8');
124
- job.output += text;
125
- // Save to conversation messages
126
- conversationMessageService.create(conversationId, text, 'log');
127
- });
128
-
129
- // Capture stderr
130
- agentProcess.stderr?.on('data', (data: Buffer) => {
131
- const text = data.toString('utf-8');
132
- const errorText = `[stderr] ${text}\n`;
133
- job.output += errorText;
134
- // Save errors to conversation messages
135
- conversationMessageService.create(conversationId, text, 'error');
136
- });
137
-
138
- agentProcess.on('close', (code: number | null) => {
139
- const success = code === 0;
140
- job.status = success ? 'completed' : 'failed';
141
-
142
- // Extract commit hash from output
143
- const commitMatch = job.output.match(/commit\s+([a-f0-9]{7,40})/i);
144
- const commitHash = commitMatch ? commitMatch[1] : undefined;
145
-
146
- // Update conversation status
147
- conversationService.complete(conversationId, {
148
- status: success ? 'completed' : 'failed',
149
- git_commit_hash: commitHash,
150
- });
151
-
152
- // Add completion message
153
- const completionMessage = success
154
- ? `✅ Task completed successfully${commitHash ? ` (commit: ${commitHash})` : ''}`
155
- : '❌ Task failed';
156
- conversationMessageService.create(conversationId, completionMessage, success ? 'success' : 'error');
157
-
158
- // Log activity
159
- activityService.log({
160
- ticket_id: ticketId,
161
- member_id: agentId,
162
- action: success ? 'AGENT_WORK_COMPLETED' : 'AGENT_WORK_FAILED',
163
- new_value: commitHash,
164
- details: success
165
- ? `${agentName} completed the task${commitHash ? ` (commit: ${commitHash})` : ''}`
166
- : `${agentName} failed to complete the task`,
167
- });
168
-
169
- // Update ticket status
170
- if (success) {
171
- ticketService.update(ticketId, { status: 'IN_REVIEW' }, agentId);
172
- }
173
-
174
- // Remove from running jobs after a delay (keep for status check)
175
- setTimeout(() => {
176
- runningJobs.delete(jobId);
177
- }, 60000); // Keep completed job info for 1 minute
178
- });
179
-
180
- agentProcess.on('error', (error: Error) => {
181
- job.status = 'failed';
182
- job.output += `\n[error] ${error.message}`;
183
-
184
- // Update conversation
185
- conversationService.complete(conversationId, {
186
- status: 'failed',
187
- });
188
-
189
- // Add error message
190
- conversationMessageService.create(conversationId, `❌ Process error: ${error.message}`, 'error');
191
-
192
- activityService.log({
193
- ticket_id: ticketId,
194
- member_id: agentId,
195
- action: 'AGENT_WORK_FAILED',
196
- details: `${agentName} failed: ${error.message}`,
197
- });
198
-
199
- setTimeout(() => {
200
- runningJobs.delete(jobId);
201
- }, 60000);
202
- });
203
- }
204
-
205
- export function cancelJob(jobId: string): boolean {
206
- const job = runningJobs.get(jobId);
207
- if (!job || job.status !== 'running') {
208
- return false;
209
- }
210
-
211
- job.process.kill('SIGTERM');
212
- job.status = 'failed';
213
- job.output += '\n[cancelled] Job was cancelled by user';
214
-
215
- // Update conversation
216
- conversationService.complete(job.conversationId, {
217
- status: 'cancelled',
218
- });
219
-
220
- // Add cancellation message
221
- conversationMessageService.create(job.conversationId, '⏹ Job was cancelled by user', 'system');
222
-
223
- activityService.log({
224
- ticket_id: job.ticketId,
225
- member_id: job.agentId,
226
- action: 'AGENT_WORK_CANCELLED',
227
- details: `${job.agentName}'s work was cancelled`,
228
- });
229
-
230
- runningJobs.delete(jobId);
231
- return true;
232
- }