aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--help.html17
-rw-r--r--main.html6
-rw-r--r--modules/core/module-loader.js2
-rw-r--r--modules/ext/skill-pack-core.js21
4 files changed, 37 insertions, 9 deletions
diff --git a/help.html b/help.html
index 9b39849..2ab9bfa 100644
--- a/help.html
+++ b/help.html
@@ -1689,6 +1689,23 @@ listmods</pre>
<h2>📋 Changelog</h2>
<div class="version-item">
+ <div class="v-header"><span class="v-num">v4.6.86–87 — October 2026</span>
+ <span class="v-date">audit honesty, static assets</span></div>
+ <ul>
+ <li><strong>"Broken refs: 2" named neither of them — because both were documentation.</strong>
+ The checker grepped for <code>skill-view &lt;name&gt;</code> in every skill's prose, so
+ the placeholder and a quoted example counted as missing skills. Placeholders are now
+ skipped, and any real breakage is named:
+ <code>Broken refs: 1 (probe-broken-ref → ghost-skill)</code>.</li>
+ <li><strong>Two quick reloads no longer break the app.</strong> Opening newOS4 costs about
+ 35 module requests at once; the site-wide rate zone (60 r/min, burst 50) treated that as a
+ flood and served <code>503</code> for part of the bundle — measured 4 modules failing on a
+ third reload. Static module and skill files now have their own zone; HTML and API requests
+ keep the strict one.</li>
+ </ul>
+ </div>
+
+ <div class="version-item">
<div class="v-header"><span class="v-num">v4.6.85 — October 2026</span>
<span class="v-date">no invented numbers</span></div>
<ul>
diff --git a/main.html b/main.html
index a8586ce..66077b5 100644
--- a/main.html
+++ b/main.html
@@ -1349,13 +1349,13 @@
</script>
<!-- v4.5.63: A2A scratchpad fixes + agent-register arg fix -->
-<script src="modules/core/core-bundle.js?v=v4.6.85"></script>
+<script src="modules/core/core-bundle.js?v=v4.6.87"></script>
<!-- Async dependency-ordered module loader now only initializes terminal and loads optional ext modules -->
-<script src="modules/core/module-loader.js?v=v4.6.85"></script>
+<script src="modules/core/module-loader.js?v=v4.6.87"></script>
<!-- Critical ext bundle loads AFTER webx11 exists so registerModule calls work -->
-<script src="modules/ext/critical-ext-bundle.js?v=v4.6.85"></script>
+<script src="modules/ext/critical-ext-bundle.js?v=v4.6.87"></script>
<script>
// ═══ ONE TRUE VERSION SOURCE ═══
diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js
index 1b0f6d9..37212f3 100644
--- a/modules/core/module-loader.js
+++ b/modules/core/module-loader.js
@@ -4,7 +4,7 @@
// Core module bundle loaded synchronously in main.html.
// This loader only handles version cache-busting, splash, terminal init, and optional ext modules.
- const LATEST_VER = 'v4.6.85';
+ const LATEST_VER = 'v4.6.87';
const CACHE = '?v=' + LATEST_VER;
const stored = localStorage.getItem('webx11_cache_ver');
if (stored !== LATEST_VER) {
diff --git a/modules/ext/skill-pack-core.js b/modules/ext/skill-pack-core.js
index cba77b6..c2c95ba 100644
--- a/modules/ext/skill-pack-core.js
+++ b/modules/ext/skill-pack-core.js
@@ -1195,6 +1195,7 @@ after the behaviour itself was fixed in v4.6.58.`),
var stale = [];
var duplicates = [];
var brokenRefs = 0;
+ var brokenList = [];
// 1. Stale check
const mg = this.terminal?.moduleManager?.modules?.['MemoryGraphModule'];
@@ -1226,13 +1227,23 @@ after the behaviour itself was fixed in v4.6.58.`),
}
// 3. Reference check
+ // Documentation is not a reference: `skill-view <name>` and quoted examples inside a skill's
+ // prose were counted as broken skills, so the audit reported 2 phantom breakages and named
+ // neither. Placeholders are skipped and the survivors are listed.
for (var name of allNames) {
var content = fs.readFile('/skills/' + name + '.md');
if (!content) continue;
- var refs = content.match(/skill-view\s+(\S+)/g) || [];
+ var refs = content.match(/skill-view\s+("[^"]+"|\S+)/g) || [];
for (var ref of refs) {
- var refName = ref.replace(/skill-view\s+/, '').replace(/\.md$/, '');
- if (!fs.readFile('/skills/' + refName + '.md')) brokenRefs++;
+ var refName = ref.replace(/skill-view\s+/, '').replace(/^"|"$/g, '').replace(/\.md$/, '');
+ // prose puts punctuation after an example: "skill-view <name>." — strip it before
+ // deciding whether this is a placeholder or a real skill name
+ refName = refName.replace(/[.,;:!?)]+$/, '');
+ if (!refName || /^<.*>$/.test(refName)) continue; // `<name>` is a placeholder
+ if (!fs.readFile('/skills/' + refName + '.md')) {
+ brokenRefs++;
+ brokenList.push(name + ' → ' + refName);
+ }
}
}
@@ -1246,14 +1257,14 @@ after the behaviour itself was fixed in v4.6.58.`),
this.terminal.print('Untracked: ' + untracked.length + ' (no usage telemetry — NOT stale)', 'info');
}
this.terminal.print('Duplicates: ' + duplicates.length + (duplicates.length > 0 ? ' (' + duplicates.join(', ') + ')' : ''), duplicates.length > 0 ? 'warning' : 'info');
- this.terminal.print('Broken refs: ' + brokenRefs, brokenRefs > 0 ? 'error' : 'info');
+ this.terminal.print('Broken refs: ' + brokenRefs + (brokenRefs > 0 ? ' (' + brokenList.join(', ') + ')' : ''), brokenRefs > 0 ? 'error' : 'info');
this.terminal.print('', '');
if (stale.length > 0 || duplicates.length > 0 || brokenRefs > 0) {
this.terminal.print('Suggestions:', 'info');
for (var st of stale) this.terminal.print('• Archive ' + st, 'warning');
for (var dup of duplicates) this.terminal.print('• Merge ' + dup, 'warning');
- if (brokenRefs > 0) this.terminal.print('• Fix ' + brokenRefs + ' broken reference(s)', 'warning');
+ if (brokenRefs > 0) this.terminal.print('• Fix ' + brokenRefs + ' broken reference(s): ' + brokenList.join(', '), 'warning');
} else {
this.terminal.print('✅ All skills healthy', 'success');
}