ai-extension-preview 0.1.6 → 0.1.8
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 +0 -0
- package/dist/plugins/BrowserPlugin.js +81 -18
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
File without changes
|
|
@@ -22,6 +22,15 @@ function findChrome() {
|
|
|
22
22
|
}
|
|
23
23
|
return null;
|
|
24
24
|
}
|
|
25
|
+
const normalizePathToWindows = (p) => {
|
|
26
|
+
// Handle Git Bash /c/ style
|
|
27
|
+
const gitBashMatch = p.match(/^\/([a-z])\/(.*)/i);
|
|
28
|
+
if (gitBashMatch) {
|
|
29
|
+
return `${gitBashMatch[1].toUpperCase()}:\\${gitBashMatch[2].replace(/\//g, '\\')}`;
|
|
30
|
+
}
|
|
31
|
+
// Handle Forward slashes
|
|
32
|
+
return p.replace(/\//g, '\\');
|
|
33
|
+
};
|
|
25
34
|
export const BrowserPlugin = {
|
|
26
35
|
name: 'browser',
|
|
27
36
|
version: '1.0.0',
|
|
@@ -36,10 +45,15 @@ export const BrowserPlugin = {
|
|
|
36
45
|
return false;
|
|
37
46
|
}
|
|
38
47
|
const isWSL = fs.existsSync('/mnt/c');
|
|
39
|
-
let executable = chromePath;
|
|
48
|
+
let executable = chromePath;
|
|
49
|
+
// Normalize Executable for Native Windows (Git Bash)
|
|
50
|
+
if (!isWSL && process.platform === 'win32') {
|
|
51
|
+
executable = normalizePathToWindows(chromePath);
|
|
52
|
+
}
|
|
40
53
|
const STAGING_DIR = isWSL ? '/mnt/c/Temp/ai-ext-preview' : path.join(config.workDir, '../staging');
|
|
41
54
|
const WIN_PROFILE_DIR = 'C:/Temp/ai-ext-profile';
|
|
42
55
|
// For native windows/linux, use local staging path
|
|
56
|
+
// Note: We will evaluate actual extension root later, but base is STAGING_DIR
|
|
43
57
|
const EXTENSION_PATH = isWSL ? 'C:/Temp/ai-ext-preview' : STAGING_DIR;
|
|
44
58
|
// --- SYNC FUNCTION ---
|
|
45
59
|
const syncToStaging = async () => {
|
|
@@ -49,7 +63,13 @@ export const BrowserPlugin = {
|
|
|
49
63
|
}
|
|
50
64
|
fs.ensureDirSync(STAGING_DIR);
|
|
51
65
|
fs.copySync(DIST_DIR, STAGING_DIR);
|
|
52
|
-
await ctx.actions.runAction('core:log', { level: 'info', message: `Synced code to Staging
|
|
66
|
+
await ctx.actions.runAction('core:log', { level: 'info', message: `Synced code to Staging` });
|
|
67
|
+
// DEBUG: Log contents of staging
|
|
68
|
+
try {
|
|
69
|
+
const files = fs.readdirSync(STAGING_DIR);
|
|
70
|
+
await ctx.actions.runAction('core:log', { level: 'info', message: `Staging Contents: ${files.join(', ')}` });
|
|
71
|
+
}
|
|
72
|
+
catch (e) { }
|
|
53
73
|
// Emit staged event for ServerPlugin (optional for now, but good practice)
|
|
54
74
|
ctx.events.emit('browser:staged', { path: STAGING_DIR });
|
|
55
75
|
}
|
|
@@ -57,8 +77,39 @@ export const BrowserPlugin = {
|
|
|
57
77
|
await ctx.actions.runAction('core:log', { level: 'error', message: `Failed to sync to staging: ${err.message}` });
|
|
58
78
|
}
|
|
59
79
|
};
|
|
80
|
+
// --- Helper to find actual extension root (handle nested folder in zip) ---
|
|
81
|
+
const findExtensionRoot = (dir) => {
|
|
82
|
+
if (fs.existsSync(path.join(dir, 'manifest.json')))
|
|
83
|
+
return dir;
|
|
84
|
+
// Check immediate subdirectories (depth 1)
|
|
85
|
+
try {
|
|
86
|
+
const items = fs.readdirSync(dir);
|
|
87
|
+
for (const item of items) {
|
|
88
|
+
const fullPath = path.join(dir, item);
|
|
89
|
+
if (fs.statSync(fullPath).isDirectory()) {
|
|
90
|
+
if (fs.existsSync(path.join(fullPath, 'manifest.json'))) {
|
|
91
|
+
return fullPath;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
// Dir might be empty or invalid
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
};
|
|
60
101
|
// Initial Sync
|
|
61
102
|
await syncToStaging();
|
|
103
|
+
// Resolve proper root AFTER sync
|
|
104
|
+
let extensionRoot = findExtensionRoot(STAGING_DIR) || STAGING_DIR;
|
|
105
|
+
// Check if we found a valid root
|
|
106
|
+
if (!fs.existsSync(path.join(extensionRoot, 'manifest.json'))) {
|
|
107
|
+
await ctx.actions.runAction('core:log', { level: 'error', message: `[CRITICAL] manifest.json not found in ${extensionRoot}. Extension will not load.` });
|
|
108
|
+
await ctx.actions.runAction('core:log', { level: 'info', message: `Checked Path: ${extensionRoot}` });
|
|
109
|
+
}
|
|
110
|
+
else if (extensionRoot !== STAGING_DIR) {
|
|
111
|
+
await ctx.actions.runAction('core:log', { level: 'info', message: `Detected nested extension at: ${path.basename(extensionRoot)}` });
|
|
112
|
+
}
|
|
62
113
|
// Listen for updates and re-sync
|
|
63
114
|
ctx.events.on('downloader:updated', async (data) => {
|
|
64
115
|
await ctx.actions.runAction('core:log', { level: 'info', message: 'Update detected. Syncing to staging...' });
|
|
@@ -71,21 +122,28 @@ export const BrowserPlugin = {
|
|
|
71
122
|
const winChromePath = chromePath
|
|
72
123
|
.replace(new RegExp(`^/mnt/${driveLetter}/`), `${driveLetter.toUpperCase()}:\\`)
|
|
73
124
|
.replace(/\//g, '\\');
|
|
74
|
-
|
|
125
|
+
// Calculate Windows path for the extension root
|
|
126
|
+
// Base Win: C:\Temp\ai-ext-preview
|
|
127
|
+
// Base Linux: /mnt/c/Temp/ai-ext-preview
|
|
128
|
+
// If extensionRoot is /mnt/c/Temp/ai-ext-preview/subdir => C:\Temp\ai-ext-preview\subdir
|
|
129
|
+
// Use relative path logic to be safe
|
|
130
|
+
const baseLinux = '/mnt/c/Temp/ai-ext-preview';
|
|
131
|
+
const relative = path.relative(baseLinux, extensionRoot);
|
|
132
|
+
const winDistRoot = relative ? `C:\\Temp\\ai-ext-preview\\${relative}` : 'C:\\Temp\\ai-ext-preview';
|
|
133
|
+
const finalWinDist = winDistRoot.replace(/\//g, '\\');
|
|
75
134
|
const winProfile = 'C:\\Temp\\ai-ext-profile';
|
|
135
|
+
await ctx.actions.runAction('core:log', { level: 'info', message: `WSL Launch Target: ${finalWinDist}` });
|
|
76
136
|
const batContent = `@echo off
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
137
|
+
start "" "${winChromePath}" --load-extension="${finalWinDist}" --user-data-dir="${winProfile}" --no-first-run --no-default-browser-check --disable-gpu about:blank
|
|
138
|
+
exit
|
|
139
|
+
`;
|
|
80
140
|
const batPath = path.join(STAGING_DIR, 'launch.bat');
|
|
81
141
|
const winBatPath = 'C:\\Temp\\ai-ext-preview\\launch.bat';
|
|
82
142
|
try {
|
|
83
143
|
fs.writeFileSync(batPath, batContent);
|
|
84
144
|
}
|
|
85
145
|
catch (e) {
|
|
86
|
-
|
|
87
|
-
// Should satisfy since we verified interop before?
|
|
88
|
-
// Actually verification was removed in this block, let's assume it works or fail.
|
|
146
|
+
await ctx.actions.runAction('core:log', { level: 'error', message: `WSL Write Bat Failed: ${e.message}` });
|
|
89
147
|
}
|
|
90
148
|
const cli = 'cmd.exe';
|
|
91
149
|
const subprocess = spawn(cli, ['/c', winBatPath], {
|
|
@@ -98,11 +156,11 @@ export const BrowserPlugin = {
|
|
|
98
156
|
}
|
|
99
157
|
else {
|
|
100
158
|
// Native Windows / Linux
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// We need a stable profile path for native too to keep Detached session alive/resuable
|
|
159
|
+
// Use extensionRoot which points to the detected subfolder or root
|
|
160
|
+
const safeDist = path.resolve(extensionRoot);
|
|
104
161
|
const safeProfile = path.join(path.dirname(config.workDir), 'profile'); // ~/.ai-extension-preview/profile
|
|
105
|
-
await ctx.actions.runAction('core:log', { level: 'info', message: `
|
|
162
|
+
await ctx.actions.runAction('core:log', { level: 'info', message: `Native Launch Executable: ${executable}` });
|
|
163
|
+
await ctx.actions.runAction('core:log', { level: 'info', message: `Native Launch Target: ${safeDist}` });
|
|
106
164
|
const cleanArgs = [
|
|
107
165
|
`--load-extension=${safeDist}`,
|
|
108
166
|
`--user-data-dir=${safeProfile}`,
|
|
@@ -111,11 +169,16 @@ export const BrowserPlugin = {
|
|
|
111
169
|
'--disable-gpu',
|
|
112
170
|
'chrome://extensions'
|
|
113
171
|
];
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
172
|
+
try {
|
|
173
|
+
const subprocess = spawn(executable, cleanArgs, {
|
|
174
|
+
detached: true,
|
|
175
|
+
stdio: 'ignore'
|
|
176
|
+
});
|
|
177
|
+
subprocess.unref();
|
|
178
|
+
}
|
|
179
|
+
catch (spawnErr) {
|
|
180
|
+
await ctx.actions.runAction('core:log', { level: 'error', message: `Spawn Failed: ${spawnErr.message}` });
|
|
181
|
+
}
|
|
119
182
|
return true;
|
|
120
183
|
}
|
|
121
184
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-extension-preview",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Local preview tool for AI Extension Builder",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"author": "AI Extension Builder",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"scripts": {
|
|
23
|
-
"build": "shx rm -rf dist && tsc -b",
|
|
23
|
+
"build": "shx rm -rf dist && tsc -b && shx chmod +x dist/index.js",
|
|
24
24
|
"start": "tsx src/index.ts",
|
|
25
25
|
"dev": "tsx watch src/index.ts",
|
|
26
26
|
"preview": "node dist/index.js"
|