awel 0.1.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/LICENSE +200 -0
- package/README.md +98 -0
- package/babel-plugin-awel-source.cjs +79 -0
- package/bin/awel.js +2 -0
- package/dist/cli/agent.d.ts +6 -0
- package/dist/cli/agent.js +266 -0
- package/dist/cli/babel-setup.d.ts +1 -0
- package/dist/cli/babel-setup.js +180 -0
- package/dist/cli/comment-popup.d.ts +2 -0
- package/dist/cli/comment-popup.js +206 -0
- package/dist/cli/config.d.ts +14 -0
- package/dist/cli/config.js +29 -0
- package/dist/cli/devserver.d.ts +17 -0
- package/dist/cli/devserver.js +43 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +34 -0
- package/dist/cli/inspector.d.ts +2 -0
- package/dist/cli/inspector.js +117 -0
- package/dist/cli/logger.d.ts +10 -0
- package/dist/cli/logger.js +40 -0
- package/dist/cli/plan-store.d.ts +14 -0
- package/dist/cli/plan-store.js +18 -0
- package/dist/cli/providers/registry.d.ts +17 -0
- package/dist/cli/providers/registry.js +112 -0
- package/dist/cli/providers/types.d.ts +17 -0
- package/dist/cli/providers/types.js +1 -0
- package/dist/cli/providers/vercel.d.ts +4 -0
- package/dist/cli/providers/vercel.js +483 -0
- package/dist/cli/proxy.d.ts +5 -0
- package/dist/cli/proxy.js +72 -0
- package/dist/cli/server.d.ts +7 -0
- package/dist/cli/server.js +104 -0
- package/dist/cli/session.d.ts +32 -0
- package/dist/cli/session.js +77 -0
- package/dist/cli/skills/react-best-practices.md +2934 -0
- package/dist/cli/skills/skills/react-best-practices.md +2934 -0
- package/dist/cli/sse.d.ts +17 -0
- package/dist/cli/sse.js +51 -0
- package/dist/cli/subprocess.d.ts +30 -0
- package/dist/cli/subprocess.js +163 -0
- package/dist/cli/tools/ask-user.d.ts +11 -0
- package/dist/cli/tools/ask-user.js +28 -0
- package/dist/cli/tools/bash.d.ts +4 -0
- package/dist/cli/tools/bash.js +30 -0
- package/dist/cli/tools/code-search.d.ts +4 -0
- package/dist/cli/tools/code-search.js +70 -0
- package/dist/cli/tools/edit.d.ts +6 -0
- package/dist/cli/tools/edit.js +37 -0
- package/dist/cli/tools/glob.d.ts +4 -0
- package/dist/cli/tools/glob.js +29 -0
- package/dist/cli/tools/grep.d.ts +5 -0
- package/dist/cli/tools/grep.js +146 -0
- package/dist/cli/tools/index.d.ts +86 -0
- package/dist/cli/tools/index.js +41 -0
- package/dist/cli/tools/ls.d.ts +3 -0
- package/dist/cli/tools/ls.js +31 -0
- package/dist/cli/tools/multi-edit.d.ts +8 -0
- package/dist/cli/tools/multi-edit.js +53 -0
- package/dist/cli/tools/propose-plan.d.ts +4 -0
- package/dist/cli/tools/propose-plan.js +21 -0
- package/dist/cli/tools/react-best-practices.d.ts +3 -0
- package/dist/cli/tools/react-best-practices.js +55 -0
- package/dist/cli/tools/read.d.ts +3 -0
- package/dist/cli/tools/read.js +24 -0
- package/dist/cli/tools/restart-dev-server.d.ts +3 -0
- package/dist/cli/tools/restart-dev-server.js +18 -0
- package/dist/cli/tools/todo.d.ts +8 -0
- package/dist/cli/tools/todo.js +59 -0
- package/dist/cli/tools/web-fetch.d.ts +5 -0
- package/dist/cli/tools/web-fetch.js +116 -0
- package/dist/cli/tools/web-search.d.ts +5 -0
- package/dist/cli/tools/web-search.js +74 -0
- package/dist/cli/tools/write.d.ts +4 -0
- package/dist/cli/tools/write.js +26 -0
- package/dist/cli/types.d.ts +16 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/undo.d.ts +49 -0
- package/dist/cli/undo.js +212 -0
- package/dist/cli/verbose.d.ts +7 -0
- package/dist/cli/verbose.js +60 -0
- package/dist/dashboard/assets/index-Bk--q3wu.js +313 -0
- package/dist/dashboard/assets/index-DkWV03So.css +1 -0
- package/dist/dashboard/index.html +16 -0
- package/dist/host/host.js +274 -0
- package/package.json +67 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { serve } from '@hono/node-server';
|
|
3
|
+
import httpProxy from 'http-proxy';
|
|
4
|
+
import { createProxyMiddleware } from './proxy.js';
|
|
5
|
+
import { createAgentRoute } from './agent.js';
|
|
6
|
+
import { createUndoRoute } from './undo.js';
|
|
7
|
+
import { createInspectorRoute } from './inspector.js';
|
|
8
|
+
import { createCommentPopupRoute } from './comment-popup.js';
|
|
9
|
+
import { trackProxySocket } from './devserver.js';
|
|
10
|
+
import { getMimeType } from './config.js';
|
|
11
|
+
import { awel } from './logger.js';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { dirname, join } from 'path';
|
|
14
|
+
import { readFileSync, existsSync } from 'fs';
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = dirname(__filename);
|
|
17
|
+
/**
|
|
18
|
+
* Serves a static file with proper MIME type, or returns null if not found
|
|
19
|
+
*/
|
|
20
|
+
function serveStaticFile(filePath) {
|
|
21
|
+
if (!existsSync(filePath))
|
|
22
|
+
return null;
|
|
23
|
+
const buffer = readFileSync(filePath);
|
|
24
|
+
// Convert Node Buffer to ArrayBuffer for Hono compatibility
|
|
25
|
+
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
26
|
+
return {
|
|
27
|
+
content: arrayBuffer,
|
|
28
|
+
mimeType: getMimeType(filePath)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Serves the dashboard index.html, or returns null if not found
|
|
33
|
+
*/
|
|
34
|
+
function serveDashboardIndex() {
|
|
35
|
+
const indexPath = join(__dirname, '../dashboard/index.html');
|
|
36
|
+
if (!existsSync(indexPath))
|
|
37
|
+
return null;
|
|
38
|
+
return readFileSync(indexPath, 'utf-8');
|
|
39
|
+
}
|
|
40
|
+
export async function startServer({ awelPort, targetPort, projectCwd }) {
|
|
41
|
+
const app = new Hono();
|
|
42
|
+
// Create a proxy for WebSocket connections
|
|
43
|
+
const wsProxy = httpProxy.createProxyServer({
|
|
44
|
+
target: `http://localhost:${targetPort}`,
|
|
45
|
+
ws: true,
|
|
46
|
+
});
|
|
47
|
+
wsProxy.on('error', (err) => {
|
|
48
|
+
console.error('WebSocket proxy error:', err.message);
|
|
49
|
+
});
|
|
50
|
+
// Track target-side sockets so we can pause HMR during agent streams
|
|
51
|
+
wsProxy.on('open', (proxySocket) => {
|
|
52
|
+
trackProxySocket(proxySocket);
|
|
53
|
+
});
|
|
54
|
+
// Mount agent API routes
|
|
55
|
+
app.route('/', createAgentRoute(projectCwd, targetPort));
|
|
56
|
+
// Mount undo API routes
|
|
57
|
+
app.route('/', createUndoRoute(projectCwd));
|
|
58
|
+
// Mount inspector relay routes
|
|
59
|
+
app.route('/', createInspectorRoute(projectCwd));
|
|
60
|
+
// Serve the comment popup page (loaded in an iframe by the host script)
|
|
61
|
+
app.route('/', createCommentPopupRoute());
|
|
62
|
+
// Serve the host script
|
|
63
|
+
app.get('/_awel/host.js', async (c) => {
|
|
64
|
+
const hostDistPath = join(__dirname, '../host/host.js');
|
|
65
|
+
const file = serveStaticFile(hostDistPath);
|
|
66
|
+
if (file) {
|
|
67
|
+
return c.body(file.content, 200, { 'Content-Type': file.mimeType });
|
|
68
|
+
}
|
|
69
|
+
return c.text('Host script not found. Run npm run build:host first.', 404);
|
|
70
|
+
});
|
|
71
|
+
// Serve the dashboard app
|
|
72
|
+
app.get('/_awel/dashboard', async (c) => {
|
|
73
|
+
const html = serveDashboardIndex();
|
|
74
|
+
if (html)
|
|
75
|
+
return c.html(html);
|
|
76
|
+
return c.text('Dashboard not found. Run npm run build:dashboard first.', 404);
|
|
77
|
+
});
|
|
78
|
+
app.get('/_awel/dashboard/*', async (c) => {
|
|
79
|
+
const path = c.req.path.replace('/_awel/dashboard/', '');
|
|
80
|
+
const filePath = join(__dirname, '../dashboard', path);
|
|
81
|
+
const file = serveStaticFile(filePath);
|
|
82
|
+
if (file) {
|
|
83
|
+
return c.body(file.content, 200, { 'Content-Type': file.mimeType });
|
|
84
|
+
}
|
|
85
|
+
// Fallback to index.html for SPA routing
|
|
86
|
+
const html = serveDashboardIndex();
|
|
87
|
+
if (html)
|
|
88
|
+
return c.html(html);
|
|
89
|
+
return c.text('Not found', 404);
|
|
90
|
+
});
|
|
91
|
+
// Proxy all other requests to the target app
|
|
92
|
+
app.all('*', createProxyMiddleware(targetPort, projectCwd));
|
|
93
|
+
// Create the HTTP server with Hono
|
|
94
|
+
const server = serve({
|
|
95
|
+
fetch: app.fetch,
|
|
96
|
+
port: awelPort,
|
|
97
|
+
}, (info) => {
|
|
98
|
+
awel.log(`🎛️ Awel control server running on http://localhost:${info.port}`);
|
|
99
|
+
});
|
|
100
|
+
// Handle WebSocket upgrades for HMR
|
|
101
|
+
server.on('upgrade', (req, socket, head) => {
|
|
102
|
+
wsProxy.ws(req, socket, head);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { StreamProvider, ResponseMessage } from './providers/types.js';
|
|
2
|
+
import type { ModelMessage, UserContent } from 'ai';
|
|
3
|
+
/**
|
|
4
|
+
* Returns the existing session if the model matches, otherwise creates a new
|
|
5
|
+
* provider while preserving message history. Messages are only reset when
|
|
6
|
+
* switching to or from the claude-code provider, whose self-contained tool
|
|
7
|
+
* set is incompatible with messages produced by other providers.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getOrCreateSession(modelId: string): {
|
|
10
|
+
provider: StreamProvider;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Builds the messages array to send to the provider.
|
|
14
|
+
* Returns the full accumulated history plus the new user message.
|
|
15
|
+
*
|
|
16
|
+
* Includes a safety net: if the session ends with an orphan user message
|
|
17
|
+
* (e.g. from an aborted stream that didn't clean up), it's removed to
|
|
18
|
+
* avoid consecutive user messages that cause API 400 errors.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getSessionMessages(prompt: string | UserContent): ModelMessage[];
|
|
21
|
+
/**
|
|
22
|
+
* Appends a user message to the session history.
|
|
23
|
+
*/
|
|
24
|
+
export declare function appendUserMessage(content: string | UserContent): void;
|
|
25
|
+
/**
|
|
26
|
+
* Appends LLM response messages to the session history.
|
|
27
|
+
*/
|
|
28
|
+
export declare function appendResponseMessages(msgs: ResponseMessage[]): void;
|
|
29
|
+
/**
|
|
30
|
+
* Resets the session entirely (called on history clear).
|
|
31
|
+
*/
|
|
32
|
+
export declare function resetSession(): void;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// ─── Chat Session ────────────────────────────────────────────
|
|
2
|
+
// Module-level singleton managing multi-turn conversation state.
|
|
3
|
+
// The provider is cached and reused across requests; a model switch
|
|
4
|
+
// swaps the provider while preserving message history (unless switching
|
|
5
|
+
// to or from the self-contained claude-code provider).
|
|
6
|
+
import { resolveProvider } from './providers/registry.js';
|
|
7
|
+
let session = null;
|
|
8
|
+
/**
|
|
9
|
+
* Returns the existing session if the model matches, otherwise creates a new
|
|
10
|
+
* provider while preserving message history. Messages are only reset when
|
|
11
|
+
* switching to or from the claude-code provider, whose self-contained tool
|
|
12
|
+
* set is incompatible with messages produced by other providers.
|
|
13
|
+
*/
|
|
14
|
+
export function getOrCreateSession(modelId) {
|
|
15
|
+
if (session && session.modelId === modelId) {
|
|
16
|
+
return { provider: session.provider };
|
|
17
|
+
}
|
|
18
|
+
const { provider, modelProvider } = resolveProvider(modelId);
|
|
19
|
+
const canPreserveMessages = session !== null &&
|
|
20
|
+
session.modelProvider !== 'claude-code' &&
|
|
21
|
+
modelProvider !== 'claude-code';
|
|
22
|
+
session = {
|
|
23
|
+
modelId,
|
|
24
|
+
modelProvider,
|
|
25
|
+
provider,
|
|
26
|
+
messages: canPreserveMessages ? session.messages : [],
|
|
27
|
+
};
|
|
28
|
+
return { provider: session.provider };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Builds the messages array to send to the provider.
|
|
32
|
+
* Returns the full accumulated history plus the new user message.
|
|
33
|
+
*
|
|
34
|
+
* Includes a safety net: if the session ends with an orphan user message
|
|
35
|
+
* (e.g. from an aborted stream that didn't clean up), it's removed to
|
|
36
|
+
* avoid consecutive user messages that cause API 400 errors.
|
|
37
|
+
*/
|
|
38
|
+
export function getSessionMessages(prompt) {
|
|
39
|
+
const userMessage = { role: 'user', content: prompt };
|
|
40
|
+
if (!session) {
|
|
41
|
+
return [userMessage];
|
|
42
|
+
}
|
|
43
|
+
// Safety net: strip trailing orphan user messages to maintain alternation.
|
|
44
|
+
// This can happen if a stream was aborted between appendUserMessage and
|
|
45
|
+
// appendResponseMessages in a previous request.
|
|
46
|
+
const messages = [...session.messages];
|
|
47
|
+
while (messages.length > 0 && messages[messages.length - 1].role === 'user') {
|
|
48
|
+
messages.pop();
|
|
49
|
+
}
|
|
50
|
+
// Also fix the actual session to prevent accumulation
|
|
51
|
+
if (messages.length !== session.messages.length) {
|
|
52
|
+
session.messages = messages;
|
|
53
|
+
}
|
|
54
|
+
return [...messages, userMessage];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Appends a user message to the session history.
|
|
58
|
+
*/
|
|
59
|
+
export function appendUserMessage(content) {
|
|
60
|
+
if (!session)
|
|
61
|
+
return;
|
|
62
|
+
session.messages.push({ role: 'user', content });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Appends LLM response messages to the session history.
|
|
66
|
+
*/
|
|
67
|
+
export function appendResponseMessages(msgs) {
|
|
68
|
+
if (!session)
|
|
69
|
+
return;
|
|
70
|
+
session.messages.push(...msgs);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resets the session entirely (called on history clear).
|
|
74
|
+
*/
|
|
75
|
+
export function resetSession() {
|
|
76
|
+
session = null;
|
|
77
|
+
}
|