idea-manager 0.4.0 → 0.6.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/package.json +1 -1
- package/src/app/projects/[id]/page.tsx +0 -4
- package/src/cli.ts +17 -0
- package/src/components/brainstorm/Editor.tsx +1 -84
- package/src/lib/ai/client.ts +22 -125
- package/src/lib/db/schema.ts +0 -70
- package/src/lib/watcher.ts +190 -0
- package/src/types/index.ts +0 -90
- package/src/app/api/projects/[id]/cleanup/route.ts +0 -32
- package/src/app/api/projects/[id]/conversations/route.ts +0 -50
- package/src/app/api/projects/[id]/items/[itemId]/prompt/route.ts +0 -51
- package/src/app/api/projects/[id]/items/[itemId]/refine/route.ts +0 -36
- package/src/app/api/projects/[id]/items/[itemId]/route.ts +0 -95
- package/src/app/api/projects/[id]/items/route.ts +0 -67
- package/src/app/api/projects/[id]/memos/route.ts +0 -18
- package/src/app/api/projects/[id]/scan/route.ts +0 -73
- package/src/app/api/projects/[id]/scan/stream/route.ts +0 -112
- package/src/app/api/projects/[id]/structure/route.ts +0 -59
- package/src/app/api/projects/[id]/structure/stream/route.ts +0 -157
- package/src/components/ScanPanel.tsx +0 -743
- package/src/components/brainstorm/MemoPin.tsx +0 -117
- package/src/components/tree/CardView.tsx +0 -206
- package/src/components/tree/ItemDetail.tsx +0 -196
- package/src/components/tree/LockToggle.tsx +0 -23
- package/src/components/tree/RefinePopover.tsx +0 -157
- package/src/components/tree/StatusBadge.tsx +0 -32
- package/src/components/tree/TreeNode.tsx +0 -227
- package/src/components/tree/TreeView.tsx +0 -304
- package/src/lib/ai/chat-responder.ts +0 -71
- package/src/lib/ai/cleanup.ts +0 -87
- package/src/lib/ai/prompter.ts +0 -78
- package/src/lib/ai/refiner.ts +0 -128
- package/src/lib/ai/structurer.ts +0 -403
- package/src/lib/db/queries/context.ts +0 -76
- package/src/lib/db/queries/conversations.ts +0 -46
- package/src/lib/db/queries/items.ts +0 -268
- package/src/lib/db/queries/memos.ts +0 -66
- package/src/lib/db/queries/prompts.ts +0 -68
- package/src/lib/scanner.ts +0 -573
- package/src/lib/task-store.ts +0 -97
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { getProject } from '@/lib/db/queries/projects';
|
|
3
|
-
import { getBrainstorm } from '@/lib/db/queries/brainstorms';
|
|
4
|
-
import { getProjectContextSummary } from '@/lib/db/queries/context';
|
|
5
|
-
import { structureWithChat } from '@/lib/ai/structurer';
|
|
6
|
-
import { getTask } from '@/lib/task-store';
|
|
7
|
-
|
|
8
|
-
export async function GET(
|
|
9
|
-
_request: NextRequest,
|
|
10
|
-
{ params }: { params: Promise<{ id: string }> },
|
|
11
|
-
) {
|
|
12
|
-
const { id } = await params;
|
|
13
|
-
const task = getTask(id);
|
|
14
|
-
if (!task) {
|
|
15
|
-
return NextResponse.json({ active: false });
|
|
16
|
-
}
|
|
17
|
-
return NextResponse.json({
|
|
18
|
-
active: task.status === 'running',
|
|
19
|
-
status: task.status,
|
|
20
|
-
startedAt: task.startedAt,
|
|
21
|
-
eventCount: task.events.length,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function POST(
|
|
26
|
-
_request: NextRequest,
|
|
27
|
-
{ params }: { params: Promise<{ id: string }> },
|
|
28
|
-
) {
|
|
29
|
-
const { id } = await params;
|
|
30
|
-
const project = getProject(id);
|
|
31
|
-
if (!project) {
|
|
32
|
-
return NextResponse.json({ error: 'Project not found' }, { status: 404 });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const brainstorm = getBrainstorm(id);
|
|
36
|
-
if (!brainstorm) {
|
|
37
|
-
return NextResponse.json({ error: 'Project not initialized' }, { status: 400 });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const hasContent = brainstorm.content.trim();
|
|
41
|
-
const hasContext = !!getProjectContextSummary(id);
|
|
42
|
-
|
|
43
|
-
if (!hasContent && !hasContext) {
|
|
44
|
-
return NextResponse.json({ error: '브레인스토밍 내용이나 프로젝트 스캔 결과가 필요합니다' }, { status: 400 });
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// If brainstorm is empty but project context exists, use a placeholder prompt
|
|
48
|
-
const content = hasContent
|
|
49
|
-
? brainstorm.content
|
|
50
|
-
: '프로젝트 스캔 결과를 분석하여 현재 프로젝트의 구조, 진행 상황, TODO 항목을 파악해주세요.';
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
const result = await structureWithChat(id, brainstorm.id, content);
|
|
54
|
-
return NextResponse.json(result);
|
|
55
|
-
} catch (error) {
|
|
56
|
-
const message = error instanceof Error ? error.message : 'AI structuring failed';
|
|
57
|
-
return NextResponse.json({ error: message }, { status: 500 });
|
|
58
|
-
}
|
|
59
|
-
}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { NextRequest } from 'next/server';
|
|
2
|
-
import { getProject } from '@/lib/db/queries/projects';
|
|
3
|
-
import { getBrainstorm } from '@/lib/db/queries/brainstorms';
|
|
4
|
-
import { getProjectContextSummary } from '@/lib/db/queries/context';
|
|
5
|
-
import { structureWithChatDirect } from '@/lib/ai/structurer';
|
|
6
|
-
import {
|
|
7
|
-
getTask, startTask, addTaskEvent, finishTask, failTask,
|
|
8
|
-
addTaskListener, cleanupTasks,
|
|
9
|
-
} from '@/lib/task-store';
|
|
10
|
-
|
|
11
|
-
export async function GET(
|
|
12
|
-
request: NextRequest,
|
|
13
|
-
{ params }: { params: Promise<{ id: string }> },
|
|
14
|
-
) {
|
|
15
|
-
const { id } = await params;
|
|
16
|
-
const project = getProject(id);
|
|
17
|
-
if (!project) {
|
|
18
|
-
return new Response('Project not found', { status: 404 });
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
cleanupTasks();
|
|
22
|
-
|
|
23
|
-
const existingTask = getTask(id);
|
|
24
|
-
|
|
25
|
-
// If there's an active task, attach to it (reconnect scenario)
|
|
26
|
-
if (existingTask && existingTask.status === 'running') {
|
|
27
|
-
return createReconnectStream(id, existingTask);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// If recently finished task exists, replay final result
|
|
31
|
-
if (existingTask && existingTask.status === 'done' && existingTask.result) {
|
|
32
|
-
return createReplayStream(existingTask);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Start new task
|
|
36
|
-
const brainstorm = getBrainstorm(id);
|
|
37
|
-
if (!brainstorm) {
|
|
38
|
-
return new Response('Project not initialized', { status: 400 });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const hasContent = brainstorm.content.trim();
|
|
42
|
-
const hasContext = !!getProjectContextSummary(id);
|
|
43
|
-
|
|
44
|
-
if (!hasContent && !hasContext) {
|
|
45
|
-
return new Response('No content to structure', { status: 400 });
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// User-provided project description from scan panel
|
|
49
|
-
const userDescription = request.nextUrl.searchParams.get('desc') || '';
|
|
50
|
-
|
|
51
|
-
let content = hasContent
|
|
52
|
-
? brainstorm.content
|
|
53
|
-
: '프로젝트 스캔 결과를 분석하여 현재 프로젝트의 구조, 진행 상황, TODO 항목을 파악해주세요.';
|
|
54
|
-
|
|
55
|
-
if (userDescription) {
|
|
56
|
-
content = `[사용자가 제공한 프로젝트 설명]\n${userDescription}\n\n${content}`;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const brainstormId = brainstorm.id;
|
|
60
|
-
|
|
61
|
-
// Start background task
|
|
62
|
-
startTask(id);
|
|
63
|
-
|
|
64
|
-
const send = async (event: string, data: unknown) => {
|
|
65
|
-
addTaskEvent(id, event, data);
|
|
66
|
-
if (event === 'done') {
|
|
67
|
-
finishTask(id, data);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// Run structuring in background (detached from stream)
|
|
72
|
-
(async () => {
|
|
73
|
-
try {
|
|
74
|
-
await structureWithChatDirect(id, brainstormId, content, send);
|
|
75
|
-
} catch (error) {
|
|
76
|
-
const msg = error instanceof Error ? error.message : 'Structure failed';
|
|
77
|
-
addTaskEvent(id, 'error', { error: msg });
|
|
78
|
-
failTask(id, msg);
|
|
79
|
-
}
|
|
80
|
-
})();
|
|
81
|
-
|
|
82
|
-
// Stream events to this client
|
|
83
|
-
return createReconnectStream(id, getTask(id)!);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function createReconnectStream(projectId: string, task: ReturnType<typeof getTask>) {
|
|
87
|
-
const encoder = new TextEncoder();
|
|
88
|
-
let unsubscribe: (() => void) | null = null;
|
|
89
|
-
|
|
90
|
-
const stream = new ReadableStream({
|
|
91
|
-
start(controller) {
|
|
92
|
-
const send = (event: string, data: unknown) => {
|
|
93
|
-
try {
|
|
94
|
-
controller.enqueue(encoder.encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`));
|
|
95
|
-
} catch {
|
|
96
|
-
// controller may be closed
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// Replay past events
|
|
101
|
-
if (task) {
|
|
102
|
-
for (const ev of task.events) {
|
|
103
|
-
send(ev.event, ev.data);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// If already finished, close immediately
|
|
107
|
-
if (task.status !== 'running') {
|
|
108
|
-
controller.close();
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Listen for new events
|
|
114
|
-
unsubscribe = addTaskListener(projectId, (event, data) => {
|
|
115
|
-
send(event, data);
|
|
116
|
-
if (event === 'done' || event === 'error') {
|
|
117
|
-
try { controller.close(); } catch { /* already closed */ }
|
|
118
|
-
unsubscribe?.();
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
},
|
|
122
|
-
cancel() {
|
|
123
|
-
unsubscribe?.();
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
return new Response(stream, {
|
|
128
|
-
headers: {
|
|
129
|
-
'Content-Type': 'text/event-stream',
|
|
130
|
-
'Cache-Control': 'no-cache',
|
|
131
|
-
'Connection': 'keep-alive',
|
|
132
|
-
'X-Accel-Buffering': 'no',
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function createReplayStream(task: NonNullable<ReturnType<typeof getTask>>) {
|
|
138
|
-
const encoder = new TextEncoder();
|
|
139
|
-
const stream = new ReadableStream({
|
|
140
|
-
start(controller) {
|
|
141
|
-
for (const ev of task.events) {
|
|
142
|
-
try {
|
|
143
|
-
controller.enqueue(encoder.encode(`event: ${ev.event}\ndata: ${JSON.stringify(ev.data)}\n\n`));
|
|
144
|
-
} catch { break; }
|
|
145
|
-
}
|
|
146
|
-
controller.close();
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
return new Response(stream, {
|
|
151
|
-
headers: {
|
|
152
|
-
'Content-Type': 'text/event-stream',
|
|
153
|
-
'Cache-Control': 'no-cache',
|
|
154
|
-
'Connection': 'keep-alive',
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
}
|