diff options
| author | Agando <roduccomm@gmail.com> | 2026-10-27 15:23:38 +0100 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-10-27 15:23:38 +0100 |
| commit | 6b4049d3ba27dd68935c0565cccfe44752175393 (patch) | |
| tree | a336032a1c463dddb53c06e20fd7cefb12f721b7 /modules/test | |
| parent | 6f2255946a834f2458613450533cd2906eb31e7d (diff) | |
fix(newos4): help names the owner of an undocumented command; loop lessons leave /skills
Two board items plus the context-window close-out.
- MAINT-019 (module-system.js): `help <cmd>` answered "No help available for X" for a command
that is registered but has no help line, which reads as if the command does not exist. It now
says "X — registered by <Module>, which publishes no help line for it. Try: help". A command
that genuinely does not exist still gets the old message.
- MAINT-020 (module-aiassist.js): auto-generated loop lessons were written into /skills with
their own index entries, so `skill list` filled up with system noise. Lessons now live in
/lessons with /lessons/index.json; the reader still falls back to legacy loop-lesson-* entries
in /skills for one release, and the one-time migration deletes them from the skills index.
Verification: test-help-and-lessons.js (10 asserts, includes a lint-style guard that no lesson is
written into /skills). Suite 14/14 files green; maintain --fix "node tests 14/14 pass",
"help coverage 362/362". Live on v4.6.108: `help agent-register` -> "registered by
AgentRegistryModule, which publishes no help line for it"; `help a2a-prune` unchanged;
`help nope-not-real` still "No help available".
MAINT-001 close-out (no code change here): history is capped at 20 messages with a "[context trim]"
marker (first trim at turn 11 in a 60-turn probe), token compression took 80 msgs/8080 tok to
17/2625, and since v4.6.107 one turn's tool bodies are clipped to 6 000 chars each and elided past
24 000 with the newest 4 kept verbatim. Residual, recorded on the board: maxContextTokens is never
sent to the server as num_ctx, so the real window is whatever the endpoint defaults to.
MAINT-018 close-out: not reproducible. Live probes on v4.6.107/108 — `sed -n '1,3p' /probe.txt`
prints lines 1-3, `sed -n "2,4p"` prints 2-4, `grep 'line4'` matches, and the same commands inside
`script /q.sh` print correctly. The "Command not found: for;" symptom belongs to the line-by-line
script runner, which is MAINT-021 and stays open.
Diffstat (limited to 'modules/test')
| -rw-r--r-- | modules/test/test-help-and-lessons.js | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/modules/test/test-help-and-lessons.js b/modules/test/test-help-and-lessons.js new file mode 100644 index 0000000..c4eb5ae --- /dev/null +++ b/modules/test/test-help-and-lessons.js @@ -0,0 +1,75 @@ +// modules/test/test-help-and-lessons.js — run: node +// MAINT-019: `help <cmd>` must not answer "No help available" for a command that exists. +// MAINT-020: loop lessons must be written to /lessons, never into /skills. +const fsMod = require('fs'), path = require('path'); +const ROOT = path.join(__dirname, '..'); +const store = {}; +global.localStorage = { getItem: k => (k in store ? store[k] : null), setItem: (k, v) => { store[k] = String(v); }, removeItem: k => { delete store[k]; } }; +global.indexedDB = { open() { throw new Error('no idb'); }, deleteDatabase() { throw new Error('no idb'); } }; +global.window = global; + +const SystemModule = new Function(fsMod.readFileSync(path.join(ROOT, 'core', 'module-system.js'), 'utf8') + '\nreturn SystemModule;')(); + +let fails = 0, passes = 0; +function ok(name, cond, detail) { + if (cond) { passes++; return; } + fails++; + console.log('FAIL ' + name + (detail ? ' — ' + detail : '')); +} + +function mkHelp(commands, help) { + const out = []; + const sys = Object.create(SystemModule.prototype); + sys.terminal = { + print: (m, t) => out.push({ text: String(m), type: t || '' }), + log: () => {}, + moduleManager: { + getAllCommands: () => commands, + getAllHelp: () => help, + }, + }; + return { sys, out }; +} +const text = out => out.map(o => o.text).join(' | '); + +// A. a documented command prints its help line +{ + const { sys, out } = mkHelp({ ls: 'FileSystemModule' }, { ls: 'ls [path] — List files' }); + sys.handleHelp(['ls']); + ok('A1 documented command shows its help', /ls \[path\]/.test(text(out)), text(out)); +} + +// B. an undocumented but registered command names its owner instead of denying it exists +{ + const { sys, out } = mkHelp({ 'agent-register': 'AgentRegistryModule' }, {}); + sys.handleHelp(['agent-register']); + const t = text(out); + ok('B1 no "No help available" for a registered command', !/No help available/.test(t), t); + ok('B2 the owning module is named', /AgentRegistryModule/.test(t), t); + ok('B3 it still says there is no help line', /no help line/i.test(t), t); +} + +// C. a command that really does not exist still says so +{ + const { sys, out } = mkHelp({ ls: 'FileSystemModule' }, { ls: 'ls — List' }); + sys.handleHelp(['definitely-not-a-command']); + ok('C1 unknown command still reports no help', /No help available/.test(text(out)), text(out)); +} + +// D. MAINT-020: no lesson is written into /skills, and /lessons is used instead +{ + const src = fsMod.readFileSync(path.join(ROOT, 'core', 'module-aiassist.js'), 'utf8'); + const writesSkils = /writeFile\(\s*'\/skills\/'\s*\+\s*skillName/.test(src); + ok('D1 no lesson file is written into /skills', !writesSkils); + ok('D2 lesson files are written into /lessons', /writeFile\(\s*'\/lessons\/'\s*\+\s*skillName/.test(src)); + ok('D3 the lessons index is written to /lessons', /fsWriteJSON\(\s*'\/lessons\/index\.json'/.test(src)); + ok('D4 the reader still handles legacy /skills lessons', /fs\.readFile\('\/skills\/' \+ recentLessons\[li\] \+ '\.md'\)/.test(src)); + ok('D5 legacy lessons are cleaned out of the skills index once', /indexOf\('loop-lesson-'\) === 0/.test(src)); +} + +if (fails === 0) { + console.log('test-help-and-lessons: ' + passes + ' passed, 0 failed'); +} else { + console.log('test-help-and-lessons: ' + passes + ' passed, ' + fails + ' FAILED'); + process.exit(1); +} |