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.
Files changed (85) hide show
  1. package/LICENSE +200 -0
  2. package/README.md +98 -0
  3. package/babel-plugin-awel-source.cjs +79 -0
  4. package/bin/awel.js +2 -0
  5. package/dist/cli/agent.d.ts +6 -0
  6. package/dist/cli/agent.js +266 -0
  7. package/dist/cli/babel-setup.d.ts +1 -0
  8. package/dist/cli/babel-setup.js +180 -0
  9. package/dist/cli/comment-popup.d.ts +2 -0
  10. package/dist/cli/comment-popup.js +206 -0
  11. package/dist/cli/config.d.ts +14 -0
  12. package/dist/cli/config.js +29 -0
  13. package/dist/cli/devserver.d.ts +17 -0
  14. package/dist/cli/devserver.js +43 -0
  15. package/dist/cli/index.d.ts +1 -0
  16. package/dist/cli/index.js +34 -0
  17. package/dist/cli/inspector.d.ts +2 -0
  18. package/dist/cli/inspector.js +117 -0
  19. package/dist/cli/logger.d.ts +10 -0
  20. package/dist/cli/logger.js +40 -0
  21. package/dist/cli/plan-store.d.ts +14 -0
  22. package/dist/cli/plan-store.js +18 -0
  23. package/dist/cli/providers/registry.d.ts +17 -0
  24. package/dist/cli/providers/registry.js +112 -0
  25. package/dist/cli/providers/types.d.ts +17 -0
  26. package/dist/cli/providers/types.js +1 -0
  27. package/dist/cli/providers/vercel.d.ts +4 -0
  28. package/dist/cli/providers/vercel.js +483 -0
  29. package/dist/cli/proxy.d.ts +5 -0
  30. package/dist/cli/proxy.js +72 -0
  31. package/dist/cli/server.d.ts +7 -0
  32. package/dist/cli/server.js +104 -0
  33. package/dist/cli/session.d.ts +32 -0
  34. package/dist/cli/session.js +77 -0
  35. package/dist/cli/skills/react-best-practices.md +2934 -0
  36. package/dist/cli/skills/skills/react-best-practices.md +2934 -0
  37. package/dist/cli/sse.d.ts +17 -0
  38. package/dist/cli/sse.js +51 -0
  39. package/dist/cli/subprocess.d.ts +30 -0
  40. package/dist/cli/subprocess.js +163 -0
  41. package/dist/cli/tools/ask-user.d.ts +11 -0
  42. package/dist/cli/tools/ask-user.js +28 -0
  43. package/dist/cli/tools/bash.d.ts +4 -0
  44. package/dist/cli/tools/bash.js +30 -0
  45. package/dist/cli/tools/code-search.d.ts +4 -0
  46. package/dist/cli/tools/code-search.js +70 -0
  47. package/dist/cli/tools/edit.d.ts +6 -0
  48. package/dist/cli/tools/edit.js +37 -0
  49. package/dist/cli/tools/glob.d.ts +4 -0
  50. package/dist/cli/tools/glob.js +29 -0
  51. package/dist/cli/tools/grep.d.ts +5 -0
  52. package/dist/cli/tools/grep.js +146 -0
  53. package/dist/cli/tools/index.d.ts +86 -0
  54. package/dist/cli/tools/index.js +41 -0
  55. package/dist/cli/tools/ls.d.ts +3 -0
  56. package/dist/cli/tools/ls.js +31 -0
  57. package/dist/cli/tools/multi-edit.d.ts +8 -0
  58. package/dist/cli/tools/multi-edit.js +53 -0
  59. package/dist/cli/tools/propose-plan.d.ts +4 -0
  60. package/dist/cli/tools/propose-plan.js +21 -0
  61. package/dist/cli/tools/react-best-practices.d.ts +3 -0
  62. package/dist/cli/tools/react-best-practices.js +55 -0
  63. package/dist/cli/tools/read.d.ts +3 -0
  64. package/dist/cli/tools/read.js +24 -0
  65. package/dist/cli/tools/restart-dev-server.d.ts +3 -0
  66. package/dist/cli/tools/restart-dev-server.js +18 -0
  67. package/dist/cli/tools/todo.d.ts +8 -0
  68. package/dist/cli/tools/todo.js +59 -0
  69. package/dist/cli/tools/web-fetch.d.ts +5 -0
  70. package/dist/cli/tools/web-fetch.js +116 -0
  71. package/dist/cli/tools/web-search.d.ts +5 -0
  72. package/dist/cli/tools/web-search.js +74 -0
  73. package/dist/cli/tools/write.d.ts +4 -0
  74. package/dist/cli/tools/write.js +26 -0
  75. package/dist/cli/types.d.ts +16 -0
  76. package/dist/cli/types.js +2 -0
  77. package/dist/cli/undo.d.ts +49 -0
  78. package/dist/cli/undo.js +212 -0
  79. package/dist/cli/verbose.d.ts +7 -0
  80. package/dist/cli/verbose.js +60 -0
  81. package/dist/dashboard/assets/index-Bk--q3wu.js +313 -0
  82. package/dist/dashboard/assets/index-DkWV03So.css +1 -0
  83. package/dist/dashboard/index.html +16 -0
  84. package/dist/host/host.js +274 -0
  85. 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
+ }