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.
- package/README.md +3 -3
- package/bin/cli.js +137 -52
- package/package.json +4 -15
- package/app/api/agent/execute/route.ts +0 -157
- package/app/api/agent/status/route.ts +0 -38
- package/app/api/check-api-key/route.ts +0 -12
- package/app/api/conversations/[id]/route.ts +0 -35
- package/app/api/conversations/route.ts +0 -24
- package/app/api/members/[id]/route.ts +0 -37
- package/app/api/members/route.ts +0 -12
- package/app/api/pm/breakdown/route.ts +0 -142
- package/app/api/pm/tickets/route.ts +0 -147
- package/app/api/projects/[id]/route.ts +0 -56
- package/app/api/projects/active/route.ts +0 -15
- package/app/api/projects/route.ts +0 -53
- package/app/api/tickets/[id]/logs/route.ts +0 -16
- package/app/api/tickets/[id]/route.ts +0 -60
- package/app/api/tickets/[id]/work-logs/route.ts +0 -16
- package/app/api/tickets/route.ts +0 -37
- package/app/design-system/page.tsx +0 -242
- package/app/favicon.ico +0 -0
- package/app/globals.css +0 -318
- package/app/layout.tsx +0 -37
- package/app/page.tsx +0 -331
- package/components/ThemeProvider.tsx +0 -56
- package/components/ThemeToggle.tsx +0 -31
- package/components/activity/ActivityLog.tsx +0 -96
- package/components/activity/index.ts +0 -1
- package/components/kanban/ConversationList.tsx +0 -75
- package/components/kanban/ConversationView.tsx +0 -132
- package/components/kanban/KanbanBoard.tsx +0 -179
- package/components/kanban/KanbanColumn.tsx +0 -80
- package/components/kanban/SortableTicket.tsx +0 -58
- package/components/kanban/TicketCard.tsx +0 -98
- package/components/kanban/TicketModal.tsx +0 -510
- package/components/kanban/TicketSidebar.tsx +0 -448
- package/components/kanban/index.ts +0 -8
- package/components/pm/PMRequestModal.tsx +0 -196
- package/components/pm/index.ts +0 -1
- package/components/project/ProjectSelector.tsx +0 -211
- package/components/project/index.ts +0 -1
- package/components/team/MemberCard.tsx +0 -147
- package/components/team/TeamPanel.tsx +0 -57
- package/components/team/index.ts +0 -2
- package/components/ui/ApiKeyModal.tsx +0 -101
- package/components/ui/Avatar.tsx +0 -95
- package/components/ui/Badge.tsx +0 -59
- package/components/ui/Button.tsx +0 -60
- package/components/ui/Card.tsx +0 -64
- package/components/ui/Input.tsx +0 -41
- package/components/ui/Modal.tsx +0 -76
- package/components/ui/ResizablePane.tsx +0 -97
- package/components/ui/Select.tsx +0 -45
- package/components/ui/Textarea.tsx +0 -41
- package/components/ui/index.ts +0 -8
- package/db/dev.sqlite +0 -0
- package/db/dev.sqlite-shm +0 -0
- package/db/dev.sqlite-wal +0 -0
- package/db/schema-conversations.sql +0 -26
- package/db/schema-projects.sql +0 -29
- package/db/schema.sql +0 -94
- package/lib/agent-jobs.ts +0 -232
- package/lib/db.ts +0 -564
- package/next.config.ts +0 -10
- package/postcss.config.mjs +0 -7
- package/public/app-icon.png +0 -0
- package/public/file.svg +0 -1
- package/public/globe.svg +0 -1
- package/public/next.svg +0 -1
- package/public/profiles/designer.png +0 -0
- package/public/profiles/dev-backend.png +0 -0
- package/public/profiles/dev-frontend.png +0 -0
- package/public/profiles/pm.png +0 -0
- package/public/profiles/qa.png +0 -0
- package/public/vercel.svg +0 -1
- package/public/window.svg +0 -1
- 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
|
-
}
|