agentstudio 0.1.0 → 0.1.2

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 (162) hide show
  1. package/.cc-sessions/ppt-editor/session_1756253549429_uau1hm6lh.json +665 -0
  2. package/.cc-sessions/ppt-editor/session_1756257240855_v0wa26mde.json +394 -0
  3. package/README.md +39 -41
  4. package/dist/bin/agentstudio.js +4 -27
  5. package/dist/bin/agentstudio.js.map +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +121 -52
  9. package/dist/index.js.map +1 -1
  10. package/dist/routes/agents.d.ts.map +1 -1
  11. package/dist/routes/agents.js +18 -19
  12. package/dist/routes/agents.js.map +1 -1
  13. package/dist/routes/commands.d.ts +4 -0
  14. package/dist/routes/commands.d.ts.map +1 -0
  15. package/dist/routes/commands.js +395 -0
  16. package/dist/routes/commands.js.map +1 -0
  17. package/dist/routes/projects.d.ts +4 -0
  18. package/dist/routes/projects.d.ts.map +1 -0
  19. package/dist/routes/projects.js +528 -0
  20. package/dist/routes/projects.js.map +1 -0
  21. package/dist/routes/sessions.d.ts +4 -0
  22. package/dist/routes/sessions.d.ts.map +1 -0
  23. package/dist/routes/sessions.js +733 -0
  24. package/dist/routes/sessions.js.map +1 -0
  25. package/dist/routes/settings.d.ts +4 -0
  26. package/dist/routes/settings.d.ts.map +1 -0
  27. package/dist/routes/settings.js +658 -0
  28. package/dist/routes/settings.js.map +1 -0
  29. package/dist/routes/subagents.d.ts +4 -0
  30. package/dist/routes/subagents.d.ts.map +1 -0
  31. package/dist/routes/subagents.js +326 -0
  32. package/dist/routes/subagents.js.map +1 -0
  33. package/docs/chat-clean-1.svg +1 -0
  34. package/docs/chat-clean.md +60 -0
  35. package/docs/chat-comprehensive-1.svg +1 -0
  36. package/docs/chat-comprehensive.md +166 -0
  37. package/docs/chat_api_sequence_diagram.md +58 -0
  38. package/docs/command-detection-logic.md +306 -0
  39. package/docs/command-detection-sequence.md +186 -0
  40. package/frontend/dist/assets/AgentsPage-Dqb_aqAA.js +1 -0
  41. package/frontend/dist/assets/ChatPage-BvQmXfcP.css +1 -0
  42. package/frontend/dist/assets/ChatPage-L8Paywyc.js +91 -0
  43. package/frontend/dist/assets/CommandForm-DLl7EIMS.js +7 -0
  44. package/frontend/dist/assets/CommandsPage-Bzavq0Ec.js +1 -0
  45. package/frontend/dist/assets/DashboardPage-B3o4AYFT.js +15 -0
  46. package/frontend/dist/assets/FileBrowser-DL3ayaqb.js +1 -0
  47. package/frontend/dist/assets/GeneralSettingsPage-CBN_de-V.js +1 -0
  48. package/frontend/dist/assets/LandingPage-Dl4ioKos.js +1 -0
  49. package/frontend/dist/assets/LoginPage-4QqRdiSi.js +12 -0
  50. package/frontend/dist/assets/McpPage-CY3tYiqj.js +39 -0
  51. package/frontend/dist/assets/MemorySettingsPage-DGxrok5K.js +1 -0
  52. package/frontend/dist/assets/ProjectSelector-hgmGYVFh.js +1 -0
  53. package/frontend/dist/assets/ProjectsPage-D399IM0c.js +14 -0
  54. package/frontend/dist/assets/SettingsLayout-CL_K-lzJ.js +1 -0
  55. package/frontend/dist/assets/SubagentForm-DXtTTIKg.js +7 -0
  56. package/frontend/dist/assets/SubagentsPage-Chbhj8p2.js +1 -0
  57. package/frontend/dist/assets/ToastTestPage-DT4wuN5C.js +1 -0
  58. package/frontend/dist/assets/UnifiedToolSelector-CsM9qBvs.js +1 -0
  59. package/frontend/dist/assets/VersionSettingsPage-74Q-LVgA.js +5 -0
  60. package/frontend/dist/assets/agents-ClAzIJTw.js +1 -0
  61. package/frontend/dist/assets/agents-DwCY2K8p.css +1 -0
  62. package/frontend/dist/assets/authFetch-BATQyPG5.js +1 -0
  63. package/frontend/dist/assets/data-structures-DLJedtzx.js +27 -0
  64. package/frontend/dist/assets/dateFormat-CXa8VnEC.js +1 -0
  65. package/frontend/dist/assets/index-B9YHa7XT.css +1 -0
  66. package/frontend/dist/assets/index-B_CTNvca.js +268 -0
  67. package/frontend/dist/assets/monaco-editor-C7Z4sOhS.js +19 -0
  68. package/frontend/dist/assets/syntax-highlighting-YWvMU4Hm.js +24 -0
  69. package/frontend/dist/assets/tabManager-DV8urRBM.js +30 -0
  70. package/frontend/dist/assets/table-D6q1rytw.js +1 -0
  71. package/frontend/dist/assets/tools-C4EPanYi.js +1 -0
  72. package/frontend/dist/assets/ui-components-Cw21Epuw.js +481 -0
  73. package/frontend/dist/assets/useAgents-DwnOE1_k.js +2 -0
  74. package/frontend/dist/assets/useClaudeVersions-CQdGnCqv.js +1 -0
  75. package/frontend/dist/assets/useCommands-CCVaurbt.js +1 -0
  76. package/frontend/dist/cc-studio.png +0 -0
  77. package/frontend/dist/index.html +68 -84
  78. package/frontend/dist/vite.svg +1 -0
  79. package/package.json +26 -27
  80. package/scripts/README.md +76 -0
  81. package/scripts/fix-project-names.js +113 -0
  82. package/scripts/migrate-projects.js +159 -0
  83. package/shared/index.d.ts +6 -0
  84. package/shared/index.d.ts.map +1 -0
  85. package/shared/index.js +7 -0
  86. package/{dist/types/index.d.ts → shared/types/agents.d.ts} +1 -2
  87. package/shared/types/agents.d.ts.map +1 -0
  88. package/{dist/types/index.js → shared/types/agents.js} +3 -8
  89. package/shared/types/claude-history.d.ts +61 -0
  90. package/shared/types/claude-history.d.ts.map +1 -0
  91. package/shared/types/claude-history.js +2 -0
  92. package/shared/types/claude-versions.d.ts +40 -0
  93. package/shared/types/claude-versions.d.ts.map +1 -0
  94. package/shared/types/claude-versions.js +1 -0
  95. package/shared/types/commands.d.ts +48 -0
  96. package/shared/types/commands.d.ts.map +1 -0
  97. package/shared/types/commands.js +19 -0
  98. package/shared/types/projects.d.ts +35 -0
  99. package/shared/types/projects.d.ts.map +1 -0
  100. package/shared/types/projects.js +2 -0
  101. package/shared/types/subagents.d.ts +26 -0
  102. package/shared/types/subagents.d.ts.map +1 -0
  103. package/shared/types/subagents.js +1 -0
  104. package/shared/utils/agentStorage.d.ts +27 -0
  105. package/shared/utils/agentStorage.d.ts.map +1 -0
  106. package/shared/utils/agentStorage.js +392 -0
  107. package/shared/utils/claudeVersionStorage.d.ts +16 -0
  108. package/shared/utils/claudeVersionStorage.d.ts.map +1 -0
  109. package/shared/utils/claudeVersionStorage.js +230 -0
  110. package/shared/utils/projectMetadataStorage.d.ts +94 -0
  111. package/shared/utils/projectMetadataStorage.d.ts.map +1 -0
  112. package/shared/utils/projectMetadataStorage.js +422 -0
  113. package/shared/utils/toolMapping.d.ts +56 -0
  114. package/shared/utils/toolMapping.d.ts.map +1 -0
  115. package/shared/utils/toolMapping.js +71 -0
  116. package/src/bin/agentstudio.ts +90 -121
  117. package/src/index.ts +139 -57
  118. package/src/routes/agents.ts +28 -29
  119. package/src/routes/{commands.ts.bak → commands.ts} +1 -1
  120. package/src/routes/{projects.ts.bak → projects.ts} +3 -3
  121. package/src/routes/{sessions.ts.bak → sessions.ts} +2 -2
  122. package/src/routes/{settings.ts.bak → settings.ts} +11 -11
  123. package/src/routes/{subagents.ts.bak → subagents.ts} +1 -1
  124. package/tsconfig.json +13 -12
  125. package/dist/types/claude-history.d.ts +0 -48
  126. package/dist/types/claude-history.d.ts.map +0 -1
  127. package/dist/types/claude-history.js +0 -2
  128. package/dist/types/claude-history.js.map +0 -1
  129. package/dist/types/claude-versions.d.ts +0 -31
  130. package/dist/types/claude-versions.d.ts.map +0 -1
  131. package/dist/types/claude-versions.js +0 -2
  132. package/dist/types/claude-versions.js.map +0 -1
  133. package/dist/types/commands.d.ts +0 -32
  134. package/dist/types/commands.d.ts.map +0 -1
  135. package/dist/types/commands.js +0 -2
  136. package/dist/types/commands.js.map +0 -1
  137. package/dist/types/index.d.ts.map +0 -1
  138. package/dist/types/index.js.map +0 -1
  139. package/dist/types/subagents.d.ts +0 -88
  140. package/dist/types/subagents.d.ts.map +0 -1
  141. package/dist/types/subagents.js +0 -2
  142. package/dist/types/subagents.js.map +0 -1
  143. package/dist/utils/agentStorage.d.ts +0 -19
  144. package/dist/utils/agentStorage.d.ts.map +0 -1
  145. package/dist/utils/agentStorage.js +0 -110
  146. package/dist/utils/agentStorage.js.map +0 -1
  147. package/dist/utils/claudeVersionStorage.d.ts +0 -33
  148. package/dist/utils/claudeVersionStorage.d.ts.map +0 -1
  149. package/dist/utils/claudeVersionStorage.js +0 -168
  150. package/dist/utils/claudeVersionStorage.js.map +0 -1
  151. package/dist/utils/projectMetadataStorage.d.ts +0 -21
  152. package/dist/utils/projectMetadataStorage.d.ts.map +0 -1
  153. package/dist/utils/projectMetadataStorage.js +0 -68
  154. package/dist/utils/projectMetadataStorage.js.map +0 -1
  155. package/src/types/claude-history.ts +0 -50
  156. package/src/types/claude-versions.ts +0 -33
  157. package/src/types/commands.ts +0 -35
  158. package/src/types/index.ts +0 -248
  159. package/src/types/subagents.ts +0 -106
  160. package/src/utils/agentStorage.ts +0 -126
  161. package/src/utils/claudeVersionStorage.ts +0 -199
  162. package/src/utils/projectMetadataStorage.ts +0 -86
@@ -1,8 +1,6 @@
1
1
  #!/usr/bin/env node
2
-
3
2
  import { program } from 'commander';
4
3
  import { startServer } from '../index.js';
5
- import { spawn } from 'child_process';
6
4
  import path from 'path';
7
5
  import { fileURLToPath } from 'url';
8
6
 
@@ -10,127 +8,98 @@ const __filename = fileURLToPath(import.meta.url);
10
8
  const __dirname = path.dirname(__filename);
11
9
 
12
10
  program
13
- .name('agentstudio')
14
- .description('AgentStudio - AI-powered presentation editor with Claude integration')
15
- .version('0.1.0');
11
+ .name('agentstudio')
12
+ .description('AgentStudio - AI-powered presentation editor with Claude integration')
13
+ .version('0.1.0');
16
14
 
17
15
  // Start both frontend and backend
18
16
  program
19
- .command('start')
20
- .description('Start both frontend and backend servers')
21
- .option('-p, --port <port>', 'backend server port', '4936')
22
- .option('-f, --frontend-port <port>', 'frontend server port', '3000')
23
- .option('-h, --host <host>', 'server host', 'localhost')
24
- .option('-c, --config <path>', 'path to config file')
25
- .option('--env <path>', 'path to .env file')
26
- .option('--no-auth', 'disable authentication (development only)')
27
- .action(async (options) => {
28
- console.log('🚀 Starting AgentStudio...');
29
-
30
- // Start backend
31
- process.env.PORT = options.port;
32
- process.env.HOST = options.host;
33
-
34
- if (options.env) {
35
- process.env.ENV_PATH = options.env;
36
- }
37
-
38
- if (options.config) {
39
- process.env.CONFIG_PATH = options.config;
40
- }
41
-
42
- if (options.noAuth) {
43
- process.env.NO_AUTH = 'true';
44
- }
45
-
46
- try {
47
- await startServer();
48
- console.log(`✅ Backend running on http://${options.host}:${options.port}`);
49
- console.log(`✅ Frontend running on http://${options.host}:${options.frontendPort}`);
50
- console.log('📖 Open your browser to http://localhost:3000 to start using AgentStudio');
51
- } catch (error) {
52
- console.error('❌ Failed to start AgentStudio:', error);
53
- process.exit(1);
54
- }
55
- });
17
+ .command('start')
18
+ .description('Start both frontend and backend servers')
19
+ .option('-p, --port <port>', 'backend server port', '4936')
20
+ .option('-f, --frontend-port <port>', 'frontend server port', '3000')
21
+ .option('-h, --host <host>', 'server host', 'localhost')
22
+ .option('-c, --config <path>', 'path to config file')
23
+ .option('--env <path>', 'path to .env file')
24
+ .option('--no-auth', 'disable authentication (development only)')
25
+ .action(async (options: any) => {
26
+ console.log('🚀 Starting AgentStudio...');
27
+
28
+ // Start backend
29
+ process.env.PORT = options.port;
30
+ process.env.HOST = options.host;
31
+
32
+ if (options.env) {
33
+ process.env.ENV_PATH = options.env;
34
+ }
35
+ if (options.config) {
36
+ process.env.CONFIG_PATH = options.config;
37
+ }
38
+ if (options.noAuth) {
39
+ process.env.NO_AUTH = 'true';
40
+ }
41
+
42
+ try {
43
+ // Start backend server
44
+ await startServer();
45
+ console.log(`✅ Backend running on http://${options.host}:${options.port}`);
46
+
47
+ // Serve frontend static files
48
+ console.log(`✅ Frontend available at http://${options.host}:${options.port}`);
49
+ console.log('📖 Open your browser to start using AgentStudio');
50
+ } catch (error) {
51
+ console.error('❌ Failed to start AgentStudio:', error);
52
+ process.exit(1);
53
+ }
54
+ });
56
55
 
57
56
  // Start backend only
58
57
  program
59
- .command('backend')
60
- .description('Start backend server only')
61
- .option('-p, --port <port>', 'server port', '4936')
62
- .option('-h, --host <host>', 'server host', 'localhost')
63
- .option('-c, --config <path>', 'path to config file')
64
- .option('--env <path>', 'path to .env file')
65
- .option('--no-auth', 'disable authentication (development only)')
66
- .action(async (options) => {
67
- console.log('🚀 Starting AgentStudio Backend...');
68
-
69
- process.env.PORT = options.port;
70
- process.env.HOST = options.host;
71
-
72
- if (options.env) {
73
- process.env.ENV_PATH = options.env;
74
- }
75
-
76
- if (options.config) {
77
- process.env.CONFIG_PATH = options.config;
78
- }
79
-
80
- if (options.noAuth) {
81
- process.env.NO_AUTH = 'true';
82
- }
83
-
84
- try {
85
- await startServer();
86
- console.log(`✅ Backend running on http://${options.host}:${options.port}`);
87
- } catch (error) {
88
- console.error('❌ Failed to start backend:', error);
89
- process.exit(1);
90
- }
91
- });
92
-
93
- // Start frontend only (development mode)
94
- program
95
- .command('frontend')
96
- .description('Start frontend development server only')
97
- .option('-p, --port <port>', 'frontend server port', '3000')
98
- .option('-h, --host <host>', 'server host', 'localhost')
99
- .action((options) => {
100
- console.log('🚀 Starting AgentStudio Frontend...');
101
-
102
- const frontendDir = path.join(__dirname, '../../frontend');
103
-
104
- const frontendProcess = spawn('npm', ['run', 'dev'], {
105
- cwd: frontendDir,
106
- stdio: 'inherit',
107
- shell: true,
108
- env: {
109
- ...process.env,
110
- PORT: options.port,
111
- HOST: options.host
112
- }
58
+ .command('backend')
59
+ .description('Start backend server only')
60
+ .option('-p, --port <port>', 'server port', '4936')
61
+ .option('-h, --host <host>', 'server host', 'localhost')
62
+ .option('-c, --config <path>', 'path to config file')
63
+ .option('--env <path>', 'path to .env file')
64
+ .option('--no-auth', 'disable authentication (development only)')
65
+ .action(async (options: any) => {
66
+ console.log('🚀 Starting AgentStudio Backend...');
67
+
68
+ process.env.PORT = options.port;
69
+ process.env.HOST = options.host;
70
+
71
+ if (options.env) {
72
+ process.env.ENV_PATH = options.env;
73
+ }
74
+ if (options.config) {
75
+ process.env.CONFIG_PATH = options.config;
76
+ }
77
+ if (options.noAuth) {
78
+ process.env.NO_AUTH = 'true';
79
+ }
80
+
81
+ try {
82
+ await startServer();
83
+ console.log(`✅ Backend running on http://${options.host}:${options.port}`);
84
+ } catch (error) {
85
+ console.error('❌ Failed to start backend:', error);
86
+ process.exit(1);
87
+ }
113
88
  });
114
89
 
115
- frontendProcess.on('error', (error) => {
116
- console.error('❌ Failed to start frontend:', error);
117
- process.exit(1);
118
- });
119
- });
120
-
121
90
  // Initialize configuration
122
91
  program
123
- .command('init')
124
- .description('Initialize AgentStudio configuration')
125
- .option('--env <path>', 'path to create .env file', '.env')
126
- .action(async (options) => {
127
- console.log('🔧 Initializing AgentStudio configuration...');
92
+ .command('init')
93
+ .description('Initialize AgentStudio configuration')
94
+ .option('--env <path>', 'path to create .env file', '.env')
95
+ .action(async (options: any) => {
96
+ console.log('🔧 Initializing AgentStudio configuration...');
128
97
 
129
- const fs = await import('fs-extra');
130
- const path = await import('path');
98
+ const fs = await import('fs-extra');
99
+ const path = await import('path');
131
100
 
132
- const envPath = path.default.resolve(options.env);
133
- const envContent = `# AgentStudio Configuration
101
+ const envPath = path.default.resolve(options.env);
102
+ const envContent = `# AgentStudio Configuration
134
103
  # AI Provider (choose one)
135
104
  OPENAI_API_KEY=your_openai_api_key_here
136
105
  ANTHROPIC_API_KEY=your_anthropic_api_key_here
@@ -147,15 +116,15 @@ SLIDES_DIR=./slides
147
116
  CORS_ORIGINS=https://your-frontend.vercel.app,https://custom-domain.com
148
117
  `;
149
118
 
150
- try {
151
- await fs.default.ensureFile(envPath);
152
- await fs.default.writeFile(envPath, envContent);
153
- console.log(`✅ Configuration file created: ${envPath}`);
154
- console.log('📝 Please edit the .env file with your API keys and settings');
155
- } catch (error) {
156
- console.error('❌ Failed to create configuration file:', error);
157
- process.exit(1);
158
- }
159
- });
119
+ try {
120
+ await fs.default.ensureFile(envPath);
121
+ await fs.default.writeFile(envPath, envContent);
122
+ console.log(`✅ Configuration file created: ${envPath}`);
123
+ console.log('📝 Please edit the .env file with your API keys and settings');
124
+ } catch (error) {
125
+ console.error('❌ Failed to create configuration file:', error);
126
+ process.exit(1);
127
+ }
128
+ });
160
129
 
161
130
  program.parse();
package/src/index.ts CHANGED
@@ -2,99 +2,181 @@ import express from 'express';
2
2
  import cors from 'cors';
3
3
  import helmet from 'helmet';
4
4
  import dotenv from 'dotenv';
5
- import path from 'path';
6
5
  import { fileURLToPath } from 'url';
6
+ import { dirname, join } from 'path';
7
7
 
8
- // Import routes
9
- import agentsRouter from './routes/agents.js';
10
- import authRouter from './routes/auth.js';
11
8
  import filesRouter from './routes/files.js';
9
+ import agentsRouter from './routes/agents.js';
12
10
  import mcpRouter from './routes/mcp.js';
11
+ import sessionsRouter from './routes/sessions.js';
13
12
  import mediaRouter from './routes/media.js';
14
- import slidesRouter from './routes/slides.js';
13
+ import settingsRouter from './routes/settings.js';
14
+ import commandsRouter from './routes/commands.js';
15
+ import subagentsRouter from './routes/subagents.js';
16
+ import projectsRouter from './routes/projects.js';
17
+ import authRouter from './routes/auth.js';
18
+ import { authMiddleware } from './middleware/auth.js';
15
19
 
16
- const __filename = fileURLToPath(import.meta.url);
17
- const __dirname = path.dirname(__filename);
20
+ dotenv.config();
18
21
 
19
- // Load environment variables
20
- const envPath = process.env.ENV_PATH || '.env';
21
- dotenv.config({ path: envPath });
22
+ const __filename = fileURLToPath(import.meta.url);
23
+ const __dirname = dirname(__filename);
22
24
 
23
25
  const app = express();
24
26
  const PORT = process.env.PORT || 4936;
25
- const HOST = process.env.HOST || 'localhost';
26
27
 
27
- // Security middleware
28
+ // Middleware
28
29
  app.use(helmet({
29
- crossOriginEmbedderPolicy: false,
30
30
  contentSecurityPolicy: {
31
31
  directives: {
32
32
  defaultSrc: ["'self'"],
33
33
  scriptSrc: ["'self'", "'unsafe-inline'"],
34
- styleSrc: ["'self'", "'unsafe-inline'"],
35
- imgSrc: ["'self'", "data:", "blob:"],
34
+ styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com", "https://cdn.jsdelivr.net"],
35
+ fontSrc: ["'self'", "https://fonts.gstatic.com", "https://cdn.jsdelivr.net"],
36
+ imgSrc: ["'self'", "data:", "https:"],
36
37
  connectSrc: ["'self'", "ws:", "wss:"],
37
- },
38
- },
38
+ frameAncestors: ["'self'", "http://localhost:3000", "https://localhost:3000", "http://localhost:3001"] // Allow iframe embedding
39
+ }
40
+ }
39
41
  }));
40
-
41
- // CORS configuration
42
- const corsOrigins = process.env.CORS_ORIGINS ?
43
- process.env.CORS_ORIGINS.split(',').map(origin => origin.trim()) :
44
- [
45
- 'http://localhost:3000',
46
- 'http://127.0.0.1:3000',
47
- 'https://*.vercel.app'
42
+ // Configure CORS origins
43
+ const getAllowedOrigins = () => {
44
+ const defaultOrigins = [
45
+ 'http://localhost:3000',
46
+ 'http://127.0.0.1:3000',
47
+ 'http://localhost:3001',
48
+ 'https://localhost:3000',
49
+ 'https://localhost:3001'
48
50
  ];
51
+
52
+ // Add custom origins from environment variable
53
+ const customOrigins = process.env.CORS_ORIGINS ?
54
+ process.env.CORS_ORIGINS.split(',').map(origin => origin.trim()) : [];
55
+
56
+ return [...defaultOrigins, ...customOrigins];
57
+ };
49
58
 
50
59
  app.use(cors({
51
- origin: corsOrigins,
52
- credentials: true
60
+ origin: (origin, callback) => {
61
+ const allowedOrigins = getAllowedOrigins();
62
+
63
+ // Allow requests with no origin (like mobile apps or curl requests)
64
+ if (!origin) return callback(null, true);
65
+
66
+ // Check if the origin is allowed
67
+ if (allowedOrigins.includes(origin)) {
68
+ return callback(null, true);
69
+ }
70
+
71
+ // Allow Vercel preview URLs (*.vercel.app)
72
+ if (origin.endsWith('.vercel.app')) {
73
+ return callback(null, true);
74
+ }
75
+
76
+ // Allow agentstudio.cc and its subdomains (*.agentstudio.cc) - hardcoded
77
+ if (origin === 'https://agentstudio.cc' || origin.endsWith('.agentstudio.cc')) {
78
+ return callback(null, true);
79
+ }
80
+
81
+ // Allow custom domains from environment variable (CORS_ALLOWED_DOMAINS)
82
+ const customDomains = process.env.CORS_ALLOWED_DOMAINS ?
83
+ process.env.CORS_ALLOWED_DOMAINS.split(',').map(domain => domain.trim()) : [];
84
+
85
+ for (const domain of customDomains) {
86
+ // Match exact domain (https://example.com)
87
+ if (origin === `https://${domain}` || origin === `http://${domain}`) {
88
+ return callback(null, true);
89
+ }
90
+ // Match subdomains (https://*.example.com)
91
+ if (origin.endsWith(`.${domain}`)) {
92
+ return callback(null, true);
93
+ }
94
+ }
95
+
96
+ // Allow any localhost with any port for development
97
+ if (origin.match(/^https?:\/\/localhost(:\d+)?$/)) {
98
+ return callback(null, true);
99
+ }
100
+
101
+ // Allow 127.0.0.1 with any port for development
102
+ if (origin.match(/^https?:\/\/127\.0\.0\.1(:\d+)?$/)) {
103
+ return callback(null, true);
104
+ }
105
+
106
+ const msg = `The CORS policy for this site does not allow access from the specified Origin: ${origin}`;
107
+ return callback(new Error(msg), false);
108
+ },
109
+ credentials: true,
110
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'],
111
+ allowedHeaders: ['Content-Type', 'Authorization', 'Cache-Control', 'X-Requested-With'],
112
+ exposedHeaders: ['Content-Range', 'X-Content-Range']
53
113
  }));
114
+ app.use(express.json({ limit: '10mb' }));
115
+ app.use(express.urlencoded({ extended: true, limit: '10mb' }));
54
116
 
55
- // Body parsing middleware
56
- app.use(express.json({ limit: '50mb' }));
57
- app.use(express.urlencoded({ extended: true, limit: '50mb' }));
117
+ // Static files - serve slides directory
118
+ const slidesDir = join(__dirname, '../..', process.env.SLIDES_DIR || 'slides');
119
+ app.use('/slides', express.static(slidesDir));
58
120
 
59
- // Serve static files
60
- const frontendDistPath = path.join(__dirname, '../frontend/dist');
61
- app.use(express.static(frontendDistPath));
121
+ // Serve frontend static files in production
122
+ const frontendDir = join(__dirname, '../frontend/dist');
123
+ if (process.env.NODE_ENV === 'production') {
124
+ app.use(express.static(frontendDir));
125
+
126
+ // Handle SPA routing - serve index.html for all other routes
127
+ app.get('*', (req, res) => {
128
+ res.sendFile(join(frontendDir, 'index.html'));
129
+ });
130
+ }
62
131
 
63
- // API routes
64
- app.use('/api/agents', agentsRouter);
132
+ // Routes - Public routes
65
133
  app.use('/api/auth', authRouter);
66
- app.use('/api/files', filesRouter);
67
- app.use('/api/mcp', mcpRouter);
68
- app.use('/api/media', mediaRouter);
69
- app.use('/api/slides', slidesRouter);
70
134
 
71
- // Health check endpoint
135
+ // Protected routes - Require authentication
136
+ app.use('/api/files', authMiddleware, filesRouter);
137
+ app.use('/api/agents', authMiddleware, agentsRouter);
138
+ app.use('/api/mcp', authMiddleware, mcpRouter);
139
+ app.use('/api/sessions', authMiddleware, sessionsRouter);
140
+ app.use('/api/settings', authMiddleware, settingsRouter);
141
+ app.use('/api/commands', authMiddleware, commandsRouter);
142
+ app.use('/api/subagents', authMiddleware, subagentsRouter);
143
+ app.use('/api/projects', authMiddleware, projectsRouter);
144
+ app.use('/media', authMiddleware, mediaRouter);
145
+
146
+ // Health check
72
147
  app.get('/api/health', (req, res) => {
73
- res.json({
74
- status: 'ok',
75
- timestamp: new Date().toISOString(),
76
- version: '0.1.0'
77
- });
148
+ res.json({ status: 'ok', timestamp: new Date().toISOString() });
78
149
  });
79
150
 
80
- // Serve frontend for all other routes (SPA routing)
81
- app.get('*', (req, res) => {
82
- res.sendFile(path.join(frontendDistPath, 'index.html'));
151
+ // Error handling
152
+ app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
153
+ console.error('Error:', err);
154
+ res.status(500).json({
155
+ error: 'Internal server error',
156
+ message: process.env.NODE_ENV === 'development' ? err.message : 'Something went wrong'
157
+ });
83
158
  });
84
159
 
85
- export function startServer(): Promise<void> {
86
- return new Promise((resolve) => {
87
- const port = parseInt(process.env.PORT || PORT.toString());
88
- const host = process.env.HOST || HOST;
89
- const server = app.listen(port, host, () => {
90
- console.log(`🚀 AgentStudio running on http://${host}:${port}`);
91
- console.log('📖 Open your browser to start using AgentStudio');
92
- resolve();
160
+ // 404 handler - only for API routes in production
161
+ if (process.env.NODE_ENV !== 'production') {
162
+ app.use('*', (req, res) => {
163
+ res.status(404).json({ error: 'Route not found' });
164
+ });
165
+ }
166
+
167
+ export function startServer() {
168
+ return new Promise((resolve, reject) => {
169
+ const server = app.listen(PORT, () => {
170
+ console.log(`AI PPT Editor backend running on http://localhost:${PORT}`);
171
+ console.log(`Serving slides from: ${slidesDir}`);
172
+ resolve(server);
93
173
  });
174
+
175
+ server.on('error', reject);
94
176
  });
95
177
  }
96
178
 
97
- // Only start server if this file is run directly
179
+ // Start server if this file is run directly
98
180
  if (import.meta.url === `file://${process.argv[1]}`) {
99
181
  startServer().catch(console.error);
100
182
  }
@@ -7,11 +7,11 @@ import { spawn } from 'child_process';
7
7
  import { exec } from 'child_process';
8
8
  import { promisify } from 'util';
9
9
  import { query, Options } from '@anthropic-ai/claude-code';
10
- import { AgentStorage } from '../utils/agentStorage.js';
11
- import { AgentConfig, BUILTIN_AGENTS } from '../types/index.js';
12
- import { ProjectMetadataStorage } from '../utils/projectMetadataStorage.js';
10
+ import { AgentStorage } from '@agentstudio/shared/utils/agentStorage';
11
+ import { AgentConfig } from '@agentstudio/shared/types/agents';
12
+ import { ProjectMetadataStorage } from '@agentstudio/shared/utils/projectMetadataStorage';
13
13
  import { sessionManager } from '../services/sessionManager.js';
14
- import { getAllVersions, getDefaultVersionId } from '../utils/claudeVersionStorage.js';
14
+ import { getAllVersions, getDefaultVersionId } from '@agentstudio/shared/utils/claudeVersionStorage';
15
15
 
16
16
  const router: express.Router = express.Router();
17
17
  const execAsync = promisify(exec);
@@ -31,6 +31,7 @@ const CreateAgentSchema = z.object({
31
31
  systemPrompt: z.string().min(1),
32
32
  maxTurns: z.number().min(1).max(100).optional().default(25),
33
33
  permissionMode: z.enum(['default', 'acceptEdits', 'bypassPermissions', 'plan']).optional().default('acceptEdits'),
34
+ model: z.string().min(1).optional().default('claude-3-5-sonnet-20241022'),
34
35
  allowedTools: z.array(z.object({
35
36
  name: z.string(),
36
37
  enabled: z.boolean(),
@@ -126,22 +127,22 @@ router.post('/sessions/:sessionId/interrupt', async (req, res) => {
126
127
  });
127
128
 
128
129
  // Get all agents
129
- router.get('/', async (req, res) => {
130
+ router.get('/', (req, res) => {
130
131
  try {
131
132
  const { enabled, type } = req.query;
132
- let agents = await globalAgentStorage.getAllAgents();
133
-
133
+ let agents = globalAgentStorage.getAllAgents();
134
+
134
135
  // Filter by enabled status
135
136
  if (enabled !== undefined) {
136
137
  const isEnabled = enabled === 'true';
137
138
  agents = agents.filter(agent => agent.enabled === isEnabled);
138
139
  }
139
-
140
+
140
141
  // Filter by component type
141
142
  if (type && typeof type === 'string') {
142
143
  agents = agents.filter(agent => agent.ui.componentType === type);
143
144
  }
144
-
145
+
145
146
  res.json({ agents });
146
147
  } catch (error) {
147
148
  console.error('Failed to get agents:', error);
@@ -153,15 +154,15 @@ router.get('/', async (req, res) => {
153
154
 
154
155
 
155
156
  // Get specific agent
156
- router.get('/:agentId', async (req, res) => {
157
+ router.get('/:agentId', (req, res) => {
157
158
  try {
158
159
  const { agentId } = req.params;
159
- const agent = await globalAgentStorage.getAgent(agentId);
160
-
160
+ const agent = globalAgentStorage.getAgent(agentId);
161
+
161
162
  if (!agent) {
162
163
  return res.status(404).json({ error: 'Agent not found' });
163
164
  }
164
-
165
+
165
166
  res.json({ agent });
166
167
  } catch (error) {
167
168
  console.error('Failed to get agent:', error);
@@ -170,7 +171,7 @@ router.get('/:agentId', async (req, res) => {
170
171
  });
171
172
 
172
173
  // Create new agent
173
- router.post('/', async (req, res) => {
174
+ router.post('/', (req, res) => {
174
175
  try {
175
176
  const validation = CreateAgentSchema.safeParse(req.body);
176
177
  if (!validation.success) {
@@ -178,16 +179,15 @@ router.post('/', async (req, res) => {
178
179
  }
179
180
 
180
181
  const agentData = validation.data;
181
-
182
+
182
183
  // Check if agent ID already exists
183
- const existingAgent = await globalAgentStorage.getAgent(agentData.id);
184
+ const existingAgent = globalAgentStorage.getAgent(agentData.id);
184
185
  if (existingAgent) {
185
186
  return res.status(409).json({ error: 'Agent with this ID already exists' });
186
187
  }
187
188
 
188
- const agent = await globalAgentStorage.createAgent({
189
+ const agent = globalAgentStorage.createAgent({
189
190
  version: '1.0.0',
190
- model: 'claude-3-5-sonnet-20241022',
191
191
  ...agentData
192
192
  } as Omit<AgentConfig, 'createdAt' | 'updatedAt'>);
193
193
 
@@ -199,16 +199,16 @@ router.post('/', async (req, res) => {
199
199
  });
200
200
 
201
201
  // Update agent
202
- router.put('/:agentId', async (req, res) => {
202
+ router.put('/:agentId', (req, res) => {
203
203
  try {
204
204
  const { agentId } = req.params;
205
205
  const validation = UpdateAgentSchema.safeParse(req.body);
206
-
206
+
207
207
  if (!validation.success) {
208
208
  return res.status(400).json({ error: 'Invalid agent data', details: validation.error });
209
209
  }
210
210
 
211
- const existingAgent = await globalAgentStorage.getAgent(agentId);
211
+ const existingAgent = globalAgentStorage.getAgent(agentId);
212
212
  if (!existingAgent) {
213
213
  return res.status(404).json({ error: 'Agent not found' });
214
214
  }
@@ -220,7 +220,7 @@ router.put('/:agentId', async (req, res) => {
220
220
  updatedAt: new Date().toISOString()
221
221
  };
222
222
 
223
- await globalAgentStorage.saveAgent(updatedAgent);
223
+ globalAgentStorage.saveAgent(updatedAgent);
224
224
  res.json({ agent: updatedAgent, message: 'Agent updated successfully' });
225
225
  } catch (error) {
226
226
  console.error('Failed to update agent:', error);
@@ -229,16 +229,15 @@ router.put('/:agentId', async (req, res) => {
229
229
  });
230
230
 
231
231
  // Delete agent
232
- router.delete('/:agentId', async (req, res) => {
232
+ router.delete('/:agentId', (req, res) => {
233
233
  try {
234
234
  const { agentId } = req.params;
235
-
236
- const existingAgent = await globalAgentStorage.getAgent(agentId);
237
- if (!existingAgent) {
235
+ const deleted = globalAgentStorage.deleteAgent(agentId);
236
+
237
+ if (!deleted) {
238
238
  return res.status(404).json({ error: 'Agent not found' });
239
239
  }
240
-
241
- await globalAgentStorage.deleteAgent(agentId);
240
+
242
241
  res.json({ success: true, message: 'Agent deleted successfully' });
243
242
  } catch (error) {
244
243
  console.error('Failed to delete agent:', error);
@@ -681,7 +680,7 @@ router.post('/chat', async (req, res) => {
681
680
  const { message, images, agentId, sessionId, projectPath, mcpTools, permissionMode, model, claudeVersion } = validation.data;
682
681
 
683
682
  // 获取 agent 配置
684
- const agent = await globalAgentStorage.getAgent(agentId);
683
+ const agent = globalAgentStorage.getAgent(agentId);
685
684
  if (!agent) {
686
685
  return res.status(404).json({ error: 'Agent not found' });
687
686
  }
@@ -3,7 +3,7 @@ import fs from 'fs';
3
3
  import path from 'path';
4
4
  import { promisify } from 'util';
5
5
  import matter from 'gray-matter';
6
- import { SlashCommand, SlashCommandCreate, SlashCommandUpdate, SlashCommandFilter } from '../types/commands.js';
6
+ import { SlashCommand, SlashCommandCreate, SlashCommandUpdate, SlashCommandFilter } from '@agentstudio/shared/types/commands';
7
7
 
8
8
  const router: Router = express.Router();
9
9
  const readdir = promisify(fs.readdir);