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/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # ARETE Starter
2
+
3
+ AI Operating System — set up in 5 minutes.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npx create-arete-workspace
9
+ ```
10
+
11
+ ## What's Included
12
+
13
+ - **Eve**: AI Chief of Staff (Telegram integration)
14
+ - **Memory Bridge**: Auto-integrate knowledge across agents
15
+ - **FORGE Workflow**: Coding agent + Impact Map
16
+ - **Verify Loop**: Automatic implementation verification
17
+ - **Tracer Agent**: Evidence-based bug causal tracking
18
+
19
+ ## 갓생OS
20
+
21
+ Neuroscience-based habit & productivity dashboard powered by Obsidian.
22
+
23
+ - **Dashboard**: Routines, goals, D-day, energy tracking, focus timer
24
+ - **Obsidian Vault Backend**: All data stored as markdown with frontmatter
25
+ - **Neuroscience Engine**: Ultradian rhythm scoring, habit stacking, Zeigarnik tracking
26
+ - **Voice AI**: Eve voice assistant integration (OpenAI)
27
+ - **Review System**: Weekly/monthly plan & retrospective
28
+
29
+ ```bash
30
+ # Launch 갓생OS dashboard
31
+ arete start
32
+ ```
33
+
34
+ Runs on `http://localhost:3000` (Next.js dev server). Requires `VAULT_PATH` pointing to your Obsidian vault.
35
+
36
+ ## Architecture
37
+
38
+ ```
39
+ Layer 1 (Framework) — updated via `arete update`
40
+ ├── scripts/ Session indexer, tracer, forge tools
41
+ └── templates/ System templates
42
+
43
+ Layer 2 (User Config) — NEVER auto-updated
44
+ ├── SOUL.md Agent personality & behavior
45
+ ├── AGENTS.md Agent routing & policies
46
+ ├── MEMORY.md Persistent memory
47
+ ├── USER.md User profile & preferences
48
+ ├── TOOLS.md Local environment config
49
+ ├── HEARTBEAT.md Health monitoring rules
50
+ └── BOOTSTRAP.md Session startup protocol
51
+ ```
52
+
53
+ ## Commands
54
+
55
+ ```bash
56
+ # Initial setup
57
+ npx create-arete-workspace
58
+
59
+ # Check status
60
+ arete status
61
+
62
+ # Launch 갓생OS dashboard
63
+ arete start
64
+
65
+ # Update framework only (config files protected)
66
+ arete update
67
+ ```
68
+
69
+ ## Update Safety
70
+
71
+ `arete update` only touches Layer 1 files (scripts, templates). Your personal configuration files (SOUL.md, AGENTS.md, MEMORY.md, USER.md, etc.) are never modified during updates.
72
+
73
+ ## Requirements
74
+
75
+ - Node.js 18+
76
+ - Python 3.10+
77
+ - macOS or Linux
package/bin/arete.js ADDED
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env node
2
+
3
+ import chalk from 'chalk';
4
+ import { checkForUpdate, runUpdate } from '../lib/updater.js';
5
+ import { execSync } from 'child_process';
6
+ import { readFileSync, existsSync, readdirSync, statSync } from 'fs';
7
+ import { resolve, join } from 'path';
8
+ import { homedir } from 'os';
9
+
10
+ const command = process.argv[2];
11
+
12
+ async function cmdUpdate() {
13
+ console.log(chalk.blue('Checking for updates...'));
14
+ const result = await checkForUpdate();
15
+
16
+ if (!result.updateAvailable) {
17
+ console.log(chalk.green(`Already on latest version (${result.currentVersion})`));
18
+ return;
19
+ }
20
+
21
+ console.log(chalk.yellow(`Update available: ${result.currentVersion} → ${result.latestVersion}`));
22
+ console.log('');
23
+
24
+ await runUpdate(result.latestVersion);
25
+ console.log(chalk.green('Update complete!'));
26
+ }
27
+
28
+ function cmdStatus() {
29
+ console.log(chalk.bold('ARETE Status'));
30
+ console.log('');
31
+
32
+ // OpenClaw running?
33
+ let openclawRunning = false;
34
+ try {
35
+ const out = execSync('openclaw status', { stdio: 'pipe', timeout: 5000 }).toString();
36
+ openclawRunning = out.toLowerCase().includes('running');
37
+ console.log(` OpenClaw: ${openclawRunning ? chalk.green('running') : chalk.yellow('stopped')}`);
38
+ } catch {
39
+ console.log(` OpenClaw: ${chalk.red('not detected')}`);
40
+ }
41
+
42
+ // Workspace path
43
+ const workspacePath = resolve(homedir(), '.openclaw', 'workspace');
44
+ if (existsSync(workspacePath)) {
45
+ console.log(` Workspace: ${chalk.dim(workspacePath)}`);
46
+ } else {
47
+ console.log(` Workspace: ${chalk.red('not found')}`);
48
+ return;
49
+ }
50
+
51
+ // Agent count
52
+ const agentsDir = resolve(homedir(), '.openclaw', 'agents');
53
+ if (existsSync(agentsDir)) {
54
+ try {
55
+ const agents = readdirSync(agentsDir).filter((f) =>
56
+ statSync(join(agentsDir, f)).isDirectory()
57
+ );
58
+ console.log(` Agents: ${chalk.bold(agents.length)}`);
59
+ } catch {
60
+ console.log(` Agents: ${chalk.dim('unknown')}`);
61
+ }
62
+ }
63
+
64
+ // Last memory update
65
+ const memoryDir = resolve(workspacePath, 'memory');
66
+ if (existsSync(memoryDir)) {
67
+ try {
68
+ const files = readdirSync(memoryDir)
69
+ .filter((f) => f.endsWith('.md') && !f.startsWith('.'))
70
+ .sort()
71
+ .reverse();
72
+ if (files.length > 0) {
73
+ console.log(` Last memory: ${chalk.dim(files[0])}`);
74
+ }
75
+ } catch {
76
+ console.log(` Last memory: ${chalk.dim('unknown')}`);
77
+ }
78
+ }
79
+
80
+ // Package version
81
+ try {
82
+ const pkg = JSON.parse(
83
+ readFileSync(new URL('../package.json', import.meta.url), 'utf-8')
84
+ );
85
+ console.log(` Version: ${chalk.dim(pkg.version)}`);
86
+ } catch {}
87
+
88
+ console.log('');
89
+ }
90
+
91
+ function cmdStart() {
92
+ const workspacePath = resolve(homedir(), '.openclaw', 'workspace');
93
+ const gatsaengDir = join(workspacePath, 'gatsaeng-os');
94
+
95
+ if (!existsSync(gatsaengDir)) {
96
+ console.log(chalk.red('갓생OS not found. Run create-arete-workspace with 갓생OS enabled.'));
97
+ process.exit(1);
98
+ }
99
+
100
+ const pkgJson = join(gatsaengDir, 'package.json');
101
+ if (!existsSync(pkgJson)) {
102
+ console.log(chalk.red('갓생OS package.json not found.'));
103
+ process.exit(1);
104
+ }
105
+
106
+ // Check if node_modules exists, install if not
107
+ if (!existsSync(join(gatsaengDir, 'node_modules'))) {
108
+ console.log(chalk.blue('Installing 갓생OS dependencies...'));
109
+ try {
110
+ execSync('npm install', { cwd: gatsaengDir, stdio: 'inherit' });
111
+ } catch {
112
+ console.log(chalk.red('Failed to install dependencies.'));
113
+ process.exit(1);
114
+ }
115
+ }
116
+
117
+ console.log(chalk.green('Starting 갓생OS...'));
118
+ console.log(chalk.dim(` ${gatsaengDir}`));
119
+ console.log('');
120
+
121
+ try {
122
+ execSync('npm run dev', { cwd: gatsaengDir, stdio: 'inherit' });
123
+ } catch {
124
+ // User ctrl-c — normal exit
125
+ }
126
+ }
127
+
128
+ function showHelp() {
129
+ console.log('');
130
+ console.log(chalk.bold(' arete') + ' — ARETE workspace manager');
131
+ console.log('');
132
+ console.log(' Commands:');
133
+ console.log(' start Launch 갓생OS dashboard');
134
+ console.log(' update Update framework files (Layer 1 only)');
135
+ console.log(' status Show workspace status');
136
+ console.log(' help Show this help');
137
+ console.log('');
138
+ }
139
+
140
+ switch (command) {
141
+ case 'start':
142
+ cmdStart();
143
+ break;
144
+ case 'update':
145
+ cmdUpdate().catch((e) => {
146
+ console.error(chalk.red('Update failed: ' + e.message));
147
+ process.exit(1);
148
+ });
149
+ break;
150
+ case 'status':
151
+ cmdStatus();
152
+ break;
153
+ default:
154
+ showHelp();
155
+ break;
156
+ }
package/bin/create.js ADDED
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, resolve } from 'path';
5
+ import chalk from 'chalk';
6
+ import { checkEnvironment } from '../lib/install-openclaw.js';
7
+ import { runWizard } from '../lib/setup-wizard.js';
8
+ import { scaffold } from '../lib/scaffold.js';
9
+ import { execSync } from 'child_process';
10
+
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+ const ROOT = resolve(__dirname, '..');
14
+
15
+ const DRY_RUN = process.argv.includes('--dry-run');
16
+
17
+ async function main() {
18
+ console.log('');
19
+ console.log(chalk.bold(' ARETE Workspace Setup'));
20
+ console.log(chalk.dim(' AI Operating System in 5 minutes'));
21
+ console.log('');
22
+
23
+ // Step 1: Environment check
24
+ console.log(chalk.blue('[1/5]') + ' Checking environment...');
25
+ const envOk = await checkEnvironment({ dryRun: DRY_RUN });
26
+ if (!envOk) {
27
+ process.exit(1);
28
+ }
29
+ console.log(chalk.green(' Environment OK'));
30
+ console.log('');
31
+
32
+ // Step 2: OpenClaw check
33
+ console.log(chalk.blue('[2/5]') + ' Checking OpenClaw...');
34
+ let openclawInstalled = false;
35
+ try {
36
+ execSync('openclaw --version', { stdio: 'pipe' });
37
+ openclawInstalled = true;
38
+ console.log(chalk.green(' OpenClaw found'));
39
+ } catch {
40
+ openclawInstalled = false;
41
+ }
42
+
43
+ if (!openclawInstalled) {
44
+ const { default: inquirer } = await import('inquirer');
45
+ const { install } = await inquirer.prompt([
46
+ {
47
+ type: 'confirm',
48
+ name: 'install',
49
+ message: 'OpenClaw not found. Install now?',
50
+ default: true,
51
+ },
52
+ ]);
53
+ if (install) {
54
+ if (DRY_RUN) {
55
+ console.log(chalk.yellow(' [dry-run] Would run: npm install -g openclaw'));
56
+ } else {
57
+ console.log(' Installing OpenClaw...');
58
+ try {
59
+ execSync('npm install -g openclaw', { stdio: 'inherit' });
60
+ console.log(chalk.green(' OpenClaw installed'));
61
+ } catch (e) {
62
+ console.log(chalk.red(' Failed to install OpenClaw.'));
63
+ console.log(chalk.dim(' Try manually: npm install -g openclaw'));
64
+ process.exit(1);
65
+ }
66
+ }
67
+ } else {
68
+ console.log(chalk.red(' OpenClaw is required. Exiting.'));
69
+ process.exit(1);
70
+ }
71
+ }
72
+ console.log('');
73
+
74
+ // Step 3: Interactive wizard
75
+ console.log(chalk.blue('[3/5]') + ' Configuration...');
76
+ const config = await runWizard({ dryRun: DRY_RUN });
77
+ console.log('');
78
+
79
+ // Step 4: Scaffold workspace
80
+ console.log(chalk.blue('[4/5]') + ' Creating workspace...');
81
+ await scaffold({ config, templateDir: resolve(ROOT, 'templates'), dryRun: DRY_RUN });
82
+ console.log(chalk.green(' Workspace created at ' + config.workspacePath));
83
+ console.log('');
84
+
85
+ // Step 5: openclaw init
86
+ console.log(chalk.blue('[5/5]') + ' Registering with OpenClaw...');
87
+ if (DRY_RUN) {
88
+ console.log(chalk.yellow(' [dry-run] Would run: openclaw init in ' + config.workspacePath));
89
+ } else {
90
+ try {
91
+ execSync('openclaw init', { cwd: config.workspacePath, stdio: 'inherit' });
92
+ } catch {
93
+ console.log(chalk.yellow(' openclaw init skipped (may need manual setup)'));
94
+ }
95
+ }
96
+
97
+ // Done
98
+ console.log('');
99
+ console.log(chalk.green.bold(' ARETE workspace setup complete!'));
100
+ console.log('');
101
+ console.log(' Next steps:');
102
+ console.log(` 1. Find your bot on Telegram and send ${chalk.bold('/start')}`);
103
+ console.log(` 2. Run ${chalk.bold('openclaw start')}`);
104
+ console.log(' 3. Send your first message');
105
+ console.log('');
106
+ }
107
+
108
+ main().catch((err) => {
109
+ console.error(chalk.red('Error: ' + err.message));
110
+ process.exit(1);
111
+ });
@@ -0,0 +1,50 @@
1
+ import { execSync } from 'child_process';
2
+ import chalk from 'chalk';
3
+
4
+ export async function checkEnvironment({ dryRun = false } = {}) {
5
+ const errors = [];
6
+
7
+ // OS check
8
+ const platform = process.platform;
9
+ if (platform !== 'darwin' && platform !== 'linux') {
10
+ errors.push(`Unsupported OS: ${platform}. ARETE requires macOS or Linux.`);
11
+ }
12
+
13
+ // Node.js 18+
14
+ const nodeVersion = process.versions.node;
15
+ const major = parseInt(nodeVersion.split('.')[0], 10);
16
+ if (major < 18) {
17
+ errors.push(`Node.js ${nodeVersion} detected. ARETE requires Node.js 18+.`);
18
+ console.log(chalk.dim(' Install: https://nodejs.org/'));
19
+ } else {
20
+ console.log(chalk.dim(` Node.js ${nodeVersion}`));
21
+ }
22
+
23
+ // Python 3.10+
24
+ try {
25
+ const pyVersion = execSync('python3 --version', { stdio: 'pipe' }).toString().trim();
26
+ const match = pyVersion.match(/Python (\d+)\.(\d+)/);
27
+ if (match) {
28
+ const pyMajor = parseInt(match[1], 10);
29
+ const pyMinor = parseInt(match[2], 10);
30
+ if (pyMajor < 3 || (pyMajor === 3 && pyMinor < 10)) {
31
+ errors.push(`${pyVersion} detected. ARETE requires Python 3.10+.`);
32
+ } else {
33
+ console.log(chalk.dim(` ${pyVersion}`));
34
+ }
35
+ }
36
+ } catch {
37
+ errors.push('Python 3 not found. ARETE requires Python 3.10+.');
38
+ console.log(chalk.dim(' Install: https://www.python.org/downloads/'));
39
+ }
40
+
41
+ if (errors.length > 0) {
42
+ console.log('');
43
+ for (const err of errors) {
44
+ console.log(chalk.red(' ' + err));
45
+ }
46
+ return false;
47
+ }
48
+
49
+ return true;
50
+ }
@@ -0,0 +1,213 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync, cpSync } from 'fs';
2
+ import { resolve, join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import chalk from 'chalk';
5
+
6
+ function replaceVars(content, vars) {
7
+ let result = content;
8
+ for (const [key, value] of Object.entries(vars)) {
9
+ result = result.replaceAll(`{{${key}}}`, value);
10
+ }
11
+ return result;
12
+ }
13
+
14
+ function generateDomainAgentsTable(domains) {
15
+ if (!domains || domains.length === 0) return '(No domain agents configured)';
16
+ const rows = domains.map(
17
+ (d) => `| ${d} | ${d}-analyst sub-agent spawn |`
18
+ );
19
+ return `| Domain | Routing |\n|--------|--------|\n${rows.join('\n')}`;
20
+ }
21
+
22
+ function generateDomainAgentsConfig(domains) {
23
+ if (!domains || domains.length === 0) return '{}';
24
+ const config = {};
25
+ for (const d of domains) {
26
+ config[`${d}-analyst`] = { tag: d.charAt(0).toUpperCase() + d.slice(1), emoji: '📊' };
27
+ }
28
+ return JSON.stringify(config, null, 4);
29
+ }
30
+
31
+ export async function scaffold({ config, templateDir, dryRun = false }) {
32
+ const { name, telegramToken, agentName, domains, workspacePath, openclawPath } = config;
33
+
34
+ const vars = {
35
+ NAME: name,
36
+ AGENT_NAME: agentName,
37
+ TELEGRAM_TOKEN: telegramToken,
38
+ WORKSPACE_PATH: workspacePath,
39
+ OPENCLAW_PATH: openclawPath,
40
+ DOMAINS: domains.join(', '),
41
+ DOMAIN_AGENTS_TABLE: generateDomainAgentsTable(domains),
42
+ DOMAIN_AGENTS_CONFIG: generateDomainAgentsConfig(domains),
43
+ };
44
+
45
+ // Create workspace directories
46
+ const dirs = [
47
+ workspacePath,
48
+ join(workspacePath, 'memory'),
49
+ join(workspacePath, 'scripts'),
50
+ join(workspacePath, 'data'),
51
+ join(workspacePath, 'data', 'traces'),
52
+ join(workspacePath, 'ref'),
53
+ ];
54
+
55
+ for (const dir of dirs) {
56
+ if (dryRun) {
57
+ console.log(chalk.yellow(` [dry-run] Would create dir: ${dir}`));
58
+ } else {
59
+ mkdirSync(dir, { recursive: true });
60
+ }
61
+ }
62
+
63
+ // Process workspace templates
64
+ const wsTemplateDir = join(templateDir, 'workspace');
65
+ if (existsSync(wsTemplateDir)) {
66
+ const templates = readdirSync(wsTemplateDir).filter((f) => f.endsWith('.tmpl'));
67
+ for (const tmpl of templates) {
68
+ const outputName = tmpl.replace('.tmpl', '');
69
+ const outputPath = join(workspacePath, outputName);
70
+ const content = readFileSync(join(wsTemplateDir, tmpl), 'utf-8');
71
+ const rendered = replaceVars(content, vars);
72
+
73
+ if (dryRun) {
74
+ console.log(chalk.yellow(` [dry-run] Would write: ${outputPath}`));
75
+ } else {
76
+ writeFileSync(outputPath, rendered, 'utf-8');
77
+ console.log(chalk.dim(` Created: ${outputName}`));
78
+ }
79
+ }
80
+ }
81
+
82
+ // Process script templates
83
+ const scriptTemplateDir = join(templateDir, 'scripts');
84
+ if (existsSync(scriptTemplateDir)) {
85
+ const scripts = readdirSync(scriptTemplateDir).filter((f) => f.endsWith('.tmpl'));
86
+ for (const tmpl of scripts) {
87
+ const outputName = tmpl.replace('.tmpl', '');
88
+ const outputPath = join(workspacePath, 'scripts', outputName);
89
+ const content = readFileSync(join(scriptTemplateDir, tmpl), 'utf-8');
90
+ const rendered = replaceVars(content, vars);
91
+
92
+ if (dryRun) {
93
+ console.log(chalk.yellow(` [dry-run] Would write: ${outputPath}`));
94
+ } else {
95
+ writeFileSync(outputPath, rendered, 'utf-8');
96
+ console.log(chalk.dim(` Created: scripts/${outputName}`));
97
+ }
98
+ }
99
+ }
100
+
101
+ // Create .env template
102
+ const envPath = join(workspacePath, '.env.example');
103
+ const envContent = `# ARETE Workspace Environment
104
+ # Copy to .env and fill in your values
105
+ TELEGRAM_BOT_TOKEN=your_token_here
106
+ OPENAI_API_KEY=
107
+ ANTHROPIC_API_KEY=
108
+ `;
109
+
110
+ if (dryRun) {
111
+ console.log(chalk.yellow(` [dry-run] Would write: ${envPath}`));
112
+ } else {
113
+ writeFileSync(envPath, envContent, 'utf-8');
114
+ console.log(chalk.dim(' Created: .env.example'));
115
+ }
116
+
117
+ // Create .gitignore
118
+ const gitignorePath = join(workspacePath, '.gitignore');
119
+ const gitignoreContent = `.env
120
+ .env.*
121
+ !.env.example
122
+ node_modules/
123
+ __pycache__/
124
+ *.pyc
125
+ .session_indexer_state.json
126
+ `;
127
+
128
+ if (dryRun) {
129
+ console.log(chalk.yellow(` [dry-run] Would write: ${gitignorePath}`));
130
+ } else {
131
+ writeFileSync(gitignorePath, gitignoreContent, 'utf-8');
132
+ console.log(chalk.dim(' Created: .gitignore'));
133
+ }
134
+
135
+ // 갓생OS scaffold
136
+ if (config.gatsaeng) {
137
+ await scaffoldGatsaeng({ config, dryRun });
138
+ }
139
+ }
140
+
141
+ export async function scaffoldGatsaeng({ config, dryRun = false }) {
142
+ const { workspacePath, vaultPath } = config;
143
+ const gatsaengDir = join(workspacePath, 'gatsaeng-os');
144
+
145
+ const __filename = fileURLToPath(import.meta.url);
146
+ const pkgRoot = resolve(dirname(__filename), '..');
147
+ const srcDir = join(pkgRoot, 'packages', 'gatsaeng-os');
148
+
149
+ if (!existsSync(srcDir)) {
150
+ console.log(chalk.red(' 갓생OS source not found in package. Skipping.'));
151
+ return;
152
+ }
153
+
154
+ console.log(chalk.blue(' Setting up 갓생OS...'));
155
+
156
+ if (dryRun) {
157
+ console.log(chalk.yellow(` [dry-run] Would copy 갓생OS to: ${gatsaengDir}`));
158
+ console.log(chalk.yellow(` [dry-run] VAULT_PATH = ${vaultPath}`));
159
+ console.log(chalk.yellow(` [dry-run] Would create Obsidian vault dirs in: ${vaultPath}`));
160
+ console.log(chalk.yellow(' [dry-run] Would run: npm install in gatsaeng-os/'));
161
+ return;
162
+ }
163
+
164
+ // Copy 갓생OS source
165
+ cpSync(srcDir, gatsaengDir, { recursive: true });
166
+ console.log(chalk.dim(' Copied 갓생OS source'));
167
+
168
+ // Create .env with VAULT_PATH
169
+ const envContent = `# 갓생OS Environment
170
+ VAULT_PATH=${vaultPath}
171
+ AUTH_USERNAME=admin
172
+ AUTH_PASSWORD=changeme
173
+ JWT_SECRET=${generateSecret()}
174
+ `;
175
+ writeFileSync(join(gatsaengDir, '.env'), envContent, 'utf-8');
176
+ console.log(chalk.dim(' Created gatsaeng-os/.env'));
177
+
178
+ // Create Obsidian vault directories
179
+ const vaultDirs = [
180
+ vaultPath,
181
+ join(vaultPath, 'areas'),
182
+ join(vaultPath, 'goals'),
183
+ join(vaultPath, 'milestones'),
184
+ join(vaultPath, 'projects'),
185
+ join(vaultPath, 'tasks'),
186
+ join(vaultPath, 'routines'),
187
+ join(vaultPath, 'reviews'),
188
+ join(vaultPath, 'sessions'),
189
+ join(vaultPath, 'timing'),
190
+ join(vaultPath, 'books'),
191
+ join(vaultPath, 'calendar'),
192
+ join(vaultPath, 'notes'),
193
+ join(vaultPath, 'logs', 'routine'),
194
+ join(vaultPath, 'logs', 'energy'),
195
+ join(vaultPath, 'logs', 'focus'),
196
+ ];
197
+
198
+ for (const dir of vaultDirs) {
199
+ mkdirSync(dir, { recursive: true });
200
+ }
201
+ console.log(chalk.dim(` Created Obsidian vault dirs at ${vaultPath}`));
202
+
203
+ console.log(chalk.green(' 갓생OS ready — run `arete start` to launch'));
204
+ }
205
+
206
+ function generateSecret() {
207
+ const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
208
+ let result = '';
209
+ for (let i = 0; i < 48; i++) {
210
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
211
+ }
212
+ return result;
213
+ }
@@ -0,0 +1,88 @@
1
+ import { resolve } from 'path';
2
+ import { homedir } from 'os';
3
+
4
+ export async function runWizard({ dryRun = false } = {}) {
5
+ if (dryRun) {
6
+ return {
7
+ name: 'TestUser',
8
+ telegramToken: 'dry-run-token',
9
+ agentName: 'Eve',
10
+ domains: ['invest', 'design'],
11
+ workspacePath: resolve(homedir(), 'arete-workspace'),
12
+ openclawPath: resolve(homedir(), '.openclaw'),
13
+ gatsaeng: true,
14
+ vaultPath: resolve(homedir(), 'Documents', 'Obsidian', 'GatsaengOS'),
15
+ };
16
+ }
17
+
18
+ const { default: inquirer } = await import('inquirer');
19
+
20
+ const answers = await inquirer.prompt([
21
+ {
22
+ type: 'input',
23
+ name: 'name',
24
+ message: 'Your name (English):',
25
+ validate: (v) => (v.trim().length > 0 ? true : 'Name is required'),
26
+ },
27
+ {
28
+ type: 'input',
29
+ name: 'telegramToken',
30
+ message: 'Telegram bot token:',
31
+ validate: (v) => (v.trim().length > 0 ? true : 'Token is required'),
32
+ },
33
+ {
34
+ type: 'input',
35
+ name: 'agentName',
36
+ message: 'Assistant name (default: Eve):',
37
+ default: 'Eve',
38
+ },
39
+ {
40
+ type: 'input',
41
+ name: 'domainsRaw',
42
+ message: 'Primary domains (comma-separated, e.g. invest, design, marketing):',
43
+ default: 'general',
44
+ },
45
+ {
46
+ type: 'input',
47
+ name: 'workspacePath',
48
+ message: `Workspace path (default: ${resolve(homedir(), 'arete-workspace')}):`,
49
+ default: resolve(homedir(), 'arete-workspace'),
50
+ },
51
+ {
52
+ type: 'confirm',
53
+ name: 'gatsaeng',
54
+ message: 'Install 갓생OS? (neuroscience-based habit & productivity dashboard)',
55
+ default: true,
56
+ },
57
+ ]);
58
+
59
+ let vaultPath = '';
60
+ if (answers.gatsaeng) {
61
+ const vaultAnswer = await inquirer.prompt([
62
+ {
63
+ type: 'input',
64
+ name: 'vaultPath',
65
+ message: 'Obsidian vault path for 갓생OS data:',
66
+ default: resolve(homedir(), 'Documents', 'Obsidian', 'GatsaengOS'),
67
+ validate: (v) => (v.trim().length > 0 ? true : 'Vault path is required for 갓생OS'),
68
+ },
69
+ ]);
70
+ vaultPath = resolve(vaultAnswer.vaultPath);
71
+ }
72
+
73
+ const domains = answers.domainsRaw
74
+ .split(',')
75
+ .map((d) => d.trim().toLowerCase())
76
+ .filter(Boolean);
77
+
78
+ return {
79
+ name: answers.name.trim(),
80
+ telegramToken: answers.telegramToken.trim(),
81
+ agentName: answers.agentName.trim(),
82
+ domains,
83
+ workspacePath: resolve(answers.workspacePath),
84
+ openclawPath: resolve(homedir(), '.openclaw'),
85
+ gatsaeng: answers.gatsaeng,
86
+ vaultPath,
87
+ };
88
+ }