@nuraly/lumenjs 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -282
- package/dist/auth/config.d.ts +23 -0
- package/dist/auth/config.js +115 -0
- package/dist/auth/guard.d.ts +12 -0
- package/dist/auth/guard.js +28 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.js +1 -0
- package/dist/auth/middleware.d.ts +23 -0
- package/dist/auth/middleware.js +89 -0
- package/dist/auth/native-auth.d.ts +82 -0
- package/dist/auth/native-auth.js +340 -0
- package/dist/auth/oidc-client.d.ts +17 -0
- package/dist/auth/oidc-client.js +123 -0
- package/dist/auth/providers/google.d.ts +23 -0
- package/dist/auth/providers/google.js +25 -0
- package/dist/auth/providers/index.d.ts +2 -0
- package/dist/auth/providers/index.js +1 -0
- package/dist/auth/routes/login.d.ts +8 -0
- package/dist/auth/routes/login.js +121 -0
- package/dist/auth/routes/logout.d.ts +4 -0
- package/dist/auth/routes/logout.js +79 -0
- package/dist/auth/routes/oidc-callback.d.ts +3 -0
- package/dist/auth/routes/oidc-callback.js +70 -0
- package/dist/auth/routes/password.d.ts +5 -0
- package/dist/auth/routes/password.js +149 -0
- package/dist/auth/routes/signup.d.ts +3 -0
- package/dist/auth/routes/signup.js +81 -0
- package/dist/auth/routes/token.d.ts +4 -0
- package/dist/auth/routes/token.js +70 -0
- package/dist/auth/routes/totp.d.ts +22 -0
- package/dist/auth/routes/totp.js +232 -0
- package/dist/auth/routes/utils.d.ts +7 -0
- package/dist/auth/routes/utils.js +35 -0
- package/dist/auth/routes/verify.d.ts +3 -0
- package/dist/auth/routes/verify.js +26 -0
- package/dist/auth/routes.d.ts +8 -0
- package/dist/auth/routes.js +124 -0
- package/dist/auth/session.d.ts +8 -0
- package/dist/auth/session.js +54 -0
- package/dist/auth/token.d.ts +33 -0
- package/dist/auth/token.js +90 -0
- package/dist/auth/types.d.ts +156 -0
- package/dist/auth/types.js +2 -0
- package/dist/build/build-client.d.ts +15 -0
- package/dist/build/build-client.js +45 -0
- package/dist/build/build-prerender.d.ts +11 -0
- package/dist/build/build-prerender.js +159 -0
- package/dist/build/build-server.d.ts +18 -0
- package/dist/build/build-server.js +107 -0
- package/dist/build/build.js +60 -123
- package/dist/build/scan.d.ts +18 -0
- package/dist/build/scan.js +77 -6
- package/dist/build/serve-api.js +8 -2
- package/dist/build/serve-loaders.d.ts +4 -4
- package/dist/build/serve-loaders.js +26 -18
- package/dist/build/serve-ssr.js +38 -11
- package/dist/build/serve-static.js +3 -3
- package/dist/build/serve.js +341 -18
- package/dist/cli.js +37 -6
- package/dist/communication/encryption.d.ts +35 -0
- package/dist/communication/encryption.js +90 -0
- package/dist/communication/handlers/context.d.ts +27 -0
- package/dist/communication/handlers/context.js +1 -0
- package/dist/communication/handlers/conversation.d.ts +24 -0
- package/dist/communication/handlers/conversation.js +113 -0
- package/dist/communication/handlers/file-upload.d.ts +17 -0
- package/dist/communication/handlers/file-upload.js +62 -0
- package/dist/communication/handlers/messaging.d.ts +30 -0
- package/dist/communication/handlers/messaging.js +237 -0
- package/dist/communication/handlers/presence.d.ts +15 -0
- package/dist/communication/handlers/presence.js +76 -0
- package/dist/communication/handlers.d.ts +5 -0
- package/dist/communication/handlers.js +5 -0
- package/dist/communication/index.d.ts +9 -0
- package/dist/communication/index.js +7 -0
- package/dist/communication/link-preview.d.ts +18 -0
- package/dist/communication/link-preview.js +115 -0
- package/dist/communication/schema.d.ts +10 -0
- package/dist/communication/schema.js +101 -0
- package/dist/communication/server.d.ts +86 -0
- package/dist/communication/server.js +212 -0
- package/dist/communication/signaling.d.ts +43 -0
- package/dist/communication/signaling.js +271 -0
- package/dist/communication/store.d.ts +71 -0
- package/dist/communication/store.js +289 -0
- package/dist/communication/types.d.ts +454 -0
- package/dist/communication/types.js +1 -0
- package/dist/create.d.ts +1 -0
- package/dist/create.js +55 -0
- package/dist/db/auto-migrate.d.ts +3 -0
- package/dist/db/auto-migrate.js +100 -0
- package/dist/db/client.d.ts +3 -0
- package/dist/db/client.js +18 -0
- package/dist/db/index.d.ts +17 -13
- package/dist/db/index.js +205 -26
- package/dist/db/seed.d.ts +12 -0
- package/dist/db/seed.js +88 -0
- package/dist/db/table.d.ts +10 -0
- package/dist/db/table.js +12 -0
- package/dist/dev-server/config.d.ts +11 -0
- package/dist/dev-server/config.js +40 -20
- package/dist/dev-server/index-html.d.ts +4 -0
- package/dist/dev-server/index-html.js +21 -6
- package/dist/dev-server/nuralyui-aliases.d.ts +0 -4
- package/dist/dev-server/nuralyui-aliases.js +115 -94
- package/dist/dev-server/plugins/vite-plugin-api-routes.js +29 -5
- package/dist/dev-server/plugins/vite-plugin-auth.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-auth.js +223 -0
- package/dist/dev-server/plugins/vite-plugin-auto-define.d.ts +16 -0
- package/dist/dev-server/plugins/vite-plugin-auto-define.js +111 -0
- package/dist/dev-server/plugins/vite-plugin-communication.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-communication.js +205 -0
- package/dist/dev-server/plugins/vite-plugin-editor-api.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-editor-api.js +318 -0
- package/dist/dev-server/plugins/vite-plugin-i18n.js +69 -2
- package/dist/dev-server/plugins/vite-plugin-lit-dedup.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-lit-dedup.js +78 -34
- package/dist/dev-server/plugins/vite-plugin-lit-hmr.js +44 -2
- package/dist/dev-server/plugins/vite-plugin-llms.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-llms.js +92 -0
- package/dist/dev-server/plugins/vite-plugin-loaders.js +146 -13
- package/dist/dev-server/plugins/vite-plugin-routes.js +16 -5
- package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
- package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
- package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
- package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
- package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +140 -3
- package/dist/dev-server/server.js +242 -70
- package/dist/dev-server/ssr-render.d.ts +2 -1
- package/dist/dev-server/ssr-render.js +117 -50
- package/dist/editor/ai/backend.d.ts +20 -0
- package/dist/editor/ai/backend.js +113 -0
- package/dist/editor/ai/claude-code-client.d.ts +20 -0
- package/dist/editor/ai/claude-code-client.js +145 -0
- package/dist/editor/ai/deepseek-client.d.ts +7 -0
- package/dist/editor/ai/deepseek-client.js +113 -0
- package/dist/editor/ai/opencode-client.d.ts +14 -0
- package/dist/editor/ai/opencode-client.js +99 -0
- package/dist/editor/ai/snapshot-store.d.ts +22 -0
- package/dist/editor/ai/snapshot-store.js +35 -0
- package/dist/editor/ai/types.d.ts +30 -0
- package/dist/editor/ai/types.js +136 -0
- package/dist/editor/ai-chat-panel.d.ts +13 -0
- package/dist/editor/ai-chat-panel.js +613 -0
- package/dist/editor/ai-markdown.d.ts +10 -0
- package/dist/editor/ai-markdown.js +70 -0
- package/dist/editor/ai-project-panel.d.ts +11 -0
- package/dist/editor/ai-project-panel.js +332 -0
- package/dist/editor/ast-modification.d.ts +11 -0
- package/dist/editor/ast-modification.js +1 -0
- package/dist/editor/ast-service.d.ts +30 -0
- package/dist/editor/ast-service.js +180 -0
- package/dist/editor/css-rules.d.ts +54 -0
- package/dist/editor/css-rules.js +423 -0
- package/dist/editor/editor-api-client.d.ts +51 -0
- package/dist/editor/editor-api-client.js +162 -0
- package/dist/editor/editor-bridge.d.ts +1 -0
- package/dist/editor/editor-bridge.js +18 -8
- package/dist/editor/editor-toolbar.d.ts +14 -0
- package/dist/editor/editor-toolbar.js +115 -0
- package/dist/editor/file-editor.d.ts +9 -0
- package/dist/editor/file-editor.js +236 -0
- package/dist/editor/file-service.d.ts +16 -0
- package/dist/editor/file-service.js +52 -0
- package/dist/editor/i18n-key-gen.d.ts +1 -0
- package/dist/editor/i18n-key-gen.js +7 -0
- package/dist/editor/inline-text-edit.d.ts +5 -0
- package/dist/editor/inline-text-edit.js +173 -92
- package/dist/editor/overlay-events.d.ts +5 -0
- package/dist/editor/overlay-events.js +364 -0
- package/dist/editor/overlay-hmr.d.ts +2 -0
- package/dist/editor/overlay-hmr.js +76 -0
- package/dist/editor/overlay-selection.d.ts +29 -0
- package/dist/editor/overlay-selection.js +148 -0
- package/dist/editor/overlay-utils.d.ts +12 -0
- package/dist/editor/overlay-utils.js +59 -0
- package/dist/editor/properties-panel-persist.d.ts +14 -0
- package/dist/editor/properties-panel-persist.js +70 -0
- package/dist/editor/properties-panel-rows.d.ts +10 -0
- package/dist/editor/properties-panel-rows.js +349 -0
- package/dist/editor/properties-panel-styles.d.ts +4 -0
- package/dist/editor/properties-panel-styles.js +174 -0
- package/dist/editor/properties-panel.d.ts +4 -0
- package/dist/editor/properties-panel.js +148 -0
- package/dist/editor/property-registry.d.ts +16 -0
- package/dist/editor/property-registry.js +303 -0
- package/dist/editor/standalone-file-panel.d.ts +0 -0
- package/dist/editor/standalone-file-panel.js +1 -0
- package/dist/editor/standalone-overlay-dom.d.ts +0 -0
- package/dist/editor/standalone-overlay-dom.js +1 -0
- package/dist/editor/standalone-overlay-styles.d.ts +0 -0
- package/dist/editor/standalone-overlay-styles.js +1 -0
- package/dist/editor/standalone-overlay.d.ts +1 -0
- package/dist/editor/standalone-overlay.js +76 -0
- package/dist/editor/syntax-highlighter.d.ts +4 -0
- package/dist/editor/syntax-highlighter.js +81 -0
- package/dist/editor/text-toolbar.d.ts +11 -0
- package/dist/editor/text-toolbar.js +327 -0
- package/dist/editor/toolbar-styles.d.ts +4 -0
- package/dist/editor/toolbar-styles.js +198 -0
- package/dist/email/index.d.ts +32 -0
- package/dist/email/index.js +154 -0
- package/dist/email/providers/resend.d.ts +2 -0
- package/dist/email/providers/resend.js +24 -0
- package/dist/email/providers/sendgrid.d.ts +2 -0
- package/dist/email/providers/sendgrid.js +31 -0
- package/dist/email/providers/smtp.d.ts +13 -0
- package/dist/email/providers/smtp.js +125 -0
- package/dist/email/template-engine.d.ts +18 -0
- package/dist/email/template-engine.js +116 -0
- package/dist/email/templates/base.d.ts +9 -0
- package/dist/email/templates/base.js +65 -0
- package/dist/email/templates/password-reset.d.ts +5 -0
- package/dist/email/templates/password-reset.js +15 -0
- package/dist/email/templates/verify-email.d.ts +5 -0
- package/dist/email/templates/verify-email.js +15 -0
- package/dist/email/templates/welcome.d.ts +5 -0
- package/dist/email/templates/welcome.js +13 -0
- package/dist/email/types.d.ts +49 -0
- package/dist/email/types.js +1 -0
- package/dist/llms/generate.d.ts +46 -0
- package/dist/llms/generate.js +185 -0
- package/dist/permissions/guard.d.ts +28 -0
- package/dist/permissions/guard.js +30 -0
- package/dist/permissions/index.d.ts +6 -0
- package/dist/permissions/index.js +3 -0
- package/dist/permissions/service.d.ts +80 -0
- package/dist/permissions/service.js +210 -0
- package/dist/permissions/tables.d.ts +5 -0
- package/dist/permissions/tables.js +68 -0
- package/dist/permissions/types.d.ts +33 -0
- package/dist/permissions/types.js +1 -0
- package/dist/runtime/app-shell.d.ts +1 -1
- package/dist/runtime/app-shell.js +164 -0
- package/dist/runtime/auth.d.ts +10 -0
- package/dist/runtime/auth.js +30 -0
- package/dist/runtime/communication.d.ts +137 -0
- package/dist/runtime/communication.js +228 -0
- package/dist/runtime/error-boundary.d.ts +23 -0
- package/dist/runtime/error-boundary.js +120 -0
- package/dist/runtime/i18n.d.ts +6 -1
- package/dist/runtime/i18n.js +42 -21
- package/dist/runtime/island.d.ts +16 -0
- package/dist/runtime/island.js +80 -0
- package/dist/runtime/router-data.d.ts +3 -0
- package/dist/runtime/router-data.js +102 -17
- package/dist/runtime/router-hydration.js +34 -2
- package/dist/runtime/router.d.ts +19 -2
- package/dist/runtime/router.js +237 -43
- package/dist/runtime/socket-client.d.ts +2 -0
- package/dist/runtime/socket-client.js +30 -0
- package/dist/runtime/webrtc.d.ts +91 -0
- package/dist/runtime/webrtc.js +428 -0
- package/dist/shared/dom-shims.js +4 -2
- package/dist/shared/graceful-shutdown.d.ts +8 -0
- package/dist/shared/graceful-shutdown.js +36 -0
- package/dist/shared/health.d.ts +8 -0
- package/dist/shared/health.js +25 -0
- package/dist/shared/llms-txt.d.ts +31 -0
- package/dist/shared/llms-txt.js +85 -0
- package/dist/shared/logger.d.ts +32 -0
- package/dist/shared/logger.js +93 -0
- package/dist/shared/meta.d.ts +27 -0
- package/dist/shared/meta.js +71 -0
- package/dist/shared/middleware-runner.d.ts +9 -0
- package/dist/shared/middleware-runner.js +29 -0
- package/dist/shared/rate-limit.d.ts +18 -0
- package/dist/shared/rate-limit.js +71 -0
- package/dist/shared/request-id.d.ts +5 -0
- package/dist/shared/request-id.js +18 -0
- package/dist/shared/route-matching.js +16 -1
- package/dist/shared/security-headers.d.ts +18 -0
- package/dist/shared/security-headers.js +38 -0
- package/dist/shared/socket-io-setup.d.ts +11 -0
- package/dist/shared/socket-io-setup.js +51 -0
- package/dist/shared/types.d.ts +15 -0
- package/dist/shared/utils.d.ts +33 -7
- package/dist/shared/utils.js +164 -27
- package/dist/storage/adapters/local.d.ts +44 -0
- package/dist/storage/adapters/local.js +85 -0
- package/dist/storage/adapters/s3.d.ts +32 -0
- package/dist/storage/adapters/s3.js +119 -0
- package/dist/storage/adapters/types.d.ts +53 -0
- package/dist/storage/adapters/types.js +1 -0
- package/dist/storage/index.d.ts +76 -0
- package/dist/storage/index.js +83 -0
- package/package.json +45 -7
- package/templates/blog/api/posts.ts +4 -18
- package/templates/blog/data/migrations/001_init.sql +6 -5
- package/templates/blog/lumenjs.config.ts +3 -0
- package/templates/blog/package.json +14 -0
- package/templates/blog/pages/_layout.ts +25 -0
- package/templates/blog/pages/index.ts +48 -22
- package/templates/blog/pages/posts/[slug].ts +45 -20
- package/templates/blog/pages/tag/[tag].ts +44 -0
- package/templates/dashboard/api/stats.ts +8 -5
- package/templates/dashboard/lumenjs.config.ts +3 -0
- package/templates/dashboard/package.json +14 -0
- package/templates/dashboard/pages/_layout.ts +25 -0
- package/templates/dashboard/pages/index.ts +54 -23
- package/templates/dashboard/pages/settings/index.ts +29 -0
- package/templates/default/lumenjs.config.ts +3 -0
- package/templates/default/package.json +14 -0
- package/templates/default/pages/index.ts +24 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode AI client — wraps the OpenCode REST API for AI coding agent integration.
|
|
3
|
+
* Connects to an OpenCode server (`opencode serve`) that handles LLM calls and file editing.
|
|
4
|
+
*/
|
|
5
|
+
import type { AiChatOptions, AiChatResult, AiStatusResult } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Stream an AI chat message via OpenCode's REST API.
|
|
8
|
+
* Creates a session, sends message, and parses the response.
|
|
9
|
+
*/
|
|
10
|
+
export declare function streamAiChat(projectDir: string, options: AiChatOptions): AiChatResult;
|
|
11
|
+
/**
|
|
12
|
+
* Check if OpenCode server is reachable.
|
|
13
|
+
*/
|
|
14
|
+
export declare function checkAiStatus(): Promise<AiStatusResult>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode AI client — wraps the OpenCode REST API for AI coding agent integration.
|
|
3
|
+
* Connects to an OpenCode server (`opencode serve`) that handles LLM calls and file editing.
|
|
4
|
+
*/
|
|
5
|
+
import { buildPrompt } from './types.js';
|
|
6
|
+
const OPENCODE_URL = process.env.OPENCODE_URL || 'http://localhost:4096';
|
|
7
|
+
const OPENCODE_PASSWORD = process.env.OPENCODE_SERVER_PASSWORD || '';
|
|
8
|
+
function buildHeaders() {
|
|
9
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
10
|
+
if (OPENCODE_PASSWORD) {
|
|
11
|
+
headers['Authorization'] = `Bearer ${OPENCODE_PASSWORD}`;
|
|
12
|
+
}
|
|
13
|
+
return headers;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Stream an AI chat message via OpenCode's REST API.
|
|
17
|
+
* Creates a session, sends message, and parses the response.
|
|
18
|
+
*/
|
|
19
|
+
export function streamAiChat(projectDir, options) {
|
|
20
|
+
const tokenCallbacks = [];
|
|
21
|
+
const doneCallbacks = [];
|
|
22
|
+
const errorCallbacks = [];
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
let sessionId = options.sessionId || '';
|
|
25
|
+
const enrichedPrompt = buildPrompt(options);
|
|
26
|
+
const run = async () => {
|
|
27
|
+
try {
|
|
28
|
+
// Create a new session if we don't have one
|
|
29
|
+
if (!sessionId) {
|
|
30
|
+
const createRes = await fetch(`${OPENCODE_URL}/session`, {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
headers: buildHeaders(),
|
|
33
|
+
body: JSON.stringify({ path: projectDir }),
|
|
34
|
+
signal: controller.signal,
|
|
35
|
+
});
|
|
36
|
+
if (!createRes.ok) {
|
|
37
|
+
throw new Error(`Failed to create OpenCode session: ${createRes.status}`);
|
|
38
|
+
}
|
|
39
|
+
const sessionData = await createRes.json();
|
|
40
|
+
sessionId = sessionData.id || sessionData.sessionId || '';
|
|
41
|
+
}
|
|
42
|
+
// Send message — OpenCode returns JSON with parts array
|
|
43
|
+
const msgRes = await fetch(`${OPENCODE_URL}/session/${sessionId}/message`, {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: buildHeaders(),
|
|
46
|
+
body: JSON.stringify({ parts: [{ type: 'text', text: enrichedPrompt }] }),
|
|
47
|
+
signal: controller.signal,
|
|
48
|
+
});
|
|
49
|
+
if (!msgRes.ok) {
|
|
50
|
+
const errText = await msgRes.text().catch(() => '');
|
|
51
|
+
throw new Error(`OpenCode message failed: ${msgRes.status} ${errText}`);
|
|
52
|
+
}
|
|
53
|
+
// OpenCode returns JSON response with parts array
|
|
54
|
+
const data = await msgRes.json();
|
|
55
|
+
let fullText = '';
|
|
56
|
+
// Extract text from response parts
|
|
57
|
+
const parts = data.parts || [];
|
|
58
|
+
for (const part of parts) {
|
|
59
|
+
if (part.type === 'text' && part.text) {
|
|
60
|
+
fullText += part.text;
|
|
61
|
+
for (const cb of tokenCallbacks)
|
|
62
|
+
cb(part.text);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const cb of doneCallbacks)
|
|
66
|
+
cb(fullText);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
if (err?.name === 'AbortError')
|
|
70
|
+
return;
|
|
71
|
+
for (const cb of errorCallbacks)
|
|
72
|
+
cb(err instanceof Error ? err : new Error(String(err)));
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
// Start the async flow
|
|
76
|
+
run();
|
|
77
|
+
return {
|
|
78
|
+
get sessionId() { return sessionId; },
|
|
79
|
+
onToken: (cb) => { tokenCallbacks.push(cb); },
|
|
80
|
+
onDone: (cb) => { doneCallbacks.push(cb); },
|
|
81
|
+
onError: (cb) => { errorCallbacks.push(cb); },
|
|
82
|
+
abort: () => controller.abort(),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if OpenCode server is reachable.
|
|
87
|
+
*/
|
|
88
|
+
export async function checkAiStatus() {
|
|
89
|
+
try {
|
|
90
|
+
const res = await fetch(`${OPENCODE_URL}/global/health`, {
|
|
91
|
+
headers: buildHeaders(),
|
|
92
|
+
signal: AbortSignal.timeout(3000),
|
|
93
|
+
});
|
|
94
|
+
return { configured: res.ok, backend: 'opencode' };
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return { configured: false, backend: 'opencode' };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory file snapshot store for AI turn rollback.
|
|
3
|
+
* Saves file contents before each AI turn so they can be restored.
|
|
4
|
+
*/
|
|
5
|
+
export interface Snapshot {
|
|
6
|
+
turnId: string;
|
|
7
|
+
files: Map<string, string>;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Save a snapshot of file contents before an AI turn.
|
|
12
|
+
*/
|
|
13
|
+
export declare function save(turnId: string, files: Map<string, string>): void;
|
|
14
|
+
/**
|
|
15
|
+
* Restore file contents from a saved snapshot.
|
|
16
|
+
* Returns the files map if found, null otherwise.
|
|
17
|
+
*/
|
|
18
|
+
export declare function restore(turnId: string): Map<string, string> | null;
|
|
19
|
+
/**
|
|
20
|
+
* List available snapshot turn IDs (newest first).
|
|
21
|
+
*/
|
|
22
|
+
export declare function listTurns(): string[];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory file snapshot store for AI turn rollback.
|
|
3
|
+
* Saves file contents before each AI turn so they can be restored.
|
|
4
|
+
*/
|
|
5
|
+
const MAX_SNAPSHOTS = 10;
|
|
6
|
+
const snapshots = [];
|
|
7
|
+
/**
|
|
8
|
+
* Save a snapshot of file contents before an AI turn.
|
|
9
|
+
*/
|
|
10
|
+
export function save(turnId, files) {
|
|
11
|
+
snapshots.push({ turnId, files, timestamp: Date.now() });
|
|
12
|
+
// Keep only the last N snapshots
|
|
13
|
+
while (snapshots.length > MAX_SNAPSHOTS) {
|
|
14
|
+
snapshots.shift();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Restore file contents from a saved snapshot.
|
|
19
|
+
* Returns the files map if found, null otherwise.
|
|
20
|
+
*/
|
|
21
|
+
export function restore(turnId) {
|
|
22
|
+
const idx = snapshots.findIndex(s => s.turnId === turnId);
|
|
23
|
+
if (idx === -1)
|
|
24
|
+
return null;
|
|
25
|
+
const snapshot = snapshots[idx];
|
|
26
|
+
// Remove this and all newer snapshots (they're invalidated by rollback)
|
|
27
|
+
snapshots.splice(idx);
|
|
28
|
+
return snapshot.files;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* List available snapshot turn IDs (newest first).
|
|
32
|
+
*/
|
|
33
|
+
export function listTurns() {
|
|
34
|
+
return snapshots.map(s => s.turnId).reverse();
|
|
35
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types and constants for AI backend clients.
|
|
3
|
+
*/
|
|
4
|
+
export interface AiChatOptions {
|
|
5
|
+
mode: 'element' | 'project';
|
|
6
|
+
prompt: string;
|
|
7
|
+
context: {
|
|
8
|
+
sourceFile?: string;
|
|
9
|
+
sourceLine?: number;
|
|
10
|
+
elementTag?: string;
|
|
11
|
+
elementAttributes?: Record<string, string>;
|
|
12
|
+
sourceContent?: string;
|
|
13
|
+
};
|
|
14
|
+
sessionId?: string;
|
|
15
|
+
/** 'fast' uses Sonnet for quick edits, 'default' uses the standard model */
|
|
16
|
+
model?: 'fast' | 'default';
|
|
17
|
+
}
|
|
18
|
+
export interface AiChatResult {
|
|
19
|
+
sessionId: string;
|
|
20
|
+
onToken: (cb: (text: string) => void) => void;
|
|
21
|
+
onDone: (cb: (fullText: string) => void) => void;
|
|
22
|
+
onError: (cb: (err: Error) => void) => void;
|
|
23
|
+
abort: () => void;
|
|
24
|
+
}
|
|
25
|
+
export interface AiStatusResult {
|
|
26
|
+
configured: boolean;
|
|
27
|
+
backend: 'claude-code' | 'opencode';
|
|
28
|
+
}
|
|
29
|
+
export declare const SYSTEM_PROMPT = "You are an AI coding assistant working inside a LumenJS project.\n\nLumenJS is a full-stack Lit web component framework with file-based routing, server loaders, SSR, and API routes.\n\nKey conventions:\n- Pages live in `pages/` directory \u2014 file path maps to URL route\n- Components are Lit web components (LitElement) auto-registered by file path\n- Layouts: `_layout.ts` in any directory for nested layouts (use <slot>)\n- API routes: `api/` directory with named exports (GET, POST, PUT, DELETE)\n- Server loaders: `export async function loader()` for server-side data fetching\n- Styles: use Tailwind CSS classes or Lit's `static styles` with css template tag\n- Config: `lumenjs.config.ts` at project root\n\nAuto-registration:\n- Pages and layouts are auto-registered by file path \u2014 do NOT add @customElement decorators.\n `pages/about.ts` \u2192 `<page-about>`, `pages/blog/_layout.ts` \u2192 `<layout-blog>`\n\nServer loaders:\n- `export async function loader({ params, query, url, headers, locale })` at file top level.\n- Return a data object \u2192 available as `this.loaderData` on the page element.\n\nSubscribe (SSE):\n- `export async function subscribe({ params, headers, locale, push })` for real-time data.\n- Call `push(data)` to send events \u2192 available as `this.liveData` on the page element.\n\nMiddleware:\n- `_middleware.ts` in any directory applies to that route subtree.\n\nDynamic routes:\n- `[slug]` for dynamic params, `[...rest]` for catch-all.\n\nProperties:\n- Use `@property()` for public reactive props, `@state()` for internal state (from `lit/decorators.js`).\n\nExample \u2014 adding a new page (`pages/contact.ts`):\n```\nimport { LitElement, html, css } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nexport default class extends LitElement {\n static styles = css\\`/* styles here */\\`;\n render() { return html\\`<h1>Contact</h1>\\`; }\n}\n```\n\nIMPORTANT \u2014 Styling rules:\n- When asked to change a style (color, font, spacing, etc.), find and UPDATE the EXISTING CSS rule in `static styles = css\\`...\\``. Do NOT add a new class or duplicate rule.\n- Never add inline `style=\"...\"` attributes on HTML template elements. Always modify the CSS rule in `static styles`.\n- Example: to change the h1 color, find the `h1 { ... }` rule in `static styles` and update its `color` property. Do not create a new class.\n- If no CSS rule exists for the element, add one to the existing `static styles` block \u2014 do not add a separate `<style>` tag.\n\nIMPORTANT \u2014 i18n / translation rules (when the project uses i18n):\n- Text content in templates uses `t('key')` from `@lumenjs/i18n` \u2014 NEVER replace a `t()` call with hardcoded text.\n- To change displayed text, edit the translation value in `locales/<locale>.json` \u2014 do NOT modify the template.\n- Example: to change the subtitle, update `\"home.subtitle\"` in `locales/en.json` (and other locale files like `locales/fr.json`).\n- To add new text, add a key to ALL locale JSON files and use `t('new.key')` in the template.\n- The dev server watches locale files and updates the page automatically via HMR.\n\nYou have full access to the filesystem and can run shell commands.\nWhen a task requires a new npm package, install it with `npm install <package>`.\nAfter npm install, the dev server will automatically restart to load the new dependency.\nVite's HMR will pick up file changes automatically \u2014 no manual restart needed.\n\nIMPORTANT \u2014 Be fast and direct:\n- Make changes immediately \u2014 do not explain what you will do before doing it.\n- Read the file, make the edit, done. Minimize tool calls.\n- For simple CSS/text changes, edit directly without reading first if you have the source context.\n- Keep responses under 2 sentences. The user sees the diff, not your explanation.\n";
|
|
30
|
+
export declare function buildPrompt(options: AiChatOptions): string;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types and constants for AI backend clients.
|
|
3
|
+
*/
|
|
4
|
+
export const SYSTEM_PROMPT = `You are an AI coding assistant working inside a LumenJS project.
|
|
5
|
+
|
|
6
|
+
LumenJS is a full-stack Lit web component framework with file-based routing, server loaders, SSR, and API routes.
|
|
7
|
+
|
|
8
|
+
Key conventions:
|
|
9
|
+
- Pages live in \`pages/\` directory — file path maps to URL route
|
|
10
|
+
- Components are Lit web components (LitElement) auto-registered by file path
|
|
11
|
+
- Layouts: \`_layout.ts\` in any directory for nested layouts (use <slot>)
|
|
12
|
+
- API routes: \`api/\` directory with named exports (GET, POST, PUT, DELETE)
|
|
13
|
+
- Server loaders: \`export async function loader()\` for server-side data fetching
|
|
14
|
+
- Styles: use Tailwind CSS classes or Lit's \`static styles\` with css template tag
|
|
15
|
+
- Config: \`lumenjs.config.ts\` at project root
|
|
16
|
+
|
|
17
|
+
Auto-registration:
|
|
18
|
+
- Pages and layouts are auto-registered by file path — do NOT add @customElement decorators.
|
|
19
|
+
\`pages/about.ts\` → \`<page-about>\`, \`pages/blog/_layout.ts\` → \`<layout-blog>\`
|
|
20
|
+
|
|
21
|
+
Server loaders:
|
|
22
|
+
- \`export async function loader({ params, query, url, headers, locale })\` at file top level.
|
|
23
|
+
- Return a data object → available as \`this.loaderData\` on the page element.
|
|
24
|
+
|
|
25
|
+
Subscribe (SSE):
|
|
26
|
+
- \`export async function subscribe({ params, headers, locale, push })\` for real-time data.
|
|
27
|
+
- Call \`push(data)\` to send events → available as \`this.liveData\` on the page element.
|
|
28
|
+
|
|
29
|
+
Middleware:
|
|
30
|
+
- \`_middleware.ts\` in any directory applies to that route subtree.
|
|
31
|
+
|
|
32
|
+
Dynamic routes:
|
|
33
|
+
- \`[slug]\` for dynamic params, \`[...rest]\` for catch-all.
|
|
34
|
+
|
|
35
|
+
Properties:
|
|
36
|
+
- Use \`@property()\` for public reactive props, \`@state()\` for internal state (from \`lit/decorators.js\`).
|
|
37
|
+
|
|
38
|
+
Example — adding a new page (\`pages/contact.ts\`):
|
|
39
|
+
\`\`\`
|
|
40
|
+
import { LitElement, html, css } from 'lit';
|
|
41
|
+
import { property } from 'lit/decorators.js';
|
|
42
|
+
|
|
43
|
+
export default class extends LitElement {
|
|
44
|
+
static styles = css\\\`/* styles here */\\\`;
|
|
45
|
+
render() { return html\\\`<h1>Contact</h1>\\\`; }
|
|
46
|
+
}
|
|
47
|
+
\`\`\`
|
|
48
|
+
|
|
49
|
+
IMPORTANT — Styling rules:
|
|
50
|
+
- When asked to change a style (color, font, spacing, etc.), find and UPDATE the EXISTING CSS rule in \`static styles = css\\\`...\\\`\`. Do NOT add a new class or duplicate rule.
|
|
51
|
+
- Never add inline \`style="..."\` attributes on HTML template elements. Always modify the CSS rule in \`static styles\`.
|
|
52
|
+
- Example: to change the h1 color, find the \`h1 { ... }\` rule in \`static styles\` and update its \`color\` property. Do not create a new class.
|
|
53
|
+
- If no CSS rule exists for the element, add one to the existing \`static styles\` block — do not add a separate \`<style>\` tag.
|
|
54
|
+
|
|
55
|
+
IMPORTANT — i18n / translation rules (when the project uses i18n):
|
|
56
|
+
- Text content in templates uses \`t('key')\` from \`@lumenjs/i18n\` — NEVER replace a \`t()\` call with hardcoded text.
|
|
57
|
+
- To change displayed text, edit the translation value in \`locales/<locale>.json\` — do NOT modify the template.
|
|
58
|
+
- Example: to change the subtitle, update \`"home.subtitle"\` in \`locales/en.json\` (and other locale files like \`locales/fr.json\`).
|
|
59
|
+
- To add new text, add a key to ALL locale JSON files and use \`t('new.key')\` in the template.
|
|
60
|
+
- The dev server watches locale files and updates the page automatically via HMR.
|
|
61
|
+
|
|
62
|
+
You have full access to the filesystem and can run shell commands.
|
|
63
|
+
When a task requires a new npm package, install it with \`npm install <package>\`.
|
|
64
|
+
After npm install, the dev server will automatically restart to load the new dependency.
|
|
65
|
+
Vite's HMR will pick up file changes automatically — no manual restart needed.
|
|
66
|
+
|
|
67
|
+
IMPORTANT — Be fast and direct:
|
|
68
|
+
- Make changes immediately — do not explain what you will do before doing it.
|
|
69
|
+
- Read the file, make the edit, done. Minimize tool calls.
|
|
70
|
+
- For simple CSS/text changes, edit directly without reading first if you have the source context.
|
|
71
|
+
- Keep responses under 2 sentences. The user sees the diff, not your explanation.
|
|
72
|
+
`;
|
|
73
|
+
export function buildPrompt(options) {
|
|
74
|
+
const { mode, prompt, context } = options;
|
|
75
|
+
let result = prompt;
|
|
76
|
+
if (mode === 'element' && context.elementTag) {
|
|
77
|
+
let enriched = `I'm looking at \`<${context.elementTag}>\``;
|
|
78
|
+
if (context.sourceFile) {
|
|
79
|
+
enriched += ` in \`${context.sourceFile}`;
|
|
80
|
+
if (context.sourceLine)
|
|
81
|
+
enriched += `:${context.sourceLine}`;
|
|
82
|
+
enriched += '`';
|
|
83
|
+
}
|
|
84
|
+
if (context.elementAttributes && Object.keys(context.elementAttributes).length > 0) {
|
|
85
|
+
const attrs = Object.entries(context.elementAttributes)
|
|
86
|
+
.map(([k, v]) => `${k}="${v}"`)
|
|
87
|
+
.join(' ');
|
|
88
|
+
enriched += ` with attributes: ${attrs}`;
|
|
89
|
+
}
|
|
90
|
+
enriched += `. ${prompt}`;
|
|
91
|
+
result = enriched;
|
|
92
|
+
}
|
|
93
|
+
// Append i18n context — only include keys actually used in the current source file
|
|
94
|
+
if (context?.i18n?.translations) {
|
|
95
|
+
const i18n = context.i18n;
|
|
96
|
+
const locales = Object.keys(i18n.translations);
|
|
97
|
+
result += `\n\nThis project uses i18n (locales: ${locales.join(', ')}).`;
|
|
98
|
+
// Extract t('key') calls from source to only send relevant translations
|
|
99
|
+
const sourceContent = context.sourceContent || '';
|
|
100
|
+
const usedKeys = new Set();
|
|
101
|
+
const tCallRegex = /t\(['"]([^'"]+)['"]\)/g;
|
|
102
|
+
let tMatch;
|
|
103
|
+
while ((tMatch = tCallRegex.exec(sourceContent)) !== null) {
|
|
104
|
+
usedKeys.add(tMatch[1]);
|
|
105
|
+
}
|
|
106
|
+
if (usedKeys.size > 0) {
|
|
107
|
+
result += ` Relevant translation keys from this file:\n`;
|
|
108
|
+
for (const [locale, trans] of Object.entries(i18n.translations)) {
|
|
109
|
+
const filtered = {};
|
|
110
|
+
for (const key of usedKeys) {
|
|
111
|
+
const value = getNestedValue(trans, key);
|
|
112
|
+
if (value !== undefined)
|
|
113
|
+
filtered[key] = value;
|
|
114
|
+
}
|
|
115
|
+
if (Object.keys(filtered).length > 0) {
|
|
116
|
+
result += `locales/${locale}.json (relevant keys): ${JSON.stringify(filtered, null, 2)}\n`;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
result += ` Edit locale JSON files in locales/ to change text — do not hardcode text in templates.\n`;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
/** Resolve a dot-separated key like 'home.subtitle' from a nested object */
|
|
127
|
+
function getNestedValue(obj, key) {
|
|
128
|
+
const parts = key.split('.');
|
|
129
|
+
let current = obj;
|
|
130
|
+
for (const part of parts) {
|
|
131
|
+
if (current == null || typeof current !== 'object')
|
|
132
|
+
return undefined;
|
|
133
|
+
current = current[part];
|
|
134
|
+
}
|
|
135
|
+
return current;
|
|
136
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Chat Bubble — floating chat popover that appears next to the selected element.
|
|
3
|
+
* Streams responses from OpenCode AI coding agent via the editor API.
|
|
4
|
+
*/
|
|
5
|
+
export declare function createAiChatPanel(): HTMLDivElement;
|
|
6
|
+
export declare function showAiChatForElement(el: HTMLElement): void;
|
|
7
|
+
export declare function showAiChatForElements(els: HTMLElement[]): void;
|
|
8
|
+
/** Update target reference after HMR and reanchor the panel to the new element */
|
|
9
|
+
export declare function updateAiChatTarget(el: HTMLElement): void;
|
|
10
|
+
export declare function hideAiChatPanel(): void;
|
|
11
|
+
export declare function isAiChatPanelOpen(): boolean;
|
|
12
|
+
/** Reposition on scroll/resize if open (skips if element was disconnected by HMR) */
|
|
13
|
+
export declare function updateAiChatPosition(): void;
|