aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/core/module-loader.js2
-rw-r--r--modules/core/module-manager.js4
-rw-r--r--modules/core/module-predictor.js3
-rw-r--r--modules/core/terminal.js8
-rw-r--r--modules/ext/skill-pack-core.js42
5 files changed, 54 insertions, 5 deletions
diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js
index c5237ad..f4bd20b 100644
--- a/modules/core/module-loader.js
+++ b/modules/core/module-loader.js
@@ -105,7 +105,7 @@
window.__moduleLoaderReload = reloadWithSelection;
-const LATEST_VER = '2026-06-06-v4.5.6';
+const LATEST_VER = '2026-06-06-v4.5.9';
const CACHE = '?v=' + LATEST_VER;
const stored = localStorage.getItem('webx11_cache_ver');
if (stored !== LATEST_VER) {
diff --git a/modules/core/module-manager.js b/modules/core/module-manager.js
index c508778..4f004ee 100644
--- a/modules/core/module-manager.js
+++ b/modules/core/module-manager.js
@@ -30,7 +30,7 @@
const instance = new ModuleClass();
this.registerModule(instance, url);
if (instance.init) {
- await instance.init();
+ await instance.init(this.terminal);
}
this.terminal.print(`Module loaded successfully from ${url}`, 'success');
return true;
@@ -88,7 +88,7 @@
const instance = new ModuleClass();
this.registerModule(instance, url);
if (instance.init) {
- instance.init();
+ instance.init(this.terminal);
}
this.terminal.print(`Module loaded from editor: ${instance.constructor.name}`, 'success');
return true;
diff --git a/modules/core/module-predictor.js b/modules/core/module-predictor.js
index 312325b..3d868ae 100644
--- a/modules/core/module-predictor.js
+++ b/modules/core/module-predictor.js
@@ -106,6 +106,7 @@ class PredictorModule {
hasWeb: /\b(fetch|url|http|web)\b/.test(lower),
hasOrchestrate: /\b(orchestrat|delegate|agent)\b/.test(lower),
hasModule: /\b(module|edit_module|view_module)\b/.test(lower),
+ hasSync: /\b(sync|recall|remember|previous session|state sync)\b/.test(lower),
complexity: Math.min(task.length / 50, 10), // 0-10 scale
keywords: [...new Set(lower.split(/\s+/).filter(w => w.length > 3))].slice(0, 10)
};
@@ -128,6 +129,7 @@ class PredictorModule {
features.hasWeb === f.hasWeb,
features.hasOrchestrate === f.hasOrchestrate,
features.hasModule === f.hasModule,
+ features.hasSync === f.hasSync,
];
score = matches.filter(Boolean).length / matches.length;
// Keyword overlap bonus
@@ -146,6 +148,7 @@ class PredictorModule {
if (features.hasSearch || features.hasWeb) { baseDuration = 25; baseTurns = 5; }
if (features.hasWrite) { baseDuration = 20; baseTurns = 4; }
if (features.hasOrchestrate) { baseDuration = 40; baseTurns = 8; }
+ if (features.hasSync) { baseDuration = 30; baseTurns = 6; }
if (features.complexity > 5) baseDuration *= 1.5;
return {
duration: baseDuration,
diff --git a/modules/core/terminal.js b/modules/core/terminal.js
index be57c05..8f1ad19 100644
--- a/modules/core/terminal.js
+++ b/modules/core/terminal.js
@@ -2167,8 +2167,12 @@
modifiedAt: new Date().toISOString(), editCount: 1
}));
try {
- await this.moduleManager.loadModuleFromCode(code, 'blob://_mods/' + mod.name + '.js');
- this.print('✅ Module loaded live from _mods/' + mod.name + '.js', 'success');
+ const ok = await this.moduleManager.loadModuleFromCode(code, 'blob://_mods/' + mod.name + '.js');
+ if (ok) {
+ this.print('✅ Module loaded live from _mods/' + mod.name + '.js', 'success');
+ } else {
+ this.print('⚠️ Auto-test failed — edits saved but module not loaded', 'warning');
+ }
} catch (e) {
this.print('⚠️ Auto-test failed: ' + e.message + ' — edits saved but module not loaded', 'error');
}
diff --git a/modules/ext/skill-pack-core.js b/modules/ext/skill-pack-core.js
index 41844bd..6f7ad4c 100644
--- a/modules/ext/skill-pack-core.js
+++ b/modules/ext/skill-pack-core.js
@@ -29,6 +29,7 @@ class SkillPackCoreModule {
'skill-export': 'skill-export <name> — Export a skill as JSON',
'skill-import': 'skill-import <json> — Import a skill from JSON string',
'skill-sync': 'skill-sync — Rebuild skills index from /skills/ directory',
+ 'skill-webdav-sync': 'skill-webdav-sync — Push all skills to WebDAV as JSON files',
};
}
@@ -487,6 +488,7 @@ class SkillPackCoreModule {
this.commands['skill-export'] = (args) => this._cmdSkillExport(args);
this.commands['skill-import'] = (args) => this._cmdSkillImport(args);
this.commands['skill-sync'] = () => this._cmdSkillSync();
+ this.commands['skill-webdav-sync'] = () => this._cmdSkillWebdavSync();
}
// ── Skill Commands ──
@@ -690,6 +692,46 @@ class SkillPackCoreModule {
this.terminal.print(`📚 Skill index rebuilt: ${synced} skills synced`, 'success');
}
+ async _cmdSkillWebdavSync() {
+ const fs = this.terminal.fs;
+ const index = fs.fsReadJSON('/skills/index.json') || {};
+ const names = Object.keys(index);
+ if (names.length === 0) {
+ this.terminal.print('No skills to sync', 'info');
+ return;
+ }
+ // Find the webdav module
+ const webdavMod = this.terminal.moduleManager.modules['WebDAVModule'];
+ if (!webdavMod || !webdavMod._webdavRequest) {
+ this.terminal.print('WebDAV module not loaded. Configure webdav first with webdav-config', 'warning');
+ return;
+ }
+ this.terminal.print(`📤 Syncing ${names.length} skills to WebDAV...`, 'info');
+ let ok = 0, fail = 0;
+ await webdavMod._ensureDir('skills');
+ for (const name of names) {
+ const content = fs.readFile(`/skills/${name}.md`);
+ if (content === null) { fail++; continue; }
+ const meta = index[name];
+ const exportObj = { ...meta, content };
+ const json = JSON.stringify(exportObj, null, 2);
+ try {
+ const resp = await webdavMod._webdavRequest('PUT', 'skills/' + name + '.json', {
+ body: json,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ if (resp.ok || resp.status === 201 || resp.status === 204) {
+ ok++;
+ } else {
+ fail++;
+ }
+ } catch (e) {
+ fail++;
+ }
+ }
+ this.terminal.print(`📤 Skill WebDAV sync complete: ${ok} pushed, ${fail} failed`, fail > 0 ? 'warning' : 'success');
+ }
+
init() {
this.seed();
}