zerg-ztc 0.1.10 → 0.1.12

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 (151) hide show
  1. package/bin/.gitkeep +0 -0
  2. package/bin/ztc-audio-darwin-arm64 +0 -0
  3. package/dist/App.d.ts.map +1 -1
  4. package/dist/App.js +63 -2
  5. package/dist/App.js.map +1 -1
  6. package/dist/agent/commands/dictation.d.ts +3 -0
  7. package/dist/agent/commands/dictation.d.ts.map +1 -0
  8. package/dist/agent/commands/dictation.js +10 -0
  9. package/dist/agent/commands/dictation.js.map +1 -0
  10. package/dist/agent/commands/index.d.ts.map +1 -1
  11. package/dist/agent/commands/index.js +2 -1
  12. package/dist/agent/commands/index.js.map +1 -1
  13. package/dist/agent/commands/types.d.ts +7 -0
  14. package/dist/agent/commands/types.d.ts.map +1 -1
  15. package/dist/components/InputArea.d.ts +1 -0
  16. package/dist/components/InputArea.d.ts.map +1 -1
  17. package/dist/components/InputArea.js +591 -43
  18. package/dist/components/InputArea.js.map +1 -1
  19. package/dist/components/SingleMessage.d.ts.map +1 -1
  20. package/dist/components/SingleMessage.js +157 -7
  21. package/dist/components/SingleMessage.js.map +1 -1
  22. package/dist/config/types.d.ts +6 -0
  23. package/dist/config/types.d.ts.map +1 -1
  24. package/dist/ui/views/status_bar.js +2 -2
  25. package/dist/ui/views/status_bar.js.map +1 -1
  26. package/dist/utils/dictation.d.ts +46 -0
  27. package/dist/utils/dictation.d.ts.map +1 -0
  28. package/dist/utils/dictation.js +409 -0
  29. package/dist/utils/dictation.js.map +1 -0
  30. package/dist/utils/dictation_native.d.ts +51 -0
  31. package/dist/utils/dictation_native.d.ts.map +1 -0
  32. package/dist/utils/dictation_native.js +236 -0
  33. package/dist/utils/dictation_native.js.map +1 -0
  34. package/dist/utils/path_format.d.ts +20 -0
  35. package/dist/utils/path_format.d.ts.map +1 -0
  36. package/dist/utils/path_format.js +90 -0
  37. package/dist/utils/path_format.js.map +1 -0
  38. package/dist/utils/table.d.ts +38 -0
  39. package/dist/utils/table.d.ts.map +1 -0
  40. package/dist/utils/table.js +133 -0
  41. package/dist/utils/table.js.map +1 -0
  42. package/dist/utils/tool_trace.d.ts +7 -2
  43. package/dist/utils/tool_trace.d.ts.map +1 -1
  44. package/dist/utils/tool_trace.js +156 -51
  45. package/dist/utils/tool_trace.js.map +1 -1
  46. package/package.json +5 -1
  47. package/src/App.tsx +0 -813
  48. package/src/agent/agent.ts +0 -534
  49. package/src/agent/backends/anthropic.ts +0 -86
  50. package/src/agent/backends/gemini.ts +0 -119
  51. package/src/agent/backends/inception.ts +0 -23
  52. package/src/agent/backends/index.ts +0 -17
  53. package/src/agent/backends/openai.ts +0 -23
  54. package/src/agent/backends/openai_compatible.ts +0 -143
  55. package/src/agent/backends/types.ts +0 -83
  56. package/src/agent/commands/clipboard.ts +0 -77
  57. package/src/agent/commands/config.ts +0 -204
  58. package/src/agent/commands/debug.ts +0 -23
  59. package/src/agent/commands/emulation.ts +0 -80
  60. package/src/agent/commands/execution.ts +0 -9
  61. package/src/agent/commands/help.ts +0 -20
  62. package/src/agent/commands/history.ts +0 -13
  63. package/src/agent/commands/index.ts +0 -46
  64. package/src/agent/commands/input_mode.ts +0 -22
  65. package/src/agent/commands/keybindings.ts +0 -40
  66. package/src/agent/commands/model.ts +0 -11
  67. package/src/agent/commands/models.ts +0 -116
  68. package/src/agent/commands/permissions.ts +0 -64
  69. package/src/agent/commands/retry.ts +0 -9
  70. package/src/agent/commands/shell.ts +0 -68
  71. package/src/agent/commands/skills.ts +0 -54
  72. package/src/agent/commands/status.ts +0 -19
  73. package/src/agent/commands/types.ts +0 -80
  74. package/src/agent/commands/update.ts +0 -32
  75. package/src/agent/factory.ts +0 -60
  76. package/src/agent/index.ts +0 -20
  77. package/src/agent/runtime/capabilities.ts +0 -7
  78. package/src/agent/runtime/memory.ts +0 -23
  79. package/src/agent/runtime/policy.ts +0 -48
  80. package/src/agent/runtime/session.ts +0 -18
  81. package/src/agent/runtime/tracing.ts +0 -23
  82. package/src/agent/tools/file.ts +0 -178
  83. package/src/agent/tools/index.ts +0 -52
  84. package/src/agent/tools/screenshot.ts +0 -821
  85. package/src/agent/tools/search.ts +0 -138
  86. package/src/agent/tools/shell.ts +0 -69
  87. package/src/agent/tools/skills.ts +0 -28
  88. package/src/agent/tools/types.ts +0 -14
  89. package/src/agent/tools/zerg.ts +0 -50
  90. package/src/cli.tsx +0 -163
  91. package/src/components/ActivityLine.tsx +0 -23
  92. package/src/components/FullScreen.tsx +0 -79
  93. package/src/components/Header.tsx +0 -27
  94. package/src/components/InputArea.tsx +0 -1096
  95. package/src/components/MessageList.tsx +0 -71
  96. package/src/components/SingleMessage.tsx +0 -59
  97. package/src/components/StatusBar.tsx +0 -55
  98. package/src/components/index.tsx +0 -8
  99. package/src/config/types.ts +0 -12
  100. package/src/config.ts +0 -186
  101. package/src/debug/logger.ts +0 -14
  102. package/src/emulation/README.md +0 -24
  103. package/src/emulation/catalog.ts +0 -82
  104. package/src/emulation/trace_style.ts +0 -8
  105. package/src/emulation/types.ts +0 -7
  106. package/src/skills/index.ts +0 -36
  107. package/src/skills/loader.ts +0 -135
  108. package/src/skills/registry.ts +0 -6
  109. package/src/skills/types.ts +0 -10
  110. package/src/types.ts +0 -84
  111. package/src/ui/README.md +0 -44
  112. package/src/ui/core/factory.ts +0 -9
  113. package/src/ui/core/index.ts +0 -4
  114. package/src/ui/core/input.ts +0 -38
  115. package/src/ui/core/input_segments.ts +0 -410
  116. package/src/ui/core/input_state.ts +0 -17
  117. package/src/ui/core/layout_yoga.ts +0 -122
  118. package/src/ui/core/style.ts +0 -38
  119. package/src/ui/core/types.ts +0 -54
  120. package/src/ui/ink/index.tsx +0 -1
  121. package/src/ui/ink/render.tsx +0 -60
  122. package/src/ui/views/activity_line.ts +0 -33
  123. package/src/ui/views/app.ts +0 -111
  124. package/src/ui/views/header.ts +0 -44
  125. package/src/ui/views/input_area.ts +0 -255
  126. package/src/ui/views/message_list.ts +0 -443
  127. package/src/ui/views/status_bar.ts +0 -114
  128. package/src/ui/vue/index.ts +0 -53
  129. package/src/ui/web/frame_render.tsx +0 -148
  130. package/src/ui/web/index.tsx +0 -1
  131. package/src/ui/web/render.tsx +0 -41
  132. package/src/utils/clipboard.ts +0 -39
  133. package/src/utils/clipboard_image.ts +0 -40
  134. package/src/utils/diff.ts +0 -52
  135. package/src/utils/image_preview.ts +0 -36
  136. package/src/utils/models.ts +0 -98
  137. package/src/utils/path_complete.ts +0 -173
  138. package/src/utils/shell.ts +0 -72
  139. package/src/utils/spinner_frames.ts +0 -1
  140. package/src/utils/spinner_verbs.ts +0 -23
  141. package/src/utils/tool_summary.ts +0 -56
  142. package/src/utils/tool_trace.ts +0 -216
  143. package/src/utils/update.ts +0 -44
  144. package/src/utils/version.ts +0 -15
  145. package/src/web/index.html +0 -352
  146. package/src/web/mirror-favicon.svg +0 -4
  147. package/src/web/mirror.html +0 -641
  148. package/src/web/mirror_hook.ts +0 -25
  149. package/src/web/mirror_server.ts +0 -204
  150. package/tsconfig.json +0 -22
  151. package/vite.config.ts +0 -363
@@ -1,204 +0,0 @@
1
- import { createServer, IncomingMessage, ServerResponse } from 'http';
2
- import { readFile, mkdir, writeFile } from 'fs/promises';
3
- import { resolve, join, basename } from 'path';
4
- import { homedir } from 'os';
5
- import { randomUUID } from 'crypto';
6
- import { InputBus, InputEvent } from '../ui/core/input.js';
7
- import { LayoutNode, computeLayout, LayoutFrame } from '../ui/core/index.js';
8
-
9
- interface Client {
10
- id: string;
11
- res: ServerResponse;
12
- cols: number;
13
- rows: number;
14
- }
15
-
16
- export class MirrorServer {
17
- private clients = new Map<string, Client>();
18
- private port: number;
19
- private server = createServer(this.handleRequest.bind(this));
20
- private lastTree: LayoutNode | null = null;
21
- private inputBus?: InputBus;
22
-
23
- constructor(port: number, inputBus?: InputBus) {
24
- this.port = port;
25
- this.inputBus = inputBus;
26
- }
27
-
28
- start(): void {
29
- this.server.listen(this.port);
30
- }
31
-
32
- stop(): void {
33
- this.server.close();
34
- }
35
-
36
- publish(tree: LayoutNode): void {
37
- this.lastTree = tree;
38
- for (const client of this.clients.values()) {
39
- this.sendLayout(client, tree);
40
- }
41
- }
42
-
43
- private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {
44
- const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
45
-
46
- if (url.pathname === '/') {
47
- const htmlPath = new URL('./mirror.html', import.meta.url);
48
- const html = await readFile(htmlPath, 'utf-8').catch(async () => {
49
- const fallback = resolve(process.cwd(), 'src/web/mirror.html');
50
- return readFile(fallback, 'utf-8');
51
- });
52
- res.writeHead(200, { 'Content-Type': 'text/html' });
53
- res.end(html);
54
- return;
55
- }
56
-
57
- if (url.pathname === '/mirror-favicon.svg' || url.pathname === '/favicon.svg' || url.pathname === '/favicon.ico') {
58
- const iconPath = new URL('./mirror-favicon.svg', import.meta.url);
59
- const icon = await readFile(iconPath, 'utf-8').catch(async () => {
60
- const fallback = resolve(process.cwd(), 'src/web/mirror-favicon.svg');
61
- return readFile(fallback, 'utf-8');
62
- });
63
- const contentType = url.pathname === '/favicon.ico' ? 'image/x-icon' : 'image/svg+xml';
64
- res.writeHead(200, { 'Content-Type': contentType, 'Cache-Control': 'no-cache' });
65
- res.end(icon);
66
- return;
67
- }
68
-
69
- if (url.pathname === '/events') {
70
- const id = url.searchParams.get('id') || `client_${Date.now()}`;
71
- res.writeHead(200, {
72
- 'Content-Type': 'text/event-stream',
73
- 'Cache-Control': 'no-cache',
74
- Connection: 'keep-alive'
75
- });
76
- res.write('\n');
77
-
78
- const client: Client = {
79
- id,
80
- res,
81
- cols: 80,
82
- rows: 24
83
- };
84
- this.clients.set(id, client);
85
-
86
- if (this.lastTree) {
87
- this.sendLayout(client, this.lastTree);
88
- }
89
-
90
- req.on('close', () => {
91
- this.clients.delete(id);
92
- });
93
- return;
94
- }
95
-
96
- if (url.pathname === '/size' && req.method === 'POST') {
97
- const id = url.searchParams.get('id');
98
- if (!id || !this.clients.has(id)) {
99
- res.writeHead(400);
100
- res.end();
101
- return;
102
- }
103
-
104
- const body = await new Promise<string>(resolve => {
105
- let data = '';
106
- req.on('data', chunk => { data += chunk; });
107
- req.on('end', () => resolve(data));
108
- });
109
-
110
- try {
111
- const parsed = JSON.parse(body) as { cols: number; rows: number };
112
- const client = this.clients.get(id);
113
- if (client) {
114
- client.cols = parsed.cols;
115
- client.rows = parsed.rows;
116
- if (this.lastTree) {
117
- this.sendLayout(client, this.lastTree);
118
- }
119
- }
120
- } catch {
121
- // Ignore invalid payloads
122
- }
123
-
124
- res.writeHead(204);
125
- res.end();
126
- return;
127
- }
128
-
129
- if (url.pathname === '/input' && req.method === 'POST') {
130
- const body = await new Promise<string>(resolve => {
131
- let data = '';
132
- req.on('data', chunk => { data += chunk; });
133
- req.on('end', () => resolve(data));
134
- });
135
-
136
- try {
137
- const parsed = JSON.parse(body) as InputEvent;
138
- this.inputBus?.emit(parsed);
139
- } catch {
140
- // Ignore invalid payloads
141
- }
142
-
143
- res.writeHead(204);
144
- res.end();
145
- return;
146
- }
147
-
148
- if (url.pathname === '/upload' && req.method === 'POST') {
149
- const buffer = await new Promise<Buffer>(resolve => {
150
- const chunks: Buffer[] = [];
151
- req.on('data', chunk => { chunks.push(Buffer.from(chunk)); });
152
- req.on('end', () => resolve(Buffer.concat(chunks)));
153
- });
154
- const headerName = req.headers['x-filename'];
155
- const rawName = typeof headerName === 'string' && headerName.trim().length > 0 ? headerName : 'upload.bin';
156
- const safeName = basename(rawName).replace(/[^a-zA-Z0-9._-]/g, '_');
157
- const dir = join(homedir(), '.ztc', 'uploads');
158
- await mkdir(dir, { recursive: true });
159
- const filePath = join(dir, `${Date.now()}-${randomUUID().slice(0, 8)}-${safeName}`);
160
- await writeFile(filePath, buffer);
161
- res.writeHead(200, { 'Content-Type': 'application/json' });
162
- res.end(JSON.stringify({ path: filePath }));
163
- return;
164
- }
165
-
166
- if (url.pathname === '/file' && req.method === 'GET') {
167
- const rawPath = url.searchParams.get('path');
168
- if (!rawPath) {
169
- res.writeHead(400);
170
- res.end();
171
- return;
172
- }
173
- const allowedRoots = [
174
- join(homedir(), '.ztc', 'uploads'),
175
- join(homedir(), '.ztc', 'clipboard')
176
- ];
177
- const resolvedPath = resolve(rawPath);
178
- const allowed = allowedRoots.some(root => resolvedPath.startsWith(resolve(root)));
179
- if (!allowed) {
180
- res.writeHead(403);
181
- res.end();
182
- return;
183
- }
184
- try {
185
- const data = await readFile(resolvedPath);
186
- res.writeHead(200, { 'Content-Type': 'application/octet-stream' });
187
- res.end(data);
188
- } catch {
189
- res.writeHead(404);
190
- res.end();
191
- }
192
- return;
193
- }
194
-
195
- res.writeHead(404);
196
- res.end();
197
- }
198
-
199
- private sendLayout(client: Client, tree: LayoutNode): void {
200
- const frame = computeLayout(tree, client.cols, client.rows);
201
- const payload = JSON.stringify(frame);
202
- client.res.write(`data: ${payload}\n\n`);
203
- }
204
- }
package/tsconfig.json DELETED
@@ -1,22 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "lib": ["ES2022"],
7
- "outDir": "./dist",
8
- "rootDir": "./src",
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "resolveJsonModule": true,
14
- "declaration": true,
15
- "declarationMap": true,
16
- "sourceMap": true,
17
- "jsx": "react-jsx",
18
- "jsxImportSource": "react"
19
- },
20
- "include": ["src/**/*"],
21
- "exclude": ["node_modules", "dist"]
22
- }
package/vite.config.ts DELETED
@@ -1,363 +0,0 @@
1
- import { defineConfig } from 'vite';
2
- import react from '@vitejs/plugin-react';
3
- import { resolve, join, basename } from 'path';
4
- import { mkdir, writeFile } from 'fs/promises';
5
- import { homedir } from 'os';
6
- import { randomUUID } from 'crypto';
7
- import { loadEmulationProfiles } from './src/emulation/catalog.js';
8
- import { configStore } from './src/config.js';
9
- import { runShellCommand, resolveWorkingDir } from './src/utils/shell.js';
10
- import { createAgentFromConfig } from './src/agent/factory.js';
11
- import { listModels } from './src/utils/models.js';
12
- import { autoActivateSkills, buildSkillPrompt } from './src/skills/index.js';
13
- import { getSkillRegistry } from './src/skills/registry.js';
14
-
15
- export default defineConfig({
16
- root: 'web/dev',
17
- plugins: [
18
- react(),
19
- {
20
- name: 'ztc-emulation',
21
- configureServer(server) {
22
- let skillCache: any[] | null = null;
23
- const loadSkills = async () => {
24
- if (skillCache) return skillCache;
25
- skillCache = await getSkillRegistry();
26
- return skillCache;
27
- };
28
- server.middlewares.use('/__emulation/list', (_req, res) => {
29
- const payload = JSON.stringify(loadEmulationProfiles().map(profile => ({
30
- id: profile.id,
31
- name: profile.name,
32
- description: profile.description,
33
- systemPrompt: profile.systemPrompt,
34
- tools: profile.tools
35
- })));
36
- res.statusCode = 200;
37
- res.setHeader('Content-Type', 'application/json');
38
- res.end(payload);
39
- });
40
- server.middlewares.use('/__config/get', async (_req, res) => {
41
- await configStore.load(true);
42
- const payload = JSON.stringify({
43
- config: configStore.get(),
44
- locationLabel: configStore.getConfigPath()
45
- });
46
- res.statusCode = 200;
47
- res.setHeader('Content-Type', 'application/json');
48
- res.end(payload);
49
- });
50
- server.middlewares.use('/__config/save', async (req, res) => {
51
- const body = await new Promise<string>((resolve) => {
52
- let data = '';
53
- req.on('data', chunk => { data += chunk; });
54
- req.on('end', () => resolve(data));
55
- });
56
- try {
57
- const parsed = JSON.parse(body) as { config?: Record<string, unknown> };
58
- if (parsed.config && typeof parsed.config === 'object') {
59
- configStore.setAll(parsed.config);
60
- await configStore.save();
61
- }
62
- } catch {
63
- // ignore invalid payloads
64
- }
65
- const payload = JSON.stringify({
66
- config: configStore.get(),
67
- locationLabel: configStore.getConfigPath()
68
- });
69
- res.statusCode = 200;
70
- res.setHeader('Content-Type', 'application/json');
71
- res.end(payload);
72
- });
73
- server.middlewares.use('/__shell/cwd', (_req, res) => {
74
- const payload = JSON.stringify({ cwd: process.cwd() });
75
- res.statusCode = 200;
76
- res.setHeader('Content-Type', 'application/json');
77
- res.end(payload);
78
- });
79
- server.middlewares.use('/__shell/resolve', async (req, res) => {
80
- const body = await new Promise<string>((resolve) => {
81
- let data = '';
82
- req.on('data', chunk => { data += chunk; });
83
- req.on('end', () => resolve(data));
84
- });
85
- try {
86
- const parsed = JSON.parse(body) as { cwd?: string; path?: string };
87
- const base = parsed.cwd || process.cwd();
88
- const next = await resolveWorkingDir(base, parsed.path || '');
89
- const payload = JSON.stringify({ cwd: next });
90
- res.statusCode = 200;
91
- res.setHeader('Content-Type', 'application/json');
92
- res.end(payload);
93
- return;
94
- } catch (err) {
95
- res.statusCode = 400;
96
- res.setHeader('Content-Type', 'application/json');
97
- res.end(JSON.stringify({ error: 'Invalid path' }));
98
- return;
99
- }
100
- });
101
- server.middlewares.use('/__shell/run', async (req, res) => {
102
- const body = await new Promise<string>((resolve) => {
103
- let data = '';
104
- req.on('data', chunk => { data += chunk; });
105
- req.on('end', () => resolve(data));
106
- });
107
- try {
108
- const parsed = JSON.parse(body) as { command?: string; cwd?: string };
109
- const command = parsed.command || '';
110
- const cwd = parsed.cwd || process.cwd();
111
- const result = await runShellCommand(command, cwd);
112
- const payload = JSON.stringify(result);
113
- res.statusCode = 200;
114
- res.setHeader('Content-Type', 'application/json');
115
- res.end(payload);
116
- return;
117
- } catch (err) {
118
- res.statusCode = 500;
119
- res.setHeader('Content-Type', 'application/json');
120
- res.end(JSON.stringify({ error: 'Command failed' }));
121
- return;
122
- }
123
- });
124
- server.middlewares.use('/__upload', async (req, res) => {
125
- if (req.method !== 'POST') {
126
- res.statusCode = 405;
127
- res.end();
128
- return;
129
- }
130
- const buffer = await new Promise<Buffer>((resolve) => {
131
- const chunks: Buffer[] = [];
132
- req.on('data', chunk => { chunks.push(Buffer.from(chunk)); });
133
- req.on('end', () => resolve(Buffer.concat(chunks)));
134
- });
135
- const headerName = req.headers['x-filename'];
136
- const rawName = typeof headerName === 'string' && headerName.trim().length > 0 ? headerName : 'upload.bin';
137
- const safeName = basename(rawName).replace(/[^a-zA-Z0-9._-]/g, '_');
138
- const dir = join(homedir(), '.ztc', 'uploads');
139
- await mkdir(dir, { recursive: true });
140
- const filePath = join(dir, `${Date.now()}-${randomUUID().slice(0, 8)}-${safeName}`);
141
- await writeFile(filePath, buffer);
142
- res.statusCode = 200;
143
- res.setHeader('Content-Type', 'application/json');
144
- res.end(JSON.stringify({ path: filePath }));
145
- });
146
- server.middlewares.use('/__file', async (req, res) => {
147
- const url = new URL(req.url || '', 'http://localhost');
148
- const rawPath = url.searchParams.get('path');
149
- if (!rawPath) {
150
- res.statusCode = 400;
151
- res.end();
152
- return;
153
- }
154
- const allowedRoots = [
155
- join(homedir(), '.ztc', 'uploads'),
156
- join(homedir(), '.ztc', 'clipboard')
157
- ];
158
- const resolvedPath = resolve(rawPath);
159
- const allowed = allowedRoots.some(root => resolvedPath.startsWith(resolve(root)));
160
- if (!allowed) {
161
- res.statusCode = 403;
162
- res.end();
163
- return;
164
- }
165
- try {
166
- const data = await (await import('fs/promises')).readFile(resolvedPath);
167
- res.statusCode = 200;
168
- res.setHeader('Content-Type', 'application/octet-stream');
169
- res.end(data);
170
- } catch {
171
- res.statusCode = 404;
172
- res.end();
173
- }
174
- });
175
- server.middlewares.use('/__agent/run', async (req, res) => {
176
- const body = await new Promise<string>((resolve) => {
177
- let data = '';
178
- req.on('data', chunk => { data += chunk; });
179
- req.on('end', () => resolve(data));
180
- });
181
- try {
182
- const parsed = JSON.parse(body) as { messages?: unknown[] };
183
- const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
184
- const lastUser = [...messages].reverse().find(msg => msg && typeof msg === 'object' && (msg as any).role === 'user');
185
- const text = lastUser && typeof (lastUser as any).content === 'string' ? (lastUser as any).content : '';
186
- const skills = await loadSkills();
187
- const activated = autoActivateSkills(text, skills);
188
- const skillPrompt = buildSkillPrompt(activated);
189
- await configStore.load();
190
- const provider = configStore.getProvider();
191
- const apiKey = configStore.getApiKey(provider);
192
- const agent = createAgentFromConfig({
193
- config: configStore.get(),
194
- provider,
195
- apiKey,
196
- openaiCompatibleBaseUrl: configStore.getOpenAICompatibleBaseUrl(),
197
- emulationId: configStore.getEmulationId(),
198
- skillPrompt
199
- });
200
- if (!agent) {
201
- res.statusCode = 400;
202
- res.setHeader('Content-Type', 'application/json');
203
- res.end(JSON.stringify({ error: 'No API key configured' }));
204
- return;
205
- }
206
- const result = await agent.run(messages as any);
207
- res.statusCode = 200;
208
- res.setHeader('Content-Type', 'application/json');
209
- res.end(JSON.stringify({
210
- content: result.content,
211
- toolCalls: result.toolCalls,
212
- usage: result.usage
213
- }));
214
- return;
215
- } catch (err) {
216
- const message = err instanceof Error ? err.message : 'Agent error';
217
- res.statusCode = 500;
218
- res.setHeader('Content-Type', 'application/json');
219
- res.end(JSON.stringify({ error: message }));
220
- }
221
- });
222
- server.middlewares.use('/__agent/stream', async (req, res) => {
223
- const body = await new Promise<string>((resolve) => {
224
- let data = '';
225
- req.on('data', chunk => { data += chunk; });
226
- req.on('end', () => resolve(data));
227
- });
228
- res.writeHead(200, {
229
- 'Content-Type': 'text/event-stream',
230
- 'Cache-Control': 'no-cache',
231
- Connection: 'keep-alive'
232
- });
233
- const send = (event: string, payload: unknown) => {
234
- res.write(`event: ${event}\n`);
235
- res.write(`data: ${JSON.stringify(payload)}\n\n`);
236
- };
237
- let cleanup: (() => void) | null = null;
238
- try {
239
- const parsed = JSON.parse(body) as { messages?: unknown[] };
240
- const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
241
- const lastUser = [...messages].reverse().find(msg => msg && typeof msg === 'object' && (msg as any).role === 'user');
242
- const text = lastUser && typeof (lastUser as any).content === 'string' ? (lastUser as any).content : '';
243
- const skills = await loadSkills();
244
- const activated = autoActivateSkills(text, skills);
245
- const skillPrompt = buildSkillPrompt(activated);
246
- if (activated.length > 0) {
247
- send('skill_activated', { skills: activated.map(skill => ({ id: skill.id, name: skill.name })) });
248
- }
249
- await configStore.load();
250
- const provider = configStore.getProvider();
251
- const apiKey = configStore.getApiKey(provider);
252
- const agent = createAgentFromConfig({
253
- config: configStore.get(),
254
- provider,
255
- apiKey,
256
- openaiCompatibleBaseUrl: configStore.getOpenAICompatibleBaseUrl(),
257
- emulationId: configStore.getEmulationId(),
258
- skillPrompt
259
- });
260
- if (!agent) {
261
- send('error', { error: 'No API key configured' });
262
- res.end();
263
- return;
264
- }
265
- cleanup = agent.on((event) => {
266
- if (event.type === 'stream_start') {
267
- send('stream_start', {});
268
- } else if (event.type === 'stream_delta') {
269
- send('stream_delta', { content: event.content });
270
- } else if (event.type === 'stream_end') {
271
- send('stream_end', {});
272
- } else if (event.type === 'token_usage') {
273
- send('token_usage', { usage: event.usage });
274
- } else if (event.type === 'tool_start') {
275
- send('tool_start', { tool: event.tool, args: event.args });
276
- } else if (event.type === 'tool_end') {
277
- send('tool_end', { tool: event.tool, result: event.result });
278
- } else if (event.type === 'tool_error') {
279
- send('tool_error', { tool: event.tool, error: event.error });
280
- }
281
- });
282
- const result = await agent.run(messages as any);
283
- send('result', {
284
- content: result.content,
285
- toolCalls: result.toolCalls,
286
- usage: result.usage
287
- });
288
- res.end();
289
- } catch (err) {
290
- const message = err instanceof Error ? err.message : 'Agent error';
291
- send('error', { error: message });
292
- res.end();
293
- } finally {
294
- cleanup?.();
295
- }
296
- });
297
- server.middlewares.use('/__models/list', async (req, res) => {
298
- try {
299
- await configStore.load();
300
- const url = new URL(req.url || '', 'http://localhost');
301
- const provider = url.searchParams.get('provider') || configStore.getProvider();
302
- const models = await listModels({
303
- provider,
304
- apiKey: configStore.getApiKey(provider),
305
- baseUrl: configStore.getOpenAICompatibleBaseUrl()
306
- });
307
- res.statusCode = 200;
308
- res.setHeader('Content-Type', 'application/json');
309
- res.end(JSON.stringify({ models }));
310
- } catch (err) {
311
- const message = err instanceof Error ? err.message : 'Models error';
312
- res.statusCode = 500;
313
- res.setHeader('Content-Type', 'application/json');
314
- res.end(JSON.stringify({ error: message }));
315
- }
316
- });
317
- server.middlewares.use('/__skills/list', async (_req, res) => {
318
- try {
319
- const skills = await loadSkills();
320
- res.statusCode = 200;
321
- res.setHeader('Content-Type', 'application/json');
322
- res.end(JSON.stringify({ skills }));
323
- } catch (err) {
324
- const message = err instanceof Error ? err.message : 'Skills error';
325
- res.statusCode = 500;
326
- res.setHeader('Content-Type', 'application/json');
327
- res.end(JSON.stringify({ error: message }));
328
- }
329
- });
330
- }
331
- }
332
- ],
333
- esbuild: {
334
- target: 'esnext'
335
- },
336
- resolve: {
337
- alias: [
338
- { find: '@src', replacement: resolve(__dirname, 'src') }
339
- ]
340
- },
341
- build: {
342
- target: 'esnext',
343
- outDir: '../../dist-web',
344
- emptyOutDir: true
345
- },
346
- optimizeDeps: {
347
- esbuildOptions: {
348
- target: 'esnext'
349
- }
350
- },
351
- ssr: {
352
- target: 'esnext'
353
- },
354
- define: {
355
- 'import.meta.env.LEGACY': 'false'
356
- },
357
- server: {
358
- port: 5175,
359
- fs: {
360
- allow: ['.']
361
- }
362
- }
363
- });