nothumanallowed 8.7.0 → 8.8.0
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 +88 -1
- package/src/constants.mjs +1 -1
- package/src/services/web-ui.mjs +47 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.8.0",
|
|
4
4
|
"description": "NotHumanAllowed — 38 AI agents + unified productivity suite. Gmail, Calendar, Drive, Contacts, Tasks, GitHub, Notion, Slack, voice chat, smart scheduler. Zero-dependency CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/commands/ui.mjs
CHANGED
|
@@ -819,6 +819,91 @@ export async function cmdUI(args) {
|
|
|
819
819
|
return;
|
|
820
820
|
}
|
|
821
821
|
|
|
822
|
+
// POST /api/agents — create custom agent
|
|
823
|
+
if (method === 'POST' && pathname === '/api/agents') {
|
|
824
|
+
const body = await parseBody(req);
|
|
825
|
+
const name = (body.name || '').toLowerCase().replace(/[^a-z0-9_-]/g, '');
|
|
826
|
+
const tagline = body.tagline || '';
|
|
827
|
+
const systemPrompt = body.systemPrompt || '';
|
|
828
|
+
if (!name || !tagline || !systemPrompt) {
|
|
829
|
+
sendJSON(res, 400, { error: 'name, tagline, and systemPrompt required' });
|
|
830
|
+
logRequest(method, pathname, 400, Date.now() - start);
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const agentFile = path.join(AGENTS_DIR, `${name}.mjs`);
|
|
834
|
+
if (fs.existsSync(agentFile)) {
|
|
835
|
+
sendJSON(res, 409, { error: `Agent "${name}" already exists` });
|
|
836
|
+
logRequest(method, pathname, 409, Date.now() - start);
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
const content = `// NHA Custom Agent: ${name}\n// Created: ${new Date().toISOString()}\n\nexport const CARD = {\n name: '${name}',\n displayName: '${name.toUpperCase()}',\n category: 'custom',\n tagline: '${tagline.replace(/'/g, "\\'")}',\n};\n\nexport const SYSTEM_PROMPT = \`${systemPrompt.replace(/`/g, '\\`')}\`;\n`;
|
|
840
|
+
if (!fs.existsSync(AGENTS_DIR)) fs.mkdirSync(AGENTS_DIR, { recursive: true });
|
|
841
|
+
fs.writeFileSync(agentFile, content, 'utf-8');
|
|
842
|
+
agentCards.push({ name, displayName: name.toUpperCase(), category: 'custom', tagline });
|
|
843
|
+
sendJSON(res, 201, { ok: true, agent: { name, category: 'custom', tagline } });
|
|
844
|
+
logRequest(method, pathname, 201, Date.now() - start);
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// PUT /api/agents/:name — edit agent
|
|
849
|
+
if (method === 'PUT' && pathname.startsWith('/api/agents/')) {
|
|
850
|
+
const name = pathname.split('/')[3];
|
|
851
|
+
const body = await parseBody(req);
|
|
852
|
+
const agentFile = path.join(AGENTS_DIR, `${name}.mjs`);
|
|
853
|
+
if (!fs.existsSync(agentFile)) {
|
|
854
|
+
sendJSON(res, 404, { error: `Agent "${name}" not found` });
|
|
855
|
+
logRequest(method, pathname, 404, Date.now() - start);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
const tagline = body.tagline || '';
|
|
859
|
+
const systemPrompt = body.systemPrompt || '';
|
|
860
|
+
if (!tagline || !systemPrompt) {
|
|
861
|
+
sendJSON(res, 400, { error: 'tagline and systemPrompt required' });
|
|
862
|
+
logRequest(method, pathname, 400, Date.now() - start);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
const content = `// NHA Custom Agent: ${name}\n// Updated: ${new Date().toISOString()}\n\nexport const CARD = {\n name: '${name}',\n displayName: '${name.toUpperCase()}',\n category: '${body.category || 'custom'}',\n tagline: '${tagline.replace(/'/g, "\\'")}',\n};\n\nexport const SYSTEM_PROMPT = \`${systemPrompt.replace(/`/g, '\\`')}\`;\n`;
|
|
866
|
+
fs.writeFileSync(agentFile, content, 'utf-8');
|
|
867
|
+
const idx = agentCards.findIndex(a => a.name === name);
|
|
868
|
+
if (idx >= 0) { agentCards[idx].tagline = tagline; }
|
|
869
|
+
sendJSON(res, 200, { ok: true });
|
|
870
|
+
logRequest(method, pathname, 200, Date.now() - start);
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// DELETE /api/agents/:name — delete agent
|
|
875
|
+
if (method === 'DELETE' && pathname.startsWith('/api/agents/')) {
|
|
876
|
+
const name = pathname.split('/')[3];
|
|
877
|
+
const agentFile = path.join(AGENTS_DIR, `${name}.mjs`);
|
|
878
|
+
if (!fs.existsSync(agentFile)) {
|
|
879
|
+
sendJSON(res, 404, { error: `Agent "${name}" not found` });
|
|
880
|
+
logRequest(method, pathname, 404, Date.now() - start);
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
fs.unlinkSync(agentFile);
|
|
884
|
+
const idx = agentCards.findIndex(a => a.name === name);
|
|
885
|
+
if (idx >= 0) agentCards.splice(idx, 1);
|
|
886
|
+
sendJSON(res, 200, { ok: true });
|
|
887
|
+
logRequest(method, pathname, 200, Date.now() - start);
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// GET /api/agents/:name — get agent details (system prompt)
|
|
892
|
+
if (method === 'GET' && pathname.startsWith('/api/agents/') && pathname.split('/').length === 4) {
|
|
893
|
+
const name = pathname.split('/')[3];
|
|
894
|
+
const agentFile = path.join(AGENTS_DIR, `${name}.mjs`);
|
|
895
|
+
if (!fs.existsSync(agentFile)) {
|
|
896
|
+
sendJSON(res, 404, { error: `Agent "${name}" not found` });
|
|
897
|
+
logRequest(method, pathname, 404, Date.now() - start);
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
const src = fs.readFileSync(agentFile, 'utf-8');
|
|
901
|
+
const parsed = parseAgentFile(src, name);
|
|
902
|
+
sendJSON(res, 200, { name, category: parsed.card?.category || 'custom', tagline: parsed.card?.tagline || '', systemPrompt: parsed.systemPrompt || '' });
|
|
903
|
+
logRequest(method, pathname, 200, Date.now() - start);
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
|
|
822
907
|
// POST /api/ask — agent call with personal context (email, calendar, tasks)
|
|
823
908
|
if (method === 'POST' && pathname === '/api/ask') {
|
|
824
909
|
const body = await parseBody(req);
|
|
@@ -834,7 +919,9 @@ export async function cmdUI(args) {
|
|
|
834
919
|
return;
|
|
835
920
|
}
|
|
836
921
|
|
|
837
|
-
|
|
922
|
+
// Allow both built-in and custom agents
|
|
923
|
+
const agentFile = path.join(AGENTS_DIR, `${body.agent}.mjs`);
|
|
924
|
+
if (!AGENTS.includes(body.agent) && !fs.existsSync(agentFile)) {
|
|
838
925
|
sendJSON(res, 400, { error: `Unknown agent: ${body.agent}` });
|
|
839
926
|
logRequest(method, pathname, 400, Date.now() - start);
|
|
840
927
|
return;
|
package/src/constants.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
|
|
|
5
5
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = path.dirname(__filename);
|
|
7
7
|
|
|
8
|
-
export const VERSION = '8.
|
|
8
|
+
export const VERSION = '8.8.0';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -1086,22 +1086,68 @@ function renderAgents(el){
|
|
|
1086
1086
|
|
|
1087
1087
|
var filtered=agentFilter?agentsList.filter(function(a){return a.category===agentFilter}):agentsList;
|
|
1088
1088
|
|
|
1089
|
+
h+='<div style="margin-bottom:10px"><button class="btn btn--primary" style="font-size:11px" onclick="showCreateAgentForm()">+ Create Agent</button></div>';
|
|
1089
1090
|
h+='<div class="agents-grid">';
|
|
1090
1091
|
filtered.forEach(function(a){
|
|
1091
1092
|
var name=a.name||a.agentName;
|
|
1092
1093
|
var display=a.displayName||name;
|
|
1093
1094
|
var icon=AGENT_ICONS[name.toLowerCase()]||'\\u{1F916}';
|
|
1094
1095
|
var desc=AGENT_DESCRIPTIONS[name.toLowerCase()]||a.tagline||a.description||'';
|
|
1095
|
-
|
|
1096
|
+
var isCustom=a.category==='custom';
|
|
1097
|
+
h+='<div class="card agent-card" style="position:relative">'+
|
|
1098
|
+
'<div style="flex:1;cursor:pointer" onclick="openAgent(\\''+esc(name)+'\\',\\''+esc(display)+'\\')">'+
|
|
1099
|
+
'<div style="display:flex;align-items:center;gap:8px">'+
|
|
1096
1100
|
'<div class="agent-card__icon">'+icon+'</div>'+
|
|
1097
1101
|
'<div class="agent-card__body"><div class="agent-card__name">'+esc(display)+'</div>'+
|
|
1098
1102
|
'<div class="agent-card__tagline">'+esc(desc)+'</div></div>'+
|
|
1103
|
+
'</div></div>'+
|
|
1104
|
+
'<div style="display:flex;gap:4px;flex-shrink:0">'+
|
|
1105
|
+
'<button onclick="editAgent(\\''+esc(name)+'\\')" style="background:none;border:none;cursor:pointer;font-size:12px;padding:2px" title="Edit">\\u{270F}\\u{FE0F}</button>'+
|
|
1106
|
+
'<button onclick="deleteAgent(\\''+esc(name)+'\\')" style="background:none;border:none;cursor:pointer;font-size:12px;padding:2px;color:#f44" title="Delete">\\u{1F5D1}</button>'+
|
|
1107
|
+
'</div>'+
|
|
1099
1108
|
'</div>';
|
|
1100
1109
|
});
|
|
1101
1110
|
h+='</div>';
|
|
1102
1111
|
el.innerHTML=h;
|
|
1103
1112
|
}
|
|
1104
1113
|
var agentFilter=null;
|
|
1114
|
+
|
|
1115
|
+
function showCreateAgentForm(){
|
|
1116
|
+
var name=prompt('Agent name (lowercase, no spaces):');
|
|
1117
|
+
if(!name)return;
|
|
1118
|
+
name=name.toLowerCase().replace(/[^a-z0-9_-]/g,'');
|
|
1119
|
+
if(!name)return;
|
|
1120
|
+
var tagline=prompt('Tagline (short description):');
|
|
1121
|
+
if(!tagline)return;
|
|
1122
|
+
var sysPrompt=prompt('System prompt (agent personality & instructions):');
|
|
1123
|
+
if(!sysPrompt)return;
|
|
1124
|
+
apiPost('/api/agents',{name:name,tagline:tagline,systemPrompt:sysPrompt}).then(function(r){
|
|
1125
|
+
if(r&&r.ok){showToast('success','Agent Created',name.toUpperCase()+' is ready to use');loadView('agents');}
|
|
1126
|
+
else{alert('Error: '+(r&&r.error||'Unknown'));}
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
function editAgent(name){
|
|
1131
|
+
fetch('/api/agents/'+name).then(function(r){return r.json()}).then(function(data){
|
|
1132
|
+
var newTagline=prompt('Tagline:',data.tagline||'');
|
|
1133
|
+
if(newTagline===null)return;
|
|
1134
|
+
var newPrompt=prompt('System prompt:',data.systemPrompt||'');
|
|
1135
|
+
if(newPrompt===null)return;
|
|
1136
|
+
fetch('/api/agents/'+name,{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify({tagline:newTagline,systemPrompt:newPrompt,category:data.category||'custom'})}).then(function(r){return r.json()}).then(function(r){
|
|
1137
|
+
if(r&&r.ok){showToast('success','Agent Updated',name.toUpperCase()+' updated');loadView('agents');}
|
|
1138
|
+
else{alert('Error: '+(r&&r.error||'Unknown'));}
|
|
1139
|
+
});
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
function deleteAgent(name){
|
|
1144
|
+
if(!confirm('Delete agent "'+name+'"? This cannot be undone.'))return;
|
|
1145
|
+
fetch('/api/agents/'+name,{method:'DELETE'}).then(function(r){return r.json()}).then(function(r){
|
|
1146
|
+
if(r&&r.ok){showToast('success','Agent Deleted',name+' removed');loadView('agents');}
|
|
1147
|
+
else{alert('Error: '+(r&&r.error||'Unknown'));}
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1105
1151
|
function openAgent(name,display){
|
|
1106
1152
|
selectedAgent=name;
|
|
1107
1153
|
attachedFileContent=null;attachedFileName=null;
|