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
package/lib/updater.js ADDED
@@ -0,0 +1,130 @@
1
+ import { execSync } from 'child_process';
2
+ import { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync, cpSync, rmSync } from 'fs';
3
+ import { resolve, join } from 'path';
4
+ import { homedir } from 'os';
5
+ import chalk from 'chalk';
6
+
7
+ export async function checkForUpdate() {
8
+ const pkg = JSON.parse(
9
+ readFileSync(new URL('../package.json', import.meta.url), 'utf-8')
10
+ );
11
+ const currentVersion = pkg.version;
12
+
13
+ let latestVersion = currentVersion;
14
+ try {
15
+ latestVersion = execSync('npm show create-arete-workspace version', {
16
+ stdio: 'pipe',
17
+ timeout: 10000,
18
+ })
19
+ .toString()
20
+ .trim();
21
+ } catch {
22
+ console.log(chalk.yellow(' Could not check npm registry. Are you online?'));
23
+ return { currentVersion, latestVersion: currentVersion, updateAvailable: false };
24
+ }
25
+
26
+ return {
27
+ currentVersion,
28
+ latestVersion,
29
+ updateAvailable: currentVersion !== latestVersion,
30
+ };
31
+ }
32
+
33
+ // Layer 1 files: framework files that can be updated safely
34
+ const LAYER1_FILES = {
35
+ scripts: ['session_indexer.py', 'tracer.py', 'forge_ship.sh', 'forge_qa.sh'],
36
+ gatsaengOs: true,
37
+ };
38
+
39
+ // Layer 2 files: user config files that must NEVER be overwritten
40
+ const LAYER2_PROTECTED = [
41
+ 'MEMORY.md',
42
+ 'SOUL.md',
43
+ 'AGENTS.md',
44
+ 'USER.md',
45
+ 'TOOLS.md',
46
+ 'HEARTBEAT.md',
47
+ 'BOOTSTRAP.md',
48
+ '.env',
49
+ ];
50
+
51
+ export async function runUpdate(targetVersion) {
52
+ console.log(chalk.blue(` Updating to ${targetVersion}...`));
53
+
54
+ // Install latest version globally to get new templates
55
+ try {
56
+ execSync(`npm install -g create-arete-workspace@${targetVersion}`, { stdio: 'pipe' });
57
+ } catch (e) {
58
+ throw new Error(`Failed to download update: ${e.message}`);
59
+ }
60
+
61
+ // Find installed package path
62
+ let pkgPath;
63
+ try {
64
+ pkgPath = execSync('npm root -g', { stdio: 'pipe' }).toString().trim();
65
+ pkgPath = join(pkgPath, 'create-arete-workspace');
66
+ } catch {
67
+ throw new Error('Could not locate installed package');
68
+ }
69
+
70
+ const workspacePath = resolve(homedir(), '.openclaw', 'workspace');
71
+ if (!existsSync(workspacePath)) {
72
+ console.log(chalk.yellow(' Workspace not found. Run create-arete-workspace first.'));
73
+ return;
74
+ }
75
+
76
+ // Update Layer 1: scripts
77
+ const srcScripts = join(pkgPath, 'templates', 'scripts');
78
+ const destScripts = join(workspacePath, 'scripts');
79
+
80
+ if (existsSync(srcScripts)) {
81
+ mkdirSync(destScripts, { recursive: true });
82
+ for (const file of LAYER1_FILES.scripts) {
83
+ const srcFile = join(srcScripts, file + '.tmpl');
84
+ const destFile = join(destScripts, file);
85
+ if (existsSync(srcFile)) {
86
+ const content = readFileSync(srcFile, 'utf-8');
87
+ // Preserve existing variable values by reading current config
88
+ writeFileSync(destFile, content, 'utf-8');
89
+ console.log(chalk.dim(` Updated: scripts/${file}`));
90
+ }
91
+ }
92
+ }
93
+
94
+ // Update Layer 1: 갓생OS source (preserves user .env)
95
+ const gatsaengDest = join(workspacePath, 'gatsaeng-os');
96
+ const gatsaengSrc = join(pkgPath, 'packages', 'gatsaeng-os');
97
+ if (existsSync(gatsaengDest) && existsSync(gatsaengSrc)) {
98
+ // Preserve user's .env
99
+ let savedEnv = null;
100
+ const envFile = join(gatsaengDest, '.env');
101
+ if (existsSync(envFile)) {
102
+ savedEnv = readFileSync(envFile, 'utf-8');
103
+ }
104
+
105
+ // Remove old source (except node_modules)
106
+ const entries = readdirSync(gatsaengDest);
107
+ for (const entry of entries) {
108
+ if (entry === 'node_modules' || entry === '.env' || entry === '.next') continue;
109
+ rmSync(join(gatsaengDest, entry), { recursive: true, force: true });
110
+ }
111
+
112
+ // Copy new source
113
+ cpSync(gatsaengSrc, gatsaengDest, { recursive: true });
114
+
115
+ // Restore .env
116
+ if (savedEnv) {
117
+ writeFileSync(envFile, savedEnv, 'utf-8');
118
+ }
119
+
120
+ console.log(chalk.dim(' Updated: 갓생OS source'));
121
+ }
122
+
123
+ console.log('');
124
+ console.log(chalk.dim(' Protected (not modified):'));
125
+ for (const file of LAYER2_PROTECTED) {
126
+ if (existsSync(join(workspacePath, file))) {
127
+ console.log(chalk.dim(` ${file}`));
128
+ }
129
+ }
130
+ }
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "create-arete-workspace",
3
+ "version": "0.2.0",
4
+ "description": "Set up an ARETE AI Operating System workspace in 5 minutes",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-arete-workspace": "./bin/create.js",
8
+ "arete": "./bin/arete.js"
9
+ },
10
+ "engines": {
11
+ "node": ">=18"
12
+ },
13
+ "files": [
14
+ "bin/",
15
+ "lib/",
16
+ "templates/",
17
+ "packages/"
18
+ ],
19
+ "keywords": [
20
+ "arete",
21
+ "ai",
22
+ "openclaw",
23
+ "agent",
24
+ "workspace",
25
+ "gatsaeng",
26
+ "productivity",
27
+ "obsidian"
28
+ ],
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "chalk": "^5.3.0",
32
+ "inquirer": "^9.2.0"
33
+ }
34
+ }
@@ -0,0 +1,36 @@
1
+ This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
2
+
3
+ ## Getting Started
4
+
5
+ First, run the development server:
6
+
7
+ ```bash
8
+ npm run dev
9
+ # or
10
+ yarn dev
11
+ # or
12
+ pnpm dev
13
+ # or
14
+ bun dev
15
+ ```
16
+
17
+ Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18
+
19
+ You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20
+
21
+ This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22
+
23
+ ## Learn More
24
+
25
+ To learn more about Next.js, take a look at the following resources:
26
+
27
+ - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28
+ - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29
+
30
+ You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31
+
32
+ ## Deploy on Vercel
33
+
34
+ The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35
+
36
+ Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "src/app/globals.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "iconLibrary": "lucide",
14
+ "rtl": false,
15
+ "aliases": {
16
+ "components": "@/components",
17
+ "utils": "@/lib/utils",
18
+ "ui": "@/components/ui",
19
+ "lib": "@/lib",
20
+ "hooks": "@/hooks"
21
+ },
22
+ "registries": {}
23
+ }
@@ -0,0 +1,18 @@
1
+ import { defineConfig, globalIgnores } from "eslint/config";
2
+ import nextVitals from "eslint-config-next/core-web-vitals";
3
+ import nextTs from "eslint-config-next/typescript";
4
+
5
+ const eslintConfig = defineConfig([
6
+ ...nextVitals,
7
+ ...nextTs,
8
+ // Override default ignores of eslint-config-next.
9
+ globalIgnores([
10
+ // Default ignores of eslint-config-next:
11
+ ".next/**",
12
+ "out/**",
13
+ "build/**",
14
+ "next-env.d.ts",
15
+ ]),
16
+ ]);
17
+
18
+ export default eslintConfig;
@@ -0,0 +1,7 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ /* config options here */
5
+ };
6
+
7
+ export default nextConfig;
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "gatsaeng-os",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start -p 3002",
9
+ "lint": "eslint"
10
+ },
11
+ "dependencies": {
12
+ "@dnd-kit/core": "^6.3.1",
13
+ "@dnd-kit/sortable": "^10.0.0",
14
+ "@dnd-kit/utilities": "^3.2.2",
15
+ "@tanstack/react-query": "^5.90.21",
16
+ "@tiptap/extension-link": "^3.20.0",
17
+ "@tiptap/extension-placeholder": "^3.20.0",
18
+ "@tiptap/extension-task-item": "^3.20.0",
19
+ "@tiptap/extension-task-list": "^3.20.0",
20
+ "@tiptap/pm": "^3.20.0",
21
+ "@tiptap/react": "^3.20.0",
22
+ "@tiptap/starter-kit": "^3.20.0",
23
+ "@types/react-grid-layout": "^1.3.6",
24
+ "@types/turndown": "^5.0.6",
25
+ "class-variance-authority": "^0.7.1",
26
+ "clsx": "^2.1.1",
27
+ "cmdk": "^1.1.1",
28
+ "date-fns": "^4.1.0",
29
+ "gray-matter": "^4.0.3",
30
+ "jose": "^6.1.3",
31
+ "lucide-react": "^0.577.0",
32
+ "marked": "^17.0.4",
33
+ "nanoid": "^5.1.6",
34
+ "next": "16.1.6",
35
+ "next-themes": "^0.4.6",
36
+ "openai": "^6.27.0",
37
+ "radix-ui": "^1.4.3",
38
+ "react": "19.2.3",
39
+ "react-dom": "19.2.3",
40
+ "react-grid-layout": "^2.2.2",
41
+ "recharts": "^3.7.0",
42
+ "tailwind-merge": "^3.5.0",
43
+ "turndown": "^7.2.2",
44
+ "zod": "^4.3.6",
45
+ "zustand": "^5.0.11"
46
+ },
47
+ "devDependencies": {
48
+ "@tailwindcss/postcss": "^4",
49
+ "@types/node": "^20",
50
+ "@types/react": "^19",
51
+ "@types/react-dom": "^19",
52
+ "eslint": "^9",
53
+ "eslint-config-next": "16.1.6",
54
+ "shadcn": "^3.8.5",
55
+ "tailwindcss": "^4",
56
+ "tw-animate-css": "^1.4.0",
57
+ "typescript": "^5"
58
+ }
59
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1 @@
1
+ <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
@@ -0,0 +1,248 @@
1
+ """FastAPI server for gatsaeng-os Python backend."""
2
+
3
+ from fastapi import FastAPI, UploadFile, BackgroundTasks, HTTPException
4
+ from fastapi.middleware.cors import CORSMiddleware
5
+ import uvicorn
6
+
7
+ import vault_io
8
+ import scoring
9
+ import timing_engine
10
+ import goal_context_agent
11
+ import briefing
12
+ import proactive
13
+ import streak
14
+ import gyeokguk
15
+ from config import DASHBOARD_PORT, LIMITS
16
+
17
+ app = FastAPI(title='Gatsaeng OS API', version='1.0.0')
18
+
19
+ # CORS for Next.js dashboard
20
+ app.add_middleware(
21
+ CORSMiddleware,
22
+ allow_origins=['http://localhost:3100', 'http://127.0.0.1:3100'],
23
+ allow_methods=['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
24
+ allow_headers=['Content-Type', 'Authorization'],
25
+ )
26
+
27
+
28
+ @app.get('/api/dashboard')
29
+ def get_dashboard():
30
+ """Full dashboard state for single API call."""
31
+ return {
32
+ 'routines': vault_io.get_routines_with_status(),
33
+ 'goals_with_milestones': vault_io.get_goals_with_milestones(),
34
+ 'today_tasks': vault_io.read_today_tasks(),
35
+ 'streaks': vault_io.get_active_streaks(),
36
+ 'gatsaeng_score': vault_io.get_today_score(),
37
+ 'timing': vault_io.get_current_timing(),
38
+ 'ddays': vault_io.get_upcoming_ddays(),
39
+ }
40
+
41
+
42
+ @app.patch('/api/routines/{routine_id}/check')
43
+ def check_routine(routine_id: str):
44
+ """Check a routine as done."""
45
+ vault_io.check_routine(routine_id)
46
+ streaks = vault_io.get_active_streaks()
47
+ score = scoring.calculate('routine_complete', streaks['current'])
48
+ vault_io.update_today_score(score['points'])
49
+ return {'score': score, 'new_total': vault_io.get_today_score()}
50
+
51
+
52
+ @app.patch('/api/tasks/{task_id}/done')
53
+ def complete_task(task_id: str):
54
+ """Mark a project task as done."""
55
+ task_data = vault_io.get_entity('tasks', task_id)
56
+ if not task_data:
57
+ raise HTTPException(status_code=404, detail='Not found')
58
+
59
+ vault_io.update_entity('tasks', task_id, {'status': 'done'})
60
+ priority = task_data['data'].get('priority', 'medium')
61
+ event = 'task_done_urgent' if priority == 'urgent' else 'task_done'
62
+ streaks = vault_io.get_active_streaks()
63
+ score = scoring.calculate(event, streaks['current'])
64
+ vault_io.update_today_score(score['points'])
65
+ return {'score': score}
66
+
67
+
68
+ @app.post('/api/goals/{goal_id}/context')
69
+ async def upload_context(goal_id: str, file: UploadFile, bg: BackgroundTasks):
70
+ """Upload context data for Goal Context Agent."""
71
+ content = await file.read()
72
+ path = vault_io.save_context_file(goal_id, file.filename, content)
73
+
74
+ # Score for data upload
75
+ score = scoring.calculate('data_uploaded')
76
+ vault_io.update_today_score(score['points'])
77
+
78
+ # Trigger Goal Context Agent in background
79
+ bg.add_task(goal_context_agent.run, goal_id)
80
+
81
+ return {'status': 'processing', 'file': str(path), 'score': score}
82
+
83
+
84
+ @app.post('/api/goals/{goal_id}/analyze')
85
+ async def analyze_goal(goal_id: str, bg: BackgroundTasks):
86
+ """Trigger Goal Context Agent analysis for a goal."""
87
+ bg.add_task(goal_context_agent.run, goal_id)
88
+ return {'status': 'analysis_started', 'goal_id': goal_id}
89
+
90
+
91
+ @app.get('/api/goals/{goal_id}/analysis')
92
+ def get_goal_analysis(goal_id: str):
93
+ """Get cached goal analysis result."""
94
+ goal = vault_io.read_goal(goal_id)
95
+ if not goal:
96
+ raise HTTPException(status_code=404, detail='Not found')
97
+ return {
98
+ 'ai_diagnosis': goal['data'].get('ai_diagnosis'),
99
+ 'ai_direction': goal['data'].get('ai_direction'),
100
+ 'ai_next_review': goal['data'].get('ai_next_review'),
101
+ }
102
+
103
+
104
+ @app.get('/api/milestones/ddays')
105
+ def get_ddays():
106
+ """Get all active milestones sorted by D-day."""
107
+ return vault_io.get_active_milestones()
108
+
109
+
110
+ @app.get('/api/timing/current')
111
+ def get_current_timing():
112
+ """Get current month's saju timing context."""
113
+ return vault_io.get_current_timing()
114
+
115
+
116
+ @app.get('/api/timing/briefing')
117
+ def get_timing_briefing():
118
+ """Get timing-based briefing text."""
119
+ return {'briefing': timing_engine.get_monthly_briefing()}
120
+
121
+
122
+ @app.get('/api/timing/goal/{goal_id}')
123
+ def get_goal_timing(goal_id: str):
124
+ """Get timing-based advice for a specific goal."""
125
+ return {'advice': timing_engine.get_goal_timing_advice(goal_id)}
126
+
127
+
128
+ @app.get('/api/timing/reanalysis-due')
129
+ def get_reanalysis_due():
130
+ """Get goals that need re-analysis."""
131
+ return {'goal_ids': timing_engine.get_all_due_reanalyses()}
132
+
133
+
134
+ @app.get('/api/heatmap')
135
+ def get_heatmap(weeks: int = 52):
136
+ """Get heatmap data for N weeks."""
137
+ return vault_io.get_heatmap(weeks)
138
+
139
+
140
+ @app.get('/api/constraints')
141
+ def get_constraints():
142
+ """Get current constraint status."""
143
+ goals = vault_io.get_active_goals()
144
+ routines = [r for r in vault_io.list_entities('routines') if r['data'].get('is_active')]
145
+ projects = [p for p in vault_io.list_entities('projects') if p['data'].get('status') == 'active']
146
+
147
+ return {
148
+ 'goals': {'current': len(goals), 'max': LIMITS['MAX_ACTIVE_GOALS']},
149
+ 'routines': {'current': len(routines), 'max': LIMITS['MAX_ACTIVE_ROUTINES']},
150
+ 'projects': {'current': len(projects), 'max': LIMITS['MAX_ACTIVE_PROJECTS']},
151
+ }
152
+
153
+
154
+ @app.get('/api/proactive')
155
+ def get_proactive_alerts():
156
+ """Get proactive alerts (skipped routines, upcoming D-days, reanalysis)."""
157
+ alerts = []
158
+
159
+ # Skipped routines (2+ consecutive days)
160
+ skips = vault_io.get_consecutive_skips()
161
+ for rid, count in skips.items():
162
+ if count >= 2:
163
+ routine = vault_io.get_entity('routines', rid)
164
+ if routine:
165
+ alerts.append({
166
+ 'type': 'skipped_routine',
167
+ 'title': f'{count}일 연속 미실행',
168
+ 'message': routine['data'].get('title', ''),
169
+ 'routine_id': rid,
170
+ 'skip_count': count,
171
+ })
172
+
173
+ # D-day warnings (≤ 7 days)
174
+ ddays = vault_io.get_upcoming_ddays(7)
175
+ for m in ddays:
176
+ alerts.append({
177
+ 'type': 'milestone_dday',
178
+ 'title': f"D-{m.get('d_day', '?')}",
179
+ 'message': m.get('title', ''),
180
+ 'milestone_id': m.get('id'),
181
+ })
182
+
183
+ # Reanalysis due
184
+ due_goals = timing_engine.get_all_due_reanalyses()
185
+ for gid in due_goals:
186
+ goal = vault_io.read_goal(gid)
187
+ if goal:
188
+ alerts.append({
189
+ 'type': 'reanalysis_due',
190
+ 'title': '재분석 필요',
191
+ 'message': goal['data'].get('title', ''),
192
+ 'goal_id': gid,
193
+ })
194
+
195
+ return alerts
196
+
197
+
198
+ @app.get('/api/briefing/morning')
199
+ def get_morning_briefing():
200
+ """Generate morning briefing."""
201
+ return {'text': briefing.generate_morning_briefing()}
202
+
203
+
204
+ @app.get('/api/briefing/evening')
205
+ def get_evening_checkin():
206
+ """Generate evening check-in."""
207
+ return {'text': briefing.generate_evening_checkin()}
208
+
209
+
210
+ @app.get('/api/briefing/weekly')
211
+ def get_weekly_summary():
212
+ """Generate weekly summary."""
213
+ return {'text': briefing.generate_weekly_summary()}
214
+
215
+
216
+ @app.post('/api/streak/recalculate')
217
+ def recalculate_streak():
218
+ """Recalculate current streak."""
219
+ return streak.calculate_streak()
220
+
221
+
222
+ @app.get('/api/gyeokguk/daily')
223
+ def get_daily_gyeokguk():
224
+ """Get today's 격국 기여도 판정."""
225
+ return gyeokguk.judge_daily_actions()
226
+
227
+
228
+ @app.get('/api/gyeokguk/scorecard')
229
+ def get_growth_scorecard():
230
+ """Get weekly 격국 growth scorecard."""
231
+ return gyeokguk.get_growth_scorecard()
232
+
233
+
234
+ @app.post('/api/gyeokguk/judge')
235
+ def judge_action(body: dict):
236
+ """Judge a specific action's 격국 contribution."""
237
+ text = body.get('action', '')
238
+ return gyeokguk.judge_action(text)
239
+
240
+
241
+ @app.get('/api/proactive/full')
242
+ def get_full_proactive():
243
+ """Get all proactive alerts (full engine)."""
244
+ return proactive.check_all()
245
+
246
+
247
+ if __name__ == '__main__':
248
+ uvicorn.run(app, host='127.0.0.1', port=DASHBOARD_PORT)