optimal-cli 1.0.0 → 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.
- package/dist/bin/optimal.d.ts +2 -0
- package/dist/bin/optimal.js +1590 -0
- package/dist/lib/assets/index.d.ts +79 -0
- package/dist/lib/assets/index.js +153 -0
- package/dist/lib/assets.d.ts +20 -0
- package/dist/lib/assets.js +112 -0
- package/dist/lib/auth/index.d.ts +83 -0
- package/dist/lib/auth/index.js +146 -0
- package/dist/lib/board/index.d.ts +39 -0
- package/dist/lib/board/index.js +285 -0
- package/dist/lib/board/types.d.ts +111 -0
- package/dist/lib/board/types.js +1 -0
- package/dist/lib/bot/claim.d.ts +3 -0
- package/dist/lib/bot/claim.js +20 -0
- package/dist/lib/bot/coordinator.d.ts +27 -0
- package/dist/lib/bot/coordinator.js +178 -0
- package/dist/lib/bot/heartbeat.d.ts +6 -0
- package/dist/lib/bot/heartbeat.js +30 -0
- package/dist/lib/bot/index.d.ts +9 -0
- package/dist/lib/bot/index.js +6 -0
- package/dist/lib/bot/protocol.d.ts +12 -0
- package/dist/lib/bot/protocol.js +74 -0
- package/dist/lib/bot/reporter.d.ts +3 -0
- package/dist/lib/bot/reporter.js +27 -0
- package/dist/lib/bot/skills.d.ts +26 -0
- package/dist/lib/bot/skills.js +69 -0
- package/dist/lib/budget/projections.d.ts +115 -0
- package/dist/lib/budget/projections.js +384 -0
- package/dist/lib/budget/scenarios.d.ts +93 -0
- package/dist/lib/budget/scenarios.js +214 -0
- package/dist/lib/cms/publish-blog.d.ts +62 -0
- package/dist/lib/cms/publish-blog.js +74 -0
- package/dist/lib/cms/strapi-client.d.ts +123 -0
- package/dist/lib/cms/strapi-client.js +213 -0
- package/dist/lib/config/registry.d.ts +17 -0
- package/dist/lib/config/registry.js +182 -0
- package/dist/lib/config/schema.d.ts +31 -0
- package/dist/lib/config/schema.js +25 -0
- package/dist/lib/config.d.ts +55 -0
- package/dist/lib/config.js +206 -0
- package/dist/lib/errors.d.ts +25 -0
- package/dist/lib/errors.js +91 -0
- package/dist/lib/format.d.ts +28 -0
- package/dist/lib/format.js +98 -0
- package/dist/lib/infra/deploy.d.ts +29 -0
- package/dist/lib/infra/deploy.js +58 -0
- package/dist/lib/infra/migrate.d.ts +34 -0
- package/dist/lib/infra/migrate.js +103 -0
- package/dist/lib/newsletter/distribute.d.ts +52 -0
- package/dist/lib/newsletter/distribute.js +193 -0
- package/{lib/newsletter/generate-insurance.ts → dist/lib/newsletter/generate-insurance.d.ts} +7 -24
- package/dist/lib/newsletter/generate-insurance.js +36 -0
- package/dist/lib/newsletter/generate.d.ts +104 -0
- package/dist/lib/newsletter/generate.js +571 -0
- package/dist/lib/returnpro/anomalies.d.ts +64 -0
- package/dist/lib/returnpro/anomalies.js +166 -0
- package/dist/lib/returnpro/audit.d.ts +32 -0
- package/dist/lib/returnpro/audit.js +147 -0
- package/dist/lib/returnpro/diagnose.d.ts +52 -0
- package/dist/lib/returnpro/diagnose.js +281 -0
- package/dist/lib/returnpro/kpis.d.ts +32 -0
- package/dist/lib/returnpro/kpis.js +192 -0
- package/dist/lib/returnpro/templates.d.ts +48 -0
- package/dist/lib/returnpro/templates.js +229 -0
- package/dist/lib/returnpro/upload-income.d.ts +25 -0
- package/dist/lib/returnpro/upload-income.js +235 -0
- package/dist/lib/returnpro/upload-netsuite.d.ts +37 -0
- package/dist/lib/returnpro/upload-netsuite.js +566 -0
- package/dist/lib/returnpro/upload-r1.d.ts +48 -0
- package/dist/lib/returnpro/upload-r1.js +398 -0
- package/dist/lib/returnpro/validate.d.ts +37 -0
- package/dist/lib/returnpro/validate.js +124 -0
- package/dist/lib/social/meta.d.ts +90 -0
- package/dist/lib/social/meta.js +160 -0
- package/dist/lib/social/post-generator.d.ts +83 -0
- package/dist/lib/social/post-generator.js +333 -0
- package/dist/lib/social/publish.d.ts +66 -0
- package/dist/lib/social/publish.js +226 -0
- package/dist/lib/social/scraper.d.ts +67 -0
- package/dist/lib/social/scraper.js +361 -0
- package/dist/lib/supabase.d.ts +4 -0
- package/dist/lib/supabase.js +20 -0
- package/dist/lib/transactions/delete-batch.d.ts +60 -0
- package/dist/lib/transactions/delete-batch.js +203 -0
- package/dist/lib/transactions/ingest.d.ts +43 -0
- package/dist/lib/transactions/ingest.js +555 -0
- package/dist/lib/transactions/stamp.d.ts +51 -0
- package/dist/lib/transactions/stamp.js +524 -0
- package/package.json +3 -4
- package/bin/optimal.ts +0 -1731
- package/lib/assets/index.ts +0 -225
- package/lib/assets.ts +0 -124
- package/lib/auth/index.ts +0 -189
- package/lib/board/index.ts +0 -309
- package/lib/board/types.ts +0 -124
- package/lib/bot/claim.ts +0 -43
- package/lib/bot/coordinator.ts +0 -254
- package/lib/bot/heartbeat.ts +0 -37
- package/lib/bot/index.ts +0 -9
- package/lib/bot/protocol.ts +0 -99
- package/lib/bot/reporter.ts +0 -42
- package/lib/bot/skills.ts +0 -81
- package/lib/budget/projections.ts +0 -561
- package/lib/budget/scenarios.ts +0 -312
- package/lib/cms/publish-blog.ts +0 -129
- package/lib/cms/strapi-client.ts +0 -302
- package/lib/config/registry.ts +0 -228
- package/lib/config/schema.ts +0 -58
- package/lib/config.ts +0 -247
- package/lib/errors.ts +0 -129
- package/lib/format.ts +0 -120
- package/lib/infra/.gitkeep +0 -0
- package/lib/infra/deploy.ts +0 -70
- package/lib/infra/migrate.ts +0 -141
- package/lib/newsletter/.gitkeep +0 -0
- package/lib/newsletter/distribute.ts +0 -256
- package/lib/newsletter/generate.ts +0 -735
- package/lib/returnpro/.gitkeep +0 -0
- package/lib/returnpro/anomalies.ts +0 -258
- package/lib/returnpro/audit.ts +0 -194
- package/lib/returnpro/diagnose.ts +0 -400
- package/lib/returnpro/kpis.ts +0 -255
- package/lib/returnpro/templates.ts +0 -323
- package/lib/returnpro/upload-income.ts +0 -311
- package/lib/returnpro/upload-netsuite.ts +0 -696
- package/lib/returnpro/upload-r1.ts +0 -563
- package/lib/returnpro/validate.ts +0 -154
- package/lib/social/meta.ts +0 -228
- package/lib/social/post-generator.ts +0 -468
- package/lib/social/publish.ts +0 -301
- package/lib/social/scraper.ts +0 -503
- package/lib/supabase.ts +0 -25
- package/lib/transactions/delete-batch.ts +0 -258
- package/lib/transactions/ingest.ts +0 -659
- package/lib/transactions/stamp.ts +0 -654
package/lib/board/index.ts
DELETED
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
import { getSupabase } from '../supabase.js'
|
|
2
|
-
import type {
|
|
3
|
-
Project, Task, Label, Comment, Milestone, ActivityEntry,
|
|
4
|
-
CreateProjectInput, CreateTaskInput, CreateCommentInput, CreateMilestoneInput,
|
|
5
|
-
UpdateTaskInput, TaskStatus,
|
|
6
|
-
} from './types.js'
|
|
7
|
-
|
|
8
|
-
export * from './types.js'
|
|
9
|
-
|
|
10
|
-
const sb = () => getSupabase('optimal')
|
|
11
|
-
|
|
12
|
-
// --- Helpers ---
|
|
13
|
-
|
|
14
|
-
export function formatBoardTable(tasks: Task[]): string {
|
|
15
|
-
if (tasks.length === 0) return 'No tasks found.'
|
|
16
|
-
const lines = [
|
|
17
|
-
'| Status | P | Title | Agent | Skill | Effort |',
|
|
18
|
-
'|-------------|---|--------------------------------|---------|-----------------|--------|',
|
|
19
|
-
]
|
|
20
|
-
const order: TaskStatus[] = ['in_progress', 'claimed', 'blocked', 'ready', 'review', 'backlog', 'done']
|
|
21
|
-
const sorted = [...tasks].sort((a, b) => {
|
|
22
|
-
const ai = order.indexOf(a.status)
|
|
23
|
-
const bi = order.indexOf(b.status)
|
|
24
|
-
if (ai !== bi) return ai - bi
|
|
25
|
-
return a.priority - b.priority
|
|
26
|
-
})
|
|
27
|
-
for (const t of sorted) {
|
|
28
|
-
const title = t.title.length > 30 ? t.title.slice(0, 27) + '...' : t.title.padEnd(30)
|
|
29
|
-
const agent = (t.claimed_by ?? t.assigned_to ?? '—').padEnd(7)
|
|
30
|
-
const skill = (t.skill_required ?? '—').padEnd(15)
|
|
31
|
-
const effort = (t.estimated_effort ?? '—').padEnd(6)
|
|
32
|
-
lines.push(`| ${t.status.padEnd(11)} | ${t.priority} | ${title} | ${agent} | ${skill} | ${effort} |`)
|
|
33
|
-
}
|
|
34
|
-
lines.push(`\nTotal: ${tasks.length} tasks`)
|
|
35
|
-
return lines.join('\n')
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function getNextClaimable(readyTasks: Task[], allTasks: Task[]): Task | null {
|
|
39
|
-
for (const task of readyTasks) {
|
|
40
|
-
if (!task.blocked_by || task.blocked_by.length === 0) return task
|
|
41
|
-
const allDone = task.blocked_by.every(depId => {
|
|
42
|
-
const dep = allTasks.find(t => t.id === depId)
|
|
43
|
-
return dep && (dep.status === 'done')
|
|
44
|
-
})
|
|
45
|
-
if (allDone) return task
|
|
46
|
-
}
|
|
47
|
-
return null
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// --- Projects ---
|
|
51
|
-
|
|
52
|
-
export async function createProject(input: CreateProjectInput): Promise<Project> {
|
|
53
|
-
const { data, error } = await sb()
|
|
54
|
-
.from('projects')
|
|
55
|
-
.insert({
|
|
56
|
-
slug: input.slug,
|
|
57
|
-
name: input.name,
|
|
58
|
-
description: input.description ?? null,
|
|
59
|
-
owner: input.owner ?? null,
|
|
60
|
-
priority: input.priority ?? 3,
|
|
61
|
-
})
|
|
62
|
-
.select()
|
|
63
|
-
.single()
|
|
64
|
-
if (error) throw new Error(`Failed to create project: ${error.message}`)
|
|
65
|
-
return data as Project
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function getProjectBySlug(slug: string): Promise<Project> {
|
|
69
|
-
const { data, error } = await sb()
|
|
70
|
-
.from('projects')
|
|
71
|
-
.select('*')
|
|
72
|
-
.eq('slug', slug)
|
|
73
|
-
.single()
|
|
74
|
-
if (error) throw new Error(`Project not found: ${slug} — ${error.message}`)
|
|
75
|
-
return data as Project
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export async function listProjects(): Promise<Project[]> {
|
|
79
|
-
const { data, error } = await sb()
|
|
80
|
-
.from('projects')
|
|
81
|
-
.select('*')
|
|
82
|
-
.neq('status', 'archived')
|
|
83
|
-
.order('priority', { ascending: true })
|
|
84
|
-
if (error) throw new Error(`Failed to list projects: ${error.message}`)
|
|
85
|
-
return (data ?? []) as Project[]
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export async function updateProject(slug: string, updates: Partial<Pick<Project, 'status' | 'owner' | 'priority' | 'description'>>): Promise<Project> {
|
|
89
|
-
const { data, error } = await sb()
|
|
90
|
-
.from('projects')
|
|
91
|
-
.update(updates)
|
|
92
|
-
.eq('slug', slug)
|
|
93
|
-
.select()
|
|
94
|
-
.single()
|
|
95
|
-
if (error) throw new Error(`Failed to update project: ${error.message}`)
|
|
96
|
-
return data as Project
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// --- Milestones ---
|
|
100
|
-
|
|
101
|
-
export async function createMilestone(input: CreateMilestoneInput): Promise<Milestone> {
|
|
102
|
-
const { data, error } = await sb()
|
|
103
|
-
.from('milestones')
|
|
104
|
-
.insert({
|
|
105
|
-
project_id: input.project_id,
|
|
106
|
-
name: input.name,
|
|
107
|
-
description: input.description ?? null,
|
|
108
|
-
due_date: input.due_date ?? null,
|
|
109
|
-
})
|
|
110
|
-
.select()
|
|
111
|
-
.single()
|
|
112
|
-
if (error) throw new Error(`Failed to create milestone: ${error.message}`)
|
|
113
|
-
return data as Milestone
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export async function listMilestones(projectId?: string): Promise<Milestone[]> {
|
|
117
|
-
let query = sb().from('milestones').select('*').order('due_date', { ascending: true })
|
|
118
|
-
if (projectId) query = query.eq('project_id', projectId)
|
|
119
|
-
const { data, error } = await query
|
|
120
|
-
if (error) throw new Error(`Failed to list milestones: ${error.message}`)
|
|
121
|
-
return (data ?? []) as Milestone[]
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// --- Labels ---
|
|
125
|
-
|
|
126
|
-
export async function createLabel(name: string, color?: string): Promise<Label> {
|
|
127
|
-
const { data, error } = await sb()
|
|
128
|
-
.from('labels')
|
|
129
|
-
.insert({ name, color: color ?? null })
|
|
130
|
-
.select()
|
|
131
|
-
.single()
|
|
132
|
-
if (error) throw new Error(`Failed to create label: ${error.message}`)
|
|
133
|
-
return data as Label
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export async function listLabels(): Promise<Label[]> {
|
|
137
|
-
const { data, error } = await sb().from('labels').select('*').order('name')
|
|
138
|
-
if (error) throw new Error(`Failed to list labels: ${error.message}`)
|
|
139
|
-
return (data ?? []) as Label[]
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export async function getLabelByName(name: string): Promise<Label | null> {
|
|
143
|
-
const { data } = await sb().from('labels').select('*').eq('name', name).single()
|
|
144
|
-
return (data as Label) ?? null
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// --- Tasks ---
|
|
148
|
-
|
|
149
|
-
export async function createTask(input: CreateTaskInput): Promise<Task> {
|
|
150
|
-
const { labels: labelNames, ...rest } = input
|
|
151
|
-
const { data, error } = await sb()
|
|
152
|
-
.from('tasks')
|
|
153
|
-
.insert({
|
|
154
|
-
...rest,
|
|
155
|
-
milestone_id: rest.milestone_id ?? null,
|
|
156
|
-
description: rest.description ?? null,
|
|
157
|
-
priority: rest.priority ?? 3,
|
|
158
|
-
skill_required: rest.skill_required ?? null,
|
|
159
|
-
source_repo: rest.source_repo ?? null,
|
|
160
|
-
target_module: rest.target_module ?? null,
|
|
161
|
-
estimated_effort: rest.estimated_effort ?? null,
|
|
162
|
-
blocked_by: rest.blocked_by ?? [],
|
|
163
|
-
})
|
|
164
|
-
.select()
|
|
165
|
-
.single()
|
|
166
|
-
if (error) throw new Error(`Failed to create task: ${error.message}`)
|
|
167
|
-
const task = data as Task
|
|
168
|
-
|
|
169
|
-
if (labelNames && labelNames.length > 0) {
|
|
170
|
-
for (const name of labelNames) {
|
|
171
|
-
const label = await getLabelByName(name)
|
|
172
|
-
if (label) {
|
|
173
|
-
await sb().from('task_labels').insert({ task_id: task.id, label_id: label.id })
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
await logActivity({ task_id: task.id, project_id: task.project_id, actor: 'system', action: 'created', new_value: { title: task.title } })
|
|
179
|
-
return task
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export async function updateTask(taskId: string, updates: UpdateTaskInput, actor?: string): Promise<Task> {
|
|
183
|
-
const old = await getTask(taskId)
|
|
184
|
-
const { data, error } = await sb()
|
|
185
|
-
.from('tasks')
|
|
186
|
-
.update(updates)
|
|
187
|
-
.eq('id', taskId)
|
|
188
|
-
.select()
|
|
189
|
-
.single()
|
|
190
|
-
if (error) throw new Error(`Failed to update task ${taskId}: ${error.message}`)
|
|
191
|
-
const task = data as Task
|
|
192
|
-
|
|
193
|
-
if (actor) {
|
|
194
|
-
await logActivity({
|
|
195
|
-
task_id: taskId,
|
|
196
|
-
project_id: task.project_id,
|
|
197
|
-
actor,
|
|
198
|
-
action: updates.status ? 'status_changed' : 'updated',
|
|
199
|
-
old_value: { status: old.status, assigned_to: old.assigned_to },
|
|
200
|
-
new_value: updates as Record<string, unknown>,
|
|
201
|
-
})
|
|
202
|
-
}
|
|
203
|
-
return task
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export async function getTask(taskId: string): Promise<Task> {
|
|
207
|
-
const { data, error } = await sb()
|
|
208
|
-
.from('tasks')
|
|
209
|
-
.select('*')
|
|
210
|
-
.eq('id', taskId)
|
|
211
|
-
.single()
|
|
212
|
-
if (error) throw new Error(`Task not found: ${taskId}`)
|
|
213
|
-
return data as Task
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export async function listTasks(opts?: {
|
|
217
|
-
project_id?: string
|
|
218
|
-
status?: TaskStatus
|
|
219
|
-
claimed_by?: string
|
|
220
|
-
assigned_to?: string
|
|
221
|
-
}): Promise<Task[]> {
|
|
222
|
-
let query = sb().from('tasks').select('*')
|
|
223
|
-
if (opts?.project_id) query = query.eq('project_id', opts.project_id)
|
|
224
|
-
if (opts?.status) query = query.eq('status', opts.status)
|
|
225
|
-
if (opts?.claimed_by) query = query.eq('claimed_by', opts.claimed_by)
|
|
226
|
-
if (opts?.assigned_to) query = query.eq('assigned_to', opts.assigned_to)
|
|
227
|
-
query = query.order('priority', { ascending: true }).order('sort_order', { ascending: true })
|
|
228
|
-
const { data, error } = await query
|
|
229
|
-
if (error) throw new Error(`Failed to list tasks: ${error.message}`)
|
|
230
|
-
return (data ?? []) as Task[]
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export async function claimTask(taskId: string, agent: string): Promise<Task> {
|
|
234
|
-
const task = await updateTask(taskId, {
|
|
235
|
-
status: 'claimed',
|
|
236
|
-
claimed_by: agent,
|
|
237
|
-
claimed_at: new Date().toISOString(),
|
|
238
|
-
}, agent)
|
|
239
|
-
|
|
240
|
-
await addComment({ task_id: taskId, author: agent, body: `Claimed by ${agent}`, comment_type: 'claim' })
|
|
241
|
-
return task
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
export async function completeTask(taskId: string, actor: string): Promise<Task> {
|
|
245
|
-
return updateTask(taskId, {
|
|
246
|
-
status: 'done',
|
|
247
|
-
completed_at: new Date().toISOString(),
|
|
248
|
-
}, actor)
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// --- Comments ---
|
|
252
|
-
|
|
253
|
-
export async function addComment(input: CreateCommentInput): Promise<Comment> {
|
|
254
|
-
const { data, error } = await sb()
|
|
255
|
-
.from('comments')
|
|
256
|
-
.insert({
|
|
257
|
-
task_id: input.task_id,
|
|
258
|
-
author: input.author,
|
|
259
|
-
body: input.body,
|
|
260
|
-
comment_type: input.comment_type ?? 'comment',
|
|
261
|
-
})
|
|
262
|
-
.select()
|
|
263
|
-
.single()
|
|
264
|
-
if (error) throw new Error(`Failed to add comment: ${error.message}`)
|
|
265
|
-
return data as Comment
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
export async function listComments(taskId: string): Promise<Comment[]> {
|
|
269
|
-
const { data, error } = await sb()
|
|
270
|
-
.from('comments')
|
|
271
|
-
.select('*')
|
|
272
|
-
.eq('task_id', taskId)
|
|
273
|
-
.order('created_at', { ascending: true })
|
|
274
|
-
if (error) throw new Error(`Failed to list comments: ${error.message}`)
|
|
275
|
-
return (data ?? []) as Comment[]
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// --- Activity Log ---
|
|
279
|
-
|
|
280
|
-
export async function logActivity(entry: {
|
|
281
|
-
task_id?: string
|
|
282
|
-
project_id?: string
|
|
283
|
-
actor: string
|
|
284
|
-
action: string
|
|
285
|
-
old_value?: Record<string, unknown>
|
|
286
|
-
new_value?: Record<string, unknown>
|
|
287
|
-
}): Promise<void> {
|
|
288
|
-
const { error } = await sb()
|
|
289
|
-
.from('activity_log')
|
|
290
|
-
.insert({
|
|
291
|
-
task_id: entry.task_id ?? null,
|
|
292
|
-
project_id: entry.project_id ?? null,
|
|
293
|
-
actor: entry.actor,
|
|
294
|
-
action: entry.action,
|
|
295
|
-
old_value: entry.old_value ?? null,
|
|
296
|
-
new_value: entry.new_value ?? null,
|
|
297
|
-
})
|
|
298
|
-
if (error) throw new Error(`Failed to log activity: ${error.message}`)
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
export async function listActivity(opts?: { task_id?: string; actor?: string; limit?: number }): Promise<ActivityEntry[]> {
|
|
302
|
-
let query = sb().from('activity_log').select('*')
|
|
303
|
-
if (opts?.task_id) query = query.eq('task_id', opts.task_id)
|
|
304
|
-
if (opts?.actor) query = query.eq('actor', opts.actor)
|
|
305
|
-
query = query.order('created_at', { ascending: false }).limit(opts?.limit ?? 50)
|
|
306
|
-
const { data, error } = await query
|
|
307
|
-
if (error) throw new Error(`Failed to list activity: ${error.message}`)
|
|
308
|
-
return (data ?? []) as ActivityEntry[]
|
|
309
|
-
}
|
package/lib/board/types.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
export interface Project {
|
|
2
|
-
id: string
|
|
3
|
-
slug: string
|
|
4
|
-
name: string
|
|
5
|
-
description: string | null
|
|
6
|
-
status: 'active' | 'paused' | 'completed' | 'archived'
|
|
7
|
-
owner: string | null
|
|
8
|
-
priority: 1 | 2 | 3 | 4
|
|
9
|
-
created_at: string
|
|
10
|
-
updated_at: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface Milestone {
|
|
14
|
-
id: string
|
|
15
|
-
project_id: string
|
|
16
|
-
name: string
|
|
17
|
-
description: string | null
|
|
18
|
-
due_date: string | null
|
|
19
|
-
status: 'open' | 'completed' | 'missed'
|
|
20
|
-
created_at: string
|
|
21
|
-
updated_at: string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface Label {
|
|
25
|
-
id: string
|
|
26
|
-
name: string
|
|
27
|
-
color: string | null
|
|
28
|
-
created_at: string
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type TaskStatus = 'backlog' | 'ready' | 'claimed' | 'in_progress' | 'review' | 'done' | 'blocked'
|
|
32
|
-
export type Priority = 1 | 2 | 3 | 4
|
|
33
|
-
export type Effort = 'xs' | 's' | 'm' | 'l' | 'xl'
|
|
34
|
-
|
|
35
|
-
export interface Task {
|
|
36
|
-
id: string
|
|
37
|
-
project_id: string
|
|
38
|
-
milestone_id: string | null
|
|
39
|
-
title: string
|
|
40
|
-
description: string | null
|
|
41
|
-
status: TaskStatus
|
|
42
|
-
priority: Priority
|
|
43
|
-
assigned_to: string | null
|
|
44
|
-
claimed_by: string | null
|
|
45
|
-
claimed_at: string | null
|
|
46
|
-
skill_required: string | null
|
|
47
|
-
source_repo: string | null
|
|
48
|
-
target_module: string | null
|
|
49
|
-
estimated_effort: Effort | null
|
|
50
|
-
blocked_by: string[]
|
|
51
|
-
sort_order: number
|
|
52
|
-
created_at: string
|
|
53
|
-
updated_at: string
|
|
54
|
-
completed_at: string | null
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface Comment {
|
|
58
|
-
id: string
|
|
59
|
-
task_id: string
|
|
60
|
-
author: string
|
|
61
|
-
body: string
|
|
62
|
-
comment_type: 'comment' | 'status_change' | 'claim' | 'review'
|
|
63
|
-
created_at: string
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface ActivityEntry {
|
|
67
|
-
id: string
|
|
68
|
-
task_id: string | null
|
|
69
|
-
project_id: string | null
|
|
70
|
-
actor: string
|
|
71
|
-
action: string
|
|
72
|
-
old_value: Record<string, unknown> | null
|
|
73
|
-
new_value: Record<string, unknown> | null
|
|
74
|
-
created_at: string
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// --- Input types ---
|
|
78
|
-
|
|
79
|
-
export interface CreateProjectInput {
|
|
80
|
-
slug: string
|
|
81
|
-
name: string
|
|
82
|
-
description?: string
|
|
83
|
-
owner?: string
|
|
84
|
-
priority?: Priority
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface CreateMilestoneInput {
|
|
88
|
-
project_id: string
|
|
89
|
-
name: string
|
|
90
|
-
description?: string
|
|
91
|
-
due_date?: string
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export interface CreateTaskInput {
|
|
95
|
-
project_id: string
|
|
96
|
-
title: string
|
|
97
|
-
description?: string
|
|
98
|
-
priority?: Priority
|
|
99
|
-
milestone_id?: string
|
|
100
|
-
skill_required?: string
|
|
101
|
-
source_repo?: string
|
|
102
|
-
target_module?: string
|
|
103
|
-
estimated_effort?: Effort
|
|
104
|
-
blocked_by?: string[]
|
|
105
|
-
labels?: string[]
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export interface UpdateTaskInput {
|
|
109
|
-
status?: TaskStatus
|
|
110
|
-
priority?: Priority
|
|
111
|
-
assigned_to?: string | null
|
|
112
|
-
claimed_by?: string | null
|
|
113
|
-
claimed_at?: string | null
|
|
114
|
-
milestone_id?: string | null
|
|
115
|
-
description?: string
|
|
116
|
-
completed_at?: string | null
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export interface CreateCommentInput {
|
|
120
|
-
task_id: string
|
|
121
|
-
author: string
|
|
122
|
-
body: string
|
|
123
|
-
comment_type?: 'comment' | 'status_change' | 'claim' | 'review'
|
|
124
|
-
}
|
package/lib/bot/claim.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
listTasks,
|
|
3
|
-
claimTask,
|
|
4
|
-
updateTask,
|
|
5
|
-
getNextClaimable,
|
|
6
|
-
type Task,
|
|
7
|
-
} from '../board/index.js'
|
|
8
|
-
|
|
9
|
-
export async function claimNextTask(
|
|
10
|
-
agentId: string,
|
|
11
|
-
skills?: string[],
|
|
12
|
-
): Promise<Task | null> {
|
|
13
|
-
const readyTasks = await listTasks({ status: 'ready' })
|
|
14
|
-
const allTasks = await listTasks()
|
|
15
|
-
|
|
16
|
-
let candidates = readyTasks
|
|
17
|
-
if (skills && skills.length > 0) {
|
|
18
|
-
candidates = readyTasks.filter(
|
|
19
|
-
(t) => !t.skill_required || skills.includes(t.skill_required),
|
|
20
|
-
)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const next = getNextClaimable(candidates, allTasks)
|
|
24
|
-
if (!next) return null
|
|
25
|
-
|
|
26
|
-
return claimTask(next.id, agentId)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export async function releaseTask(
|
|
30
|
-
taskId: string,
|
|
31
|
-
agentId: string,
|
|
32
|
-
reason?: string,
|
|
33
|
-
): Promise<Task> {
|
|
34
|
-
return updateTask(
|
|
35
|
-
taskId,
|
|
36
|
-
{
|
|
37
|
-
status: 'ready',
|
|
38
|
-
claimed_by: null,
|
|
39
|
-
claimed_at: null,
|
|
40
|
-
},
|
|
41
|
-
agentId,
|
|
42
|
-
)
|
|
43
|
-
}
|