@epiphytic/claudecodeui 1.1.0 → 1.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/dist/assets/{index-D0xTNXrF.js → index-DqxzEd_8.js} +213 -215
- package/dist/assets/index-r43D8sh4.css +32 -0
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/database/db.js +98 -0
- package/server/database/init.sql +13 -1
- package/server/index.js +69 -6
- package/server/orchestrator/client.js +361 -16
- package/server/orchestrator/index.js +83 -8
- package/server/orchestrator/protocol.js +67 -0
- package/server/projects.js +2 -1
- package/dist/assets/index-DKDK7xNY.css +0 -32
|
@@ -18,6 +18,7 @@ export {
|
|
|
18
18
|
createRegisterMessage,
|
|
19
19
|
createStatusUpdateMessage,
|
|
20
20
|
createPingMessage,
|
|
21
|
+
createPendingRegisterMessage,
|
|
21
22
|
createResponseMessage,
|
|
22
23
|
createResponseChunkMessage,
|
|
23
24
|
createResponseCompleteMessage,
|
|
@@ -61,6 +62,11 @@ export {
|
|
|
61
62
|
/**
|
|
62
63
|
* Creates and configures an orchestrator client from environment variables
|
|
63
64
|
*
|
|
65
|
+
* Token Precedence:
|
|
66
|
+
* 1. .env file ORCHESTRATOR_TOKEN - Highest priority, always used if set
|
|
67
|
+
* 2. Database token for specific host - Used when .env token is empty/missing
|
|
68
|
+
* 3. No token available - Uses pending mode with claim patterns
|
|
69
|
+
*
|
|
64
70
|
* @param {Object} [overrides] - Configuration overrides
|
|
65
71
|
* @returns {Promise<OrchestratorClient|null>} Configured client or null if not in client mode
|
|
66
72
|
*/
|
|
@@ -74,7 +80,6 @@ export async function createOrchestratorClientFromEnv(overrides = {}) {
|
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
const url = overrides.url || process.env.ORCHESTRATOR_URL;
|
|
77
|
-
const token = overrides.token || process.env.ORCHESTRATOR_TOKEN;
|
|
78
83
|
|
|
79
84
|
if (!url) {
|
|
80
85
|
console.warn(
|
|
@@ -83,16 +88,46 @@ export async function createOrchestratorClientFromEnv(overrides = {}) {
|
|
|
83
88
|
return null;
|
|
84
89
|
}
|
|
85
90
|
|
|
86
|
-
if
|
|
91
|
+
// Token is now optional - if not set, pending mode will be used
|
|
92
|
+
const token = overrides.token || process.env.ORCHESTRATOR_TOKEN || null;
|
|
93
|
+
|
|
94
|
+
// Build claim patterns for pending mode
|
|
95
|
+
// Fall back to ORCHESTRATOR_GITHUB_* variables if ORCHESTRATOR_CLAIM_* not set
|
|
96
|
+
const claimPatterns = overrides.claimPatterns || {
|
|
97
|
+
user:
|
|
98
|
+
process.env.ORCHESTRATOR_CLAIM_USER ||
|
|
99
|
+
process.env.ORCHESTRATOR_GITHUB_USERS ||
|
|
100
|
+
"",
|
|
101
|
+
org:
|
|
102
|
+
process.env.ORCHESTRATOR_CLAIM_ORG ||
|
|
103
|
+
process.env.ORCHESTRATOR_GITHUB_ORG ||
|
|
104
|
+
"",
|
|
105
|
+
team:
|
|
106
|
+
process.env.ORCHESTRATOR_CLAIM_TEAM ||
|
|
107
|
+
process.env.ORCHESTRATOR_GITHUB_TEAM ||
|
|
108
|
+
"",
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// Validate: need either a token or at least one claim pattern
|
|
112
|
+
const hasToken = token && token.trim() !== "";
|
|
113
|
+
const hasClaimPattern =
|
|
114
|
+
(claimPatterns.user && claimPatterns.user.trim()) ||
|
|
115
|
+
(claimPatterns.org && claimPatterns.org.trim()) ||
|
|
116
|
+
(claimPatterns.team && claimPatterns.team.trim());
|
|
117
|
+
|
|
118
|
+
if (!hasToken && !hasClaimPattern) {
|
|
87
119
|
console.warn(
|
|
88
|
-
"[ORCHESTRATOR]
|
|
120
|
+
"[ORCHESTRATOR] No token and no claim patterns set, running in standalone mode",
|
|
121
|
+
);
|
|
122
|
+
console.warn(
|
|
123
|
+
"[ORCHESTRATOR] Set ORCHESTRATOR_TOKEN or at least one of ORCHESTRATOR_CLAIM_USER, ORCHESTRATOR_CLAIM_ORG, ORCHESTRATOR_CLAIM_TEAM",
|
|
89
124
|
);
|
|
90
125
|
return null;
|
|
91
126
|
}
|
|
92
127
|
|
|
93
128
|
const config = {
|
|
94
129
|
url,
|
|
95
|
-
token,
|
|
130
|
+
token: hasToken ? token : null,
|
|
96
131
|
clientId: overrides.clientId || process.env.ORCHESTRATOR_CLIENT_ID,
|
|
97
132
|
reconnectInterval:
|
|
98
133
|
overrides.reconnectInterval ||
|
|
@@ -103,6 +138,7 @@ export async function createOrchestratorClientFromEnv(overrides = {}) {
|
|
|
103
138
|
parseInt(process.env.ORCHESTRATOR_HEARTBEAT_INTERVAL) ||
|
|
104
139
|
30000,
|
|
105
140
|
metadata: overrides.metadata || {},
|
|
141
|
+
claimPatterns,
|
|
106
142
|
};
|
|
107
143
|
|
|
108
144
|
return new OrchestratorClient(config);
|
|
@@ -117,6 +153,11 @@ export async function createOrchestratorClientFromEnv(overrides = {}) {
|
|
|
117
153
|
* 3. Connects to the orchestrator
|
|
118
154
|
* 4. Sets up user request handling
|
|
119
155
|
*
|
|
156
|
+
* Token Precedence:
|
|
157
|
+
* 1. .env file ORCHESTRATOR_TOKEN - Highest priority, always used if set
|
|
158
|
+
* 2. Database token for specific host - Used when .env token is empty/missing
|
|
159
|
+
* 3. No token available - Uses pending mode with claim patterns
|
|
160
|
+
*
|
|
120
161
|
* @param {Object} options - Initialization options
|
|
121
162
|
* @param {Object} options.handlers - Handler functions for proxied requests
|
|
122
163
|
* @param {Object} [options.config] - Configuration overrides
|
|
@@ -138,11 +179,44 @@ export async function initializeOrchestrator(options = {}) {
|
|
|
138
179
|
}
|
|
139
180
|
|
|
140
181
|
const url = config.url || process.env.ORCHESTRATOR_URL;
|
|
141
|
-
const token = config.token || process.env.ORCHESTRATOR_TOKEN;
|
|
142
182
|
|
|
143
|
-
if (!url
|
|
183
|
+
if (!url) {
|
|
184
|
+
console.warn(
|
|
185
|
+
"[ORCHESTRATOR] URL not configured, running in standalone mode",
|
|
186
|
+
);
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Token is now optional - if not set, pending mode will be used
|
|
191
|
+
const token = config.token || process.env.ORCHESTRATOR_TOKEN || null;
|
|
192
|
+
|
|
193
|
+
// Build claim patterns for pending mode
|
|
194
|
+
// Fall back to ORCHESTRATOR_GITHUB_* variables if ORCHESTRATOR_CLAIM_* not set
|
|
195
|
+
const claimPatterns = config.claimPatterns || {
|
|
196
|
+
user:
|
|
197
|
+
process.env.ORCHESTRATOR_CLAIM_USER ||
|
|
198
|
+
process.env.ORCHESTRATOR_GITHUB_USERS ||
|
|
199
|
+
"",
|
|
200
|
+
org:
|
|
201
|
+
process.env.ORCHESTRATOR_CLAIM_ORG ||
|
|
202
|
+
process.env.ORCHESTRATOR_GITHUB_ORG ||
|
|
203
|
+
"",
|
|
204
|
+
team:
|
|
205
|
+
process.env.ORCHESTRATOR_CLAIM_TEAM ||
|
|
206
|
+
process.env.ORCHESTRATOR_GITHUB_TEAM ||
|
|
207
|
+
"",
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// Validate: need either a token or at least one claim pattern
|
|
211
|
+
const hasToken = token && token.trim() !== "";
|
|
212
|
+
const hasClaimPattern =
|
|
213
|
+
(claimPatterns.user && claimPatterns.user.trim()) ||
|
|
214
|
+
(claimPatterns.org && claimPatterns.org.trim()) ||
|
|
215
|
+
(claimPatterns.team && claimPatterns.team.trim());
|
|
216
|
+
|
|
217
|
+
if (!hasToken && !hasClaimPattern) {
|
|
144
218
|
console.warn(
|
|
145
|
-
"[ORCHESTRATOR]
|
|
219
|
+
"[ORCHESTRATOR] No token and no claim patterns set, running in standalone mode",
|
|
146
220
|
);
|
|
147
221
|
return null;
|
|
148
222
|
}
|
|
@@ -155,7 +229,7 @@ export async function initializeOrchestrator(options = {}) {
|
|
|
155
229
|
// Create client
|
|
156
230
|
const client = new OrchestratorClient({
|
|
157
231
|
url,
|
|
158
|
-
token,
|
|
232
|
+
token: hasToken ? token : null,
|
|
159
233
|
clientId: config.clientId || process.env.ORCHESTRATOR_CLIENT_ID,
|
|
160
234
|
reconnectInterval:
|
|
161
235
|
config.reconnectInterval ||
|
|
@@ -167,6 +241,7 @@ export async function initializeOrchestrator(options = {}) {
|
|
|
167
241
|
30000,
|
|
168
242
|
metadata: config.metadata || {},
|
|
169
243
|
callbackUrl,
|
|
244
|
+
claimPatterns,
|
|
170
245
|
});
|
|
171
246
|
|
|
172
247
|
// Create status hooks
|
|
@@ -17,6 +17,8 @@ export const OutboundMessageTypes = {
|
|
|
17
17
|
RESPONSE_COMPLETE: "response_complete",
|
|
18
18
|
ERROR: "error",
|
|
19
19
|
HTTP_PROXY_RESPONSE: "http_proxy_response",
|
|
20
|
+
// Pending mode messages
|
|
21
|
+
PENDING_REGISTER: "pending_register",
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
/**
|
|
@@ -30,6 +32,11 @@ export const InboundMessageTypes = {
|
|
|
30
32
|
USER_REQUEST: "user_request",
|
|
31
33
|
USER_REQUEST_FOLLOW_UP: "user_request_follow_up",
|
|
32
34
|
HTTP_PROXY_REQUEST: "http_proxy_request",
|
|
35
|
+
// Pending mode responses
|
|
36
|
+
PENDING_REGISTERED: "pending_registered",
|
|
37
|
+
TOKEN_GRANTED: "token_granted",
|
|
38
|
+
AUTHORIZATION_DENIED: "authorization_denied",
|
|
39
|
+
AUTHORIZATION_TIMEOUT: "authorization_timeout",
|
|
33
40
|
};
|
|
34
41
|
|
|
35
42
|
/**
|
|
@@ -97,6 +104,29 @@ export function createPingMessage(clientId) {
|
|
|
97
104
|
};
|
|
98
105
|
}
|
|
99
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Creates a pending register message for pending mode
|
|
109
|
+
* @param {string} pendingId - Unique pending client identifier
|
|
110
|
+
* @param {string} hostname - Machine hostname
|
|
111
|
+
* @param {string} project - Current project/working directory
|
|
112
|
+
* @param {string} platform - Operating system platform
|
|
113
|
+
* @returns {Object} Pending register message
|
|
114
|
+
*/
|
|
115
|
+
export function createPendingRegisterMessage(
|
|
116
|
+
pendingId,
|
|
117
|
+
hostname,
|
|
118
|
+
project,
|
|
119
|
+
platform,
|
|
120
|
+
) {
|
|
121
|
+
return {
|
|
122
|
+
type: OutboundMessageTypes.PENDING_REGISTER,
|
|
123
|
+
pending_id: pendingId,
|
|
124
|
+
hostname,
|
|
125
|
+
project,
|
|
126
|
+
platform,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
100
130
|
/**
|
|
101
131
|
* Creates a response message (for proxied requests)
|
|
102
132
|
* @param {string} requestId - Original request ID
|
|
@@ -254,6 +284,43 @@ export function validateInboundMessage(message) {
|
|
|
254
284
|
typeof message.path === "string"
|
|
255
285
|
);
|
|
256
286
|
|
|
287
|
+
case InboundMessageTypes.PENDING_REGISTERED:
|
|
288
|
+
// pending_registered message structure:
|
|
289
|
+
// {
|
|
290
|
+
// type: "pending_registered",
|
|
291
|
+
// success: boolean,
|
|
292
|
+
// message?: string
|
|
293
|
+
// }
|
|
294
|
+
return typeof message.success === "boolean";
|
|
295
|
+
|
|
296
|
+
case InboundMessageTypes.TOKEN_GRANTED:
|
|
297
|
+
// token_granted message structure:
|
|
298
|
+
// {
|
|
299
|
+
// type: "token_granted",
|
|
300
|
+
// token: string, // Full token: "ao_xxx_yyy"
|
|
301
|
+
// client_id: string // Assigned client ID
|
|
302
|
+
// }
|
|
303
|
+
return (
|
|
304
|
+
typeof message.token === "string" &&
|
|
305
|
+
typeof message.client_id === "string"
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
case InboundMessageTypes.AUTHORIZATION_DENIED:
|
|
309
|
+
// authorization_denied message structure:
|
|
310
|
+
// {
|
|
311
|
+
// type: "authorization_denied",
|
|
312
|
+
// reason: string
|
|
313
|
+
// }
|
|
314
|
+
return typeof message.reason === "string";
|
|
315
|
+
|
|
316
|
+
case InboundMessageTypes.AUTHORIZATION_TIMEOUT:
|
|
317
|
+
// authorization_timeout message structure:
|
|
318
|
+
// {
|
|
319
|
+
// type: "authorization_timeout",
|
|
320
|
+
// message: string
|
|
321
|
+
// }
|
|
322
|
+
return typeof message.message === "string";
|
|
323
|
+
|
|
257
324
|
default:
|
|
258
325
|
// Unknown message types are considered valid (forward compatibility)
|
|
259
326
|
return true;
|
package/server/projects.js
CHANGED
|
@@ -1134,7 +1134,8 @@ async function addProjectManually(projectPath, displayName = null) {
|
|
|
1134
1134
|
}
|
|
1135
1135
|
|
|
1136
1136
|
// Generate project name (encode path for use as directory name)
|
|
1137
|
-
|
|
1137
|
+
// Claude's encoding replaces /, :, spaces, ~, _, and . with -
|
|
1138
|
+
const projectName = absolutePath.replace(/[\\/:\s~_.]/g, "-");
|
|
1138
1139
|
|
|
1139
1140
|
// Check if project already exists in config
|
|
1140
1141
|
const config = await loadProjectConfig();
|