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 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; // Define in scope
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: ${EXTENSION_PATH}` });
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
- const winDist = 'C:\\Temp\\ai-ext-preview';
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
- start "" "${winChromePath}" --load-extension="${winDist}" --user-data-dir="${winProfile}" --no-first-run --no-default-browser-check --disable-gpu about:blank
78
- exit
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
- // Fallback if staging writes fail inside WSL mount for some reason?
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
- const safeDist = path.resolve(STAGING_DIR);
102
- // Linux/Mac/Win Native Profile Path
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: `SPAWN: ${executable}` });
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
- const subprocess = spawn(executable, cleanArgs, {
115
- detached: true,
116
- stdio: 'ignore'
117
- });
118
- subprocess.unref();
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.6",
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"