create-arete-workspace 0.2.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.
Files changed (180) hide show
  1. package/README.md +77 -0
  2. package/bin/arete.js +156 -0
  3. package/bin/create.js +111 -0
  4. package/lib/install-openclaw.js +50 -0
  5. package/lib/scaffold.js +213 -0
  6. package/lib/setup-wizard.js +88 -0
  7. package/lib/updater.js +130 -0
  8. package/package.json +34 -0
  9. package/packages/gatsaeng-os/README.md +36 -0
  10. package/packages/gatsaeng-os/components.json +23 -0
  11. package/packages/gatsaeng-os/eslint.config.mjs +18 -0
  12. package/packages/gatsaeng-os/next.config.ts +7 -0
  13. package/packages/gatsaeng-os/package.json +59 -0
  14. package/packages/gatsaeng-os/postcss.config.mjs +7 -0
  15. package/packages/gatsaeng-os/public/file.svg +1 -0
  16. package/packages/gatsaeng-os/public/globe.svg +1 -0
  17. package/packages/gatsaeng-os/public/next.svg +1 -0
  18. package/packages/gatsaeng-os/public/vercel.svg +1 -0
  19. package/packages/gatsaeng-os/public/window.svg +1 -0
  20. package/packages/gatsaeng-os/python/api_server.py +248 -0
  21. package/packages/gatsaeng-os/python/briefing.py +145 -0
  22. package/packages/gatsaeng-os/python/config.py +55 -0
  23. package/packages/gatsaeng-os/python/goal_context_agent.py +193 -0
  24. package/packages/gatsaeng-os/python/gyeokguk.py +171 -0
  25. package/packages/gatsaeng-os/python/proactive.py +158 -0
  26. package/packages/gatsaeng-os/python/requirements.txt +11 -0
  27. package/packages/gatsaeng-os/python/run.py +28 -0
  28. package/packages/gatsaeng-os/python/scoring.py +44 -0
  29. package/packages/gatsaeng-os/python/streak.py +70 -0
  30. package/packages/gatsaeng-os/python/telegram_bot.py +331 -0
  31. package/packages/gatsaeng-os/python/timing_engine.py +117 -0
  32. package/packages/gatsaeng-os/python/vault_io.py +423 -0
  33. package/packages/gatsaeng-os/src/app/(dashboard)/areas/[id]/page.tsx +215 -0
  34. package/packages/gatsaeng-os/src/app/(dashboard)/areas/page.tsx +161 -0
  35. package/packages/gatsaeng-os/src/app/(dashboard)/books/[id]/page.tsx +215 -0
  36. package/packages/gatsaeng-os/src/app/(dashboard)/books/page.tsx +268 -0
  37. package/packages/gatsaeng-os/src/app/(dashboard)/calendar/page.tsx +379 -0
  38. package/packages/gatsaeng-os/src/app/(dashboard)/error.tsx +30 -0
  39. package/packages/gatsaeng-os/src/app/(dashboard)/focus/page.tsx +293 -0
  40. package/packages/gatsaeng-os/src/app/(dashboard)/goals/[id]/page.tsx +426 -0
  41. package/packages/gatsaeng-os/src/app/(dashboard)/goals/page.tsx +178 -0
  42. package/packages/gatsaeng-os/src/app/(dashboard)/layout.tsx +29 -0
  43. package/packages/gatsaeng-os/src/app/(dashboard)/notes/[id]/page.tsx +147 -0
  44. package/packages/gatsaeng-os/src/app/(dashboard)/notes/page.tsx +254 -0
  45. package/packages/gatsaeng-os/src/app/(dashboard)/page.tsx +26 -0
  46. package/packages/gatsaeng-os/src/app/(dashboard)/projects/[id]/page.tsx +86 -0
  47. package/packages/gatsaeng-os/src/app/(dashboard)/projects/page.tsx +215 -0
  48. package/packages/gatsaeng-os/src/app/(dashboard)/review/page.tsx +475 -0
  49. package/packages/gatsaeng-os/src/app/(dashboard)/routines/page.tsx +436 -0
  50. package/packages/gatsaeng-os/src/app/(dashboard)/tasks/[id]/page.tsx +210 -0
  51. package/packages/gatsaeng-os/src/app/(dashboard)/tasks/page.tsx +307 -0
  52. package/packages/gatsaeng-os/src/app/(dashboard)/voice/page.tsx +212 -0
  53. package/packages/gatsaeng-os/src/app/api/areas/[id]/route.ts +26 -0
  54. package/packages/gatsaeng-os/src/app/api/areas/route.ts +22 -0
  55. package/packages/gatsaeng-os/src/app/api/auth/login/route.ts +52 -0
  56. package/packages/gatsaeng-os/src/app/api/auth/logout/route.ts +8 -0
  57. package/packages/gatsaeng-os/src/app/api/books/[id]/route.ts +27 -0
  58. package/packages/gatsaeng-os/src/app/api/books/route.ts +20 -0
  59. package/packages/gatsaeng-os/src/app/api/calendar/[id]/route.ts +24 -0
  60. package/packages/gatsaeng-os/src/app/api/calendar/import/route.ts +52 -0
  61. package/packages/gatsaeng-os/src/app/api/calendar/route.ts +37 -0
  62. package/packages/gatsaeng-os/src/app/api/daily/route.ts +51 -0
  63. package/packages/gatsaeng-os/src/app/api/goals/[id]/route.ts +34 -0
  64. package/packages/gatsaeng-os/src/app/api/goals/route.ts +30 -0
  65. package/packages/gatsaeng-os/src/app/api/logs/energy/route.ts +40 -0
  66. package/packages/gatsaeng-os/src/app/api/logs/focus/route.ts +22 -0
  67. package/packages/gatsaeng-os/src/app/api/logs/routine/route.ts +54 -0
  68. package/packages/gatsaeng-os/src/app/api/milestones/[id]/route.ts +26 -0
  69. package/packages/gatsaeng-os/src/app/api/milestones/route.ts +47 -0
  70. package/packages/gatsaeng-os/src/app/api/notes/[id]/route.ts +29 -0
  71. package/packages/gatsaeng-os/src/app/api/notes/route.ts +37 -0
  72. package/packages/gatsaeng-os/src/app/api/profile/route.ts +17 -0
  73. package/packages/gatsaeng-os/src/app/api/projects/[id]/route.ts +27 -0
  74. package/packages/gatsaeng-os/src/app/api/projects/route.ts +25 -0
  75. package/packages/gatsaeng-os/src/app/api/reviews/[id]/route.ts +26 -0
  76. package/packages/gatsaeng-os/src/app/api/reviews/route.ts +29 -0
  77. package/packages/gatsaeng-os/src/app/api/routines/[id]/route.ts +26 -0
  78. package/packages/gatsaeng-os/src/app/api/routines/route.ts +28 -0
  79. package/packages/gatsaeng-os/src/app/api/tasks/[id]/route.ts +28 -0
  80. package/packages/gatsaeng-os/src/app/api/tasks/route.ts +66 -0
  81. package/packages/gatsaeng-os/src/app/api/timing/current/route.ts +63 -0
  82. package/packages/gatsaeng-os/src/app/api/voice/chat/route.ts +50 -0
  83. package/packages/gatsaeng-os/src/app/api/voice/transcribe/route.ts +25 -0
  84. package/packages/gatsaeng-os/src/app/api/voice/tts/route.ts +36 -0
  85. package/packages/gatsaeng-os/src/app/error.tsx +30 -0
  86. package/packages/gatsaeng-os/src/app/favicon.ico +0 -0
  87. package/packages/gatsaeng-os/src/app/globals.css +208 -0
  88. package/packages/gatsaeng-os/src/app/layout.tsx +33 -0
  89. package/packages/gatsaeng-os/src/app/login/page.tsx +87 -0
  90. package/packages/gatsaeng-os/src/app/providers.tsx +27 -0
  91. package/packages/gatsaeng-os/src/components/ErrorBoundary.tsx +46 -0
  92. package/packages/gatsaeng-os/src/components/dashboard/DashboardGrid.tsx +86 -0
  93. package/packages/gatsaeng-os/src/components/dashboard/DdayWidget.tsx +88 -0
  94. package/packages/gatsaeng-os/src/components/dashboard/EnergyTracker.tsx +87 -0
  95. package/packages/gatsaeng-os/src/components/dashboard/FocusTimer.tsx +139 -0
  96. package/packages/gatsaeng-os/src/components/dashboard/GatsaengScore.tsx +30 -0
  97. package/packages/gatsaeng-os/src/components/dashboard/GoalRings.tsx +107 -0
  98. package/packages/gatsaeng-os/src/components/dashboard/ProactiveBar.tsx +98 -0
  99. package/packages/gatsaeng-os/src/components/dashboard/RoutineChecklist.tsx +81 -0
  100. package/packages/gatsaeng-os/src/components/dashboard/TimingWidget.tsx +86 -0
  101. package/packages/gatsaeng-os/src/components/dashboard/WidgetCustomizer.tsx +95 -0
  102. package/packages/gatsaeng-os/src/components/dashboard/WidgetWrapper.tsx +33 -0
  103. package/packages/gatsaeng-os/src/components/dashboard/ZeigarnikPanel.tsx +43 -0
  104. package/packages/gatsaeng-os/src/components/editor/EditorToolbar.tsx +186 -0
  105. package/packages/gatsaeng-os/src/components/editor/TiptapEditor.tsx +114 -0
  106. package/packages/gatsaeng-os/src/components/layout/Header.tsx +47 -0
  107. package/packages/gatsaeng-os/src/components/layout/MobileBottomNav.tsx +122 -0
  108. package/packages/gatsaeng-os/src/components/layout/MobileSidebar.tsx +29 -0
  109. package/packages/gatsaeng-os/src/components/layout/Sidebar.tsx +142 -0
  110. package/packages/gatsaeng-os/src/components/onboarding/OnboardingFlow.tsx +229 -0
  111. package/packages/gatsaeng-os/src/components/onboarding/OnboardingGate.tsx +78 -0
  112. package/packages/gatsaeng-os/src/components/projects/CalendarView.tsx +152 -0
  113. package/packages/gatsaeng-os/src/components/projects/KanbanView.tsx +180 -0
  114. package/packages/gatsaeng-os/src/components/projects/ListView.tsx +82 -0
  115. package/packages/gatsaeng-os/src/components/projects/TableView.tsx +206 -0
  116. package/packages/gatsaeng-os/src/components/projects/TaskCard.tsx +154 -0
  117. package/packages/gatsaeng-os/src/components/projects/TaskForm.tsx +128 -0
  118. package/packages/gatsaeng-os/src/components/projects/ViewSwitcher.tsx +40 -0
  119. package/packages/gatsaeng-os/src/components/search/GlobalSearch.tsx +179 -0
  120. package/packages/gatsaeng-os/src/components/shared/InlineEdit.tsx +77 -0
  121. package/packages/gatsaeng-os/src/components/shared/PinButton.tsx +42 -0
  122. package/packages/gatsaeng-os/src/components/tasks/DDayBadge.tsx +34 -0
  123. package/packages/gatsaeng-os/src/components/ui/badge.tsx +48 -0
  124. package/packages/gatsaeng-os/src/components/ui/button.tsx +64 -0
  125. package/packages/gatsaeng-os/src/components/ui/card.tsx +92 -0
  126. package/packages/gatsaeng-os/src/components/ui/checkbox.tsx +32 -0
  127. package/packages/gatsaeng-os/src/components/ui/command.tsx +184 -0
  128. package/packages/gatsaeng-os/src/components/ui/dialog.tsx +158 -0
  129. package/packages/gatsaeng-os/src/components/ui/input.tsx +21 -0
  130. package/packages/gatsaeng-os/src/components/ui/label.tsx +24 -0
  131. package/packages/gatsaeng-os/src/components/ui/popover.tsx +89 -0
  132. package/packages/gatsaeng-os/src/components/ui/progress.tsx +31 -0
  133. package/packages/gatsaeng-os/src/components/ui/select.tsx +190 -0
  134. package/packages/gatsaeng-os/src/components/ui/sheet.tsx +143 -0
  135. package/packages/gatsaeng-os/src/components/ui/tabs.tsx +91 -0
  136. package/packages/gatsaeng-os/src/components/ui/toggle-group.tsx +83 -0
  137. package/packages/gatsaeng-os/src/components/ui/toggle.tsx +47 -0
  138. package/packages/gatsaeng-os/src/components/ui/tooltip.tsx +57 -0
  139. package/packages/gatsaeng-os/src/hooks/useAreas.ts +53 -0
  140. package/packages/gatsaeng-os/src/hooks/useBooks.ts +62 -0
  141. package/packages/gatsaeng-os/src/hooks/useCalendar.ts +59 -0
  142. package/packages/gatsaeng-os/src/hooks/useDaily.ts +15 -0
  143. package/packages/gatsaeng-os/src/hooks/useGlobalTasks.ts +45 -0
  144. package/packages/gatsaeng-os/src/hooks/useGoals.ts +53 -0
  145. package/packages/gatsaeng-os/src/hooks/useMilestones.ts +75 -0
  146. package/packages/gatsaeng-os/src/hooks/useNotes.ts +65 -0
  147. package/packages/gatsaeng-os/src/hooks/useProjects.ts +102 -0
  148. package/packages/gatsaeng-os/src/hooks/useRoutines.ts +76 -0
  149. package/packages/gatsaeng-os/src/hooks/useTiming.ts +27 -0
  150. package/packages/gatsaeng-os/src/lib/apiFetch.ts +14 -0
  151. package/packages/gatsaeng-os/src/lib/auth.ts +32 -0
  152. package/packages/gatsaeng-os/src/lib/date.ts +7 -0
  153. package/packages/gatsaeng-os/src/lib/editor/markdown.ts +35 -0
  154. package/packages/gatsaeng-os/src/lib/llm-governor.ts +167 -0
  155. package/packages/gatsaeng-os/src/lib/neuroscience/energyCycle.ts +35 -0
  156. package/packages/gatsaeng-os/src/lib/neuroscience/habitStack.ts +22 -0
  157. package/packages/gatsaeng-os/src/lib/neuroscience/scoring.ts +32 -0
  158. package/packages/gatsaeng-os/src/lib/routes.ts +15 -0
  159. package/packages/gatsaeng-os/src/lib/utils.ts +6 -0
  160. package/packages/gatsaeng-os/src/lib/vault/config.ts +29 -0
  161. package/packages/gatsaeng-os/src/lib/vault/frontmatter.ts +84 -0
  162. package/packages/gatsaeng-os/src/lib/vault/index.ts +180 -0
  163. package/packages/gatsaeng-os/src/lib/vault/schemas.ts +274 -0
  164. package/packages/gatsaeng-os/src/middleware.ts +34 -0
  165. package/packages/gatsaeng-os/src/stores/dashboardStore.ts +26 -0
  166. package/packages/gatsaeng-os/src/stores/favoritesStore.ts +47 -0
  167. package/packages/gatsaeng-os/src/stores/timerStore.ts +65 -0
  168. package/packages/gatsaeng-os/src/types/index.ts +320 -0
  169. package/packages/gatsaeng-os/tsconfig.json +34 -0
  170. package/templates/scripts/forge_qa.sh.tmpl +237 -0
  171. package/templates/scripts/forge_ship.sh.tmpl +183 -0
  172. package/templates/scripts/session_indexer.py.tmpl +420 -0
  173. package/templates/scripts/tracer.py.tmpl +266 -0
  174. package/templates/workspace/AGENTS.md.tmpl +190 -0
  175. package/templates/workspace/BOOTSTRAP.md.tmpl +27 -0
  176. package/templates/workspace/HEARTBEAT.md.tmpl +23 -0
  177. package/templates/workspace/MEMORY.md.tmpl +35 -0
  178. package/templates/workspace/SOUL.md.tmpl +258 -0
  179. package/templates/workspace/TOOLS.md.tmpl +28 -0
  180. package/templates/workspace/USER.md.tmpl +43 -0
@@ -0,0 +1,24 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
3
+ import { calendarEventSchema } from '@/lib/vault/schemas'
4
+ import type { CalendarEvent } from '@/types'
5
+
6
+ export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
7
+ const { id } = await params
8
+ const entity = await getEntity<CalendarEvent>('calendar', id, calendarEventSchema)
9
+ if (!entity) return NextResponse.json({ error: 'Not found' }, { status: 404 })
10
+ return NextResponse.json(entity.data)
11
+ }
12
+
13
+ export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
14
+ const { id } = await params
15
+ const body = await request.json()
16
+ const result = await updateEntity<CalendarEvent>('calendar', id, body)
17
+ return NextResponse.json(result)
18
+ }
19
+
20
+ export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
21
+ const { id } = await params
22
+ await deleteEntity('calendar', id)
23
+ return NextResponse.json({ ok: true })
24
+ }
@@ -0,0 +1,52 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { createEntity, listEntities, deleteEntity } from '@/lib/vault'
3
+ import { calendarEventSchema } from '@/lib/vault/schemas'
4
+ import type { CalendarEvent } from '@/types'
5
+
6
+ /**
7
+ * POST /api/calendar/import
8
+ * Bulk import calendar events (e.g., from Telegram weekly schedule).
9
+ *
10
+ * Body:
11
+ * {
12
+ * events: CalendarEvent[], // array of events to create
13
+ * clear_week?: boolean, // if true, delete existing events in the date range first
14
+ * week_start?: string, // YYYY-MM-DD, required if clear_week is true
15
+ * week_end?: string, // YYYY-MM-DD, required if clear_week is true
16
+ * created_by?: string // defaults to 'telegram'
17
+ * }
18
+ */
19
+ export async function POST(request: Request) {
20
+ const body = await request.json()
21
+ const { events, clear_week, week_start, week_end, created_by = 'telegram' } = body
22
+
23
+ if (!events || !Array.isArray(events) || events.length === 0) {
24
+ return NextResponse.json({ error: 'events array is required' }, { status: 400 })
25
+ }
26
+
27
+ // Optionally clear existing events in the week range
28
+ if (clear_week && week_start && week_end) {
29
+ const existing = await listEntities<CalendarEvent>('calendar', calendarEventSchema)
30
+ const toDelete = existing
31
+ .map(e => e.data)
32
+ .filter(e => e.date >= week_start && e.date <= week_end && e.created_by === 'telegram')
33
+
34
+ for (const event of toDelete) {
35
+ await deleteEntity('calendar', event.id)
36
+ }
37
+ }
38
+
39
+ // Create new events
40
+ const created = []
41
+ for (const event of events) {
42
+ const data = {
43
+ ...event,
44
+ created_by: event.created_by || created_by,
45
+ created_at: event.created_at || new Date().toISOString(),
46
+ }
47
+ const result = await createEntity<CalendarEvent>('calendar', data)
48
+ created.push(result)
49
+ }
50
+
51
+ return NextResponse.json({ imported: created.length, events: created }, { status: 201 })
52
+ }
@@ -0,0 +1,37 @@
1
+ import { NextRequest, NextResponse } from 'next/server'
2
+ import { listEntities, createEntity } from '@/lib/vault'
3
+ import { calendarEventSchema } from '@/lib/vault/schemas'
4
+ import type { CalendarEvent } from '@/types'
5
+
6
+ export async function GET(request: NextRequest) {
7
+ const { searchParams } = new URL(request.url)
8
+ const weekStart = searchParams.get('week_start')
9
+ const weekEnd = searchParams.get('week_end')
10
+ const date = searchParams.get('date')
11
+
12
+ const events = await listEntities<CalendarEvent>('calendar', calendarEventSchema)
13
+ let filtered = events.map(e => e.data)
14
+
15
+ if (date) {
16
+ filtered = filtered.filter(e => e.date === date)
17
+ } else if (weekStart && weekEnd) {
18
+ filtered = filtered.filter(e => e.date >= weekStart && e.date <= weekEnd)
19
+ }
20
+
21
+ filtered.sort((a, b) => {
22
+ if (a.date !== b.date) return a.date.localeCompare(b.date)
23
+ return (a.time_start ?? '00:00').localeCompare(b.time_start ?? '00:00')
24
+ })
25
+
26
+ return NextResponse.json(filtered)
27
+ }
28
+
29
+ export async function POST(request: Request) {
30
+ const body = await request.json()
31
+ const data = {
32
+ ...body,
33
+ created_at: body.created_at || new Date().toISOString(),
34
+ }
35
+ const result = await createEntity<CalendarEvent>('calendar', data)
36
+ return NextResponse.json(result, { status: 201 })
37
+ }
@@ -0,0 +1,51 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getEntityByDate, createDateEntity, updateDateEntity } from '@/lib/vault'
3
+ import { dailyManifestSchema } from '@/lib/vault/schemas'
4
+ import type { DailyManifest } from '@/types'
5
+ import { format } from 'date-fns'
6
+
7
+ export async function GET(req: Request) {
8
+ const { searchParams } = new URL(req.url)
9
+ const date = searchParams.get('date') || format(new Date(), 'yyyy-MM-dd')
10
+
11
+ const item = await getEntityByDate<DailyManifest>('tasks', date, dailyManifestSchema)
12
+
13
+ if (!item) {
14
+ // return empty manifest for today
15
+ const empty: DailyManifest = {
16
+ date,
17
+ gatsaeng_score: 0,
18
+ routines_done: 0,
19
+ routines_total: 0,
20
+ focus_minutes: 0,
21
+ }
22
+ return NextResponse.json(empty)
23
+ }
24
+
25
+ return NextResponse.json(item.data)
26
+ }
27
+
28
+ export async function POST(req: Request) {
29
+ const body = await req.json()
30
+ const date = body.date || format(new Date(), 'yyyy-MM-dd')
31
+
32
+ const existing = await getEntityByDate<DailyManifest>('tasks', date)
33
+
34
+ if (existing) {
35
+ // update
36
+ const merged = { ...existing.data, ...body, date }
37
+ const updated = await updateDateEntity<DailyManifest>('tasks', date, merged)
38
+ return NextResponse.json(updated)
39
+ }
40
+
41
+ // create
42
+ const data: DailyManifest = {
43
+ date,
44
+ gatsaeng_score: body.gatsaeng_score ?? 0,
45
+ routines_done: body.routines_done ?? 0,
46
+ routines_total: body.routines_total ?? 0,
47
+ focus_minutes: body.focus_minutes ?? 0,
48
+ }
49
+ const created = await createDateEntity<DailyManifest>('tasks', date, data)
50
+ return NextResponse.json(created, { status: 201 })
51
+ }
@@ -0,0 +1,34 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
3
+ import { goalSchema } from '@/lib/vault/schemas'
4
+ import type { Goal } from '@/types'
5
+
6
+ export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
7
+ const { id } = await params
8
+ const result = await getEntity<Goal>('goals', id, goalSchema)
9
+ if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
10
+ return NextResponse.json({ ...result.data, _content: result.content })
11
+ }
12
+
13
+ export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
14
+ const { id } = await params
15
+ const body = await request.json()
16
+ const updates = { ...body, updated_at: new Date().toISOString() }
17
+
18
+ const sections: string[] = []
19
+ if (body.why_statement) sections.push(`## Why Statement\n${body.why_statement}`)
20
+ if (body.identity_statement) sections.push(`## Identity Statement\n${body.identity_statement}`)
21
+ if (body.when_where_how) sections.push(`## Implementation Intention\n${body.when_where_how}`)
22
+ const mdBody = sections.length > 0 ? sections.join('\n\n') : undefined
23
+
24
+ const result = await updateEntity<Goal>('goals', id, updates, mdBody)
25
+ if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
26
+ return NextResponse.json(result)
27
+ }
28
+
29
+ export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
30
+ const { id } = await params
31
+ const deleted = await deleteEntity('goals', id)
32
+ if (!deleted) return NextResponse.json({ error: 'Not found' }, { status: 404 })
33
+ return NextResponse.json({ success: true })
34
+ }
@@ -0,0 +1,30 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { listEntities, createEntity } from '@/lib/vault'
3
+ import { goalSchema } from '@/lib/vault/schemas'
4
+ import type { Goal } from '@/types'
5
+
6
+ export async function GET() {
7
+ const results = await listEntities<Goal>('goals', goalSchema)
8
+ return NextResponse.json(results.map(r => ({ ...r.data, _content: r.content })))
9
+ }
10
+
11
+ export async function POST(request: Request) {
12
+ const body = await request.json()
13
+ const now = new Date().toISOString()
14
+ const data = {
15
+ ...body,
16
+ current_value: body.current_value ?? 0,
17
+ color: body.color ?? '#f5a623',
18
+ status: body.status ?? 'active',
19
+ created_at: now,
20
+ updated_at: now,
21
+ }
22
+
23
+ const sections: string[] = []
24
+ if (body.why_statement) sections.push(`## Why Statement\n${body.why_statement}`)
25
+ if (body.identity_statement) sections.push(`## Identity Statement\n${body.identity_statement}`)
26
+ if (body.when_where_how) sections.push(`## Implementation Intention\n${body.when_where_how}`)
27
+
28
+ const entity = await createEntity<Goal>('goals', data, sections.join('\n\n'))
29
+ return NextResponse.json(entity, { status: 201 })
30
+ }
@@ -0,0 +1,40 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getEntityByDate, createDateEntity, updateDateEntity } from '@/lib/vault'
3
+ import { energyLogSchema } from '@/lib/vault/schemas'
4
+ import type { EnergyLog } from '@/types'
5
+
6
+ export async function GET(request: Request) {
7
+ const { searchParams } = new URL(request.url)
8
+ const date = searchParams.get('date') || new Date().toISOString().split('T')[0]
9
+
10
+ const result = await getEntityByDate<EnergyLog>('energyLogs', date, energyLogSchema)
11
+ if (!result) return NextResponse.json({ date, entries: [] })
12
+ return NextResponse.json(result.data)
13
+ }
14
+
15
+ export async function POST(request: Request) {
16
+ const body = await request.json()
17
+ const date = body.date || new Date().toISOString().split('T')[0]
18
+
19
+ const existing = await getEntityByDate<EnergyLog>('energyLogs', date, energyLogSchema)
20
+
21
+ const entry = { hour: body.hour, level: body.level, note: body.note }
22
+
23
+ if (existing) {
24
+ const entries = [...existing.data.entries]
25
+ const idx = entries.findIndex(e => e.hour === body.hour)
26
+ if (idx >= 0) {
27
+ entries[idx] = entry
28
+ } else {
29
+ entries.push(entry)
30
+ }
31
+ entries.sort((a, b) => a.hour - b.hour)
32
+
33
+ const updated = await updateDateEntity<EnergyLog>('energyLogs', date, { date, entries })
34
+ return NextResponse.json(updated)
35
+ }
36
+
37
+ const log: EnergyLog = { date, entries: [entry] }
38
+ const created = await createDateEntity<EnergyLog>('energyLogs', date, log)
39
+ return NextResponse.json(created, { status: 201 })
40
+ }
@@ -0,0 +1,22 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { listEntities, createEntity } from '@/lib/vault'
3
+ import { focusSessionSchema } from '@/lib/vault/schemas'
4
+ import type { FocusSession } from '@/types'
5
+
6
+ export async function GET() {
7
+ const results = await listEntities<FocusSession>('focusSessions', focusSessionSchema)
8
+ return NextResponse.json(results.map(r => r.data))
9
+ }
10
+
11
+ export async function POST(request: Request) {
12
+ const body = await request.json()
13
+ const data = {
14
+ ...body,
15
+ session_type: body.session_type ?? 'pomodoro_25',
16
+ completed: body.completed ?? false,
17
+ started_at: body.started_at ?? new Date().toISOString(),
18
+ }
19
+
20
+ const entity = await createEntity<FocusSession>('focusSessions', data)
21
+ return NextResponse.json(entity, { status: 201 })
22
+ }
@@ -0,0 +1,54 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getEntityByDate, createDateEntity, updateDateEntity } from '@/lib/vault'
3
+ import { routineLogSchema } from '@/lib/vault/schemas'
4
+ import type { RoutineLog } from '@/types'
5
+
6
+ export async function GET(request: Request) {
7
+ const { searchParams } = new URL(request.url)
8
+ const date = searchParams.get('date') || new Date().toISOString().split('T')[0]
9
+
10
+ const result = await getEntityByDate<RoutineLog>('routineLogs', date, routineLogSchema)
11
+ if (!result) return NextResponse.json({ date, completions: [] })
12
+ return NextResponse.json(result.data)
13
+ }
14
+
15
+ export async function POST(request: Request) {
16
+ const body = await request.json()
17
+ const date = body.date || new Date().toISOString().split('T')[0]
18
+
19
+ const existing = await getEntityByDate<RoutineLog>('routineLogs', date, routineLogSchema)
20
+
21
+ if (existing) {
22
+ const completions = [...existing.data.completions]
23
+ const idx = completions.findIndex(c => c.routine_id === body.routine_id)
24
+
25
+ if (body.undo && idx >= 0) {
26
+ completions.splice(idx, 1)
27
+ } else if (!body.undo && idx < 0) {
28
+ completions.push({
29
+ routine_id: body.routine_id,
30
+ completed_at: new Date().toISOString(),
31
+ mood: body.mood,
32
+ })
33
+ }
34
+
35
+ const updated = await updateDateEntity<RoutineLog>('routineLogs', date, { date, completions })
36
+ return NextResponse.json(updated)
37
+ }
38
+
39
+ if (body.undo) {
40
+ return NextResponse.json({ date, completions: [] })
41
+ }
42
+
43
+ const log: RoutineLog = {
44
+ date,
45
+ completions: [{
46
+ routine_id: body.routine_id,
47
+ completed_at: new Date().toISOString(),
48
+ mood: body.mood,
49
+ }],
50
+ }
51
+
52
+ const created = await createDateEntity<RoutineLog>('routineLogs', date, log)
53
+ return NextResponse.json(created, { status: 201 })
54
+ }
@@ -0,0 +1,26 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
3
+ import { milestoneSchema } from '@/lib/vault/schemas'
4
+ import type { Milestone } from '@/types'
5
+
6
+ export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
7
+ const { id } = await params
8
+ const item = await getEntity<Milestone>('milestones', id, milestoneSchema)
9
+ if (!item) return NextResponse.json({ error: 'Not found' }, { status: 404 })
10
+ return NextResponse.json(item.data)
11
+ }
12
+
13
+ export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
14
+ const { id } = await params
15
+ const body = await req.json()
16
+ const updated = await updateEntity<Milestone>('milestones', id, body)
17
+ if (!updated) return NextResponse.json({ error: 'Not found' }, { status: 404 })
18
+ return NextResponse.json(updated)
19
+ }
20
+
21
+ export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
22
+ const { id } = await params
23
+ const ok = await deleteEntity('milestones', id)
24
+ if (!ok) return NextResponse.json({ error: 'Not found' }, { status: 404 })
25
+ return NextResponse.json({ ok: true })
26
+ }
@@ -0,0 +1,47 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { listEntities, createEntity } from '@/lib/vault'
3
+ import { milestoneSchema } from '@/lib/vault/schemas'
4
+ import type { Milestone } from '@/types'
5
+ import { LIMITS } from '@/types'
6
+
7
+ export async function GET(req: Request) {
8
+ const { searchParams } = new URL(req.url)
9
+ const goalId = searchParams.get('goal_id')
10
+
11
+ const items = await listEntities<Milestone>('milestones', milestoneSchema)
12
+ let data = items.map(i => i.data)
13
+
14
+ if (goalId) {
15
+ data = data.filter(m => m.goal_id === goalId)
16
+ }
17
+
18
+ // sort by due_date
19
+ data.sort((a, b) => new Date(a.due_date).getTime() - new Date(b.due_date).getTime())
20
+ return NextResponse.json(data)
21
+ }
22
+
23
+ export async function POST(req: Request) {
24
+ const body = await req.json()
25
+
26
+ // constraint: max 4 milestones per goal
27
+ if (body.goal_id) {
28
+ const existing = await listEntities<Milestone>('milestones', milestoneSchema)
29
+ const goalMilestones = existing.filter(m => m.data.goal_id === body.goal_id && m.data.status === 'active')
30
+ if (goalMilestones.length >= LIMITS.MAX_MILESTONES_PER_GOAL) {
31
+ return NextResponse.json(
32
+ { error: `목표당 마일스톤은 최대 ${LIMITS.MAX_MILESTONES_PER_GOAL}개입니다.` },
33
+ { status: 400 }
34
+ )
35
+ }
36
+ }
37
+
38
+ const now = new Date().toISOString()
39
+ const data = await createEntity<Milestone>('milestones', {
40
+ ...body,
41
+ current_value: body.current_value ?? 0,
42
+ status: 'active',
43
+ created_by: body.created_by || 'user',
44
+ created: now,
45
+ }, body.body_content)
46
+ return NextResponse.json(data, { status: 201 })
47
+ }
@@ -0,0 +1,29 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
3
+ import { noteSchema } from '@/lib/vault/schemas'
4
+ import type { Note } from '@/types'
5
+
6
+ export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
7
+ const { id } = await params
8
+ const result = await getEntity<Note>('notes', id, noteSchema)
9
+ if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
10
+ return NextResponse.json({ ...result.data, _content: result.content })
11
+ }
12
+
13
+ export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
14
+ const { id } = await params
15
+ const body = await request.json()
16
+ const result = await updateEntity<Note>('notes', id, {
17
+ ...body,
18
+ updated_at: new Date().toISOString(),
19
+ }, body.content)
20
+ if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
21
+ return NextResponse.json(result)
22
+ }
23
+
24
+ export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
25
+ const { id } = await params
26
+ const deleted = await deleteEntity('notes', id)
27
+ if (!deleted) return NextResponse.json({ error: 'Not found' }, { status: 404 })
28
+ return NextResponse.json({ success: true })
29
+ }
@@ -0,0 +1,37 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { listEntities, createEntity } from '@/lib/vault'
3
+ import { noteSchema } from '@/lib/vault/schemas'
4
+ import type { Note } from '@/types'
5
+
6
+ export async function GET(request: Request) {
7
+ const { searchParams } = new URL(request.url)
8
+ const type = searchParams.get('type')
9
+ const areaId = searchParams.get('area_id')
10
+
11
+ const results = await listEntities<Note>('notes', noteSchema)
12
+ let notes = results.map(r => ({ ...r.data, _content: r.content }))
13
+
14
+ if (type) notes = notes.filter(n => n.type === type)
15
+ if (areaId) notes = notes.filter(n => n.area_id === areaId)
16
+
17
+ notes.sort((a, b) => a.priority - b.priority || b.created_at.localeCompare(a.created_at))
18
+
19
+ return NextResponse.json(notes)
20
+ }
21
+
22
+ export async function POST(request: Request) {
23
+ const body = await request.json()
24
+ const now = new Date().toISOString()
25
+ const note = await createEntity<Note>('notes', {
26
+ title: body.title,
27
+ type: body.type || 'note',
28
+ priority: body.priority || 2,
29
+ area_id: body.area_id,
30
+ project_id: body.project_id,
31
+ url: body.url,
32
+ created_at: now,
33
+ updated_at: now,
34
+ }, body.content)
35
+
36
+ return NextResponse.json(note, { status: 201 })
37
+ }
@@ -0,0 +1,17 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getProfile, updateProfile } from '@/lib/vault'
3
+ import { profileSchema } from '@/lib/vault/schemas'
4
+ import type { Profile } from '@/types'
5
+
6
+ export async function GET() {
7
+ // Return full profile without schema filtering (allows saju_motto etc.)
8
+ const result = await getProfile()
9
+ return NextResponse.json(result.data)
10
+ }
11
+
12
+ export async function PUT(request: Request) {
13
+ const body = await request.json()
14
+ const updates = { ...body, updated_at: new Date().toISOString() }
15
+ const result = await updateProfile<Profile>(updates)
16
+ return NextResponse.json(result)
17
+ }
@@ -0,0 +1,27 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
3
+ import { projectSchema } from '@/lib/vault/schemas'
4
+ import type { Project } from '@/types'
5
+
6
+ export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
7
+ const { id } = await params
8
+ const result = await getEntity<Project>('projects', id, projectSchema)
9
+ if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
10
+ return NextResponse.json(result.data)
11
+ }
12
+
13
+ export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
14
+ const { id } = await params
15
+ const body = await request.json()
16
+ const updates = { ...body, updated_at: new Date().toISOString() }
17
+ const result = await updateEntity<Project>('projects', id, updates)
18
+ if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
19
+ return NextResponse.json(result)
20
+ }
21
+
22
+ export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
23
+ const { id } = await params
24
+ const deleted = await deleteEntity('projects', id)
25
+ if (!deleted) return NextResponse.json({ error: 'Not found' }, { status: 404 })
26
+ return NextResponse.json({ success: true })
27
+ }
@@ -0,0 +1,25 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { listEntities, createEntity } from '@/lib/vault'
3
+ import { projectSchema } from '@/lib/vault/schemas'
4
+ import type { Project } from '@/types'
5
+
6
+ export async function GET() {
7
+ const results = await listEntities<Project>('projects', projectSchema)
8
+ return NextResponse.json(results.map(r => r.data))
9
+ }
10
+
11
+ export async function POST(request: Request) {
12
+ const body = await request.json()
13
+ const now = new Date().toISOString()
14
+ const data = {
15
+ ...body,
16
+ status: body.status ?? 'active',
17
+ color: body.color ?? '#7c5cbf',
18
+ default_view: body.default_view ?? 'kanban',
19
+ created_at: now,
20
+ updated_at: now,
21
+ }
22
+
23
+ const entity = await createEntity<Project>('projects', data)
24
+ return NextResponse.json(entity, { status: 201 })
25
+ }
@@ -0,0 +1,26 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
3
+ import { reviewSchema } from '@/lib/vault/schemas'
4
+ import type { Review } from '@/types'
5
+
6
+ export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
7
+ const { id } = await params
8
+ const result = await getEntity<Review>('reviews', id, reviewSchema)
9
+ if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
10
+ return NextResponse.json({ ...result.data, _content: result.content })
11
+ }
12
+
13
+ export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
14
+ const { id } = await params
15
+ const body = await request.json()
16
+ const result = await updateEntity<Review>('reviews', id, body)
17
+ if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
18
+ return NextResponse.json(result)
19
+ }
20
+
21
+ export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
22
+ const { id } = await params
23
+ const deleted = await deleteEntity('reviews', id)
24
+ if (!deleted) return NextResponse.json({ error: 'Not found' }, { status: 404 })
25
+ return NextResponse.json({ success: true })
26
+ }
@@ -0,0 +1,29 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { listEntities, createEntity } from '@/lib/vault'
3
+ import { reviewSchema } from '@/lib/vault/schemas'
4
+ import type { Review } from '@/types'
5
+
6
+ export async function GET() {
7
+ const results = await listEntities<Review>('reviews', reviewSchema)
8
+ return NextResponse.json(results.map(r => r.data))
9
+ }
10
+
11
+ export async function POST(request: Request) {
12
+ const body = await request.json()
13
+ const now = new Date().toISOString()
14
+ const data = {
15
+ ...body,
16
+ created_at: now,
17
+ }
18
+
19
+ const sections: string[] = []
20
+ if (body.accomplished) sections.push(`## 이번 주 가장 잘한 것\n${body.accomplished}`)
21
+ if (body.struggled) sections.push(`## 어디서 막혔는가\n${body.struggled}`)
22
+ if (body.learnings) sections.push(`## 배운 점\n${body.learnings}`)
23
+ if (body.next_week_focus) sections.push(`## 다음 주 포커스\n${body.next_week_focus}`)
24
+ if (body.energy_pattern) sections.push(`## 에너지 패턴\n${body.energy_pattern}`)
25
+ if (body.habit_insight) sections.push(`## 루틴 인사이트\n${body.habit_insight}`)
26
+
27
+ const entity = await createEntity<Review>('reviews', data, sections.join('\n\n'))
28
+ return NextResponse.json(entity, { status: 201 })
29
+ }
@@ -0,0 +1,26 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
3
+ import { routineSchema } from '@/lib/vault/schemas'
4
+ import type { Routine } from '@/types'
5
+
6
+ export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
7
+ const { id } = await params
8
+ const result = await getEntity<Routine>('routines', id, routineSchema)
9
+ if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
10
+ return NextResponse.json(result.data)
11
+ }
12
+
13
+ export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
14
+ const { id } = await params
15
+ const body = await request.json()
16
+ const result = await updateEntity<Routine>('routines', id, body)
17
+ if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
18
+ return NextResponse.json(result)
19
+ }
20
+
21
+ export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
22
+ const { id } = await params
23
+ const deleted = await deleteEntity('routines', id)
24
+ if (!deleted) return NextResponse.json({ error: 'Not found' }, { status: 404 })
25
+ return NextResponse.json({ success: true })
26
+ }