Compare commits

...

11 Commits

Author SHA1 Message Date
ad5e0c1afc v2.9.3
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-24 15:06:01 +00:00
cb5d827420 fix(config): migrate configuration loading and init output from npmextra.json to smartconfig.json 2026-03-24 15:06:01 +00:00
5a5f6c6944 v2.9.2
Some checks failed
Default (tags) / security (push) Successful in 43s
Default (tags) / test (push) Failing after 38s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-11 19:34:52 +00:00
54ac7e7188 fix(mod_esbuild): preserve function and class names in esbuild output by enabling keepNames in both dev and prod configs 2026-03-11 19:34:52 +00:00
5f0507b2c7 v2.9.1
Some checks failed
Default (tags) / security (push) Successful in 41s
Default (tags) / test (push) Failing after 34s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-05 16:47:47 +00:00
ecfd7600e2 fix(mod_custom): use absolute smartfs entry.path instead of joining with dirPath when building fullPath 2026-03-05 16:47:47 +00:00
9cf173293d v2.9.0
Some checks failed
Default (tags) / security (push) Successful in 43s
Default (tags) / test (push) Failing after 39s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-02-24 19:00:42 +00:00
3a53fffe3d feat(exports): expose mod_custom, mod_output and interfaces from entry; make processSingleBundle public 2026-02-24 19:00:42 +00:00
8f129527d9 v2.8.4
Some checks failed
Default (tags) / security (push) Successful in 41s
Default (tags) / test (push) Failing after 36s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-02-24 17:03:04 +00:00
5d9052018e fix(): no changes — empty diff, nothing to commit 2026-02-24 17:03:04 +00:00
12c5655251 feat(includeFiles): support {from, to} object form for custom serve paths
includeFiles now accepts string | {from, to} entries. The object form
allows specifying a custom serve path (e.g. ./html/index.html -> index.html)
for base64ts bundled content.
2026-02-24 17:02:46 +00:00
11 changed files with 113 additions and 53 deletions

View File

@@ -1,5 +1,36 @@
# Changelog # Changelog
## 2026-03-24 - 2.9.3 - fix(config)
migrate configuration loading and init output from npmextra.json to smartconfig.json
- replace @push.rocks/npmextra with @push.rocks/smartconfig
- load project configuration via Smartconfig in the custom module
- update init wizard to read from and write to smartconfig.json and adjust user-facing messages accordingly
## 2026-03-11 - 2.9.2 - fix(mod_esbuild)
preserve function and class names in esbuild output by enabling keepNames in both dev and prod configs
- Added keepNames: true to esbuild options in ts/mod_esbuild/index.child.ts for the non-minified/dev build
- Added keepNames: true to esbuild options in ts/mod_esbuild/index.child.ts for the minified/production build to improve stack traces, debugging, and runtime reflection
## 2026-03-05 - 2.9.1 - fix(mod_custom)
use absolute smartfs entry.path instead of joining with dirPath when building fullPath
- entry.path is already absolute (from smartfs); avoid joining it with dirPath which produced incorrect paths
- Fixes file copy path construction so plugins.fs.file(fullPath).copy(destPath) uses the correct source path
## 2026-02-24 - 2.9.0 - feat(exports)
expose mod_custom, mod_output and interfaces from entry; make processSingleBundle public
- Exported ./mod_custom, ./mod_output and ./interfaces from ts/index.ts to expose these modules in the public API.
- Changed processSingleBundle in ts/mod_custom/index.ts from private to public to allow programmatic invocation.
- Non-breaking API expansion; recommend a minor version bump.
## 2026-02-24 - 2.8.4 - fix()
no changes — empty diff, nothing to commit
- Diff contained no modifications; no release required
## 2026-01-23 - 2.8.3 - fix(mod_output) ## 2026-01-23 - 2.8.3 - fix(mod_output)
use pattern base dir when computing relative paths for files to serve use pattern base dir when computing relative paths for files to serve

View File

@@ -1,6 +1,6 @@
{ {
"name": "@git.zone/tsbundle", "name": "@git.zone/tsbundle",
"version": "2.8.3", "version": "2.9.3",
"private": false, "private": false,
"description": "a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects", "description": "a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
@@ -24,7 +24,7 @@
}, },
"dependencies": { "dependencies": {
"@push.rocks/early": "^4.0.4", "@push.rocks/early": "^4.0.4",
"@push.rocks/npmextra": "^5.1.3", "@push.rocks/smartconfig": "^6.0.0",
"@push.rocks/smartcli": "^4.0.20", "@push.rocks/smartcli": "^4.0.20",
"@push.rocks/smartdelay": "^3.0.5", "@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfs": "^1.1.3", "@push.rocks/smartfs": "^1.1.3",

46
pnpm-lock.yaml generated
View File

@@ -11,12 +11,12 @@ importers:
'@push.rocks/early': '@push.rocks/early':
specifier: ^4.0.4 specifier: ^4.0.4
version: 4.0.4 version: 4.0.4
'@push.rocks/npmextra':
specifier: ^5.1.3
version: 5.3.3
'@push.rocks/smartcli': '@push.rocks/smartcli':
specifier: ^4.0.20 specifier: ^4.0.20
version: 4.0.20 version: 4.0.20
'@push.rocks/smartconfig':
specifier: ^6.0.0
version: 6.0.0
'@push.rocks/smartdelay': '@push.rocks/smartdelay':
specifier: ^3.0.5 specifier: ^3.0.5
version: 3.0.5 version: 3.0.5
@@ -886,9 +886,6 @@ packages:
'@push.rocks/mongodump@1.1.0': '@push.rocks/mongodump@1.1.0':
resolution: {integrity: sha512-kW0ZUGyf1e4nwloVwBQjNId+MzgTcNS834C+RxH21i1NqyOubbpWZtJtPP+K+s35nSJRyCTy3ICfBMdDBTAm2w==} resolution: {integrity: sha512-kW0ZUGyf1e4nwloVwBQjNId+MzgTcNS834C+RxH21i1NqyOubbpWZtJtPP+K+s35nSJRyCTy3ICfBMdDBTAm2w==}
'@push.rocks/npmextra@5.3.3':
resolution: {integrity: sha512-snLpSHwaQ5OXlZzF1KX/FY71W5LwajjBzor82Vue0smjEPnSeUPY5/JcVdMwtdprdJe13pc/EQQuIiL/zw4/yg==}
'@push.rocks/qenv@6.1.3': '@push.rocks/qenv@6.1.3':
resolution: {integrity: sha512-+z2hsAU/7CIgpYLFqvda8cn9rUBMHqLdQLjsFfRn5jPoD7dJ5rFlpkbhfM4Ws8mHMniwWaxGKo+q/YBhtzRBLg==} resolution: {integrity: sha512-+z2hsAU/7CIgpYLFqvda8cn9rUBMHqLdQLjsFfRn5jPoD7dJ5rFlpkbhfM4Ws8mHMniwWaxGKo+q/YBhtzRBLg==}
@@ -919,6 +916,9 @@ packages:
'@push.rocks/smartclickhouse@2.0.17': '@push.rocks/smartclickhouse@2.0.17':
resolution: {integrity: sha512-IYO8Obor/Ruam2KQ2B/+5uQ+rL0exU5KZoSgOc3jkkrfjn+zZenN2xoV8lVqavAtxZVfG7MfxFrcv6I7I9ZMmA==} resolution: {integrity: sha512-IYO8Obor/Ruam2KQ2B/+5uQ+rL0exU5KZoSgOc3jkkrfjn+zZenN2xoV8lVqavAtxZVfG7MfxFrcv6I7I9ZMmA==}
'@push.rocks/smartconfig@6.0.0':
resolution: {integrity: sha512-ohXwJdbDXV2budErnZKWBOz01YkjP6gJsZ7QM9+6Wsh+r7O1CVT3JpV+mD8xJWy5tZRHI+3B9L8z0+WkIDtKzw==}
'@push.rocks/smartcrypto@2.0.4': '@push.rocks/smartcrypto@2.0.4':
resolution: {integrity: sha512-1+/5bsjyataf5uUkUNnnVXGRAt+gHVk1KDzozjTqgqJxHvQk1d9fVDohL6CxUhUucTPtu5VR5xNBiV8YCDuGyw==} resolution: {integrity: sha512-1+/5bsjyataf5uUkUNnnVXGRAt+gHVk1KDzozjTqgqJxHvQk1d9fVDohL6CxUhUucTPtu5VR5xNBiV8YCDuGyw==}
@@ -5319,23 +5319,6 @@ snapshots:
- snappy - snappy
- socks - socks
'@push.rocks/npmextra@5.3.3':
dependencies:
'@push.rocks/qenv': 6.1.3
'@push.rocks/smartfile': 11.2.7
'@push.rocks/smartjson': 5.2.0
'@push.rocks/smartlog': 3.1.10
'@push.rocks/smartpath': 6.0.0
'@push.rocks/smartpromise': 4.2.3
'@push.rocks/smartrx': 3.0.10
'@push.rocks/taskbuffer': 3.4.0
'@tsclass/tsclass': 9.3.0
transitivePeerDependencies:
- '@nuxt/kit'
- react
- supports-color
- vue
'@push.rocks/qenv@6.1.3': '@push.rocks/qenv@6.1.3':
dependencies: dependencies:
'@api.global/typedrequest': 3.1.10 '@api.global/typedrequest': 3.1.10
@@ -5446,6 +5429,23 @@ snapshots:
'@push.rocks/smarturl': 3.1.0 '@push.rocks/smarturl': 3.1.0
'@push.rocks/webrequest': 3.0.37 '@push.rocks/webrequest': 3.0.37
'@push.rocks/smartconfig@6.0.0':
dependencies:
'@push.rocks/qenv': 6.1.3
'@push.rocks/smartfile': 11.2.7
'@push.rocks/smartjson': 5.2.0
'@push.rocks/smartlog': 3.1.10
'@push.rocks/smartpath': 6.0.0
'@push.rocks/smartpromise': 4.2.3
'@push.rocks/smartrx': 3.0.10
'@push.rocks/taskbuffer': 3.4.0
'@tsclass/tsclass': 9.3.0
transitivePeerDependencies:
- '@nuxt/kit'
- react
- supports-color
- vue
'@push.rocks/smartcrypto@2.0.4': '@push.rocks/smartcrypto@2.0.4':
dependencies: dependencies:
'@push.rocks/smartpromise': 4.2.3 '@push.rocks/smartpromise': 4.2.3

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@git.zone/tsbundle', name: '@git.zone/tsbundle',
version: '2.8.3', version: '2.9.3',
description: 'a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects' description: 'a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects'
} }

View File

@@ -11,4 +11,7 @@ early.stop();
export * from './tsbundle.class.tsbundle.js'; export * from './tsbundle.class.tsbundle.js';
export * from './mod_assets/index.js'; export * from './mod_assets/index.js';
export * from './mod_html/index.js'; export * from './mod_html/index.js';
export * from './mod_custom/index.js';
export * from './mod_output/index.js';
export * from './interfaces/index.js';
export { runCli }; export { runCli };

View File

@@ -17,13 +17,15 @@ export interface IEnvTransportOptions {
export type TOutputMode = 'bundle' | 'base64ts'; export type TOutputMode = 'bundle' | 'base64ts';
export type TBundler = 'esbuild' | 'rolldown' | 'rspack'; export type TBundler = 'esbuild' | 'rolldown' | 'rspack';
export type TIncludeFile = string | { from: string; to: string };
export interface IBundleConfig { export interface IBundleConfig {
from: string; from: string;
to: string; to: string;
outputMode?: TOutputMode; outputMode?: TOutputMode;
bundler?: TBundler; bundler?: TBundler;
production?: boolean; production?: boolean;
includeFiles?: string[]; includeFiles?: TIncludeFile[];
maxLineLength?: number; // For base64ts output: max chars per line. 0 or undefined = unlimited (default) maxLineLength?: number; // For base64ts output: max chars per line. 0 or undefined = unlimited (default)
} }

View File

@@ -19,7 +19,7 @@ export class CustomBundleHandler {
* Load configuration from npmextra.json * Load configuration from npmextra.json
*/ */
public async loadConfig(): Promise<boolean> { public async loadConfig(): Promise<boolean> {
const npmextraInstance = new plugins.npmextra.Npmextra(this.cwd); const npmextraInstance = new plugins.npmextra.Smartconfig(this.cwd);
this.config = npmextraInstance.dataFor<interfaces.ITsbundleConfig>('@git.zone/tsbundle', { this.config = npmextraInstance.dataFor<interfaces.ITsbundleConfig>('@git.zone/tsbundle', {
bundles: [], bundles: [],
}); });
@@ -48,7 +48,7 @@ export class CustomBundleHandler {
/** /**
* Process a single bundle configuration * Process a single bundle configuration
*/ */
private async processSingleBundle(bundleConfig: interfaces.IBundleConfig): Promise<void> { public async processSingleBundle(bundleConfig: interfaces.IBundleConfig): Promise<void> {
const outputMode = bundleConfig.outputMode || 'bundle'; const outputMode = bundleConfig.outputMode || 'bundle';
const bundler = bundleConfig.bundler || 'esbuild'; const bundler = bundleConfig.bundler || 'esbuild';
@@ -105,8 +105,12 @@ export class CustomBundleHandler {
// Add included files // Add included files
if (bundleConfig.includeFiles && bundleConfig.includeFiles.length > 0) { if (bundleConfig.includeFiles && bundleConfig.includeFiles.length > 0) {
for (const pattern of bundleConfig.includeFiles) { for (const entry of bundleConfig.includeFiles) {
await base64Output.addFilesFromGlob(pattern); if (typeof entry === 'string') {
await base64Output.addFilesFromGlob(entry);
} else {
await base64Output.addFileWithServePath(entry.from, entry.to);
}
} }
} }
@@ -135,7 +139,8 @@ export class CustomBundleHandler {
const htmlHandler = new HtmlHandler(); const htmlHandler = new HtmlHandler();
const outputDir = plugins.path.dirname(toPath); const outputDir = plugins.path.dirname(toPath);
for (const pattern of bundleConfig.includeFiles) { for (const entry of bundleConfig.includeFiles) {
const pattern = typeof entry === 'string' ? entry : entry.from;
await this.copyIncludedFiles(pattern, outputDir); await this.copyIncludedFiles(pattern, outputDir);
} }
} }
@@ -171,7 +176,8 @@ export class CustomBundleHandler {
for (const entry of entries) { for (const entry of entries) {
if (!entry.isDirectory && regex.test(entry.name)) { if (!entry.isDirectory && regex.test(entry.name)) {
const fullPath = plugins.path.join(dirPath, entry.path); // entry.path is already absolute from smartfs
const fullPath = entry.path;
const relativePath = plugins.path.relative(this.cwd, fullPath); const relativePath = plugins.path.relative(this.cwd, fullPath);
const destPath = plugins.path.join(outputDir, plugins.path.basename(entry.path)); const destPath = plugins.path.join(outputDir, plugins.path.basename(entry.path));
await plugins.fs.directory(plugins.path.dirname(destPath)).create(); await plugins.fs.directory(plugins.path.dirname(destPath)).create();

View File

@@ -43,6 +43,7 @@ export class TsBundleProcess {
sourcemap: true, sourcemap: true,
format: 'esm', format: 'esm',
target: 'es2022', target: 'es2022',
keepNames: true,
entryNames: plugins.path.parse(toArg).name, entryNames: plugins.path.parse(toArg).name,
outdir: plugins.path.parse(toArg).dir, outdir: plugins.path.parse(toArg).dir,
splitting: false, splitting: false,
@@ -67,6 +68,7 @@ export class TsBundleProcess {
format: 'esm', format: 'esm',
target: 'es2022', target: 'es2022',
minify: true, minify: true,
keepNames: true,
entryNames: plugins.path.parse(toArg).name, entryNames: plugins.path.parse(toArg).name,
outdir: plugins.path.parse(toArg).dir, outdir: plugins.path.parse(toArg).dir,
tsconfig: paths.tsconfigPath, tsconfig: paths.tsconfigPath,

View File

@@ -36,20 +36,20 @@ const PRESETS: Record<string, { description: string; config: interfaces.IBundleC
export class InitHandler { export class InitHandler {
private cwd: string; private cwd: string;
private npmextraPath: string; private smartconfigPath: string;
constructor(cwd: string = paths.cwd) { constructor(cwd: string = paths.cwd) {
this.cwd = cwd; this.cwd = cwd;
this.npmextraPath = plugins.path.join(this.cwd, 'npmextra.json'); this.smartconfigPath = plugins.path.join(this.cwd, 'smartconfig.json');
} }
/** /**
* Load existing npmextra.json or create empty config * Load existing npmextra.json or create empty config
*/ */
private async loadExistingConfig(): Promise<any> { private async loadExistingConfig(): Promise<any> {
const fileExists = await plugins.fs.file(this.npmextraPath).exists(); const fileExists = await plugins.fs.file(this.smartconfigPath).exists();
if (fileExists) { if (fileExists) {
const content = (await plugins.fs.file(this.npmextraPath).encoding('utf8').read()) as string; const content = (await plugins.fs.file(this.smartconfigPath).encoding('utf8').read()) as string;
try { try {
return JSON.parse(content); return JSON.parse(content);
} catch { } catch {
@@ -64,8 +64,8 @@ export class InitHandler {
*/ */
private async saveConfig(config: any): Promise<void> { private async saveConfig(config: any): Promise<void> {
const content = JSON.stringify(config, null, 2); const content = JSON.stringify(config, null, 2);
await plugins.fs.file(this.npmextraPath).encoding('utf8').write(content); await plugins.fs.file(this.smartconfigPath).encoding('utf8').write(content);
console.log(`\n✅ Configuration saved to npmextra.json`); console.log(`\n✅ Configuration saved to smartconfig.json`);
} }
/** /**
@@ -73,15 +73,15 @@ export class InitHandler {
*/ */
public async runWizard(): Promise<void> { public async runWizard(): Promise<void> {
console.log('\n🚀 tsbundle configuration wizard\n'); console.log('\n🚀 tsbundle configuration wizard\n');
console.log('This wizard will help you configure bundle settings in npmextra.json.\n'); console.log('This wizard will help you configure bundle settings in smartconfig.json.\n');
const npmextraJson = await this.loadExistingConfig(); const smartconfigJson = await this.loadExistingConfig();
if (!npmextraJson['@git.zone/tsbundle']) { if (!smartconfigJson['@git.zone/tsbundle']) {
npmextraJson['@git.zone/tsbundle'] = { bundles: [] }; smartconfigJson['@git.zone/tsbundle'] = { bundles: [] };
} }
const existingBundles = npmextraJson['@git.zone/tsbundle'].bundles || []; const existingBundles = smartconfigJson['@git.zone/tsbundle'].bundles || [];
if (existingBundles.length > 0) { if (existingBundles.length > 0) {
console.log(`Found ${existingBundles.length} existing bundle configuration(s):\n`); console.log(`Found ${existingBundles.length} existing bundle configuration(s):\n`);
@@ -95,7 +95,7 @@ export class InitHandler {
while (addMore) { while (addMore) {
const bundle = await this.configureSingleBundle(); const bundle = await this.configureSingleBundle();
if (bundle) { if (bundle) {
npmextraJson['@git.zone/tsbundle'].bundles.push(bundle); smartconfigJson['@git.zone/tsbundle'].bundles.push(bundle);
console.log(`\n✅ Bundle configuration added!`); console.log(`\n✅ Bundle configuration added!`);
} }
@@ -112,10 +112,10 @@ export class InitHandler {
addMore = answers.getAnswerFor('addAnother'); addMore = answers.getAnswerFor('addAnother');
} }
await this.saveConfig(npmextraJson); await this.saveConfig(smartconfigJson);
console.log('\n📋 Final configuration:\n'); console.log('\n📋 Final configuration:\n');
const bundles = npmextraJson['@git.zone/tsbundle'].bundles; const bundles = smartconfigJson['@git.zone/tsbundle'].bundles;
bundles.forEach((bundle: interfaces.IBundleConfig, i: number) => { bundles.forEach((bundle: interfaces.IBundleConfig, i: number) => {
console.log(` Bundle ${i + 1}:`); console.log(` Bundle ${i + 1}:`);
console.log(` From: ${bundle.from}`); console.log(` From: ${bundle.from}`);
@@ -123,7 +123,8 @@ export class InitHandler {
console.log(` Mode: ${bundle.outputMode || 'bundle'}`); console.log(` Mode: ${bundle.outputMode || 'bundle'}`);
console.log(` Bundler: ${bundle.bundler || 'esbuild'}`); console.log(` Bundler: ${bundle.bundler || 'esbuild'}`);
if (bundle.includeFiles && bundle.includeFiles.length > 0) { if (bundle.includeFiles && bundle.includeFiles.length > 0) {
console.log(` Include: ${bundle.includeFiles.join(', ')}`); const display = bundle.includeFiles.map(f => typeof f === 'string' ? f : `${f.from} -> ${f.to}`);
console.log(` Include: ${display.join(', ')}`);
} }
console.log(''); console.log('');
}); });
@@ -168,7 +169,8 @@ export class InitHandler {
console.log(` Mode: ${preset.config.outputMode}`); console.log(` Mode: ${preset.config.outputMode}`);
console.log(` Bundler: ${preset.config.bundler}`); console.log(` Bundler: ${preset.config.bundler}`);
if (preset.config.includeFiles && preset.config.includeFiles.length > 0) { if (preset.config.includeFiles && preset.config.includeFiles.length > 0) {
console.log(` Include: ${preset.config.includeFiles.join(', ')}`); const display = preset.config.includeFiles.map(f => typeof f === 'string' ? f : `${f.from} -> ${f.to}`);
console.log(` Include: ${display.join(', ')}`);
} }
const confirmInteract = new plugins.smartinteract.SmartInteract(); const confirmInteract = new plugins.smartinteract.SmartInteract();
@@ -293,14 +295,14 @@ export class InitHandler {
/** /**
* Configure files to include * Configure files to include
*/ */
private async configureIncludeFiles(prefill?: string[]): Promise<string[]> { private async configureIncludeFiles(prefill?: interfaces.TIncludeFile[]): Promise<interfaces.TIncludeFile[]> {
const includeFiles: string[] = []; const includeFiles: interfaces.TIncludeFile[] = [];
let addMore = true; let addMore = true;
// If we have prefilled values, show them first // If we have prefilled values, show them first
if (prefill && prefill.length > 0) { if (prefill && prefill.length > 0) {
console.log('\nPre-configured include patterns:'); console.log('\nPre-configured include patterns:');
prefill.forEach((p) => console.log(` - ${p}`)); prefill.forEach((p) => console.log(` - ${typeof p === 'string' ? p : `${p.from} -> ${p.to}`}`));
const keepInteract = new plugins.smartinteract.SmartInteract(); const keepInteract = new plugins.smartinteract.SmartInteract();
keepInteract.addQuestions([ keepInteract.addQuestions([

View File

@@ -22,6 +22,20 @@ export class Base64TsOutput {
}); });
} }
/**
* Add a file with a custom serve path
*/
public async addFileWithServePath(fromPath: string, servePath: string): Promise<void> {
const absolutePath = plugins.smartpath.transform.toAbsolute(fromPath, this.cwd) as string;
const fileExists = await plugins.fs.file(absolutePath).exists();
if (!fileExists) {
console.log(`File does not exist: ${absolutePath}`);
return;
}
const content = await plugins.fs.file(absolutePath).read();
this.addFile(servePath, content);
}
/** /**
* Add files matching a glob pattern * Add files matching a glob pattern
*/ */

View File

@@ -4,7 +4,7 @@ import * as path from 'path';
export { path }; export { path };
// pushrocks scope // pushrocks scope
import * as npmextra from '@push.rocks/npmextra'; import * as npmextra from '@push.rocks/smartconfig';
import * as smartcli from '@push.rocks/smartcli'; import * as smartcli from '@push.rocks/smartcli';
import * as smartfs from '@push.rocks/smartfs'; import * as smartfs from '@push.rocks/smartfs';
import * as smartinteract from '@push.rocks/smartinteract'; import * as smartinteract from '@push.rocks/smartinteract';