ai-extension-preview 0.1.4 → 0.1.5

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/dist/index.js CHANGED
@@ -9,6 +9,7 @@ import { Runtime } from 'skeleton-crew-runtime';
9
9
  import { CorePlugin } from './plugins/CorePlugin.js';
10
10
  import { DownloaderPlugin } from './plugins/DownloaderPlugin.js';
11
11
  import { BrowserPlugin } from './plugins/BrowserPlugin.js';
12
+ import { ServerPlugin } from './plugins/ServerPlugin.js';
12
13
  import axios from 'axios';
13
14
  import chalk from 'chalk';
14
15
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -100,6 +101,7 @@ async function main() {
100
101
  runtime.registerPlugin(CorePlugin);
101
102
  runtime.registerPlugin(DownloaderPlugin);
102
103
  runtime.registerPlugin(BrowserPlugin);
104
+ runtime.registerPlugin(ServerPlugin);
103
105
  runtime.logger.info('Initializing runtime...');
104
106
  await runtime.initialize();
105
107
  const ctx = runtime.getContext();
@@ -97,6 +97,57 @@ export const DownloaderPlugin = {
97
97
  await fs.emptyDir(DIST_DIR);
98
98
  const zip = new AdmZip(DOWNLOAD_PATH);
99
99
  zip.extractAllTo(DIST_DIR, true);
100
+ // --- HOT RELOAD INJECTION ---
101
+ try {
102
+ const HOT_RELOAD_CODE = `
103
+ const EVENT_SOURCE_URL = 'http://localhost:3500/status';
104
+ let lastVersion = null;
105
+
106
+ setInterval(async () => {
107
+ try {
108
+ const res = await fetch(EVENT_SOURCE_URL);
109
+ const data = await res.json();
110
+
111
+ if (lastVersion && data.version !== lastVersion) {
112
+ console.log('[Hot Reload] New version detected:', data.version);
113
+ chrome.runtime.reload();
114
+ }
115
+
116
+ lastVersion = data.version;
117
+ } catch (err) {
118
+ // Build tool might be offline
119
+ }
120
+ }, 1000);
121
+ console.log('[Hot Reload] Active');
122
+ `;
123
+ const hotReloadPath = path.join(DIST_DIR, 'hot-reload.js');
124
+ await fs.writeFile(hotReloadPath, HOT_RELOAD_CODE);
125
+ // Patch Manifest / Background
126
+ const manifestPath = path.join(DIST_DIR, 'manifest.json');
127
+ if (await fs.pathExists(manifestPath)) {
128
+ const manifest = await fs.readJson(manifestPath);
129
+ // MV3 Module Worker Strategy
130
+ if (manifest.manifest_version === 3 && manifest.background?.service_worker) {
131
+ const swPath = path.join(DIST_DIR, manifest.background.service_worker);
132
+ if (await fs.pathExists(swPath)) {
133
+ const swContent = await fs.readFile(swPath, 'utf-8');
134
+ // Prepend import
135
+ await fs.writeFile(swPath, "import './hot-reload.js';\n" + swContent);
136
+ await ctx.actions.runAction('core:log', { level: 'info', message: 'Injected Hot Reload script into background worker.' });
137
+ }
138
+ }
139
+ // MV2 Scripts Strategy (Fallback if user generates MV2)
140
+ else if (manifest.background?.scripts) {
141
+ manifest.background.scripts.push('hot-reload.js');
142
+ await fs.writeJson(manifestPath, manifest, { spaces: 2 });
143
+ await ctx.actions.runAction('core:log', { level: 'info', message: 'Injected Hot Reload script into background scripts.' });
144
+ }
145
+ }
146
+ }
147
+ catch (injectErr) {
148
+ await ctx.actions.runAction('core:log', { level: 'error', message: `Hot Reload Injection Failed: ${injectErr.message}` });
149
+ }
150
+ // ----------------------------
100
151
  spinner.succeed('Updated extension code!');
101
152
  return true;
102
153
  }
@@ -0,0 +1,54 @@
1
+ import http from 'http';
2
+ export const ServerPlugin = {
3
+ name: 'server',
4
+ version: '1.0.0',
5
+ setup(ctx) {
6
+ let currentVersion = '0.0.0';
7
+ const PORT = 3500;
8
+ // Listen for version updates
9
+ ctx.events.on('downloader:updated', (data) => {
10
+ if (data && data.version) {
11
+ currentVersion = data.version;
12
+ ctx.actions.runAction('core:log', { level: 'info', message: `Server: Reporting version ${currentVersion}` });
13
+ }
14
+ });
15
+ const server = http.createServer((req, res) => {
16
+ // CORS Headers
17
+ res.setHeader('Access-Control-Allow-Origin', '*');
18
+ res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
19
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
20
+ if (req.method === 'OPTIONS') {
21
+ res.writeHead(204);
22
+ res.end();
23
+ return;
24
+ }
25
+ if (req.url === '/status') {
26
+ res.writeHead(200, { 'Content-Type': 'application/json' });
27
+ res.end(JSON.stringify({ version: currentVersion }));
28
+ }
29
+ else {
30
+ res.writeHead(404);
31
+ res.end('Not Found');
32
+ }
33
+ });
34
+ server.listen(PORT, () => {
35
+ ctx.actions.runAction('core:log', { level: 'info', message: `Hot Reload Server running on port ${PORT}` });
36
+ });
37
+ server.on('error', (err) => {
38
+ if (err.code === 'EADDRINUSE') {
39
+ ctx.actions.runAction('core:log', { level: 'error', message: `Port ${PORT} is busy. Hot reload may fail.` });
40
+ }
41
+ else {
42
+ ctx.actions.runAction('core:log', { level: 'error', message: `Server error: ${err.message}` });
43
+ }
44
+ });
45
+ // Store server instance to close later
46
+ ctx._serverInstance = server;
47
+ },
48
+ dispose(ctx) {
49
+ const server = ctx._serverInstance;
50
+ if (server) {
51
+ server.close();
52
+ }
53
+ }
54
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-extension-preview",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Local preview tool for AI Extension Builder",
5
5
  "type": "module",
6
6
  "bin": {