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,320 @@
1
+ // ─── Base Types ───
2
+ export type GoalStatus = 'active' | 'completed' | 'archived'
3
+ export type TaskStatus = 'backlog' | 'todo' | 'doing' | 'done'
4
+ export type TaskPriority = 'low' | 'medium' | 'high' | 'urgent'
5
+ export type EnergyLevel = 'low' | 'medium' | 'high'
6
+ export type ViewType = 'kanban' | 'table' | 'calendar' | 'list'
7
+ export type SessionType = 'pomodoro_25' | 'focus_90' | 'deep_work'
8
+ export type TriggerType = 'time' | 'event' | 'location'
9
+ export type WidgetId = 'routine' | 'goals' | 'heatmap' | 'kanban' | 'timer' | 'zeigarnik' | 'energy' | 'dday' | 'proactive'
10
+ export type ReviewType = 'daily' | 'weekly' | 'monthly'
11
+ export type CreatedBy = 'user' | 'ai'
12
+
13
+ // ─── Area (영역) ───
14
+ export interface Area {
15
+ id: string
16
+ title: string
17
+ icon: string
18
+ status: GoalStatus
19
+ linked_goals: string[]
20
+ created?: string
21
+ }
22
+
23
+ // ─── Goal (목표) ───
24
+ export interface KeyMetric {
25
+ name: string
26
+ current: number
27
+ target: number
28
+ unit: string
29
+ }
30
+
31
+ export interface Goal {
32
+ id: string
33
+ area_id?: string
34
+ title: string
35
+ description?: string
36
+ type: string
37
+ status: GoalStatus
38
+ color: string
39
+ created?: string
40
+ ai_next_review?: string
41
+ ai_diagnosis?: string
42
+ ai_direction?: string
43
+ linked_milestones: string[]
44
+ linked_routines: string[]
45
+ linked_projects: string[]
46
+ key_metrics: KeyMetric[]
47
+ why_statement?: string
48
+ identity_statement?: string
49
+ when_where_how?: string
50
+ // v2 compat
51
+ target_value?: number
52
+ current_value?: number
53
+ unit?: string
54
+ due_date?: string
55
+ core_value?: string
56
+ created_at?: string
57
+ updated_at?: string
58
+ }
59
+
60
+ // ─── Milestone (마일스톤) ───
61
+ export interface Milestone {
62
+ id: string
63
+ goal_id: string
64
+ title: string
65
+ target_value: number
66
+ current_value: number
67
+ unit: string
68
+ due_date: string
69
+ status: GoalStatus
70
+ created_by: CreatedBy
71
+ created?: string
72
+ }
73
+
74
+ // ─── Project (프로젝트) ───
75
+ export interface Project {
76
+ id: string
77
+ goal_id?: string
78
+ milestone_id?: string
79
+ title: string
80
+ description?: string
81
+ status: GoalStatus
82
+ color: string
83
+ due_date?: string
84
+ default_view: ViewType
85
+ created_by?: CreatedBy
86
+ created_at: string
87
+ updated_at: string
88
+ }
89
+
90
+ // ─── Task (프로젝트 소속 태스크 — 개별 파일) ───
91
+ export interface Task {
92
+ id: string
93
+ project_id: string
94
+ parent_task_id?: string
95
+ title: string
96
+ description?: string
97
+ status: TaskStatus
98
+ priority: TaskPriority
99
+ energy_required?: EnergyLevel
100
+ tag?: string
101
+ due_date?: string
102
+ position: number
103
+ goal_ids?: string[]
104
+ area_id?: string
105
+ created_at: string
106
+ updated_at: string
107
+ }
108
+
109
+ // ─── Book (독서) ───
110
+ export type BookStatus = 'reading' | 'completed' | 'want_to_read' | 'dropped'
111
+
112
+ export interface Book {
113
+ id: string
114
+ title: string
115
+ author: string
116
+ status: BookStatus
117
+ rating?: number
118
+ total_pages?: number
119
+ current_page?: number
120
+ goal_id?: string
121
+ started_at?: string
122
+ finished_at?: string
123
+ created_at?: string
124
+ }
125
+
126
+ // ─── CalendarEvent (캘린더) ───
127
+ export type CalendarCategory = 'work' | 'personal' | 'health' | 'study' | 'social' | 'other'
128
+
129
+ export interface CalendarEvent {
130
+ id: string
131
+ title: string
132
+ date: string
133
+ time_start?: string
134
+ time_end?: string
135
+ all_day?: boolean
136
+ category?: CalendarCategory
137
+ location?: string
138
+ description?: string
139
+ goal_id?: string
140
+ created_by?: 'user' | 'ai' | 'telegram'
141
+ created_at?: string
142
+ }
143
+
144
+ // ─── Note (노트) ───
145
+ export type NoteType = 'note' | 'file' | 'reference' | 'link'
146
+ export type NotePriority = 1 | 2 | 3
147
+
148
+ export interface Note {
149
+ id: string
150
+ title: string
151
+ type: NoteType
152
+ priority: NotePriority
153
+ area_id?: string
154
+ project_id?: string
155
+ url?: string
156
+ created_at: string
157
+ updated_at: string
158
+ }
159
+
160
+ // ─── DailyManifest (일일 매니페스트 — 날짜별 파일) ───
161
+ export interface DailyManifest {
162
+ date: string
163
+ gatsaeng_score: number
164
+ routines_done: number
165
+ routines_total: number
166
+ focus_minutes: number
167
+ }
168
+
169
+ // ─── Routine (루틴) ───
170
+ export interface Routine {
171
+ id: string
172
+ title: string
173
+ area_id?: string
174
+ goal_id?: string
175
+ scheduled_time?: string
176
+ scheduled_days: number[]
177
+ trigger_cue?: string
178
+ trigger_type: TriggerType
179
+ after_routine_id?: string | null
180
+ reward_note?: string
181
+ energy_required: EnergyLevel
182
+ streak: number
183
+ longest_streak: number
184
+ is_active: boolean
185
+ position: number
186
+ created_by?: CreatedBy
187
+ created?: string
188
+ // v2 compat
189
+ days_of_week?: number[]
190
+ created_at?: string
191
+ }
192
+
193
+ export interface RoutineCompletion {
194
+ routine_id: string
195
+ completed_at: string
196
+ mood?: number
197
+ }
198
+
199
+ export interface RoutineLog {
200
+ date: string
201
+ completions: RoutineCompletion[]
202
+ }
203
+
204
+ // ─── Energy ───
205
+ export interface EnergyEntry {
206
+ hour: number
207
+ level: number
208
+ note?: string
209
+ }
210
+
211
+ export interface EnergyLog {
212
+ date: string
213
+ entries: EnergyEntry[]
214
+ }
215
+
216
+ // ─── Focus Session ───
217
+ export interface FocusSession {
218
+ id: string
219
+ date?: string
220
+ task_id?: string
221
+ duration_minutes: number
222
+ session_type: SessionType
223
+ energy_level?: number
224
+ completed: boolean
225
+ started_at: string
226
+ }
227
+
228
+ // ─── Review (회고) ───
229
+ export interface Review {
230
+ id?: string
231
+ type: ReviewType
232
+ // daily
233
+ date?: string
234
+ // weekly
235
+ week?: string
236
+ week_start?: string
237
+ week_end?: string
238
+ routines_completion_rate?: number
239
+ tasks_completed?: number
240
+ gatsaeng_score_total?: number
241
+ ai_reanalysis_triggered?: boolean
242
+ goal_ids_to_review?: string[]
243
+ // shared
244
+ accomplished?: string
245
+ struggled?: string
246
+ learnings?: string
247
+ next_week_focus?: string
248
+ energy_pattern?: string
249
+ habit_insight?: string
250
+ mood?: number
251
+ score?: number
252
+ created_at?: string
253
+ }
254
+
255
+ // ─── Profile ───
256
+ export interface Profile {
257
+ display_name: string
258
+ level: number
259
+ total_score: number
260
+ longest_streak: number
261
+ current_streak: number
262
+ peak_hours: number[]
263
+ dashboard_widgets: WidgetId[]
264
+ created_at: string
265
+ updated_at: string
266
+ }
267
+
268
+ // ─── Derived / UI Types ───
269
+ export interface RoutineWithStatus extends Routine {
270
+ completed_today: boolean
271
+ }
272
+
273
+ export interface MilestoneWithDDay extends Milestone {
274
+ d_day: number
275
+ }
276
+
277
+ export interface GoalWithMilestones extends Goal {
278
+ milestones: MilestoneWithDDay[]
279
+ area?: Area
280
+ }
281
+
282
+ export interface ProactiveAlert {
283
+ id: string
284
+ type: 'skipped_routine' | 'deadline' | 'milestone_dday' | 'reanalysis_due'
285
+ title: string
286
+ message: string
287
+ actions?: { label: string; value: string }[]
288
+ created_at: string
289
+ }
290
+
291
+ export type ScoreEventType =
292
+ | 'routine_complete'
293
+ | 'task_done'
294
+ | 'task_done_urgent'
295
+ | 'milestone_complete'
296
+ | 'review_written'
297
+ | 'data_uploaded'
298
+ | 'goal_25pct'
299
+ | 'goal_50pct'
300
+ | 'goal_100pct'
301
+
302
+ export interface ScoreEvent {
303
+ type: ScoreEventType
304
+ streakCount?: number
305
+ }
306
+
307
+ export interface ScoreResult {
308
+ points: number
309
+ bonus_message: string | null
310
+ }
311
+
312
+ // ─── Constraints (제약 원칙) ───
313
+ export const LIMITS = {
314
+ MAX_ACTIVE_GOALS: 5,
315
+ MAX_ACTIVE_ROUTINES: 6,
316
+ MAX_DAILY_TASKS: 6,
317
+ MAX_ACTIVE_PROJECTS: 3,
318
+ MAX_MILESTONES_PER_GOAL: 4,
319
+ MIN_REANALYSIS_WEEKS: 2,
320
+ } as const
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ # forge_qa.sh — Diff-based visual QA via OpenClaw browser
5
+ # Changed files → affected pages → screenshot capture
6
+
7
+ ###############################################################################
8
+ # Config
9
+ ###############################################################################
10
+ SCREENSHOT_DIR="/tmp/qa_screenshots"
11
+ DATE_TAG=$(date +%Y%m%d)
12
+ OPENCLAW_BIN=$(command -v openclaw || echo "/opt/homebrew/bin/openclaw")
13
+ GATEWAY_PORT=4000
14
+
15
+ ###############################################################################
16
+ # Usage
17
+ ###############################################################################
18
+ usage() {
19
+ cat <<EOF
20
+ Usage: $(basename "$0") --repo <path> [--url <base_url>] [--quick]
21
+
22
+ Options:
23
+ --repo <path> Git repo root (required)
24
+ --url <base_url> Base URL for the app (default: http://localhost:3000)
25
+ --quick Quick mode: home + 1 key page only
26
+ -h, --help Show this help
27
+ EOF
28
+ exit 0
29
+ }
30
+
31
+ ###############################################################################
32
+ # Parse args
33
+ ###############################################################################
34
+ REPO=""
35
+ BASE_URL=""
36
+ QUICK=false
37
+
38
+ while [[ $# -gt 0 ]]; do
39
+ case "$1" in
40
+ --repo) REPO="$2"; shift 2 ;;
41
+ --url) BASE_URL="$2"; shift 2 ;;
42
+ --quick) QUICK=true; shift ;;
43
+ -h|--help) usage ;;
44
+ *) echo "Unknown option: $1"; usage ;;
45
+ esac
46
+ done
47
+
48
+ if [[ -z "$REPO" ]]; then
49
+ echo "ERROR: --repo is required"
50
+ usage
51
+ fi
52
+
53
+ if [[ ! -d "$REPO/.git" ]]; then
54
+ echo "ERROR: $REPO is not a git repository"
55
+ exit 1
56
+ fi
57
+
58
+ ###############################################################################
59
+ # Auto-detect base URL
60
+ ###############################################################################
61
+ if [[ -z "$BASE_URL" ]]; then
62
+ BASE_URL="http://localhost:3000"
63
+ echo "Using default base URL: $BASE_URL"
64
+ fi
65
+
66
+ ###############################################################################
67
+ # Prepare screenshot dir
68
+ ###############################################################################
69
+ mkdir -p "$SCREENSHOT_DIR"
70
+
71
+ ###############################################################################
72
+ # Get changed files
73
+ ###############################################################################
74
+ echo ""
75
+ echo "=== Diff Analysis ==="
76
+ CHANGED_FILES=$(cd "$REPO" && git diff --name-only origin/main..HEAD 2>/dev/null || true)
77
+
78
+ if [[ -z "$CHANGED_FILES" ]]; then
79
+ CHANGED_FILES=$(cd "$REPO" && git diff --name-only HEAD 2>/dev/null || true)
80
+ fi
81
+
82
+ if [[ -z "$CHANGED_FILES" ]]; then
83
+ echo "No changed files detected. Nothing to QA."
84
+ exit 0
85
+ fi
86
+
87
+ FILE_COUNT=$(echo "$CHANGED_FILES" | wc -l | tr -d ' ')
88
+ echo "Changed files ($FILE_COUNT):"
89
+ echo "$CHANGED_FILES" | sed 's/^/ /'
90
+
91
+ ###############################################################################
92
+ # Map changed files → affected routes
93
+ ###############################################################################
94
+ declare -a PAGES=()
95
+ declare -a PAGE_NAMES=()
96
+
97
+ add_page() {
98
+ local route="$1"
99
+ local name="$2"
100
+ for existing in "${PAGES[@]}"; do
101
+ [[ "$existing" == "$route" ]] && return
102
+ done
103
+ PAGES+=("$route")
104
+ PAGE_NAMES+=("$name")
105
+ }
106
+
107
+ # Always include home
108
+ add_page "/" "home"
109
+
110
+ while IFS= read -r file; do
111
+ [[ -z "$file" ]] && continue
112
+
113
+ # App router pages → direct route
114
+ if [[ "$file" =~ ^(web/)?(src/)?app/(.+)/page\.(tsx|ts|jsx|js)$ ]]; then
115
+ route="/${BASH_REMATCH[3]}"
116
+ route=$(echo "$route" | sed 's|/\(([^)]*)\)||g; s|//|/|g')
117
+ name=$(echo "$route" | tr '/' '_' | sed 's/^_//')
118
+ [[ -z "$name" ]] && name="root"
119
+ add_page "$route" "$name"
120
+ continue
121
+ fi
122
+
123
+ # Layout/template changes → affected route
124
+ if [[ "$file" =~ ^(web/)?(src/)?app/(.+)/(layout|template)\.(tsx|ts|jsx|js)$ ]]; then
125
+ route="/${BASH_REMATCH[3]}"
126
+ route=$(echo "$route" | sed 's|/\(([^)]*)\)||g; s|//|/|g')
127
+ name=$(echo "$route" | tr '/' '_' | sed 's/^_//; s/$/_layout/')
128
+ add_page "$route" "$name"
129
+ continue
130
+ fi
131
+
132
+ # Global CSS → home
133
+ if [[ "$file" =~ \.(css|scss|sass)$ ]] && [[ "$file" =~ global ]]; then
134
+ add_page "/" "home"
135
+ fi
136
+
137
+ done <<< "$CHANGED_FILES"
138
+
139
+ ###############################################################################
140
+ # Quick mode: trim to home + 1 key page
141
+ ###############################################################################
142
+ if $QUICK && [[ ${#PAGES[@]} -gt 2 ]]; then
143
+ PAGES=("${PAGES[0]}" "${PAGES[1]}")
144
+ PAGE_NAMES=("${PAGE_NAMES[0]}" "${PAGE_NAMES[1]}")
145
+ echo ""
146
+ echo "(--quick mode: limited to ${#PAGES[@]} pages)"
147
+ fi
148
+
149
+ echo ""
150
+ echo "=== Pages to QA (${#PAGES[@]}) ==="
151
+ for i in "${!PAGES[@]}"; do
152
+ echo " ${PAGE_NAMES[$i]} → ${PAGES[$i]}"
153
+ done
154
+
155
+ ###############################################################################
156
+ # Screenshot helper
157
+ ###############################################################################
158
+ take_screenshot() {
159
+ local url="$1"
160
+ local output_path="$2"
161
+
162
+ if [[ -x "$OPENCLAW_BIN" ]]; then
163
+ "$OPENCLAW_BIN" browser navigate "$url" --timeout 15000 2>/dev/null || true
164
+ "$OPENCLAW_BIN" browser wait --load networkidle --timeout-ms 10000 2>/dev/null || true
165
+ local result
166
+ result=$("$OPENCLAW_BIN" browser screenshot --json --full-page 2>/dev/null || echo '{"ok":false}')
167
+ local ok
168
+ ok=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('ok',False))" 2>/dev/null || echo "False")
169
+ if [[ "$ok" == "True" ]]; then
170
+ local media_path
171
+ media_path=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('path',''))" 2>/dev/null)
172
+ if [[ -n "$media_path" && -f "$media_path" ]]; then
173
+ cp "$media_path" "$output_path"
174
+ return 0
175
+ fi
176
+ fi
177
+ fi
178
+
179
+ echo " WARNING: screenshot failed for $url"
180
+ return 1
181
+ }
182
+
183
+ ###############################################################################
184
+ # Capture screenshots
185
+ ###############################################################################
186
+ echo ""
187
+ echo "=== Capturing Screenshots ==="
188
+
189
+ declare -a CAPTURED=()
190
+ FAIL_COUNT=0
191
+
192
+ if [[ -x "$OPENCLAW_BIN" ]]; then
193
+ "$OPENCLAW_BIN" browser start 2>/dev/null || true
194
+ sleep 1
195
+ fi
196
+
197
+ for i in "${!PAGES[@]}"; do
198
+ route="${PAGES[$i]}"
199
+ name="${PAGE_NAMES[$i]}"
200
+ url="${BASE_URL}${route}"
201
+ safe_name=$(echo "$name" | tr -cs 'a-zA-Z0-9_-' '_' | sed 's/_$//')
202
+ output_file="${SCREENSHOT_DIR}/${DATE_TAG}_${safe_name}.png"
203
+
204
+ echo -n " [$((i+1))/${#PAGES[@]}] ${name} (${url}) ... "
205
+
206
+ if take_screenshot "$url" "$output_file"; then
207
+ echo "OK → $output_file"
208
+ CAPTURED+=("$output_file")
209
+ else
210
+ echo "FAIL"
211
+ FAIL_COUNT=$((FAIL_COUNT + 1))
212
+ fi
213
+ done
214
+
215
+ ###############################################################################
216
+ # Summary
217
+ ###############################################################################
218
+ echo ""
219
+ echo "========================================="
220
+ echo " Forge QA Summary"
221
+ echo "========================================="
222
+ echo " Changed files: $FILE_COUNT"
223
+ echo " Pages tested: ${#PAGES[@]}"
224
+ echo " Screenshots OK: ${#CAPTURED[@]}"
225
+ echo " Screenshots FAIL: $FAIL_COUNT"
226
+ echo " Output dir: $SCREENSHOT_DIR"
227
+ echo ""
228
+
229
+ if [[ ${#CAPTURED[@]} -gt 0 ]]; then
230
+ echo " Screenshots:"
231
+ for f in "${CAPTURED[@]}"; do
232
+ echo " $f"
233
+ done
234
+ fi
235
+
236
+ echo ""
237
+ echo "========================================="