@exreve/exk 1.0.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 +109 -0
- package/agentLogger.ts +162 -0
- package/agentSession.ts +1176 -0
- package/app-child.ts +2769 -0
- package/appManager.ts +275 -0
- package/appRunner.ts +475 -0
- package/bin/exk +45 -0
- package/container-entrypoint.sh +177 -0
- package/index.ts +2798 -0
- package/install-service.sh +122 -0
- package/moduleMcpServer.ts +131 -0
- package/package.json +67 -0
- package/projectAnalyzer.ts +341 -0
- package/projectManager.ts +111 -0
- package/runnerGenerator.ts +218 -0
- package/shared/types.ts +488 -0
- package/skills/code-review.md +49 -0
- package/skills/front-glass.md +36 -0
- package/skills/frontend-design.md +41 -0
- package/skills/index.ts +151 -0
- package/tsconfig.json +22 -0
- package/updater.ts +512 -0
package/shared/types.ts
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
// ============ Core Types ============
|
|
2
|
+
|
|
3
|
+
export interface ChoiceRequest {
|
|
4
|
+
choiceId: string
|
|
5
|
+
question: string
|
|
6
|
+
options: Array<{ label: string; value: string }>
|
|
7
|
+
timeout?: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ChoiceResponse {
|
|
11
|
+
choiceId: string
|
|
12
|
+
selectedValue: string | null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface Schedule {
|
|
16
|
+
scheduleId: string
|
|
17
|
+
name: string
|
|
18
|
+
intervalMinutes: number
|
|
19
|
+
prompts: string[]
|
|
20
|
+
enabled: boolean
|
|
21
|
+
paused?: boolean
|
|
22
|
+
continuous?: boolean
|
|
23
|
+
lastRun?: string
|
|
24
|
+
nextRun?: string
|
|
25
|
+
runningPrompts?: string[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Project {
|
|
29
|
+
projectId: string
|
|
30
|
+
deviceId: string
|
|
31
|
+
name: string
|
|
32
|
+
path: string
|
|
33
|
+
sourcePath?: string
|
|
34
|
+
guidelines?: string // Per-project guidelines/prompts for Claude agent
|
|
35
|
+
schedules?: Schedule[]
|
|
36
|
+
archived?: boolean // Whether the project is archived
|
|
37
|
+
createdAt: string
|
|
38
|
+
updatedAt: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Session {
|
|
42
|
+
id: string
|
|
43
|
+
projectId: string
|
|
44
|
+
deviceId: string
|
|
45
|
+
createdAt: string
|
|
46
|
+
logFile: string
|
|
47
|
+
status: 'idle' | 'active' | 'processing'
|
|
48
|
+
model: string // AI model to use (e.g., 'glm-5', 'glm-4.7', 'glm-4.5-air')
|
|
49
|
+
name?: string // Optional: AI-generated session name from first prompt
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface Device {
|
|
53
|
+
deviceId: string
|
|
54
|
+
name: string
|
|
55
|
+
ipAddress?: string
|
|
56
|
+
hostname?: string
|
|
57
|
+
email?: string
|
|
58
|
+
approved?: boolean
|
|
59
|
+
approvedAt?: string
|
|
60
|
+
registeredAt: string
|
|
61
|
+
lastSeen: string
|
|
62
|
+
guidelines?: string // Account-level guidelines/prompts for Claude agent
|
|
63
|
+
cloudflared?: {
|
|
64
|
+
authenticated: boolean
|
|
65
|
+
authenticatedAt?: string
|
|
66
|
+
accountId?: string
|
|
67
|
+
accountName?: string
|
|
68
|
+
apiToken?: string // API token (not exposed to frontend, only stored)
|
|
69
|
+
zoneId?: string
|
|
70
|
+
tunnelId?: string // Tunnel ID configured on device
|
|
71
|
+
tunnelName?: string // Tunnel name configured on device
|
|
72
|
+
}
|
|
73
|
+
containers?: {
|
|
74
|
+
enabled: boolean
|
|
75
|
+
runtime?: 'docker' | 'podman'
|
|
76
|
+
version?: string
|
|
77
|
+
activeContainers?: Array<{
|
|
78
|
+
containerId: string
|
|
79
|
+
name: string
|
|
80
|
+
image: string
|
|
81
|
+
status: 'running' | 'stopped' | 'exited' | 'paused'
|
|
82
|
+
ports: Array<{ host: number; container: number }>
|
|
83
|
+
createdAt: string
|
|
84
|
+
}>
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface Script {
|
|
89
|
+
id: string
|
|
90
|
+
name: string
|
|
91
|
+
description: string
|
|
92
|
+
command: string
|
|
93
|
+
createdAt: string
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface Enhancer {
|
|
97
|
+
id: string
|
|
98
|
+
title: string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface User {
|
|
102
|
+
id: string
|
|
103
|
+
email: string
|
|
104
|
+
createdAt: string
|
|
105
|
+
lastLoginAt?: string
|
|
106
|
+
settings?: {
|
|
107
|
+
whisperModel?: 'small' | 'turbo'
|
|
108
|
+
enabledModules?: string[]
|
|
109
|
+
moduleSettings?: Record<string, any>
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface PromptMessage {
|
|
114
|
+
sequence: number
|
|
115
|
+
output: SessionOutput
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface Prompt {
|
|
119
|
+
promptId: string
|
|
120
|
+
sessionId: string
|
|
121
|
+
text: string
|
|
122
|
+
status: 'pending' | 'running' | 'completed' | 'error' | 'cancelled'
|
|
123
|
+
createdAt: string
|
|
124
|
+
startedAt?: string
|
|
125
|
+
completedAt?: string
|
|
126
|
+
messages?: SessionOutput[] // Optional in-memory cache
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface SessionOutput {
|
|
130
|
+
type: 'stdout' | 'stderr' | 'exit' | 'system' | 'user' | 'assistant' | 'tool_result' | 'tool_progress' | 'result' | 'auth_status' | 'progress' | 'stream_event' | 'todo_write'
|
|
131
|
+
data: string | object
|
|
132
|
+
timestamp: number
|
|
133
|
+
metadata?: {
|
|
134
|
+
messageType?: string
|
|
135
|
+
subtype?: string
|
|
136
|
+
toolName?: string
|
|
137
|
+
toolResult?: any
|
|
138
|
+
toolUseId?: string
|
|
139
|
+
parentToolUseId?: string | null
|
|
140
|
+
progress?: {
|
|
141
|
+
current?: number
|
|
142
|
+
total?: number
|
|
143
|
+
message?: string
|
|
144
|
+
}
|
|
145
|
+
[key: string]: any
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ============ Socket Event Data Types ============
|
|
150
|
+
|
|
151
|
+
export interface ClientInfo {
|
|
152
|
+
type: 'web' | 'cli'
|
|
153
|
+
deviceId?: string
|
|
154
|
+
userEmail?: string // User email for web clients
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface RegisterData {
|
|
158
|
+
type: 'web' | 'cli'
|
|
159
|
+
deviceId?: string
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface SessionSubscribeData {
|
|
163
|
+
sessionId: string
|
|
164
|
+
// Note: Sync is now prompt-based, not session-based
|
|
165
|
+
// Clients sync individual prompts via prompt:sync
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
export interface SessionPromptData {
|
|
170
|
+
sessionId: string
|
|
171
|
+
prompt: string
|
|
172
|
+
promptId?: string // Optional when sending from client, required when routing to device
|
|
173
|
+
enhancers?: string[] // Optional: list of skill/enhancer names to apply
|
|
174
|
+
projectPath?: string // Optional: project path when routing to device
|
|
175
|
+
model?: string // Optional: AI model to use for this session
|
|
176
|
+
enabledModules?: string[] // Optional: list of enabled module IDs (sent by backend to CLI)
|
|
177
|
+
moduleSettings?: Record<string, any> // Optional: per-module settings (sent by backend to CLI)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface DeviceRegisterData {
|
|
181
|
+
deviceId: string
|
|
182
|
+
name?: string
|
|
183
|
+
ipAddress?: string
|
|
184
|
+
hostname?: string
|
|
185
|
+
email?: string
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export interface ScriptCreateData {
|
|
189
|
+
name: string
|
|
190
|
+
description: string
|
|
191
|
+
command: string
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export interface ScriptRunData {
|
|
195
|
+
scriptId: string
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface ProjectCreateData {
|
|
199
|
+
deviceId: string
|
|
200
|
+
name: string
|
|
201
|
+
path: string
|
|
202
|
+
sourcePath?: string
|
|
203
|
+
projectId?: string // Optional, backend generates if not provided
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface ProjectListData {
|
|
207
|
+
deviceId?: string
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export interface ProjectDeleteData {
|
|
211
|
+
projectId: string
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export interface SessionCreateData {
|
|
215
|
+
projectId: string
|
|
216
|
+
model?: string // Optional: AI model to use (defaults to glm-5.1)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ============ Project Configuration Types ============
|
|
220
|
+
|
|
221
|
+
export interface ProjectApp {
|
|
222
|
+
name: string
|
|
223
|
+
description?: string
|
|
224
|
+
type: 'http' | 'tcp' | 'udp' | 'websocket' | 'grpc' | 'other'
|
|
225
|
+
port?: number
|
|
226
|
+
protocol?: string
|
|
227
|
+
directory?: string // Directory where this app is located (relative to project root, empty string for root)
|
|
228
|
+
framework?: string // e.g., 'react', 'express', 'fastapi', 'django'
|
|
229
|
+
appType?: 'static-frontend' | 'backend' // Detected app type for runner selection
|
|
230
|
+
buildDir?: string // Build output directory for static frontends (dist/build/public)
|
|
231
|
+
env?: Record<string, string> // Environment variables
|
|
232
|
+
endpoints?: string[] // HTTP endpoints/routes (e.g., ['/api', '/api/v1', '/'])
|
|
233
|
+
healthCheck?: {
|
|
234
|
+
url?: string
|
|
235
|
+
command?: string
|
|
236
|
+
}
|
|
237
|
+
buildCommand?: string
|
|
238
|
+
startCommand: string // Required: how to start the app
|
|
239
|
+
stopCommand?: string // Optional: how to stop the app (defaults to killing process)
|
|
240
|
+
restartCommand?: string // Optional: how to restart (defaults to stop + start)
|
|
241
|
+
dependencies?: string[]
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export interface ProjectConfig {
|
|
245
|
+
version: string
|
|
246
|
+
projectName: string
|
|
247
|
+
description?: string
|
|
248
|
+
apps: ProjectApp[] // Renamed from services
|
|
249
|
+
directories?: string[] // Multiple directories/apps in the project
|
|
250
|
+
metadata?: {
|
|
251
|
+
analyzedAt?: string
|
|
252
|
+
analyzedBy?: string
|
|
253
|
+
framework?: string
|
|
254
|
+
language?: string
|
|
255
|
+
packageManager?: string
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export interface ProjectConfigData {
|
|
260
|
+
projectId: string
|
|
261
|
+
config: ProjectConfig
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export interface ProjectConfigUpdateData {
|
|
265
|
+
projectId: string
|
|
266
|
+
config: Partial<ProjectConfig>
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ============ Socket Events Interface ============
|
|
270
|
+
|
|
271
|
+
export interface SocketEvents {
|
|
272
|
+
// Client → Server
|
|
273
|
+
register: (data: RegisterData) => void
|
|
274
|
+
'session:subscribe': (data: SessionSubscribeData) => void
|
|
275
|
+
'session:unsubscribe': (data: SessionSubscribeData) => void
|
|
276
|
+
'project:create': (data: ProjectCreateData, callback: (response: { success: boolean; project?: Project; error?: string }) => void) => void
|
|
277
|
+
'project:update:guidelines': (data: { projectId: string; guidelines: string }, callback: (response: { success: boolean; project?: Project; error?: string }) => void) => void
|
|
278
|
+
'project:list': (data: ProjectListData & { includeArchived?: boolean }, callback: (response: { projects: Project[] }) => void) => void
|
|
279
|
+
'project:delete': (data: ProjectDeleteData, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
280
|
+
'project:archive': (data: { projectId: string; archived: boolean }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
281
|
+
'device:update:guidelines': (data: { deviceId: string; guidelines: string }, callback: (response: { success: boolean; device?: Device; error?: string }) => void) => void
|
|
282
|
+
'session:create': (data: SessionCreateData, callback: (response: { success: boolean; session?: Session; error?: string }) => void) => void
|
|
283
|
+
'session:update:model': (data: { sessionId: string; model: string }, callback: (response: { success: boolean; session?: Session; error?: string }) => void) => void
|
|
284
|
+
'session:delete': (data: { sessionId: string }, callback: (response: { success: boolean }) => void) => void
|
|
285
|
+
'session:prompt': (data: SessionPromptData, callback: (response: { success: boolean; promptId?: string; error?: string }) => void) => void
|
|
286
|
+
'prompts:list': (data: { sessionId: string }, callback: (response: { prompts: Prompt[]; error?: string }) => void) => void
|
|
287
|
+
'prompt:messages': (data: { promptId: string; fromTimestamp?: number }, callback: (response: { promptId: string; messages: SessionOutput[]; latestTimestamp: number; hasMore: boolean; error?: string }) => void) => void
|
|
288
|
+
'prompt:sync': (data: { promptId: string; lastTimestamp?: number }, callback: (response: { promptId: string; messages: SessionOutput[]; latestTimestamp: number; hasMore: boolean; error?: string }) => void) => void
|
|
289
|
+
'device:register': (data: DeviceRegisterData, callback: (response: { success: boolean; device?: Device }) => void) => void
|
|
290
|
+
'sessions:list': (callback: (response: { sessions: Session[] }) => void) => void
|
|
291
|
+
'devices:list': (callback: (response: { devices: Device[] }) => void) => void
|
|
292
|
+
'scripts:list': (callback: (response: { scripts: Script[] }) => void) => void
|
|
293
|
+
'script:create': (data: ScriptCreateData, callback: (response: { success: boolean; script?: Script }) => void) => void
|
|
294
|
+
'script:run': (data: ScriptRunData, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
295
|
+
'app:start': (data: { projectId: string; appName: string }, callback: (response: { success: boolean; error?: string; processId?: string }) => void) => void
|
|
296
|
+
'app:stop': (data: { projectId: string; appName: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
297
|
+
'app:restart': (data: { projectId: string; appName: string }, callback: (response: { success: boolean; error?: string; processId?: string }) => void) => void
|
|
298
|
+
'app:status': (data: { projectId: string; appName?: string }, callback: (response: { success: boolean; apps?: Array<{ name: string; running: boolean; processId?: string; pid?: number }>; error?: string }) => void) => void
|
|
299
|
+
'app:logs': (data: { projectId: string; appName: string; follow?: boolean }, callback: (response: { success: boolean; logs?: string; error?: string }) => void) => void
|
|
300
|
+
'cloudflared:check': (data: { deviceId: string }, callback: (response: { success: boolean; installed: boolean; hasCert: boolean; authenticated: boolean; tunnelId?: string; tunnelName?: string; error?: string }) => void) => void
|
|
301
|
+
'cloudflared:sync': (data: { deviceId: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
302
|
+
'cloudflared:login:start': (data: { deviceId: string }, callback: (response: { success: boolean; loginUrl?: string; alreadyLoggedIn?: boolean; certPath?: string; error?: string }) => void) => void
|
|
303
|
+
'cloudflared:login:complete': (data: { deviceId: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
304
|
+
'cloudflared:regenerate': (data: { deviceId: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
305
|
+
'cloudflared:tunnels:list': (data: { deviceId: string }, callback: (response: { success: boolean; tunnels?: Array<{ id: string; name: string; created_at: string }>; error?: string }) => void) => void
|
|
306
|
+
'cloudflared:routes:list': (data: { deviceId: string; tunnelId?: string }, callback: (response: { success: boolean; routes?: Array<{ id: string; name: string; type: string; content: string; zone_name: string }>; error?: string }) => void) => void
|
|
307
|
+
'cloudflared:route:get': (data: { deviceId: string; tunnelId: string; routeId: string; hostname: string }, callback: (response: { success: boolean; route?: { hostname: string; port: number }; error?: string }) => void) => void
|
|
308
|
+
'cloudflared:route:create': (data: { deviceId: string; tunnelId: string; hostname: string; port: number; zoneId?: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
309
|
+
'cloudflared:route:update': (data: { deviceId: string; tunnelId: string; routeId: string; hostname: string; port: number; zoneId?: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
310
|
+
'cloudflared:route:delete': (data: { deviceId: string; tunnelId: string; routeId: string; hostname: string; zoneId?: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
311
|
+
'github:status': (data: { projectId: string }, callback: (response: { success: boolean; isRepo?: boolean; hasChanges?: boolean; branch?: string; remote?: string; changedFiles?: Array<{ path: string; status: string }>; changesCount?: number; error?: string }) => void) => void
|
|
312
|
+
'fs:list': (data: { deviceId: string; dirPath: string }, callback: (response: { success: boolean; entries?: Array<{ name: string; path: string; isDir: boolean }>; error?: string }) => void) => void
|
|
313
|
+
'fs:write': (data: { deviceId: string; filePath: string; content: string; encoding?: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
314
|
+
'github:commit': (data: { projectId: string; message?: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
315
|
+
'github:push': (data: { projectId: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
316
|
+
'github:discard': (data: { projectId: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
317
|
+
'schedule:add': (data: { projectId: string; name: string; intervalMinutes?: number; prompts: string[]; continuous?: boolean }, callback: (response: { success: boolean; schedule?: Schedule; error?: string }) => void) => void
|
|
318
|
+
'schedule:update': (data: { projectId: string; scheduleId: string; name?: string; intervalMinutes?: number; prompts?: string[]; enabled?: boolean; paused?: boolean; continuous?: boolean }, callback: (response: { success: boolean; schedule?: Schedule; error?: string }) => void) => void
|
|
319
|
+
'schedule:trigger': (data: { projectId: string; scheduleId: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
320
|
+
'schedule:delete': (data: { projectId: string; scheduleId: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
321
|
+
// Container management
|
|
322
|
+
'container:check': (data: { deviceId: string }, callback: (response: { success: boolean; enabled: boolean; runtime?: 'docker' | 'podman'; version?: string; error?: string }) => void) => void
|
|
323
|
+
'container:list': (data: { deviceId: string }, callback: (response: { success: boolean; containers?: Array<{ containerId: string; name: string; image: string; status: string; ports: Array<{ host: number; container: number }>; createdAt: string }>; error?: string }) => void) => void
|
|
324
|
+
'container:start': (data: { deviceId: string; name: string; image: string; ports?: Array<{ host: number; container: number }>; env?: Record<string, string>; runAsRoot?: boolean }, callback: (response: { success: boolean; containerId?: string; error?: string }) => void) => void
|
|
325
|
+
'container:stop': (data: { deviceId: string; containerId: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
326
|
+
'container:remove': (data: { deviceId: string; containerId: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
327
|
+
'container:logs': (data: { deviceId: string; containerId: string; lines?: number }, callback: (response: { success: boolean; logs?: string; error?: string }) => void) => void
|
|
328
|
+
// Device token generation (for container auth bypass)
|
|
329
|
+
'device:generate-token': (data: { deviceId: string; description?: string }, callback: (response: { success: boolean; token?: string; error?: string }) => void) => void
|
|
330
|
+
'device:list-tokens': (data: { deviceId: string }, callback: (response: { success: boolean; tokens?: Array<{ token: string; createdAt: string; lastUsed?: string; description?: string }>; error?: string }) => void) => void
|
|
331
|
+
'device:revoke-token': (data: { deviceId: string; token: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
332
|
+
// User settings
|
|
333
|
+
'user:settings:get': (callback: (response: { success: boolean; settings?: { whisperModel?: string; userChoiceEnabled?: boolean }; error?: string }) => void) => void
|
|
334
|
+
// User choice feedback
|
|
335
|
+
'user:choice:response': (data: { sessionId: string; choiceId: string; selectedValue: string | null }) => void
|
|
336
|
+
// Image generation
|
|
337
|
+
'image:generate': (data: { prompt: string }, callback: (response: { success: boolean; imageUrl?: string; error?: string }) => void) => void
|
|
338
|
+
// Image save to client
|
|
339
|
+
'image:save': (data: { images: Array<{ name: string; data: string }> }, callback: (response: { success: boolean; savedCount?: number; error?: string }) => void) => void
|
|
340
|
+
|
|
341
|
+
// Server → Client
|
|
342
|
+
registered: (data: { socketId: string; type: string }) => void
|
|
343
|
+
'session:created': (session: Session) => void
|
|
344
|
+
'session:updated': (session: Session) => void
|
|
345
|
+
'session:deleted': (data: { sessionId: string }) => void
|
|
346
|
+
'session:status:updated': (data: { sessionId: string; status: 'idle' | 'active' | 'processing' }) => void
|
|
347
|
+
'prompt:created': (data: { promptId: string; sessionId: string; text: string; status: 'pending' | 'running' | 'completed' | 'error' | 'cancelled' }) => void
|
|
348
|
+
'prompt:cancel': (data: { promptId: string; sessionId: string }, callback: (response: { success: boolean; error?: string }) => void) => void
|
|
349
|
+
'prompt:updated': (data: Prompt) => void
|
|
350
|
+
'session:state': (data: { sessionId: string; prompts: Prompt[]; isActive: boolean }) => void
|
|
351
|
+
'prompt:sync:messages': (data: { promptId: string; messages: SessionOutput[]; latestTimestamp: number; hasMore: boolean }) => void
|
|
352
|
+
'prompt:output': (data: { sessionId: string; promptId: string; type: string; data: string; timestamp: number; metadata?: any }) => void
|
|
353
|
+
'session:exited': (data: { sessionId: string; exitCode: number | null }) => void
|
|
354
|
+
'session:result': (data: { sessionId: string; promptId: string; exitCode: number | null }) => void
|
|
355
|
+
'session:transcription': (data: { text: string }) => void
|
|
356
|
+
'session:processing': (data: { status: string }) => void
|
|
357
|
+
'session:prompt:received': (data: { sessionId: string; prompt: string; timestamp: number }) => void
|
|
358
|
+
'session:error': (data: { error: string }) => void
|
|
359
|
+
'device:registered': (device: Device) => void
|
|
360
|
+
'project:created': (project: Project) => void
|
|
361
|
+
'project:updated': (project: Project) => void
|
|
362
|
+
'project:deleted': (data: { projectId: string }) => void
|
|
363
|
+
'device:updated': (device: Device) => void
|
|
364
|
+
'projects:list': (data: { projects: Project[] }) => void
|
|
365
|
+
'project:config:updated': (data: { projectId: string; config: ProjectConfig }) => void
|
|
366
|
+
'project:config:analyzed': (data: { projectId: string; config: ProjectConfig }) => void
|
|
367
|
+
'project:config:analyze:error': (data: { projectId: string; error: string }) => void
|
|
368
|
+
'script:created': (script: Script) => void
|
|
369
|
+
'script:started': (data: { scriptId: string; script: Script }) => void
|
|
370
|
+
'app:started': (data: { projectId: string; appName: string; processId: string; pid?: number }) => void
|
|
371
|
+
'app:stopped': (data: { projectId: string; appName: string }) => void
|
|
372
|
+
'app:restarted': (data: { projectId: string; appName: string; processId: string; pid?: number }) => void
|
|
373
|
+
'app:status:update': (data: { projectId: string; apps: Array<{ name: string; running: boolean; processId?: string; pid?: number }> }) => void
|
|
374
|
+
'app:log': (data: { projectId: string; appName: string; log: string; timestamp: number }) => void
|
|
375
|
+
'cloudflared:status:updated': (data: { deviceId: string; authenticated: boolean; accountId?: string; accountName?: string }) => void
|
|
376
|
+
'cloudflared:login:url': (data: { deviceId: string; loginUrl: string }) => void
|
|
377
|
+
'cloudflared:login:completed': (data: { deviceId: string }) => void
|
|
378
|
+
'github:status:updated': (data: { projectId: string; isRepo: boolean; hasChanges: boolean; branch?: string; remote?: string; changedFiles?: Array<{ path: string; status: string }>; changesCount?: number }) => void
|
|
379
|
+
'schedule:added': (data: { projectId: string; schedule: Schedule }) => void
|
|
380
|
+
'schedule:updated': (data: { projectId: string; schedule: Schedule }) => void
|
|
381
|
+
'schedule:deleted': (data: { projectId: string; scheduleId: string }) => void
|
|
382
|
+
'container:status:updated': (data: { deviceId: string; containers: Array<{ containerId: string; name: string; image: string; status: string; ports: Array<{ host: number; container: number }>; createdAt: string }> }) => void
|
|
383
|
+
'user:choice:request': (data: { sessionId: string; choiceId: string; question: string; options: Array<{ label: string; value: string }>; timeout?: number }) => void
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// ============ Response Types ============
|
|
387
|
+
|
|
388
|
+
export interface SuccessResponse {
|
|
389
|
+
success: boolean
|
|
390
|
+
error?: string
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export interface SessionResponse extends SuccessResponse {
|
|
394
|
+
session?: Session
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export interface DeviceResponse extends SuccessResponse {
|
|
398
|
+
device?: Device
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export interface ScriptResponse extends SuccessResponse {
|
|
402
|
+
script?: Script
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export interface SessionsListResponse {
|
|
406
|
+
sessions: Session[]
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export interface DevicesListResponse {
|
|
410
|
+
devices: Device[]
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export interface ScriptsListResponse {
|
|
414
|
+
scripts: Script[]
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export interface EnhancersListResponse {
|
|
418
|
+
enhancers: Enhancer[]
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// ============ Module Types ============
|
|
422
|
+
|
|
423
|
+
export type ModuleCategory = 'agent' | 'ui' | 'integration' | 'experimental'
|
|
424
|
+
|
|
425
|
+
export type ModuleSettingType = 'boolean' | 'string' | 'number' | 'select' | 'multiselect'
|
|
426
|
+
|
|
427
|
+
export interface ModuleSettingSchema {
|
|
428
|
+
key: string
|
|
429
|
+
type: ModuleSettingType
|
|
430
|
+
label: string
|
|
431
|
+
description?: string
|
|
432
|
+
default?: any
|
|
433
|
+
options?: Array<{ label: string; value: any }>
|
|
434
|
+
required?: boolean
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export interface ModulePermission {
|
|
438
|
+
resource: string
|
|
439
|
+
actions: string[]
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
export interface ModuleRoute {
|
|
443
|
+
path: string
|
|
444
|
+
component: string
|
|
445
|
+
permissions?: string[]
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export interface ModuleEndpoint {
|
|
449
|
+
method: 'get' | 'post' | 'put' | 'delete'
|
|
450
|
+
path: string
|
|
451
|
+
handler: string
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export interface ModuleFrontendConfig {
|
|
455
|
+
socketEvents?: string[]
|
|
456
|
+
routes?: ModuleRoute[]
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export interface ModuleBackendConfig {
|
|
460
|
+
socketHandlers?: Record<string, string>
|
|
461
|
+
endpoints?: ModuleEndpoint[]
|
|
462
|
+
middleware?: string[]
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
export interface ModuleState {
|
|
466
|
+
initial?: Record<string, any>
|
|
467
|
+
persistKey?: string
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export interface Module {
|
|
471
|
+
id: string
|
|
472
|
+
name: string
|
|
473
|
+
description: string
|
|
474
|
+
icon?: string
|
|
475
|
+
version: string
|
|
476
|
+
category: ModuleCategory
|
|
477
|
+
enabledByDefault?: boolean // If true, module is enabled by default for new users
|
|
478
|
+
settingsSchema?: ModuleSettingSchema[]
|
|
479
|
+
permissions?: ModulePermission[]
|
|
480
|
+
frontend?: ModuleFrontendConfig
|
|
481
|
+
backend?: ModuleBackendConfig
|
|
482
|
+
state?: ModuleState
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export interface ModuleRegistry {
|
|
486
|
+
modules: Record<string, Module>
|
|
487
|
+
enabledModules: string[]
|
|
488
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-review
|
|
3
|
+
description: Thoroughly review code for quality, security, performance, and best practices. Use this skill when the user asks to review, audit, or analyze code.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
This skill guides comprehensive code reviews that identify issues, security vulnerabilities, performance problems, and violations of best practices.
|
|
7
|
+
|
|
8
|
+
## Review Process
|
|
9
|
+
|
|
10
|
+
1. **Understanding Context**: Identify the code's purpose, language, framework, and intended use case.
|
|
11
|
+
|
|
12
|
+
2. **Security Analysis**: Look for:
|
|
13
|
+
- SQL injection, XSS, CSRF vulnerabilities
|
|
14
|
+
- Hardcoded secrets or API keys
|
|
15
|
+
- Insecure authentication/authorization
|
|
16
|
+
- Dependency vulnerabilities
|
|
17
|
+
- Input validation issues
|
|
18
|
+
|
|
19
|
+
3. **Code Quality**: Assess:
|
|
20
|
+
- Code organization and structure
|
|
21
|
+
- Naming conventions
|
|
22
|
+
- Error handling
|
|
23
|
+
- Edge case coverage
|
|
24
|
+
- Code duplication
|
|
25
|
+
|
|
26
|
+
4. **Performance**: Evaluate:
|
|
27
|
+
- Algorithmic complexity
|
|
28
|
+
- Memory usage patterns
|
|
29
|
+
- Database query efficiency
|
|
30
|
+
- Caching opportunities
|
|
31
|
+
- Unnecessary re-renders (frontend)
|
|
32
|
+
|
|
33
|
+
5. **Best Practices**: Check for:
|
|
34
|
+
- Language/framework idioms
|
|
35
|
+
- Design patterns
|
|
36
|
+
- SOLID principles
|
|
37
|
+
- Testing coverage gaps
|
|
38
|
+
- Documentation issues
|
|
39
|
+
|
|
40
|
+
## Output Format
|
|
41
|
+
|
|
42
|
+
Provide a structured review with:
|
|
43
|
+
- **Summary**: Overall assessment and priority issues
|
|
44
|
+
- **Critical Issues**: Security vulnerabilities or bugs that must be fixed
|
|
45
|
+
- **Warnings**: Potential problems or code smells
|
|
46
|
+
- **Suggestions**: Improvements for code quality and maintainability
|
|
47
|
+
- **Positive Notes**: Well-implemented aspects
|
|
48
|
+
|
|
49
|
+
Be specific with file:line references and provide code examples for fixes.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-design
|
|
3
|
+
description: Create distinctive, production-grade frontend interfaces with high design quality using clearglass/glassmorphism aesthetic. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
This skill guides **clearglass (glassmorphism)** frontends: production-grade, distinctive, avoiding generic "AI slop." Implement real code with attention to aesthetic detail. The user provides requirements (component, page, app) and may give purpose, audience, or constraints.
|
|
7
|
+
|
|
8
|
+
## Design Thinking
|
|
9
|
+
|
|
10
|
+
Before coding: **Purpose**—what problem, who uses it. **Tone**—iOS-inspired frosted glass, premium and refined (calm, confident, slightly iridescent); not brutalist or playful. **Constraints**—contrast and readability non-negotiable. **Differentiation**—frosted panels with a subtle rainbow shimmer on the edges; unmistakable and cohesive. Execute with precision; keep glass to nav, modals, cards (two or three per screen), not everything.
|
|
11
|
+
|
|
12
|
+
## Clearglass Sentiment
|
|
13
|
+
|
|
14
|
+
**Core**: Frosted glass over dark space, hint of iridescence, warm gold accent. iOS control center meets dark high-end app—layers you can almost see through, soft blur, delicate borders in a spectrum (pink → orange → yellow → green → cyan → purple → pink). Dark background so glass floats; gold sparingly for primary actions and highlights. Refined, uncluttered, quietly luxurious.
|
|
15
|
+
|
|
16
|
+
- **Glass**: Secondary only (nav, modals, cards, sidebars). Strong blur and slight saturation; enough opacity for readable text. Two or three glass surfaces per screen.
|
|
17
|
+
- **Iridescence**: Subtle rainbow gradient on panel edges—thin shimmer, understated. Separates clearglass from generic glassmorphism.
|
|
18
|
+
- **Color**: Dark base; glass semi-transparent, tinted dark. White/near-white text with subtle shadow when needed. Gold only for CTAs and key highlights. Soft white/light-gray borders at low opacity.
|
|
19
|
+
- **Typography**: Clear, confident; system fonts, medium-to-bold. Generous size; contrast and light shadow so text stays legible on glass.
|
|
20
|
+
- **Motion**: Smooth, short transitions; slight scale-down on press. No flashy or drawn-out animation—personality from glass and edge.
|
|
21
|
+
- **Space**: Generous padding and rounding; negative space so few glass elements stand out. Asymmetry when it serves hierarchy.
|
|
22
|
+
- **Depth**: Layered shadows and faint inner highlight so panels feel lifted. Transparent root chrome over map/gradient/image when appropriate.
|
|
23
|
+
|
|
24
|
+
**Text vs. icon-only**: Where **text and readability matter** (labels, cards, modals, nav with words)—use full clearglass: darker, more opaque glass; iridescent edges; text shadows. Where **only an icon or compact control matters** (floating filter/location button over a map)—lighter, whitish glass; clearer border; compact round/pill; no text, so no readability trade-off. Choose per element: full clearglass for reading; lighter filter-button style for recognize-and-tap.
|
|
25
|
+
|
|
26
|
+
## Rules
|
|
27
|
+
|
|
28
|
+
**DO**: Glass sparingly. Full clearglass where text matters; lighter glass for icon-only controls. Contrast and readability above all for text. Rainbow shimmer on content panels; gold for primary actions only. System fonts. Respect reduced motion/transparency; solid fallbacks where blur isn’t supported.
|
|
29
|
+
|
|
30
|
+
**DON’T**: Cover the screen in glass; sacrifice readability; use thin or decorative fonts; rely on color alone; ignore a11y or performance; drift to generic AI style.
|
|
31
|
+
|
|
32
|
+
**A11y & performance**: WCAG contrast; legible text on glass (shadow when needed). Honor reduced motion/transparency. Few blurred layers—a few well-placed elements are enough.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
**Remember**: Clearglass = frosted glass over dark, rainbow on the edges, gold for emphasis. Precision and restraint; sentiment consistent and memorable.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-design
|
|
3
|
+
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
|
|
7
|
+
|
|
8
|
+
The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints.
|
|
9
|
+
|
|
10
|
+
## Design Thinking
|
|
11
|
+
|
|
12
|
+
Before coding, understand the context and commit to a BOLD aesthetic direction:
|
|
13
|
+
- **Purpose**: What problem does this interface solve? Who uses it?
|
|
14
|
+
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
|
|
15
|
+
- **Constraints**: Technical requirements (framework, performance, accessibility).
|
|
16
|
+
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
|
|
17
|
+
|
|
18
|
+
**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.
|
|
19
|
+
|
|
20
|
+
Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is:
|
|
21
|
+
- Production-grade and functional
|
|
22
|
+
- Visually striking and memorable
|
|
23
|
+
- Cohesive with a clear aesthetic point-of-view
|
|
24
|
+
- Meticulously refined in every detail
|
|
25
|
+
|
|
26
|
+
## Frontend Aesthetics Guidelines
|
|
27
|
+
|
|
28
|
+
Focus on:
|
|
29
|
+
- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font.
|
|
30
|
+
- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
|
|
31
|
+
- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise.
|
|
32
|
+
- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
|
|
33
|
+
- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays.
|
|
34
|
+
|
|
35
|
+
NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character.
|
|
36
|
+
|
|
37
|
+
Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations.
|
|
38
|
+
|
|
39
|
+
**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.
|
|
40
|
+
|
|
41
|
+
Remember: You are capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
|