feat: Add intelligent auto-router and enhanced integrations

- Add intelligent-router.sh hook for automatic agent routing
- Add AUTO-TRIGGER-SUMMARY.md documentation
- Add FINAL-INTEGRATION-SUMMARY.md documentation
- Complete Prometheus integration (6 commands + 4 tools)
- Complete Dexto integration (12 commands + 5 tools)
- Enhanced Ralph with access to all agents
- Fix /clawd command (removed disable-model-invocation)
- Update hooks.json to v5 with intelligent routing
- 291 total skills now available
- All 21 commands with automatic routing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
admin
2026-01-28 00:27:56 +04:00
Unverified
parent 3b128ba3bd
commit b52318eeae
1724 changed files with 351216 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
# @dexto/image-bundler
## 1.5.6
### Patch Changes
- 042f4f0: ### CLI Improvements
- Add `/export` command to export conversations as Markdown or JSON
- Add `Ctrl+T` toggle for task list visibility during processing
- Improve task list UI with collapsible view near the processing message
- Fix race condition causing duplicate rendering (mainly visible with explore tool)
- Don't truncate `pattern` and `question` args in tool output display
### Bug Fixes
- Fix build script to preserve `.dexto` storage (conversations, logs) during clean builds
- Fix `@dexto/tools-todo` versioning - add to fixed version group in changeset config
### Configuration Changes
- Remove approval timeout defaults - now waits indefinitely (better UX for CLI)
- Add package versioning guidelines to AGENTS.md
- Updated dependencies [042f4f0]
- @dexto/core@1.5.6
## 1.5.5
### Patch Changes
- Updated dependencies [63fa083]
- Updated dependencies [6df3ca9]
- @dexto/core@1.5.5
## 1.5.4
### Patch Changes
- Updated dependencies [0016cd3]
- Updated dependencies [499b890]
- Updated dependencies [aa2c9a0]
- @dexto/core@1.5.4
## 1.5.3
### Patch Changes
- Updated dependencies [4f00295]
- Updated dependencies [69c944c]
- @dexto/core@1.5.3
## 1.5.2
### Patch Changes
- Updated dependencies [8a85ea4]
- Updated dependencies [527f3f9]
- @dexto/core@1.5.2
## 1.5.1
### Patch Changes
- Updated dependencies [bfcc7b1]
- Updated dependencies [4aabdb7]
- @dexto/core@1.5.1
## 1.5.0
### Minor Changes
- e7722e5: Minor version bump for new release with bundler, custom tool pkgs, etc.
### Patch Changes
- 1e7e974: Added image bundler, @dexto/image-local and moved tool services outside core. Added registry providers to select core services.
- 5fa79fa: Renamed compression to compaction, added context-awareness to hono, updated cli tool display formatting and added integration test for image-local.
- ef40e60: Upgrades package versions and related changes to MCP SDK. CLI colors improved and token streaming added to status bar.
Security: Resolve all Dependabot security vulnerabilities. Updated @modelcontextprotocol/sdk to 1.25.2, esbuild to 0.25.0, langchain to 0.3.37, and @langchain/core to 0.3.80. Added pnpm overrides for indirect vulnerabilities (preact@10.27.3, qs@6.14.1, jws@3.2.3, mdast-util-to-hast@13.2.1). Fixed type errors from MCP SDK breaking changes.
- Updated dependencies [ee12727]
- Updated dependencies [1e7e974]
- Updated dependencies [4c05310]
- Updated dependencies [5fa79fa]
- Updated dependencies [ef40e60]
- Updated dependencies [e714418]
- Updated dependencies [e7722e5]
- Updated dependencies [7d5ab19]
- Updated dependencies [436a900]
- @dexto/core@1.5.0

View File

@@ -0,0 +1,33 @@
{
"name": "@dexto/image-bundler",
"version": "1.5.6",
"description": "Bundler for Dexto base images",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"bin": {
"dexto-bundle": "./dist/cli.js"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@dexto/core": "workspace:*",
"commander": "^12.0.0",
"esbuild": "^0.25.0",
"picocolors": "^1.0.0"
},
"devDependencies": {
"@types/node": "^20.11.5",
"tsup": "^8.0.1",
"typescript": "^5.3.3"
}
}

View File

@@ -0,0 +1,361 @@
/**
* Main bundler logic
*/
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync, statSync } from 'node:fs';
import { dirname, join, resolve, relative, extname } from 'node:path';
import { pathToFileURL } from 'node:url';
import { validateImageDefinition } from '@dexto/core';
import type { ImageDefinition } from '@dexto/core';
import type { BundleOptions, BundleResult } from './types.js';
import { generateEntryPoint } from './generator.js';
import ts from 'typescript';
/**
* Bundle a Dexto base image
*/
export async function bundle(options: BundleOptions): Promise<BundleResult> {
const warnings: string[] = [];
// 1. Load and validate image definition
console.log(`📦 Loading image definition from ${options.imagePath}`);
const definition = await loadImageDefinition(options.imagePath);
console.log(`✅ Loaded image: ${definition.name} v${definition.version}`);
// 2. Validate definition
console.log(`🔍 Validating image definition...`);
try {
validateImageDefinition(definition);
console.log(`✅ Image definition is valid`);
} catch (error) {
throw new Error(`Image validation failed: ${error}`);
}
// 3. Get core version (from package.json)
const coreVersion = getCoreVersion();
// 3.5. Discover providers from convention-based folders
console.log(`🔍 Discovering providers from folders...`);
const imageDir = dirname(options.imagePath);
const discoveredProviders = discoverProviders(imageDir);
console.log(`✅ Discovered ${discoveredProviders.totalCount} provider(s)`);
// 4. Generate code
console.log(`🔨 Generating entry point...`);
const generated = generateEntryPoint(definition, coreVersion, discoveredProviders);
// 5. Ensure output directory exists
const outDir = resolve(options.outDir);
if (!existsSync(outDir)) {
mkdirSync(outDir, { recursive: true });
}
// 5.5. Compile provider category folders
console.log(`🔨 Compiling provider source files...`);
const categories = ['blob-store', 'tools', 'compaction', 'plugins'];
let compiledCount = 0;
for (const category of categories) {
const categoryDir = join(imageDir, category);
if (existsSync(categoryDir)) {
compileSourceFiles(categoryDir, join(outDir, category));
compiledCount++;
}
}
if (compiledCount > 0) {
console.log(
`✅ Compiled ${compiledCount} provider categor${compiledCount === 1 ? 'y' : 'ies'}`
);
}
// 6. Write generated files
const entryFile = join(outDir, 'index.js');
const typesFile = join(outDir, 'index.d.ts');
console.log(`📝 Writing ${entryFile}...`);
writeFileSync(entryFile, generated.js, 'utf-8');
console.log(`📝 Writing ${typesFile}...`);
writeFileSync(typesFile, generated.dts, 'utf-8');
// 7. Generate package.json exports
updatePackageJson(dirname(options.imagePath), outDir);
console.log(`✨ Build complete!`);
console.log(` Entry: ${entryFile}`);
console.log(` Types: ${typesFile}`);
const metadata = {
name: definition.name,
version: definition.version,
description: definition.description,
target: definition.target || 'custom',
constraints: definition.constraints || [],
builtAt: new Date().toISOString(),
coreVersion,
};
return {
entryFile,
typesFile,
metadata,
warnings,
};
}
/**
* Load image definition from file
*/
async function loadImageDefinition(imagePath: string): Promise<ImageDefinition> {
const absolutePath = resolve(imagePath);
if (!existsSync(absolutePath)) {
throw new Error(`Image file not found: ${absolutePath}`);
}
try {
// Convert to file:// URL for ESM import
const fileUrl = pathToFileURL(absolutePath).href;
// Dynamic import
const module = await import(fileUrl);
// Get default export
const definition = module.default as ImageDefinition;
if (!definition) {
throw new Error('Image file must have a default export');
}
return definition;
} catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to load image definition: ${error.message}`);
}
throw error;
}
}
/**
* Get @dexto/core version
*/
function getCoreVersion(): string {
try {
// Try to read from node_modules
const corePackageJson = join(process.cwd(), 'node_modules/@dexto/core/package.json');
if (existsSync(corePackageJson)) {
const pkg = JSON.parse(readFileSync(corePackageJson, 'utf-8'));
return pkg.version;
}
// Fallback to workspace version
return '1.0.0';
} catch {
return '1.0.0';
}
}
/**
* Update or create package.json with proper exports
*/
function updatePackageJson(imageDir: string, outDir: string): void {
const packageJsonPath = join(imageDir, 'package.json');
if (!existsSync(packageJsonPath)) {
console.log(`⚠️ No package.json found, skipping exports update`);
return;
}
try {
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
// Update exports
pkg.exports = {
'.': {
types: './dist/index.d.ts',
import: './dist/index.js',
},
};
// Update main and types fields
pkg.main = './dist/index.js';
pkg.types = './dist/index.d.ts';
writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2), 'utf-8');
console.log(`✅ Updated package.json exports`);
} catch (error) {
console.warn(`⚠️ Failed to update package.json: ${error}`);
}
}
/**
* Compile TypeScript source files to JavaScript
*/
function compileSourceFiles(srcDir: string, outDir: string): void {
// Find all .ts files
const tsFiles = findTypeScriptFiles(srcDir);
if (tsFiles.length === 0) {
console.log(` No TypeScript files found in ${srcDir}`);
return;
}
console.log(` Found ${tsFiles.length} TypeScript file(s) to compile`);
// TypeScript compiler options
const compilerOptions: ts.CompilerOptions = {
target: ts.ScriptTarget.ES2022,
module: ts.ModuleKind.ESNext,
moduleResolution: ts.ModuleResolutionKind.Bundler,
outDir: outDir,
rootDir: srcDir, // Use srcDir as root
declaration: true,
esModuleInterop: true,
skipLibCheck: true,
strict: true,
resolveJsonModule: true,
};
// Create program
const program = ts.createProgram(tsFiles, compilerOptions);
// Emit compiled files
const emitResult = program.emit();
// Check for errors
const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
if (allDiagnostics.length > 0) {
allDiagnostics.forEach((diagnostic) => {
if (diagnostic.file) {
const { line, character } = ts.getLineAndCharacterOfPosition(
diagnostic.file,
diagnostic.start!
);
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
console.error(
` ${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`
);
} else {
console.error(
` ${ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`
);
}
});
if (emitResult.emitSkipped) {
throw new Error('TypeScript compilation failed');
}
}
}
/**
* Recursively find all TypeScript files in a directory
*/
function findTypeScriptFiles(dir: string): string[] {
const files: string[] = [];
function walk(currentDir: string) {
const entries = readdirSync(currentDir);
for (const entry of entries) {
const fullPath = join(currentDir, entry);
const stat = statSync(fullPath);
if (stat.isDirectory()) {
walk(fullPath);
} else if (stat.isFile() && extname(entry) === '.ts') {
files.push(fullPath);
}
}
}
walk(dir);
return files;
}
/**
* Provider discovery result for a single category
*/
export interface DiscoveredProviders {
blobStore: string[];
customTools: string[];
compaction: string[];
plugins: string[];
totalCount: number;
}
/**
* Discover providers from convention-based folder structure
*
* Convention (folder-based with index.ts):
* tools/ - CustomToolProvider folders
* weather/ - Provider folder
* index.ts - Provider implementation (auto-discovered)
* helpers.ts - Optional helper files
* types.ts - Optional type definitions
* blob-store/ - BlobStoreProvider folders
* compaction/ - CompactionProvider folders
* plugins/ - PluginProvider folders
*
* Naming Convention (Node.js standard):
* <folder>/index.ts - Auto-discovered and registered
* <folder>/other.ts - Ignored unless imported by index.ts
*/
function discoverProviders(imageDir: string): DiscoveredProviders {
const result: DiscoveredProviders = {
blobStore: [],
customTools: [],
compaction: [],
plugins: [],
totalCount: 0,
};
// Category mapping: folder name -> property name
const categories = {
'blob-store': 'blobStore',
tools: 'customTools',
compaction: 'compaction',
plugins: 'plugins',
} as const;
for (const [folderName, propName] of Object.entries(categories)) {
const categoryDir = join(imageDir, folderName);
if (!existsSync(categoryDir)) {
continue;
}
// Find all provider folders (those with index.ts)
const providerFolders = readdirSync(categoryDir)
.filter((entry) => {
const entryPath = join(categoryDir, entry);
const stat = statSync(entryPath);
// Must be a directory
if (!stat.isDirectory()) {
return false;
}
// Must contain index.ts
const indexPath = join(entryPath, 'index.ts');
return existsSync(indexPath);
})
.map((folder) => {
// Return relative path for imports
return `./${folderName}/${folder}/index.js`;
});
if (providerFolders.length > 0) {
result[propName as keyof Omit<DiscoveredProviders, 'totalCount'>].push(
...providerFolders
);
result.totalCount += providerFolders.length;
console.log(` Found ${providerFolders.length} provider(s) in ${folderName}/`);
}
}
return result;
}

View File

@@ -0,0 +1,93 @@
#!/usr/bin/env node
/**
* CLI for bundling Dexto base images
*/
// Suppress experimental warnings (e.g., Type Stripping)
process.removeAllListeners('warning');
process.on('warning', (warning) => {
if (warning.name !== 'ExperimentalWarning') {
console.warn(warning);
}
});
import { Command } from 'commander';
import { bundle } from './bundler.js';
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import pc from 'picocolors';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Read version from package.json
const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
const program = new Command();
program.name('dexto-bundle').description('Bundle Dexto base images').version(packageJson.version);
program
.command('build')
.description('Build a base image from dexto.image.ts')
.option('-i, --image <path>', 'Path to dexto.image.ts file', 'dexto.image.ts')
.option('-o, --out <dir>', 'Output directory', 'dist')
.option('--sourcemap', 'Generate source maps', false)
.option('--minify', 'Minify output', false)
.action(async (options) => {
try {
console.log(pc.cyan('🚀 Dexto Image Bundler\n'));
const result = await bundle({
imagePath: options.image,
outDir: options.out,
sourcemap: options.sourcemap,
minify: options.minify,
});
console.log(pc.green('\n✨ Build successful!\n'));
console.log(pc.bold('Image Details:'));
console.log(` Name: ${result.metadata.name}`);
console.log(` Version: ${result.metadata.version}`);
console.log(` Target: ${result.metadata.target}`);
console.log(` Built at: ${result.metadata.builtAt}`);
console.log(` Core: v${result.metadata.coreVersion}`);
if (result.metadata.constraints.length > 0) {
console.log(` Constraints: ${result.metadata.constraints.join(', ')}`);
}
if (result.warnings.length > 0) {
console.log(pc.yellow('\n⚠ Warnings:'));
result.warnings.forEach((w) => console.log(` - ${w}`));
}
// Read package.json to get the actual package name
const packageJsonPath = join(process.cwd(), 'package.json');
let packageName = result.metadata.name;
try {
if (readFileSync) {
const pkgJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
packageName = pkgJson.name || result.metadata.name;
}
} catch {
// Use metadata name as fallback
}
console.log(pc.green('\n✅ Image is ready to use!'));
console.log(' To use this image in an app:');
console.log(
pc.dim(
` 1. Install it: pnpm add ${packageName}@file:../${packageName.split('/').pop()}`
)
);
console.log(pc.dim(` 2. Import it: import { createAgent } from '${packageName}';`));
console.log(pc.dim(`\n Or publish to npm and install normally.`));
} catch (error) {
console.error(pc.red('\n❌ Build failed:'), error);
process.exit(1);
}
});
program.parse();

View File

@@ -0,0 +1,336 @@
/**
* Code generator for base images
*
* Transforms image definitions into importable packages with:
* - Side-effect provider registration
* - createAgent() factory
* - Utility exports
* - Metadata exports
*/
import type { ImageDefinition } from '@dexto/core';
import type { GeneratedCode } from './types.js';
import type { DiscoveredProviders } from './bundler.js';
/**
* Generate JavaScript entry point for an image
*/
export function generateEntryPoint(
definition: ImageDefinition,
coreVersion: string,
discoveredProviders?: DiscoveredProviders
): GeneratedCode {
// Generate imports section
const imports = generateImports(definition, discoveredProviders);
// Generate provider registration section
const registrations = generateProviderRegistrations(definition, discoveredProviders);
// Generate factory function
const factory = generateFactory();
// Generate utility exports
const utilityExports = generateUtilityExports(definition);
// Generate metadata export
const metadata = generateMetadata(definition, coreVersion);
// Combine all sections
const js = `// AUTO-GENERATED by @dexto/bundler
// Do not edit this file directly. Edit dexto.image.ts instead.
${imports}
${registrations}
${factory}
${utilityExports}
${metadata}
`;
// Generate TypeScript definitions
const dts = generateTypeDefinitions(definition);
return { js, dts };
}
function generateImports(
definition: ImageDefinition,
discoveredProviders?: DiscoveredProviders
): string {
const imports: string[] = [];
// Import base image first (if extending) - triggers side-effect provider registration
if (definition.extends) {
imports.push(`// Import base image for provider registration (side effect)`);
imports.push(`import '${definition.extends}';`);
imports.push(``);
}
// Core imports
imports.push(`import { DextoAgent } from '@dexto/core';`);
// Always import all registries since we re-export them in generateFactory()
// This ensures the re-exports don't reference unimported identifiers
imports.push(
`import { customToolRegistry, pluginRegistry, compactionRegistry, blobStoreRegistry } from '@dexto/core';`
);
// Import discovered providers
if (discoveredProviders) {
const categories = [
{ key: 'blobStore', label: 'Blob Storage' },
{ key: 'customTools', label: 'Custom Tools' },
{ key: 'compaction', label: 'Compaction' },
{ key: 'plugins', label: 'Plugins' },
] as const;
for (const { key, label } of categories) {
const providers = discoveredProviders[key];
if (providers.length > 0) {
imports.push(``);
imports.push(`// ${label} providers (auto-discovered)`);
providers.forEach((path, index) => {
const varName = `${key}Provider${index}`;
imports.push(`import * as ${varName} from '${path}';`);
});
}
}
}
return imports.join('\n');
}
function generateProviderRegistrations(
definition: ImageDefinition,
discoveredProviders?: DiscoveredProviders
): string {
const registrations: string[] = [];
if (definition.extends) {
registrations.push(
`// Base image providers already registered via import of '${definition.extends}'`
);
registrations.push('');
}
registrations.push('// SIDE EFFECT: Register providers on import');
registrations.push('');
// Auto-register discovered providers
if (discoveredProviders) {
const categoryMap = [
{ key: 'blobStore', registry: 'blobStoreRegistry', label: 'Blob Storage' },
{ key: 'customTools', registry: 'customToolRegistry', label: 'Custom Tools' },
{ key: 'compaction', registry: 'compactionRegistry', label: 'Compaction' },
{ key: 'plugins', registry: 'pluginRegistry', label: 'Plugins' },
] as const;
for (const { key, registry, label } of categoryMap) {
const providers = discoveredProviders[key];
if (providers.length === 0) continue;
registrations.push(`// Auto-register ${label} providers`);
providers.forEach((path, index) => {
const varName = `${key}Provider${index}`;
registrations.push(`// From ${path}`);
registrations.push(`for (const exported of Object.values(${varName})) {`);
registrations.push(
` if (exported && typeof exported === 'object' && 'type' in exported && 'create' in exported) {`
);
registrations.push(` try {`);
registrations.push(` ${registry}.register(exported);`);
registrations.push(
` console.log(\`✓ Registered ${key}: \${exported.type}\`);`
);
registrations.push(` } catch (err) {`);
registrations.push(` // Ignore duplicate registration errors`);
registrations.push(
` if (!err.message?.includes('already registered')) throw err;`
);
registrations.push(` }`);
registrations.push(` }`);
registrations.push(`}`);
});
registrations.push('');
}
}
// Handle manual registration functions (backwards compatibility)
for (const [category, config] of Object.entries(definition.providers)) {
if (!config) continue;
if (config.register) {
// Async registration function with duplicate prevention
registrations.push(`// Register ${category} via custom function (from dexto.image.ts)`);
registrations.push(`await (async () => {`);
registrations.push(` try {`);
registrations.push(
` ${config.register
.toString()
.replace(/^async\s*\(\)\s*=>\s*{/, '')
.replace(/}$/, '')}`
);
registrations.push(` } catch (err) {`);
registrations.push(` // Ignore duplicate registration errors`);
registrations.push(` if (!err.message?.includes('already registered')) {`);
registrations.push(` throw err;`);
registrations.push(` }`);
registrations.push(` }`);
registrations.push(`})();`);
registrations.push('');
}
}
return registrations.join('\n');
}
function generateFactory(): string {
return `/**
* Create a Dexto agent using this image's registered providers.
*
* @param config - Agent configuration
* @param configPath - Optional path to config file
* @returns DextoAgent instance with providers already registered
*/
export function createAgent(config, configPath) {
return new DextoAgent(config, configPath);
}
/**
* Re-export registries for runtime customization.
* This allows apps to add custom providers without depending on @dexto/core directly.
*/
export {
customToolRegistry,
pluginRegistry,
compactionRegistry,
blobStoreRegistry,
} from '@dexto/core';`;
}
function generateUtilityExports(definition: ImageDefinition): string {
const sections: string[] = [];
// Generate wildcard utility exports
if (definition.utils && Object.keys(definition.utils).length > 0) {
sections.push('// Utility exports');
for (const [name, path] of Object.entries(definition.utils)) {
sections.push(`export * from '${path}';`);
}
}
// Generate selective named exports (filter out type-only exports for runtime JS)
if (definition.exports && Object.keys(definition.exports).length > 0) {
if (sections.length > 0) sections.push('');
sections.push('// Selective package re-exports');
for (const [packageName, exports] of Object.entries(definition.exports)) {
// Check for wildcard re-export
if (exports.length === 1 && exports[0] === '*') {
sections.push(`export * from '${packageName}';`);
continue;
}
// Filter out type-only exports (those starting with 'type ')
const runtimeExports = exports.filter((exp) => !exp.startsWith('type '));
if (runtimeExports.length > 0) {
sections.push(`export {`);
sections.push(` ${runtimeExports.join(',\n ')}`);
sections.push(`} from '${packageName}';`);
}
}
}
if (sections.length === 0) {
return '// No utilities or exports defined for this image';
}
return sections.join('\n');
}
function generateMetadata(definition: ImageDefinition, coreVersion: string): string {
const metadata: Record<string, any> = {
name: definition.name,
version: definition.version,
description: definition.description,
target: definition.target || 'custom',
constraints: definition.constraints || [],
builtAt: new Date().toISOString(),
coreVersion: coreVersion,
};
// Include extends information if present
if (definition.extends) {
metadata.extends = definition.extends;
}
// Include bundled plugins if present
if (definition.bundledPlugins && definition.bundledPlugins.length > 0) {
metadata.bundledPlugins = definition.bundledPlugins;
}
return `/**
* Image metadata
* Generated at build time
*/
export const imageMetadata = ${JSON.stringify(metadata, null, 4)};`;
}
function generateTypeDefinitions(definition: ImageDefinition): string {
const sections: string[] = [];
// Wildcard utility exports
if (definition.utils && Object.keys(definition.utils).length > 0) {
sections.push('// Utility re-exports');
for (const path of Object.values(definition.utils)) {
sections.push(`export * from '${path}';`);
}
}
// Selective named exports
if (definition.exports && Object.keys(definition.exports).length > 0) {
if (sections.length > 0) sections.push('');
sections.push('// Selective package re-exports');
for (const [packageName, exports] of Object.entries(definition.exports)) {
// Check for wildcard re-export
if (exports.length === 1 && exports[0] === '*') {
sections.push(`export * from '${packageName}';`);
continue;
}
sections.push(`export {`);
sections.push(` ${exports.join(',\n ')}`);
sections.push(`} from '${packageName}';`);
}
}
const utilityExports = sections.length > 0 ? '\n\n' + sections.join('\n') : '';
return `// AUTO-GENERATED TypeScript definitions
// Do not edit this file directly
import type { DextoAgent, AgentConfig, ImageMetadata } from '@dexto/core';
/**
* Create a Dexto agent using this image's registered providers.
*/
export declare function createAgent(config: AgentConfig, configPath?: string): DextoAgent;
/**
* Image metadata
*/
export declare const imageMetadata: ImageMetadata;
/**
* Re-exported registries for runtime customization
*/
export {
customToolRegistry,
pluginRegistry,
compactionRegistry,
blobStoreRegistry,
} from '@dexto/core';${utilityExports}
`;
}

View File

@@ -0,0 +1,9 @@
/**
* @dexto/bundler
*
* Bundles Dexto base images from dexto.image.ts definitions
* into importable packages with side-effect provider registration.
*/
export { bundle } from './bundler.js';
export type { BundleOptions, BundleResult, GeneratedCode } from './types.js';

View File

@@ -0,0 +1,30 @@
import type { ImageDefinition, ImageMetadata } from '@dexto/core';
export interface BundleOptions {
/** Path to dexto.image.ts file */
imagePath: string;
/** Output directory for built image */
outDir: string;
/** Whether to generate source maps */
sourcemap?: boolean;
/** Whether to minify output */
minify?: boolean;
}
export interface BundleResult {
/** Path to generated entry file */
entryFile: string;
/** Path to generated types file */
typesFile: string;
/** Image metadata */
metadata: ImageMetadata;
/** Warnings encountered during build */
warnings: string[];
}
export interface GeneratedCode {
/** Generated JavaScript code */
js: string;
/** Generated TypeScript definitions */
dts: string;
}

View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"allowImportingTsExtensions": true,
"noEmit": true
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist"]
}

View File

@@ -0,0 +1,13 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts', 'src/cli.ts'],
format: ['esm'],
dts: true,
clean: true,
sourcemap: true,
splitting: false,
shims: true,
external: ['typescript', '@dexto/core', 'picocolors', 'commander'],
noExternal: [],
});