nothumanallowed 13.5.75 → 13.5.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/commands/ui.mjs +36 -5
- package/src/services/web-ui.mjs +51 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.5.
|
|
3
|
+
"version": "13.5.77",
|
|
4
4
|
"description": "NotHumanAllowed — 38 AI agents, 80 tools, Studio (visual agentic workflows). Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, Alexandria E2E messaging, GitHub, Notion, Slack, voice chat, free AI (Liara), 28 languages. Zero-dependency CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/commands/ui.mjs
CHANGED
|
@@ -3997,12 +3997,15 @@ ${completedHeadings ? `## SECTIONS ALREADY WRITTEN (headings only):\n${completed
|
|
|
3997
3997
|
// Default types for well-known filenames
|
|
3998
3998
|
const defaultType = (n) => n === 'memory.md' ? 'memory' : n === 'liara.md' ? 'provider' : 'skill';
|
|
3999
3999
|
const skills = [];
|
|
4000
|
-
|
|
4001
|
-
|
|
4000
|
+
// .md first (sorted), then .log files (sorted newest-first by filename)
|
|
4001
|
+
const allFiles = fs.readdirSync(skillsDir);
|
|
4002
|
+
const mdFiles = allFiles.filter(f => f.endsWith('.md')).sort();
|
|
4003
|
+
const logFiles = allFiles.filter(f => f.endsWith('.log')).sort().reverse();
|
|
4004
|
+
for (const fname of [...mdFiles, ...logFiles]) {
|
|
4002
4005
|
try {
|
|
4003
4006
|
const content = fs.readFileSync(path.join(skillsDir, fname), 'utf8');
|
|
4004
4007
|
const type = typeIndex[fname] || defaultType(fname);
|
|
4005
|
-
skills.push({ name: fname, content, type });
|
|
4008
|
+
skills.push({ name: fname, content, type: fname.endsWith('.log') ? 'log' : type });
|
|
4006
4009
|
} catch(_) {}
|
|
4007
4010
|
}
|
|
4008
4011
|
sendJSON(res, 200, { skills });
|
|
@@ -4048,6 +4051,30 @@ ${completedHeadings ? `## SECTIONS ALREADY WRITTEN (headings only):\n${completed
|
|
|
4048
4051
|
return;
|
|
4049
4052
|
}
|
|
4050
4053
|
|
|
4054
|
+
// POST /api/studio/webcraft/skills/:name/delete { name } → delete a single skill/log file
|
|
4055
|
+
if (pathname.match(/^\/api\/studio\/webcraft\/skills\/[^/]+\/delete$/) && method === 'POST') {
|
|
4056
|
+
const projName = decodeURIComponent(pathname.replace('/api/studio/webcraft/skills/', '').replace('/delete', '')).replace(/[^a-zA-Z0-9_-]/g, '');
|
|
4057
|
+
const body = await parseBody(req);
|
|
4058
|
+
const fname = (body.name || '').replace(/[^a-zA-Z0-9_. -]/g, '_');
|
|
4059
|
+
if (!fname || !projName) { sendJSON(res, 400, { error: 'invalid' }); return; }
|
|
4060
|
+
// Protect the 3 default .md files from deletion
|
|
4061
|
+
const PROTECTED = new Set(['memory.md', 'liara.md', 'skills.md']);
|
|
4062
|
+
if (PROTECTED.has(fname)) { sendJSON(res, 400, { error: 'protected file' }); return; }
|
|
4063
|
+
const skillsDir = path.join(os.homedir(), '.nha', 'webcraft', projName, 'skills');
|
|
4064
|
+
const filePath = path.join(skillsDir, fname);
|
|
4065
|
+
try { if (fs.existsSync(filePath)) fs.unlinkSync(filePath); } catch(_) {}
|
|
4066
|
+
// Remove from _index.json too
|
|
4067
|
+
const idxPath = path.join(skillsDir, '_index.json');
|
|
4068
|
+
try {
|
|
4069
|
+
let idx = JSON.parse(fs.readFileSync(idxPath, 'utf8'));
|
|
4070
|
+
delete idx[fname];
|
|
4071
|
+
fs.writeFileSync(idxPath, JSON.stringify(idx), 'utf8');
|
|
4072
|
+
} catch(_) {}
|
|
4073
|
+
sendJSON(res, 200, { ok: true });
|
|
4074
|
+
logRequest(method, pathname, 200, Date.now() - start);
|
|
4075
|
+
return;
|
|
4076
|
+
}
|
|
4077
|
+
|
|
4051
4078
|
// GET /api/studio/webcraft/projects/load/:name → { projectName, description, files[] }
|
|
4052
4079
|
if (pathname.startsWith('/api/studio/webcraft/projects/load/') && method === 'GET') {
|
|
4053
4080
|
const projName = decodeURIComponent(pathname.replace('/api/studio/webcraft/projects/load/', '')).replace(/[^a-zA-Z0-9_-]/g, '');
|
|
@@ -4581,7 +4608,9 @@ module.exports = { validateEmail, sanitizeText, validatePassword, validateUserna
|
|
|
4581
4608
|
// Write sandbox log to skills/ so the agent can read it as context
|
|
4582
4609
|
try {
|
|
4583
4610
|
const _nl = '\n';
|
|
4584
|
-
const
|
|
4611
|
+
const _now = new Date();
|
|
4612
|
+
const _pad = n => String(n).padStart(2,'0');
|
|
4613
|
+
const logTs = _now.getFullYear()+'-'+_pad(_now.getMonth()+1)+'-'+_pad(_now.getDate())+' '+_pad(_now.getHours())+':'+_pad(_now.getMinutes())+':'+_pad(_now.getSeconds());
|
|
4585
4614
|
const logName = projName + '-' + logTs.replace(/[: ]/g, '-') + '.log';
|
|
4586
4615
|
const logsDir = path.join(sandboxDir, 'skills');
|
|
4587
4616
|
fs.mkdirSync(logsDir, { recursive: true });
|
|
@@ -4603,7 +4632,9 @@ module.exports = { validateEmail, sanitizeText, validatePassword, validateUserna
|
|
|
4603
4632
|
// Write error log too
|
|
4604
4633
|
try {
|
|
4605
4634
|
const _nl = '\n';
|
|
4606
|
-
const
|
|
4635
|
+
const _now2 = new Date();
|
|
4636
|
+
const _pad2 = n => String(n).padStart(2,'0');
|
|
4637
|
+
const logTs = _now2.getFullYear()+'-'+_pad2(_now2.getMonth()+1)+'-'+_pad2(_now2.getDate())+' '+_pad2(_now2.getHours())+':'+_pad2(_now2.getMinutes())+':'+_pad2(_now2.getSeconds());
|
|
4607
4638
|
const logName = projName + '-' + logTs.replace(/[: ]/g, '-') + '-ERROR.log';
|
|
4608
4639
|
const logsDir = path.join(sandboxDir, 'skills');
|
|
4609
4640
|
fs.mkdirSync(logsDir, { recursive: true });
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -6786,6 +6786,22 @@ function wcSkillsPanelHtml() {
|
|
|
6786
6786
|
function wcSkillModalHtml() {
|
|
6787
6787
|
if (!wcSkillModal) return '';
|
|
6788
6788
|
var m = wcSkillModal;
|
|
6789
|
+
// Log files: read-only viewer
|
|
6790
|
+
if (m.mode === 'view') {
|
|
6791
|
+
return '<div onclick="wcCloseSkillModal(event)" style="position:fixed;inset:0;background:rgba(0,0,0,.75);z-index:9999;display:flex;align-items:center;justify-content:center">' +
|
|
6792
|
+
'<div onclick="event.stopPropagation()" style="background:var(--bg2);border:1px solid var(--border);border-radius:14px;width:680px;max-width:96vw;max-height:88vh;display:flex;flex-direction:column;overflow:hidden">' +
|
|
6793
|
+
'<div style="padding:14px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px">' +
|
|
6794
|
+
'<span style="font-size:14px">📄</span>' +
|
|
6795
|
+
'<span style="font-size:13px;font-weight:700;color:var(--text);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+wcEsc(m.name)+'</span>' +
|
|
6796
|
+
'<span style="font-size:10px;background:#333;color:#aaa;padding:2px 8px;border-radius:10px">log</span>' +
|
|
6797
|
+
'<button onclick="wcCloseSkillModal()" style="background:none;border:none;color:var(--dim);font-size:18px;cursor:pointer;line-height:1;margin-left:4px">×</button>' +
|
|
6798
|
+
'</div>' +
|
|
6799
|
+
'<div style="flex:1;overflow:auto;padding:14px 18px">' +
|
|
6800
|
+
'<pre style="margin:0;font-size:11px;line-height:1.7;color:var(--text);font-family:var(--mono);white-space:pre-wrap;word-break:break-all">'+wcEsc(m.content || '')+'</pre>' +
|
|
6801
|
+
'</div>' +
|
|
6802
|
+
'</div>' +
|
|
6803
|
+
'</div>';
|
|
6804
|
+
}
|
|
6789
6805
|
var isNew = m.mode === 'new';
|
|
6790
6806
|
var charCount = (m.content || '').length;
|
|
6791
6807
|
// Length guidance per type
|
|
@@ -6878,7 +6894,8 @@ function wcNewSkill() {
|
|
|
6878
6894
|
function wcOpenSkill(si) {
|
|
6879
6895
|
var s = wcSkills[si];
|
|
6880
6896
|
if (!s) return;
|
|
6881
|
-
|
|
6897
|
+
var mode = (s.type === 'log') ? 'view' : 'edit';
|
|
6898
|
+
wcSkillModal = { mode: mode, idx: si, name: s.name, content: s.content, type: s.type || 'skill', generating: false };
|
|
6882
6899
|
renderWebCraft(document.getElementById('content'));
|
|
6883
6900
|
}
|
|
6884
6901
|
|
|
@@ -6964,7 +6981,19 @@ async function wcSaveSkill() {
|
|
|
6964
6981
|
}
|
|
6965
6982
|
|
|
6966
6983
|
async function wcDeleteSkill(si) {
|
|
6967
|
-
|
|
6984
|
+
var s = wcSkills[si];
|
|
6985
|
+
if (!s) return;
|
|
6986
|
+
if (!confirm('Eliminare "' + s.name + '"?')) return;
|
|
6987
|
+
// Delete the file on disk via the delete-skill endpoint
|
|
6988
|
+
try {
|
|
6989
|
+
await fetch(API + '/api/studio/webcraft/skills/' + encodeURIComponent(wcState.projectName) + '/delete', {
|
|
6990
|
+
method: 'POST',
|
|
6991
|
+
headers: {'Content-Type':'application/json'},
|
|
6992
|
+
body: JSON.stringify({ name: s.name })
|
|
6993
|
+
});
|
|
6994
|
+
} catch(_) {}
|
|
6995
|
+
wcSkills.splice(si, 1);
|
|
6996
|
+
renderWebCraft(document.getElementById('content'));
|
|
6968
6997
|
}
|
|
6969
6998
|
|
|
6970
6999
|
async function wcPersistSkills() {
|
|
@@ -7901,10 +7930,22 @@ async function wcCallLLM(sys, user, signal) {
|
|
|
7901
7930
|
body: JSON.stringify({system: sys, user: user, max_tokens: 4096})
|
|
7902
7931
|
};
|
|
7903
7932
|
if (signal) fetchOpts.signal = signal;
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
|
|
7933
|
+
// Retry up to 2 times on 5xx errors (Liara may be temporarily overloaded)
|
|
7934
|
+
for (var attempt = 0; attempt < 3; attempt++) {
|
|
7935
|
+
if (signal && signal.aborted) throw new DOMException('Aborted', 'AbortError');
|
|
7936
|
+
var r = await fetch(API + '/api/studio/webcraft', fetchOpts);
|
|
7937
|
+
if (r.ok) {
|
|
7938
|
+
var d = await r.json();
|
|
7939
|
+
return (d && (d.text || d.content || d.result)) || '';
|
|
7940
|
+
}
|
|
7941
|
+
if (r.status < 500 || attempt === 2) {
|
|
7942
|
+
var errBody = '';
|
|
7943
|
+
try { var eb = await r.json(); errBody = eb.error || ''; } catch(_) {}
|
|
7944
|
+
throw new Error('LLM error ' + r.status + (errBody ? ': ' + errBody : ''));
|
|
7945
|
+
}
|
|
7946
|
+
// 5xx — wait 2s then retry
|
|
7947
|
+
await new Promise(function(resolve) { setTimeout(resolve, 2000); });
|
|
7948
|
+
}
|
|
7908
7949
|
}
|
|
7909
7950
|
|
|
7910
7951
|
function wcSandboxPanelHtml() {
|
|
@@ -8091,10 +8132,14 @@ async function wcStartSandbox() {
|
|
|
8091
8132
|
wcState.sandbox.dir = evt.dir;
|
|
8092
8133
|
_wcAutoFixAttempts = 0;
|
|
8093
8134
|
wcStartAutoFixPoller();
|
|
8135
|
+
// Reload skills so newly written log file appears in the panel
|
|
8136
|
+
_wcSkillsLoaded = false;
|
|
8094
8137
|
renderWebCraft(document.getElementById('content'));
|
|
8095
8138
|
} else if (evt.type === 'error') {
|
|
8096
8139
|
wcState.sandbox.running = false;
|
|
8097
8140
|
wcState.sandbox.error = evt.msg;
|
|
8141
|
+
// Reload skills so error log appears in the panel
|
|
8142
|
+
_wcSkillsLoaded = false;
|
|
8098
8143
|
renderWebCraft(document.getElementById('content'));
|
|
8099
8144
|
// Auto-fix: try to detect MODULE_NOT_FOUND in crash message and fix it
|
|
8100
8145
|
var errMsg = evt.msg || '';
|