idea-manager 0.2.0 → 0.3.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.
Files changed (61) hide show
  1. package/README.md +33 -41
  2. package/next.config.ts +0 -1
  3. package/package.json +2 -2
  4. package/{src/app/icon.svg → public/favicon.svg} +2 -2
  5. package/src/app/api/filesystem/route.ts +49 -0
  6. package/src/app/api/projects/[id]/cleanup/route.ts +32 -0
  7. package/src/app/api/projects/[id]/items/[itemId]/refine/route.ts +36 -0
  8. package/src/app/api/projects/[id]/items/[itemId]/route.ts +23 -1
  9. package/src/app/api/projects/[id]/items/route.ts +51 -1
  10. package/src/app/api/projects/[id]/scan/route.ts +73 -0
  11. package/src/app/api/projects/[id]/scan/stream/route.ts +112 -0
  12. package/src/app/api/projects/[id]/structure/route.ts +34 -3
  13. package/src/app/api/projects/[id]/structure/stream/route.ts +157 -0
  14. package/src/app/api/projects/[id]/sub-projects/[subId]/route.ts +39 -0
  15. package/src/app/api/projects/[id]/sub-projects/[subId]/tasks/[taskId]/chat/route.ts +60 -0
  16. package/src/app/api/projects/[id]/sub-projects/[subId]/tasks/[taskId]/prompt/route.ts +26 -0
  17. package/src/app/api/projects/[id]/sub-projects/[subId]/tasks/[taskId]/route.ts +39 -0
  18. package/src/app/api/projects/[id]/sub-projects/[subId]/tasks/route.ts +33 -0
  19. package/src/app/api/projects/[id]/sub-projects/route.ts +31 -0
  20. package/src/app/api/projects/route.ts +1 -1
  21. package/src/app/globals.css +465 -5
  22. package/src/app/layout.tsx +3 -0
  23. package/src/app/page.tsx +260 -88
  24. package/src/app/projects/[id]/page.tsx +366 -183
  25. package/src/cli.ts +10 -10
  26. package/src/components/DirectoryPicker.tsx +137 -0
  27. package/src/components/ScanPanel.tsx +743 -0
  28. package/src/components/brainstorm/Editor.tsx +20 -4
  29. package/src/components/brainstorm/MemoPin.tsx +91 -5
  30. package/src/components/dashboard/SubProjectCard.tsx +76 -0
  31. package/src/components/dashboard/TabBar.tsx +42 -0
  32. package/src/components/task/ProjectTree.tsx +223 -0
  33. package/src/components/task/PromptEditor.tsx +107 -0
  34. package/src/components/task/StatusFlow.tsx +43 -0
  35. package/src/components/task/TaskChat.tsx +134 -0
  36. package/src/components/task/TaskDetail.tsx +205 -0
  37. package/src/components/task/TaskList.tsx +119 -0
  38. package/src/components/tree/CardView.tsx +206 -0
  39. package/src/components/tree/RefinePopover.tsx +157 -0
  40. package/src/components/tree/TreeNode.tsx +147 -38
  41. package/src/components/tree/TreeView.tsx +270 -26
  42. package/src/components/ui/ConfirmDialog.tsx +88 -0
  43. package/src/lib/ai/chat-responder.ts +4 -2
  44. package/src/lib/ai/cleanup.ts +87 -0
  45. package/src/lib/ai/client.ts +175 -58
  46. package/src/lib/ai/prompter.ts +19 -24
  47. package/src/lib/ai/refiner.ts +128 -0
  48. package/src/lib/ai/structurer.ts +340 -11
  49. package/src/lib/db/queries/context.ts +76 -0
  50. package/src/lib/db/queries/items.ts +133 -12
  51. package/src/lib/db/queries/projects.ts +12 -8
  52. package/src/lib/db/queries/sub-projects.ts +122 -0
  53. package/src/lib/db/queries/task-conversations.ts +27 -0
  54. package/src/lib/db/queries/task-prompts.ts +32 -0
  55. package/src/lib/db/queries/tasks.ts +133 -0
  56. package/src/lib/db/schema.ts +75 -0
  57. package/src/lib/mcp/server.ts +38 -39
  58. package/src/lib/mcp/tools.ts +47 -45
  59. package/src/lib/scanner.ts +573 -0
  60. package/src/lib/task-store.ts +97 -0
  61. package/src/types/index.ts +65 -0
package/src/cli.ts CHANGED
@@ -3,8 +3,9 @@
3
3
  import { Command } from 'commander';
4
4
  import { startMcpServer } from '@/lib/mcp/server';
5
5
  import { listProjects, getProject } from '@/lib/db/queries/projects';
6
- import { getItemTree, getItems, updateItem } from '@/lib/db/queries/items';
7
- import { getPrompt } from '@/lib/db/queries/prompts';
6
+ import { getSubProjects } from '@/lib/db/queries/sub-projects';
7
+ import { getTasksByProject, updateTask } from '@/lib/db/queries/tasks';
8
+ import { getTaskPrompt } from '@/lib/db/queries/task-prompts';
8
9
  import type { McpToolContext } from '@/lib/mcp/tools';
9
10
  import { spawn } from 'child_process';
10
11
  import path from 'path';
@@ -18,8 +19,8 @@ const program = new Command();
18
19
 
19
20
  program
20
21
  .name('im')
21
- .description('Idea Manager - AI 기반 브레인스토밍 구조화 → 프롬프트 생성 도구')
22
- .version('0.1.0');
22
+ .description('Idea Manager v2 - Brainstorming to structured tasks with prompts')
23
+ .version('0.2.0');
23
24
 
24
25
  program
25
26
  .command('mcp')
@@ -28,10 +29,10 @@ program
28
29
  const ctx: McpToolContext = {
29
30
  listProjects,
30
31
  getProject,
31
- getItemTree,
32
- getItems,
33
- getPrompt,
34
- updateItem: (id, data) => updateItem(id, data as Parameters<typeof updateItem>[1]),
32
+ getSubProjects,
33
+ getTasksByProject,
34
+ getTaskPrompt,
35
+ updateTask: (id, data) => updateTask(id, data as Parameters<typeof updateTask>[1]),
35
36
  };
36
37
 
37
38
  await startMcpServer(ctx);
@@ -43,7 +44,7 @@ program
43
44
  .option('-p, --port <port>', 'Port number', '3456')
44
45
  .action(async (opts) => {
45
46
  const port = opts.port;
46
- console.log(`\n IM - 아이디어 매니저`);
47
+ console.log(`\n IM - Idea Manager v2`);
47
48
  console.log(` Starting on http://localhost:${port}\n`);
48
49
 
49
50
  const nextBin = path.join(PKG_ROOT, 'node_modules', '.bin', 'next');
@@ -58,7 +59,6 @@ program
58
59
  process.exit(1);
59
60
  });
60
61
 
61
- // 서버 시작 후 브라우저 오픈
62
62
  setTimeout(async () => {
63
63
  try {
64
64
  const open = (await import('open')).default;
@@ -0,0 +1,137 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect, useCallback } from 'react';
4
+
5
+ interface DirEntry {
6
+ name: string;
7
+ path: string;
8
+ }
9
+
10
+ interface DirInfo {
11
+ current: string;
12
+ parent: string | null;
13
+ dirs: DirEntry[];
14
+ isProject: boolean;
15
+ }
16
+
17
+ interface DirectoryPickerProps {
18
+ onSelect: (path: string) => void;
19
+ onCancel: () => void;
20
+ initialPath?: string;
21
+ }
22
+
23
+ export default function DirectoryPicker({ onSelect, onCancel, initialPath }: DirectoryPickerProps) {
24
+ const [dirInfo, setDirInfo] = useState<DirInfo | null>(null);
25
+ const [loading, setLoading] = useState(true);
26
+ const [error, setError] = useState<string | null>(null);
27
+
28
+ const loadDir = useCallback(async (dirPath?: string) => {
29
+ setLoading(true);
30
+ setError(null);
31
+ try {
32
+ const params = dirPath ? `?path=${encodeURIComponent(dirPath)}` : '';
33
+ const res = await fetch(`/api/filesystem${params}`);
34
+ if (res.ok) {
35
+ setDirInfo(await res.json());
36
+ } else {
37
+ const data = await res.json();
38
+ setError(data.error || '불러오기 실패');
39
+ }
40
+ } catch {
41
+ setError('불러오기 실패');
42
+ } finally {
43
+ setLoading(false);
44
+ }
45
+ }, []);
46
+
47
+ useEffect(() => {
48
+ loadDir(initialPath);
49
+ }, [loadDir, initialPath]);
50
+
51
+ return (
52
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50" onClick={onCancel}>
53
+ <div
54
+ className="bg-card border border-border rounded-lg shadow-xl w-[520px] max-h-[70vh] flex flex-col"
55
+ onClick={e => e.stopPropagation()}
56
+ >
57
+ {/* Header */}
58
+ <div className="flex items-center justify-between px-4 py-3 border-b border-border">
59
+ <h3 className="text-sm font-semibold">프로젝트 폴더 선택</h3>
60
+ <button onClick={onCancel} className="text-muted-foreground hover:text-foreground text-lg leading-none">&times;</button>
61
+ </div>
62
+
63
+ {/* Current path */}
64
+ <div className="px-4 py-2 border-b border-border bg-muted">
65
+ <div className="flex items-center gap-2">
66
+ <span className="text-xs text-muted-foreground shrink-0">경로:</span>
67
+ <span className="text-xs font-mono truncate flex-1" title={dirInfo?.current}>
68
+ {dirInfo?.current || '...'}
69
+ </span>
70
+ {dirInfo?.isProject && (
71
+ <span className="text-xs text-success shrink-0 font-medium">프로젝트 감지</span>
72
+ )}
73
+ </div>
74
+ </div>
75
+
76
+ {/* Directory list */}
77
+ <div className="flex-1 overflow-y-auto min-h-0">
78
+ {loading ? (
79
+ <div className="p-8 text-center text-muted-foreground text-sm">불러오는 중...</div>
80
+ ) : error ? (
81
+ <div className="p-8 text-center text-destructive text-sm">{error}</div>
82
+ ) : (
83
+ <div className="py-1">
84
+ {/* Parent directory */}
85
+ {dirInfo?.parent && (
86
+ <button
87
+ onClick={() => loadDir(dirInfo.parent!)}
88
+ className="w-full text-left px-4 py-2 text-sm hover:bg-muted transition-colors
89
+ flex items-center gap-2 text-muted-foreground"
90
+ >
91
+ <span>↑</span>
92
+ <span>..</span>
93
+ </button>
94
+ )}
95
+
96
+ {/* Subdirectories */}
97
+ {dirInfo?.dirs.length === 0 && (
98
+ <div className="px-4 py-6 text-center text-muted-foreground text-xs">
99
+ 하위 폴더가 없습니다
100
+ </div>
101
+ )}
102
+ {dirInfo?.dirs.map(dir => (
103
+ <button
104
+ key={dir.path}
105
+ onClick={() => loadDir(dir.path)}
106
+ className="w-full text-left px-4 py-2 text-sm hover:bg-muted transition-colors
107
+ flex items-center gap-2"
108
+ >
109
+ <span className="text-muted-foreground">📁</span>
110
+ <span>{dir.name}</span>
111
+ </button>
112
+ ))}
113
+ </div>
114
+ )}
115
+ </div>
116
+
117
+ {/* Footer */}
118
+ <div className="flex items-center justify-end gap-2 px-4 py-3 border-t border-border">
119
+ <button
120
+ onClick={onCancel}
121
+ className="px-3 py-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors"
122
+ >
123
+ 취소
124
+ </button>
125
+ <button
126
+ onClick={() => dirInfo && onSelect(dirInfo.current)}
127
+ disabled={!dirInfo}
128
+ className="px-4 py-1.5 text-xs bg-primary hover:bg-primary-hover text-white
129
+ rounded-md transition-colors disabled:opacity-50"
130
+ >
131
+ 이 폴더 선택
132
+ </button>
133
+ </div>
134
+ </div>
135
+ </div>
136
+ );
137
+ }