@stoneforge/shared-routes 0.1.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.
- package/LICENSE +13 -0
- package/README.md +69 -0
- package/dist/channels.d.ts +9 -0
- package/dist/channels.d.ts.map +1 -0
- package/dist/channels.js +413 -0
- package/dist/channels.js.map +1 -0
- package/dist/documents.d.ts +9 -0
- package/dist/documents.d.ts.map +1 -0
- package/dist/documents.js +1205 -0
- package/dist/documents.js.map +1 -0
- package/dist/elements.d.ts +9 -0
- package/dist/elements.d.ts.map +1 -0
- package/dist/elements.js +87 -0
- package/dist/elements.js.map +1 -0
- package/dist/entities.d.ts +9 -0
- package/dist/entities.d.ts.map +1 -0
- package/dist/entities.js +92 -0
- package/dist/entities.js.map +1 -0
- package/dist/inbox.d.ts +10 -0
- package/dist/inbox.d.ts.map +1 -0
- package/dist/inbox.js +538 -0
- package/dist/inbox.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/libraries.d.ts +9 -0
- package/dist/libraries.d.ts.map +1 -0
- package/dist/libraries.js +467 -0
- package/dist/libraries.js.map +1 -0
- package/dist/messages.d.ts +9 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +338 -0
- package/dist/messages.js.map +1 -0
- package/dist/plans.d.ts +10 -0
- package/dist/plans.d.ts.map +1 -0
- package/dist/plans.js +495 -0
- package/dist/plans.js.map +1 -0
- package/dist/types.d.ts +128 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/ws/broadcaster.d.ts +62 -0
- package/dist/ws/broadcaster.d.ts.map +1 -0
- package/dist/ws/broadcaster.js +146 -0
- package/dist/ws/broadcaster.js.map +1 -0
- package/dist/ws/handler.d.ts +11 -0
- package/dist/ws/handler.d.ts.map +1 -0
- package/dist/ws/handler.js +38 -0
- package/dist/ws/handler.js.map +1 -0
- package/dist/ws/index.d.ts +11 -0
- package/dist/ws/index.d.ts.map +1 -0
- package/dist/ws/index.js +11 -0
- package/dist/ws/index.js.map +1 -0
- package/dist/ws/types.d.ts +85 -0
- package/dist/ws/types.d.ts.map +1 -0
- package/dist/ws/types.js +63 -0
- package/dist/ws/types.js.map +1 -0
- package/package.json +40 -0
package/dist/plans.js
ADDED
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plans Routes Factory
|
|
3
|
+
*
|
|
4
|
+
* Plan management endpoints for listing, viewing, creating, and updating plans.
|
|
5
|
+
* Includes task association and progress tracking (TB24, TB86, TB121).
|
|
6
|
+
*/
|
|
7
|
+
import { Hono } from 'hono';
|
|
8
|
+
import { createPlan, createTask, } from '@stoneforge/core';
|
|
9
|
+
export function createPlanRoutes(services) {
|
|
10
|
+
const { api } = services;
|
|
11
|
+
const app = new Hono();
|
|
12
|
+
/**
|
|
13
|
+
* GET /api/plans
|
|
14
|
+
* List all plans with optional filtering.
|
|
15
|
+
*
|
|
16
|
+
* Query params:
|
|
17
|
+
* - status: Filter by status (draft, active, completed, cancelled)
|
|
18
|
+
* - limit: Max number of results
|
|
19
|
+
* - offset: Skip first N results
|
|
20
|
+
* - hydrate.progress: Include progress info for each plan (TB86)
|
|
21
|
+
*/
|
|
22
|
+
app.get('/api/plans', async (c) => {
|
|
23
|
+
try {
|
|
24
|
+
const url = new URL(c.req.url);
|
|
25
|
+
const statusParam = url.searchParams.get('status');
|
|
26
|
+
const limitParam = url.searchParams.get('limit');
|
|
27
|
+
const offsetParam = url.searchParams.get('offset');
|
|
28
|
+
const hydrateProgress = url.searchParams.get('hydrate.progress') === 'true';
|
|
29
|
+
const filter = {
|
|
30
|
+
type: 'plan',
|
|
31
|
+
orderBy: 'updated_at',
|
|
32
|
+
orderDir: 'desc',
|
|
33
|
+
};
|
|
34
|
+
if (statusParam) {
|
|
35
|
+
filter.status = statusParam;
|
|
36
|
+
}
|
|
37
|
+
if (limitParam) {
|
|
38
|
+
filter.limit = parseInt(limitParam, 10);
|
|
39
|
+
}
|
|
40
|
+
if (offsetParam) {
|
|
41
|
+
filter.offset = parseInt(offsetParam, 10);
|
|
42
|
+
}
|
|
43
|
+
const plans = await api.list(filter);
|
|
44
|
+
// Optionally hydrate progress for all plans (TB86)
|
|
45
|
+
if (hydrateProgress) {
|
|
46
|
+
const plansWithProgress = await Promise.all(plans.map(async (plan) => {
|
|
47
|
+
const progress = await api.getPlanProgress(plan.id);
|
|
48
|
+
return { ...plan, _progress: progress };
|
|
49
|
+
}));
|
|
50
|
+
return c.json(plansWithProgress);
|
|
51
|
+
}
|
|
52
|
+
return c.json(plans);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.error('[stoneforge] Failed to get plans:', error);
|
|
56
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Failed to get plans' } }, 500);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* GET /api/plans/:id
|
|
61
|
+
* Get a single plan by ID.
|
|
62
|
+
*
|
|
63
|
+
* Query params:
|
|
64
|
+
* - hydrate.progress: Include progress info
|
|
65
|
+
*/
|
|
66
|
+
app.get('/api/plans/:id', async (c) => {
|
|
67
|
+
try {
|
|
68
|
+
const id = c.req.param('id');
|
|
69
|
+
const url = new URL(c.req.url);
|
|
70
|
+
const hydrateProgress = url.searchParams.get('hydrate.progress') === 'true';
|
|
71
|
+
const plan = await api.get(id);
|
|
72
|
+
if (!plan) {
|
|
73
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
74
|
+
}
|
|
75
|
+
if (plan.type !== 'plan') {
|
|
76
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
77
|
+
}
|
|
78
|
+
// Optionally hydrate progress
|
|
79
|
+
if (hydrateProgress) {
|
|
80
|
+
const progress = await api.getPlanProgress(id);
|
|
81
|
+
return c.json({ ...plan, _progress: progress });
|
|
82
|
+
}
|
|
83
|
+
return c.json(plan);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error('[stoneforge] Failed to get plan:', error);
|
|
87
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Failed to get plan' } }, 500);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* GET /api/plans/:id/tasks
|
|
92
|
+
* Get tasks in a plan.
|
|
93
|
+
*
|
|
94
|
+
* Query params:
|
|
95
|
+
* - status: Filter tasks by status
|
|
96
|
+
* - limit: Max number of results
|
|
97
|
+
* - offset: Skip first N results
|
|
98
|
+
*/
|
|
99
|
+
app.get('/api/plans/:id/tasks', async (c) => {
|
|
100
|
+
try {
|
|
101
|
+
const id = c.req.param('id');
|
|
102
|
+
const url = new URL(c.req.url);
|
|
103
|
+
const statusParam = url.searchParams.get('status');
|
|
104
|
+
const limitParam = url.searchParams.get('limit');
|
|
105
|
+
const offsetParam = url.searchParams.get('offset');
|
|
106
|
+
// First verify plan exists
|
|
107
|
+
const plan = await api.get(id);
|
|
108
|
+
if (!plan) {
|
|
109
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
110
|
+
}
|
|
111
|
+
if (plan.type !== 'plan') {
|
|
112
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
113
|
+
}
|
|
114
|
+
// Build filter for getTasksInPlan
|
|
115
|
+
const filter = {};
|
|
116
|
+
if (statusParam) {
|
|
117
|
+
filter.status = statusParam;
|
|
118
|
+
}
|
|
119
|
+
if (limitParam) {
|
|
120
|
+
filter.limit = parseInt(limitParam, 10);
|
|
121
|
+
}
|
|
122
|
+
if (offsetParam) {
|
|
123
|
+
filter.offset = parseInt(offsetParam, 10);
|
|
124
|
+
}
|
|
125
|
+
const tasks = await api.getTasksInPlan(id, filter);
|
|
126
|
+
return c.json(tasks);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
console.error('[stoneforge] Failed to get plan tasks:', error);
|
|
130
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Failed to get plan tasks' } }, 500);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
/**
|
|
134
|
+
* GET /api/plans/:id/progress
|
|
135
|
+
* Get progress summary for a plan.
|
|
136
|
+
*/
|
|
137
|
+
app.get('/api/plans/:id/progress', async (c) => {
|
|
138
|
+
try {
|
|
139
|
+
const id = c.req.param('id');
|
|
140
|
+
// First verify plan exists
|
|
141
|
+
const plan = await api.get(id);
|
|
142
|
+
if (!plan) {
|
|
143
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
144
|
+
}
|
|
145
|
+
if (plan.type !== 'plan') {
|
|
146
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
147
|
+
}
|
|
148
|
+
const progress = await api.getPlanProgress(id);
|
|
149
|
+
return c.json(progress);
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
console.error('[stoneforge] Failed to get plan progress:', error);
|
|
153
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Failed to get plan progress' } }, 500);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
/**
|
|
157
|
+
* POST /api/plans/:id/tasks
|
|
158
|
+
* Add a task to a plan.
|
|
159
|
+
*
|
|
160
|
+
* Body:
|
|
161
|
+
* - taskId: ID of task to add
|
|
162
|
+
* - actor: Optional entity ID for audit
|
|
163
|
+
*/
|
|
164
|
+
app.post('/api/plans/:id/tasks', async (c) => {
|
|
165
|
+
try {
|
|
166
|
+
const planId = c.req.param('id');
|
|
167
|
+
const body = await c.req.json();
|
|
168
|
+
// Validate required fields
|
|
169
|
+
if (!body.taskId || typeof body.taskId !== 'string') {
|
|
170
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: 'taskId is required and must be a string' } }, 400);
|
|
171
|
+
}
|
|
172
|
+
// Verify plan exists
|
|
173
|
+
const plan = await api.get(planId);
|
|
174
|
+
if (!plan) {
|
|
175
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
176
|
+
}
|
|
177
|
+
if (plan.type !== 'plan') {
|
|
178
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
179
|
+
}
|
|
180
|
+
// Verify task exists
|
|
181
|
+
const task = await api.get(body.taskId);
|
|
182
|
+
if (!task) {
|
|
183
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Task not found' } }, 404);
|
|
184
|
+
}
|
|
185
|
+
if (task.type !== 'task') {
|
|
186
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Task not found' } }, 404);
|
|
187
|
+
}
|
|
188
|
+
// Add the task to the plan
|
|
189
|
+
const dependency = await api.addTaskToPlan(body.taskId, planId, { actor: body.actor });
|
|
190
|
+
return c.json(dependency, 201);
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
const errorCode = error.code;
|
|
194
|
+
const errorMessage = error.message || '';
|
|
195
|
+
if (errorCode === 'ALREADY_EXISTS' || errorMessage.includes('already in plan')) {
|
|
196
|
+
return c.json({ error: { code: 'ALREADY_EXISTS', message: 'Task is already in a plan. Each task can only belong to one plan.' } }, 409);
|
|
197
|
+
}
|
|
198
|
+
if (errorCode === 'VALIDATION_ERROR') {
|
|
199
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: errorMessage } }, 400);
|
|
200
|
+
}
|
|
201
|
+
// Handle ConstraintError for task already in plan
|
|
202
|
+
if (error instanceof Error && (error.name === 'ConstraintError' || errorMessage.includes('already in plan'))) {
|
|
203
|
+
return c.json({ error: { code: 'ALREADY_EXISTS', message: 'Task is already in a plan. Each task can only belong to one plan.' } }, 409);
|
|
204
|
+
}
|
|
205
|
+
console.error('[stoneforge] Failed to add task to plan:', error);
|
|
206
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Failed to add task to plan' } }, 500);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
/**
|
|
210
|
+
* GET /api/plans/:id/can-delete-task/:taskId
|
|
211
|
+
* Check if task can be deleted from plan (TB121 - Plans must have at least one task).
|
|
212
|
+
*/
|
|
213
|
+
app.get('/api/plans/:id/can-delete-task/:taskId', async (c) => {
|
|
214
|
+
try {
|
|
215
|
+
const planId = c.req.param('id');
|
|
216
|
+
const taskId = c.req.param('taskId');
|
|
217
|
+
// Verify plan exists
|
|
218
|
+
const plan = await api.get(planId);
|
|
219
|
+
if (!plan) {
|
|
220
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
221
|
+
}
|
|
222
|
+
if (plan.type !== 'plan') {
|
|
223
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
224
|
+
}
|
|
225
|
+
// Get tasks in plan
|
|
226
|
+
const tasks = await api.getTasksInPlan(planId);
|
|
227
|
+
// Check if this task is in the plan
|
|
228
|
+
const taskInPlan = tasks.some(t => t.id === taskId);
|
|
229
|
+
if (!taskInPlan) {
|
|
230
|
+
return c.json({ canDelete: false, reason: 'Task is not in this plan' });
|
|
231
|
+
}
|
|
232
|
+
// Check if this is the last task
|
|
233
|
+
const isLastTask = tasks.length === 1;
|
|
234
|
+
if (isLastTask) {
|
|
235
|
+
return c.json({ canDelete: false, reason: 'Cannot remove the last task from a plan. Plans must have at least one task.' });
|
|
236
|
+
}
|
|
237
|
+
return c.json({ canDelete: true });
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
console.error('[stoneforge] Failed to check if task can be deleted:', error);
|
|
241
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Failed to check if task can be deleted' } }, 500);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
/**
|
|
245
|
+
* DELETE /api/plans/:id/tasks/:taskId
|
|
246
|
+
* Remove a task from a plan.
|
|
247
|
+
*/
|
|
248
|
+
app.delete('/api/plans/:id/tasks/:taskId', async (c) => {
|
|
249
|
+
try {
|
|
250
|
+
const planId = c.req.param('id');
|
|
251
|
+
const taskId = c.req.param('taskId');
|
|
252
|
+
// Verify plan exists
|
|
253
|
+
const plan = await api.get(planId);
|
|
254
|
+
if (!plan) {
|
|
255
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
256
|
+
}
|
|
257
|
+
if (plan.type !== 'plan') {
|
|
258
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
259
|
+
}
|
|
260
|
+
// TB121: Check if this is the last task - plans must have at least one task
|
|
261
|
+
const tasks = await api.getTasksInPlan(planId);
|
|
262
|
+
const taskInPlan = tasks.some(t => t.id === taskId);
|
|
263
|
+
if (taskInPlan && tasks.length === 1) {
|
|
264
|
+
return c.json({
|
|
265
|
+
error: {
|
|
266
|
+
code: 'LAST_TASK',
|
|
267
|
+
message: 'Cannot remove the last task from a plan. Plans must have at least one task.'
|
|
268
|
+
}
|
|
269
|
+
}, 400);
|
|
270
|
+
}
|
|
271
|
+
// Remove the task from the plan
|
|
272
|
+
await api.removeTaskFromPlan(taskId, planId);
|
|
273
|
+
return c.json({ success: true });
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
const errorCode = error.code;
|
|
277
|
+
if (errorCode === 'NOT_FOUND' || errorCode === 'DEPENDENCY_NOT_FOUND') {
|
|
278
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Task is not in this plan' } }, 404);
|
|
279
|
+
}
|
|
280
|
+
console.error('[stoneforge] Failed to remove task from plan:', error);
|
|
281
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Failed to remove task from plan' } }, 500);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
/**
|
|
285
|
+
* POST /api/plans
|
|
286
|
+
* Create a new plan with an initial task (TB121).
|
|
287
|
+
*
|
|
288
|
+
* Body:
|
|
289
|
+
* - title: Plan title (required)
|
|
290
|
+
* - createdBy: Entity ID of creator (required)
|
|
291
|
+
* - status: Initial status (default: draft)
|
|
292
|
+
* - tags: Array of tags
|
|
293
|
+
* - descriptionRef: Optional document reference
|
|
294
|
+
* - initialTaskId: ID of existing task to add (one of initialTaskId or initialTask required)
|
|
295
|
+
* - initialTask: Object with title, status, priority, complexity, tags to create new task
|
|
296
|
+
*/
|
|
297
|
+
app.post('/api/plans', async (c) => {
|
|
298
|
+
try {
|
|
299
|
+
const body = await c.req.json();
|
|
300
|
+
// Validate required fields
|
|
301
|
+
if (!body.title || typeof body.title !== 'string') {
|
|
302
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: 'title is required and must be a string' } }, 400);
|
|
303
|
+
}
|
|
304
|
+
if (!body.createdBy || typeof body.createdBy !== 'string') {
|
|
305
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: 'createdBy is required and must be a string' } }, 400);
|
|
306
|
+
}
|
|
307
|
+
// Validate title length
|
|
308
|
+
if (body.title.length < 1 || body.title.length > 500) {
|
|
309
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: 'title must be between 1 and 500 characters' } }, 400);
|
|
310
|
+
}
|
|
311
|
+
// TB121: Plans must have at least one task
|
|
312
|
+
// Accept either:
|
|
313
|
+
// 1. initialTaskId - existing task to add to the plan
|
|
314
|
+
// 2. initialTask - object with task details to create and add
|
|
315
|
+
const hasInitialTaskId = body.initialTaskId && typeof body.initialTaskId === 'string';
|
|
316
|
+
const hasInitialTask = body.initialTask && typeof body.initialTask === 'object' && body.initialTask.title;
|
|
317
|
+
if (!hasInitialTaskId && !hasInitialTask) {
|
|
318
|
+
return c.json({
|
|
319
|
+
error: {
|
|
320
|
+
code: 'VALIDATION_ERROR',
|
|
321
|
+
message: 'Plans must have at least one task. Provide either initialTaskId (existing task ID) or initialTask (object with title to create new task).'
|
|
322
|
+
}
|
|
323
|
+
}, 400);
|
|
324
|
+
}
|
|
325
|
+
// Validate initialTaskId exists if provided
|
|
326
|
+
if (hasInitialTaskId) {
|
|
327
|
+
const existingTask = await api.get(body.initialTaskId);
|
|
328
|
+
if (!existingTask) {
|
|
329
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Initial task not found' } }, 404);
|
|
330
|
+
}
|
|
331
|
+
if (existingTask.type !== 'task') {
|
|
332
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: 'initialTaskId must reference a task' } }, 400);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// Validate initialTask title if provided
|
|
336
|
+
if (hasInitialTask) {
|
|
337
|
+
if (typeof body.initialTask.title !== 'string' || body.initialTask.title.length < 1 || body.initialTask.title.length > 500) {
|
|
338
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: 'initialTask.title must be between 1 and 500 characters' } }, 400);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
// Create the plan using the factory function
|
|
342
|
+
const planInput = {
|
|
343
|
+
title: body.title,
|
|
344
|
+
createdBy: body.createdBy,
|
|
345
|
+
status: body.status || 'draft',
|
|
346
|
+
tags: body.tags || [],
|
|
347
|
+
descriptionRef: body.descriptionRef,
|
|
348
|
+
};
|
|
349
|
+
const plan = await createPlan(planInput);
|
|
350
|
+
const created = await api.create(plan);
|
|
351
|
+
// Now add or create the initial task
|
|
352
|
+
let taskId;
|
|
353
|
+
let createdTask = null;
|
|
354
|
+
if (hasInitialTaskId) {
|
|
355
|
+
taskId = body.initialTaskId;
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
// Create a new task using the proper factory function
|
|
359
|
+
const taskInput = {
|
|
360
|
+
title: body.initialTask.title,
|
|
361
|
+
status: (body.initialTask.status || 'open'),
|
|
362
|
+
priority: body.initialTask.priority || 3,
|
|
363
|
+
complexity: body.initialTask.complexity || 3,
|
|
364
|
+
tags: body.initialTask.tags || [],
|
|
365
|
+
createdBy: body.createdBy,
|
|
366
|
+
};
|
|
367
|
+
const task = await createTask(taskInput);
|
|
368
|
+
createdTask = await api.create(task);
|
|
369
|
+
taskId = createdTask.id;
|
|
370
|
+
}
|
|
371
|
+
// Add the task to the plan
|
|
372
|
+
await api.addTaskToPlan(taskId, created.id, { actor: body.createdBy });
|
|
373
|
+
// Return the plan along with the initial task info
|
|
374
|
+
return c.json({
|
|
375
|
+
...created,
|
|
376
|
+
initialTask: createdTask || { id: taskId }
|
|
377
|
+
}, 201);
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
const errorCode = error.code;
|
|
381
|
+
const errorMessage = error.message || '';
|
|
382
|
+
if (errorCode === 'VALIDATION_ERROR') {
|
|
383
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: errorMessage } }, 400);
|
|
384
|
+
}
|
|
385
|
+
if (errorCode === 'ALREADY_EXISTS' || errorMessage.includes('already in plan')) {
|
|
386
|
+
return c.json({ error: { code: 'ALREADY_EXISTS', message: 'Task is already in another plan. Each task can only belong to one plan.' } }, 409);
|
|
387
|
+
}
|
|
388
|
+
// Handle ConstraintError for task already in plan
|
|
389
|
+
if (error instanceof Error && (error.name === 'ConstraintError' || errorMessage.includes('already in plan'))) {
|
|
390
|
+
return c.json({ error: { code: 'ALREADY_EXISTS', message: 'Task is already in another plan. Each task can only belong to one plan.' } }, 409);
|
|
391
|
+
}
|
|
392
|
+
console.error('[stoneforge] Failed to create plan:', error);
|
|
393
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Failed to create plan' } }, 500);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
/**
|
|
397
|
+
* DELETE /api/plans/:id
|
|
398
|
+
* Delete a plan and remove all task associations.
|
|
399
|
+
*/
|
|
400
|
+
app.delete('/api/plans/:id', async (c) => {
|
|
401
|
+
try {
|
|
402
|
+
const id = c.req.param('id');
|
|
403
|
+
// First verify plan exists
|
|
404
|
+
const plan = await api.get(id);
|
|
405
|
+
if (!plan) {
|
|
406
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
407
|
+
}
|
|
408
|
+
if (plan.type !== 'plan') {
|
|
409
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
410
|
+
}
|
|
411
|
+
// Remove all task associations from this plan
|
|
412
|
+
const tasks = await api.getTasksInPlan(id);
|
|
413
|
+
for (const task of tasks) {
|
|
414
|
+
try {
|
|
415
|
+
await api.removeTaskFromPlan(task.id, id);
|
|
416
|
+
}
|
|
417
|
+
catch (err) {
|
|
418
|
+
// Continue even if removal fails - task might already be removed
|
|
419
|
+
console.warn(`[stoneforge] Failed to remove task ${task.id} from plan ${id}:`, err);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
// Delete the plan
|
|
423
|
+
await api.delete(id);
|
|
424
|
+
return c.json({ success: true });
|
|
425
|
+
}
|
|
426
|
+
catch (error) {
|
|
427
|
+
if (error.code === 'NOT_FOUND') {
|
|
428
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
429
|
+
}
|
|
430
|
+
console.error('[stoneforge] Failed to delete plan:', error);
|
|
431
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Failed to delete plan' } }, 500);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
/**
|
|
435
|
+
* PATCH /api/plans/:id
|
|
436
|
+
* Update a plan.
|
|
437
|
+
*
|
|
438
|
+
* Body (all optional):
|
|
439
|
+
* - title: New title
|
|
440
|
+
* - status: New status
|
|
441
|
+
* - tags: New tags
|
|
442
|
+
* - metadata: New metadata
|
|
443
|
+
* - descriptionRef: New description reference
|
|
444
|
+
* - cancelReason: Reason for cancellation
|
|
445
|
+
*/
|
|
446
|
+
app.patch('/api/plans/:id', async (c) => {
|
|
447
|
+
try {
|
|
448
|
+
const id = c.req.param('id');
|
|
449
|
+
const body = await c.req.json();
|
|
450
|
+
// First verify plan exists
|
|
451
|
+
const existing = await api.get(id);
|
|
452
|
+
if (!existing) {
|
|
453
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
454
|
+
}
|
|
455
|
+
if (existing.type !== 'plan') {
|
|
456
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
457
|
+
}
|
|
458
|
+
// Extract allowed updates
|
|
459
|
+
const updates = {};
|
|
460
|
+
const allowedFields = ['title', 'status', 'tags', 'metadata', 'descriptionRef', 'cancelReason'];
|
|
461
|
+
for (const field of allowedFields) {
|
|
462
|
+
if (body[field] !== undefined) {
|
|
463
|
+
updates[field] = body[field];
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
// Validate title if provided
|
|
467
|
+
if (updates.title !== undefined) {
|
|
468
|
+
if (typeof updates.title !== 'string' || updates.title.length < 1 || updates.title.length > 500) {
|
|
469
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: 'title must be between 1 and 500 characters' } }, 400);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
// Validate status if provided
|
|
473
|
+
if (updates.status !== undefined) {
|
|
474
|
+
const validStatuses = ['draft', 'active', 'completed', 'cancelled'];
|
|
475
|
+
if (!validStatuses.includes(updates.status)) {
|
|
476
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: `Invalid status. Must be one of: ${validStatuses.join(', ')}` } }, 400);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const updated = await api.update(id, updates);
|
|
480
|
+
return c.json(updated);
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
if (error.code === 'NOT_FOUND') {
|
|
484
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Plan not found' } }, 404);
|
|
485
|
+
}
|
|
486
|
+
if (error.code === 'VALIDATION_ERROR') {
|
|
487
|
+
return c.json({ error: { code: 'VALIDATION_ERROR', message: error.message } }, 400);
|
|
488
|
+
}
|
|
489
|
+
console.error('[stoneforge] Failed to update plan:', error);
|
|
490
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Failed to update plan' } }, 500);
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
return app;
|
|
494
|
+
}
|
|
495
|
+
//# sourceMappingURL=plans.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plans.js","sourceRoot":"","sources":["../src/plans.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Types for Collaborate Routes
|
|
3
|
+
*
|
|
4
|
+
* Defines the services interface that both main server and orchestrator-server satisfy.
|
|
5
|
+
* Uses duck-typed interfaces to avoid circular dependency on @stoneforge/quarry.
|
|
6
|
+
*/
|
|
7
|
+
import type { StorageBackend } from '@stoneforge/storage';
|
|
8
|
+
import type { Element, ElementId, EntityId, Document, DocumentId, Task, Channel, Dependency, DependencyType, PlanProgress, InboxFilter, InboxItem, CreateInboxItemInput } from '@stoneforge/core';
|
|
9
|
+
/**
|
|
10
|
+
* Subset of QuarryAPI methods used by shared routes.
|
|
11
|
+
* Avoids a circular dependency on @stoneforge/quarry.
|
|
12
|
+
*/
|
|
13
|
+
export interface QuarryLikeAPI {
|
|
14
|
+
get<T extends Element>(id: ElementId, options?: {
|
|
15
|
+
hydrate?: {
|
|
16
|
+
description?: boolean;
|
|
17
|
+
content?: boolean;
|
|
18
|
+
attachments?: boolean;
|
|
19
|
+
};
|
|
20
|
+
}): Promise<T | null>;
|
|
21
|
+
list<T extends Element>(filter?: Record<string, unknown>): Promise<T[]>;
|
|
22
|
+
listPaginated<T extends Element>(filter?: Record<string, unknown>): Promise<{
|
|
23
|
+
items: T[];
|
|
24
|
+
total: number;
|
|
25
|
+
offset: number;
|
|
26
|
+
limit: number;
|
|
27
|
+
hasMore: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
create<T extends Element>(input: Record<string, unknown>): Promise<T>;
|
|
30
|
+
update<T extends Element>(id: ElementId, updates: Partial<T>, options?: {
|
|
31
|
+
actor?: EntityId;
|
|
32
|
+
expectedUpdatedAt?: string;
|
|
33
|
+
}): Promise<T>;
|
|
34
|
+
delete(id: ElementId, options?: {
|
|
35
|
+
actor?: EntityId;
|
|
36
|
+
reason?: string;
|
|
37
|
+
}): Promise<void>;
|
|
38
|
+
search(query: string, filter?: Record<string, unknown>): Promise<Element[]>;
|
|
39
|
+
searchDocumentsFTS(query: string, options?: Record<string, unknown>): Promise<Array<{
|
|
40
|
+
document: Document;
|
|
41
|
+
score: number;
|
|
42
|
+
snippet: string;
|
|
43
|
+
}>>;
|
|
44
|
+
getDependencies(id: ElementId, types?: DependencyType[]): Promise<Dependency[]>;
|
|
45
|
+
getDependents(id: ElementId, types?: DependencyType[]): Promise<Dependency[]>;
|
|
46
|
+
addDependency(dep: {
|
|
47
|
+
blockedId: ElementId;
|
|
48
|
+
blockerId: ElementId;
|
|
49
|
+
type: DependencyType;
|
|
50
|
+
metadata?: Record<string, unknown>;
|
|
51
|
+
actor?: EntityId;
|
|
52
|
+
}): Promise<Dependency>;
|
|
53
|
+
removeDependency(blockedId: ElementId, blockerId: ElementId, type: DependencyType, actor?: EntityId): Promise<void>;
|
|
54
|
+
addChannelMember(channelId: ElementId, entityId: EntityId, options?: {
|
|
55
|
+
actor?: EntityId;
|
|
56
|
+
}): Promise<{
|
|
57
|
+
success: boolean;
|
|
58
|
+
channel: Channel;
|
|
59
|
+
entityId: EntityId;
|
|
60
|
+
}>;
|
|
61
|
+
removeChannelMember(channelId: ElementId, entityId: EntityId, options?: {
|
|
62
|
+
actor?: EntityId;
|
|
63
|
+
reason?: string;
|
|
64
|
+
}): Promise<{
|
|
65
|
+
success: boolean;
|
|
66
|
+
channel: Channel;
|
|
67
|
+
entityId: EntityId;
|
|
68
|
+
}>;
|
|
69
|
+
leaveChannel(channelId: ElementId, actor: EntityId): Promise<{
|
|
70
|
+
success: boolean;
|
|
71
|
+
channel: Channel;
|
|
72
|
+
entityId: EntityId;
|
|
73
|
+
}>;
|
|
74
|
+
mergeChannels(sourceId: ElementId, targetId: ElementId, options?: {
|
|
75
|
+
newName?: string;
|
|
76
|
+
actor?: EntityId;
|
|
77
|
+
}): Promise<{
|
|
78
|
+
target: Channel;
|
|
79
|
+
sourceArchived: boolean;
|
|
80
|
+
messagesMoved: number;
|
|
81
|
+
}>;
|
|
82
|
+
getDocumentHistory(id: DocumentId): Promise<Document[]>;
|
|
83
|
+
getDocumentVersion(id: DocumentId, version: number): Promise<Document | null>;
|
|
84
|
+
getPlanProgress(planId: ElementId): Promise<PlanProgress>;
|
|
85
|
+
getTasksInPlan(planId: ElementId, filter?: Record<string, unknown>): Promise<Task[]>;
|
|
86
|
+
addTaskToPlan(taskId: ElementId, planId: ElementId, options?: {
|
|
87
|
+
actor?: EntityId;
|
|
88
|
+
}): Promise<Dependency>;
|
|
89
|
+
removeTaskFromPlan(taskId: ElementId, planId: ElementId, actor?: EntityId): Promise<void>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Subset of InboxService methods used by shared routes.
|
|
93
|
+
* Avoids a circular dependency on @stoneforge/quarry.
|
|
94
|
+
*/
|
|
95
|
+
export interface InboxLikeService {
|
|
96
|
+
getInboxPaginated(recipientId: string, filter?: InboxFilter): {
|
|
97
|
+
items: InboxItem[];
|
|
98
|
+
total: number;
|
|
99
|
+
};
|
|
100
|
+
getUnreadCount(recipientId: string): number;
|
|
101
|
+
markAllAsRead(recipientId: string): number;
|
|
102
|
+
getInboxItem(itemId: string): InboxItem | null;
|
|
103
|
+
markAsRead(itemId: string): InboxItem;
|
|
104
|
+
markAsUnread(itemId: string): InboxItem;
|
|
105
|
+
archive(itemId: string): InboxItem;
|
|
106
|
+
addToInbox(input: CreateInboxItemInput): InboxItem;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Services required for collaborate routes.
|
|
110
|
+
* Both main server and orchestrator-server provide these services.
|
|
111
|
+
*/
|
|
112
|
+
export interface CollaborateServices {
|
|
113
|
+
api: QuarryLikeAPI;
|
|
114
|
+
inboxService: InboxLikeService;
|
|
115
|
+
storageBackend: StorageBackend;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Optional callback for broadcasting inbox events in real-time.
|
|
119
|
+
* Used by servers with WebSocket support.
|
|
120
|
+
*/
|
|
121
|
+
export type BroadcastInboxEventFn = (id: string, recipientId: EntityId, action: 'created' | 'updated' | 'deleted', oldData: Record<string, unknown> | null, newData: Record<string, unknown> | null, actor: EntityId) => void;
|
|
122
|
+
/**
|
|
123
|
+
* Extended services including optional real-time features.
|
|
124
|
+
*/
|
|
125
|
+
export interface CollaborateServicesWithBroadcast extends CollaborateServices {
|
|
126
|
+
broadcastInboxEvent?: BroadcastInboxEventFn;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=types.d.ts.map
|