@larkup/marketplace 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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @larkup/marketplace
2
2
 
3
+ ## 0.1.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 19767f8: Fix isolated Marketplace tool loading in Docker, improve Video & Audio setup guidance, and reliably index PDF images.
8
+
3
9
  ## 0.1.4
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@larkup/marketplace",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -147,8 +147,15 @@ export async function checkSystemDeps(toolId: string): Promise<string[]> {
147
147
  const descriptor = await getToolById(toolId);
148
148
  if (!descriptor?.systemDeps?.length) return [];
149
149
 
150
+ const target = detectDeploymentTarget();
151
+
150
152
  const missing: string[] = [];
151
153
  for (const dep of descriptor.systemDeps) {
154
+ // A container cannot normally talk to the host Docker daemon. Do not block
155
+ // installation of tools that use Docker only for optional capabilities
156
+ // (for example DOCX/PPTX editing); those capabilities report their own
157
+ // actionable error when actually used.
158
+ if (target === 'docker' && dep === 'docker') continue;
152
159
  try {
153
160
  await execAsync(`which ${dep}`);
154
161
  } catch {
@@ -492,6 +499,8 @@ export async function uninstallTool(toolId: string): Promise<void> {
492
499
 
493
500
  // Refresh registry cache
494
501
  invalidateRegistryCache();
502
+ const { unloadTool } = await import('./tool-loader');
503
+ unloadTool(toolId);
495
504
  }
496
505
 
497
506
  export async function updateToolConfig(toolId: string, config: Record<string, any>): Promise<void> {
@@ -1,4 +1,6 @@
1
+ import { promises as fs } from 'node:fs';
1
2
  import path from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
2
4
  import type { InstalledTool } from './types';
3
5
  import { getInstalledTool } from './tool-installer';
4
6
 
@@ -37,7 +39,7 @@ export async function loadTool<T = any>(toolId: string): Promise<T | null> {
37
39
 
38
40
  try {
39
41
  // Determine what to import
40
- const importPath = resolveImportPath(installed);
42
+ const importPath = await resolveImportPath(installed);
41
43
  const mod = await import(/* webpackIgnore: true */ importPath);
42
44
  moduleCache.set(toolId, mod);
43
45
  return mod as T;
@@ -54,7 +56,7 @@ export async function loadTool<T = any>(toolId: string): Promise<T | null> {
54
56
  * - `registry` (npm): import from the isolated node_modules via absolute path
55
57
  * - `sandbox`: import from the sandbox tool path
56
58
  */
57
- function resolveImportPath(installed: InstalledTool): string {
59
+ async function resolveImportPath(installed: InstalledTool): Promise<string> {
58
60
  switch (installed.source) {
59
61
  case 'local':
60
62
  // In monorepo, the package name resolves via pnpm workspace linking
@@ -62,8 +64,10 @@ function resolveImportPath(installed: InstalledTool): string {
62
64
 
63
65
  case 'registry':
64
66
  case 'sandbox':
65
- // Use the absolute resolved path from the isolated install
66
- return installed.resolvedPath;
67
+ // Node ESM cannot import a package directory by absolute path. Resolve
68
+ // the package's declared ESM entry so isolated marketplace installs work
69
+ // the same way as a normal package-name import.
70
+ return resolvePackageEntry(installed.resolvedPath);
67
71
 
68
72
  default:
69
73
  // Fallback: try package name (backwards compat)
@@ -71,6 +75,22 @@ function resolveImportPath(installed: InstalledTool): string {
71
75
  }
72
76
  }
73
77
 
78
+ async function resolvePackageEntry(packageDir: string): Promise<string> {
79
+ const manifestPath = path.join(packageDir, 'package.json');
80
+ const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')) as {
81
+ exports?: string | { '.': string | { import?: string; default?: string } };
82
+ main?: string;
83
+ };
84
+ const rootExport =
85
+ typeof manifest.exports === 'object' ? manifest.exports['.'] : manifest.exports;
86
+ const entry =
87
+ (typeof rootExport === 'object' ? rootExport.import ?? rootExport.default : rootExport) ??
88
+ manifest.main ??
89
+ 'index.js';
90
+
91
+ return pathToFileURL(path.resolve(packageDir, entry)).href;
92
+ }
93
+
74
94
  /**
75
95
  * Check if a tool is loaded and available for use.
76
96
  */