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.
- package/README.md +77 -0
- package/bin/arete.js +156 -0
- package/bin/create.js +111 -0
- package/lib/install-openclaw.js +50 -0
- package/lib/scaffold.js +213 -0
- package/lib/setup-wizard.js +88 -0
- package/lib/updater.js +130 -0
- package/package.json +34 -0
- package/packages/gatsaeng-os/README.md +36 -0
- package/packages/gatsaeng-os/components.json +23 -0
- package/packages/gatsaeng-os/eslint.config.mjs +18 -0
- package/packages/gatsaeng-os/next.config.ts +7 -0
- package/packages/gatsaeng-os/package.json +59 -0
- package/packages/gatsaeng-os/postcss.config.mjs +7 -0
- package/packages/gatsaeng-os/public/file.svg +1 -0
- package/packages/gatsaeng-os/public/globe.svg +1 -0
- package/packages/gatsaeng-os/public/next.svg +1 -0
- package/packages/gatsaeng-os/public/vercel.svg +1 -0
- package/packages/gatsaeng-os/public/window.svg +1 -0
- package/packages/gatsaeng-os/python/api_server.py +248 -0
- package/packages/gatsaeng-os/python/briefing.py +145 -0
- package/packages/gatsaeng-os/python/config.py +55 -0
- package/packages/gatsaeng-os/python/goal_context_agent.py +193 -0
- package/packages/gatsaeng-os/python/gyeokguk.py +171 -0
- package/packages/gatsaeng-os/python/proactive.py +158 -0
- package/packages/gatsaeng-os/python/requirements.txt +11 -0
- package/packages/gatsaeng-os/python/run.py +28 -0
- package/packages/gatsaeng-os/python/scoring.py +44 -0
- package/packages/gatsaeng-os/python/streak.py +70 -0
- package/packages/gatsaeng-os/python/telegram_bot.py +331 -0
- package/packages/gatsaeng-os/python/timing_engine.py +117 -0
- package/packages/gatsaeng-os/python/vault_io.py +423 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/areas/[id]/page.tsx +215 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/areas/page.tsx +161 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/books/[id]/page.tsx +215 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/books/page.tsx +268 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/calendar/page.tsx +379 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/error.tsx +30 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/focus/page.tsx +293 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/goals/[id]/page.tsx +426 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/goals/page.tsx +178 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/layout.tsx +29 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/notes/[id]/page.tsx +147 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/notes/page.tsx +254 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/page.tsx +26 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/projects/[id]/page.tsx +86 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/projects/page.tsx +215 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/review/page.tsx +475 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/routines/page.tsx +436 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/tasks/[id]/page.tsx +210 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/tasks/page.tsx +307 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/voice/page.tsx +212 -0
- package/packages/gatsaeng-os/src/app/api/areas/[id]/route.ts +26 -0
- package/packages/gatsaeng-os/src/app/api/areas/route.ts +22 -0
- package/packages/gatsaeng-os/src/app/api/auth/login/route.ts +52 -0
- package/packages/gatsaeng-os/src/app/api/auth/logout/route.ts +8 -0
- package/packages/gatsaeng-os/src/app/api/books/[id]/route.ts +27 -0
- package/packages/gatsaeng-os/src/app/api/books/route.ts +20 -0
- package/packages/gatsaeng-os/src/app/api/calendar/[id]/route.ts +24 -0
- package/packages/gatsaeng-os/src/app/api/calendar/import/route.ts +52 -0
- package/packages/gatsaeng-os/src/app/api/calendar/route.ts +37 -0
- package/packages/gatsaeng-os/src/app/api/daily/route.ts +51 -0
- package/packages/gatsaeng-os/src/app/api/goals/[id]/route.ts +34 -0
- package/packages/gatsaeng-os/src/app/api/goals/route.ts +30 -0
- package/packages/gatsaeng-os/src/app/api/logs/energy/route.ts +40 -0
- package/packages/gatsaeng-os/src/app/api/logs/focus/route.ts +22 -0
- package/packages/gatsaeng-os/src/app/api/logs/routine/route.ts +54 -0
- package/packages/gatsaeng-os/src/app/api/milestones/[id]/route.ts +26 -0
- package/packages/gatsaeng-os/src/app/api/milestones/route.ts +47 -0
- package/packages/gatsaeng-os/src/app/api/notes/[id]/route.ts +29 -0
- package/packages/gatsaeng-os/src/app/api/notes/route.ts +37 -0
- package/packages/gatsaeng-os/src/app/api/profile/route.ts +17 -0
- package/packages/gatsaeng-os/src/app/api/projects/[id]/route.ts +27 -0
- package/packages/gatsaeng-os/src/app/api/projects/route.ts +25 -0
- package/packages/gatsaeng-os/src/app/api/reviews/[id]/route.ts +26 -0
- package/packages/gatsaeng-os/src/app/api/reviews/route.ts +29 -0
- package/packages/gatsaeng-os/src/app/api/routines/[id]/route.ts +26 -0
- package/packages/gatsaeng-os/src/app/api/routines/route.ts +28 -0
- package/packages/gatsaeng-os/src/app/api/tasks/[id]/route.ts +28 -0
- package/packages/gatsaeng-os/src/app/api/tasks/route.ts +66 -0
- package/packages/gatsaeng-os/src/app/api/timing/current/route.ts +63 -0
- package/packages/gatsaeng-os/src/app/api/voice/chat/route.ts +50 -0
- package/packages/gatsaeng-os/src/app/api/voice/transcribe/route.ts +25 -0
- package/packages/gatsaeng-os/src/app/api/voice/tts/route.ts +36 -0
- package/packages/gatsaeng-os/src/app/error.tsx +30 -0
- package/packages/gatsaeng-os/src/app/favicon.ico +0 -0
- package/packages/gatsaeng-os/src/app/globals.css +208 -0
- package/packages/gatsaeng-os/src/app/layout.tsx +33 -0
- package/packages/gatsaeng-os/src/app/login/page.tsx +87 -0
- package/packages/gatsaeng-os/src/app/providers.tsx +27 -0
- package/packages/gatsaeng-os/src/components/ErrorBoundary.tsx +46 -0
- package/packages/gatsaeng-os/src/components/dashboard/DashboardGrid.tsx +86 -0
- package/packages/gatsaeng-os/src/components/dashboard/DdayWidget.tsx +88 -0
- package/packages/gatsaeng-os/src/components/dashboard/EnergyTracker.tsx +87 -0
- package/packages/gatsaeng-os/src/components/dashboard/FocusTimer.tsx +139 -0
- package/packages/gatsaeng-os/src/components/dashboard/GatsaengScore.tsx +30 -0
- package/packages/gatsaeng-os/src/components/dashboard/GoalRings.tsx +107 -0
- package/packages/gatsaeng-os/src/components/dashboard/ProactiveBar.tsx +98 -0
- package/packages/gatsaeng-os/src/components/dashboard/RoutineChecklist.tsx +81 -0
- package/packages/gatsaeng-os/src/components/dashboard/TimingWidget.tsx +86 -0
- package/packages/gatsaeng-os/src/components/dashboard/WidgetCustomizer.tsx +95 -0
- package/packages/gatsaeng-os/src/components/dashboard/WidgetWrapper.tsx +33 -0
- package/packages/gatsaeng-os/src/components/dashboard/ZeigarnikPanel.tsx +43 -0
- package/packages/gatsaeng-os/src/components/editor/EditorToolbar.tsx +186 -0
- package/packages/gatsaeng-os/src/components/editor/TiptapEditor.tsx +114 -0
- package/packages/gatsaeng-os/src/components/layout/Header.tsx +47 -0
- package/packages/gatsaeng-os/src/components/layout/MobileBottomNav.tsx +122 -0
- package/packages/gatsaeng-os/src/components/layout/MobileSidebar.tsx +29 -0
- package/packages/gatsaeng-os/src/components/layout/Sidebar.tsx +142 -0
- package/packages/gatsaeng-os/src/components/onboarding/OnboardingFlow.tsx +229 -0
- package/packages/gatsaeng-os/src/components/onboarding/OnboardingGate.tsx +78 -0
- package/packages/gatsaeng-os/src/components/projects/CalendarView.tsx +152 -0
- package/packages/gatsaeng-os/src/components/projects/KanbanView.tsx +180 -0
- package/packages/gatsaeng-os/src/components/projects/ListView.tsx +82 -0
- package/packages/gatsaeng-os/src/components/projects/TableView.tsx +206 -0
- package/packages/gatsaeng-os/src/components/projects/TaskCard.tsx +154 -0
- package/packages/gatsaeng-os/src/components/projects/TaskForm.tsx +128 -0
- package/packages/gatsaeng-os/src/components/projects/ViewSwitcher.tsx +40 -0
- package/packages/gatsaeng-os/src/components/search/GlobalSearch.tsx +179 -0
- package/packages/gatsaeng-os/src/components/shared/InlineEdit.tsx +77 -0
- package/packages/gatsaeng-os/src/components/shared/PinButton.tsx +42 -0
- package/packages/gatsaeng-os/src/components/tasks/DDayBadge.tsx +34 -0
- package/packages/gatsaeng-os/src/components/ui/badge.tsx +48 -0
- package/packages/gatsaeng-os/src/components/ui/button.tsx +64 -0
- package/packages/gatsaeng-os/src/components/ui/card.tsx +92 -0
- package/packages/gatsaeng-os/src/components/ui/checkbox.tsx +32 -0
- package/packages/gatsaeng-os/src/components/ui/command.tsx +184 -0
- package/packages/gatsaeng-os/src/components/ui/dialog.tsx +158 -0
- package/packages/gatsaeng-os/src/components/ui/input.tsx +21 -0
- package/packages/gatsaeng-os/src/components/ui/label.tsx +24 -0
- package/packages/gatsaeng-os/src/components/ui/popover.tsx +89 -0
- package/packages/gatsaeng-os/src/components/ui/progress.tsx +31 -0
- package/packages/gatsaeng-os/src/components/ui/select.tsx +190 -0
- package/packages/gatsaeng-os/src/components/ui/sheet.tsx +143 -0
- package/packages/gatsaeng-os/src/components/ui/tabs.tsx +91 -0
- package/packages/gatsaeng-os/src/components/ui/toggle-group.tsx +83 -0
- package/packages/gatsaeng-os/src/components/ui/toggle.tsx +47 -0
- package/packages/gatsaeng-os/src/components/ui/tooltip.tsx +57 -0
- package/packages/gatsaeng-os/src/hooks/useAreas.ts +53 -0
- package/packages/gatsaeng-os/src/hooks/useBooks.ts +62 -0
- package/packages/gatsaeng-os/src/hooks/useCalendar.ts +59 -0
- package/packages/gatsaeng-os/src/hooks/useDaily.ts +15 -0
- package/packages/gatsaeng-os/src/hooks/useGlobalTasks.ts +45 -0
- package/packages/gatsaeng-os/src/hooks/useGoals.ts +53 -0
- package/packages/gatsaeng-os/src/hooks/useMilestones.ts +75 -0
- package/packages/gatsaeng-os/src/hooks/useNotes.ts +65 -0
- package/packages/gatsaeng-os/src/hooks/useProjects.ts +102 -0
- package/packages/gatsaeng-os/src/hooks/useRoutines.ts +76 -0
- package/packages/gatsaeng-os/src/hooks/useTiming.ts +27 -0
- package/packages/gatsaeng-os/src/lib/apiFetch.ts +14 -0
- package/packages/gatsaeng-os/src/lib/auth.ts +32 -0
- package/packages/gatsaeng-os/src/lib/date.ts +7 -0
- package/packages/gatsaeng-os/src/lib/editor/markdown.ts +35 -0
- package/packages/gatsaeng-os/src/lib/llm-governor.ts +167 -0
- package/packages/gatsaeng-os/src/lib/neuroscience/energyCycle.ts +35 -0
- package/packages/gatsaeng-os/src/lib/neuroscience/habitStack.ts +22 -0
- package/packages/gatsaeng-os/src/lib/neuroscience/scoring.ts +32 -0
- package/packages/gatsaeng-os/src/lib/routes.ts +15 -0
- package/packages/gatsaeng-os/src/lib/utils.ts +6 -0
- package/packages/gatsaeng-os/src/lib/vault/config.ts +29 -0
- package/packages/gatsaeng-os/src/lib/vault/frontmatter.ts +84 -0
- package/packages/gatsaeng-os/src/lib/vault/index.ts +180 -0
- package/packages/gatsaeng-os/src/lib/vault/schemas.ts +274 -0
- package/packages/gatsaeng-os/src/middleware.ts +34 -0
- package/packages/gatsaeng-os/src/stores/dashboardStore.ts +26 -0
- package/packages/gatsaeng-os/src/stores/favoritesStore.ts +47 -0
- package/packages/gatsaeng-os/src/stores/timerStore.ts +65 -0
- package/packages/gatsaeng-os/src/types/index.ts +320 -0
- package/packages/gatsaeng-os/tsconfig.json +34 -0
- package/templates/scripts/forge_qa.sh.tmpl +237 -0
- package/templates/scripts/forge_ship.sh.tmpl +183 -0
- package/templates/scripts/session_indexer.py.tmpl +420 -0
- package/templates/scripts/tracer.py.tmpl +266 -0
- package/templates/workspace/AGENTS.md.tmpl +190 -0
- package/templates/workspace/BOOTSTRAP.md.tmpl +27 -0
- package/templates/workspace/HEARTBEAT.md.tmpl +23 -0
- package/templates/workspace/MEMORY.md.tmpl +35 -0
- package/templates/workspace/SOUL.md.tmpl +258 -0
- package/templates/workspace/TOOLS.md.tmpl +28 -0
- 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,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 @@
|
|
|
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)
|