nothumanallowed 8.0.4 → 8.1.1
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 +22 -0
- package/src/constants.mjs +1 -1
- package/src/services/ops-pipeline.mjs +21 -16
- package/src/services/task-store.mjs +49 -0
- package/src/services/tool-executor.mjs +45 -0
- package/src/services/web-ui.mjs +16 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.1.1",
|
|
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
|
@@ -575,6 +575,28 @@ export async function cmdUI(args) {
|
|
|
575
575
|
return;
|
|
576
576
|
}
|
|
577
577
|
|
|
578
|
+
// POST /api/tasks/:id/delete
|
|
579
|
+
const taskDeleteMatch = pathname.match(/^\/api\/tasks\/(\d+)\/delete$/);
|
|
580
|
+
if (method === 'POST' && taskDeleteMatch) {
|
|
581
|
+
const { deleteTask } = await import('../services/task-store.mjs');
|
|
582
|
+
const taskId = parseInt(taskDeleteMatch[1], 10);
|
|
583
|
+
const success = deleteTask(taskId);
|
|
584
|
+
sendJSON(res, 200, { ok: success, id: taskId });
|
|
585
|
+
logRequest(method, pathname, 200, Date.now() - start);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// POST /api/tasks/clear
|
|
590
|
+
if (method === 'POST' && pathname === '/api/tasks/clear') {
|
|
591
|
+
const { clearTasks } = await import('../services/task-store.mjs');
|
|
592
|
+
const body = await parseBody(req);
|
|
593
|
+
const mode = body.mode || 'all';
|
|
594
|
+
const count = clearTasks(mode);
|
|
595
|
+
sendJSON(res, 200, { ok: true, removed: count });
|
|
596
|
+
logRequest(method, pathname, 200, Date.now() - start);
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
|
|
578
600
|
// GET /api/plan
|
|
579
601
|
if (method === 'GET' && pathname === '/api/plan') {
|
|
580
602
|
const plan = loadTodayPlan();
|
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.1.1';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -140,13 +140,16 @@ export async function runPlanningPipeline(config, opts = {}) {
|
|
|
140
140
|
// ── Phase 6: CONDUCTOR — Synthesize daily plan ─────────────────────────
|
|
141
141
|
info('Phase 6: CONDUCTOR synthesizing daily plan...');
|
|
142
142
|
|
|
143
|
-
const conductorPrompt = `You are the NHA Daily Planner. Synthesize intelligence from
|
|
143
|
+
const conductorPrompt = `You are the NHA Daily Planner. Synthesize intelligence from specialist agents into a structured daily plan.
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
145
|
+
CRITICAL RULES — READ CAREFULLY:
|
|
146
|
+
1. ONLY include events that appear in the CALENDAR section below. NEVER invent, hallucinate, or assume meetings/appointments that are not listed.
|
|
147
|
+
2. If there are 0 events in the calendar, the schedule section must ONLY contain suggested focus blocks and task time — NO invented meetings.
|
|
148
|
+
3. Be PRACTICAL, not alarmist. Routine notifications (Google login alerts from your own devices, npm publish confirmations, GitHub 2FA, password change emails) are NOT security threats. Mark them as SAFE.
|
|
149
|
+
4. Only put items in "security_alerts" for GENUINE threats: phishing, unknown device access from unexpected locations, credential leaks, social engineering.
|
|
150
|
+
5. Security alerts must be simple strings, NOT JSON objects. Example: "Verify Google login from unknown Mac device in Italy"
|
|
151
|
+
6. The "schedule" section should reflect REAL calendar events + suggested blocks for tasks. Do not fabricate appointments.
|
|
152
|
+
7. Do not create new_tasks that duplicate existing tasks.
|
|
150
153
|
|
|
151
154
|
AGENT REPORTS:
|
|
152
155
|
${agentResults.saber ? `\n[SABER — Security Scan]\n${agentResults.saber}` : ''}
|
|
@@ -160,22 +163,22 @@ Events: ${events.length}
|
|
|
160
163
|
Unread emails: ${emails.length}
|
|
161
164
|
Tasks: ${tasks.length}
|
|
162
165
|
|
|
163
|
-
CALENDAR:
|
|
164
|
-
${calendarContext || 'No events.'}
|
|
166
|
+
CALENDAR (these are the ONLY real events — do NOT add any others):
|
|
167
|
+
${calendarContext || 'No events scheduled.'}
|
|
165
168
|
|
|
166
|
-
EXISTING TASKS:
|
|
169
|
+
EXISTING TASKS (do NOT duplicate these):
|
|
167
170
|
${taskContext || 'No tasks.'}
|
|
168
171
|
|
|
169
|
-
|
|
172
|
+
Output strict JSON:
|
|
170
173
|
{
|
|
171
174
|
"date": "${dateStr}",
|
|
172
|
-
"executive_summary": "2-3 sentence overview",
|
|
175
|
+
"executive_summary": "2-3 sentence overview of the ACTUAL day based on real data",
|
|
173
176
|
"priority_actions": [{ "time": "HH:MM", "action": "...", "source": "email|calendar|task", "priority": "critical|high|medium|low" }],
|
|
174
177
|
"schedule": [{ "time_start": "HH:MM", "time_end": "HH:MM", "type": "meeting|focus|break|task", "title": "...", "notes": "...", "preparation": "..." }],
|
|
175
178
|
"email_actions": [{ "from": "...", "subject": "...", "action": "reply|archive|flag|defer", "suggested_reply": "..." }],
|
|
176
|
-
"security_alerts": [],
|
|
177
|
-
"new_tasks": [{ "description": "...", "priority": "high|medium|low", "estimated_minutes":
|
|
178
|
-
"insights": []
|
|
179
|
+
"security_alerts": ["simple string descriptions only"],
|
|
180
|
+
"new_tasks": [{ "description": "...", "priority": "high|medium|low", "estimated_minutes": 30, "suggested_slot": "HH:MM" }],
|
|
181
|
+
"insights": ["simple string insights only"]
|
|
179
182
|
}`;
|
|
180
183
|
|
|
181
184
|
let plan;
|
|
@@ -266,7 +269,8 @@ function displayPlan(plan) {
|
|
|
266
269
|
if (plan.security_alerts?.length > 0) {
|
|
267
270
|
console.log(` ${BOLD}\x1b[0;31mSecurity Alerts${NC}`);
|
|
268
271
|
for (const a of plan.security_alerts) {
|
|
269
|
-
|
|
272
|
+
const text = typeof a === 'string' ? a : a.description || a.message || a.action_required || `[${a.type || 'alert'}] ${a.severity || ''} — ${JSON.stringify(a)}`;
|
|
273
|
+
console.log(` \x1b[0;31m!\x1b[0m ${text}`);
|
|
270
274
|
}
|
|
271
275
|
console.log('');
|
|
272
276
|
}
|
|
@@ -274,7 +278,8 @@ function displayPlan(plan) {
|
|
|
274
278
|
if (plan.insights?.length > 0) {
|
|
275
279
|
console.log(` ${BOLD}${D}Insights${NC}`);
|
|
276
280
|
for (const i of plan.insights) {
|
|
277
|
-
|
|
281
|
+
const text = typeof i === 'string' ? i : i.message || i.insight || JSON.stringify(i);
|
|
282
|
+
console.log(` ${D}→ ${text}${NC}`);
|
|
278
283
|
}
|
|
279
284
|
console.log('');
|
|
280
285
|
}
|
|
@@ -113,6 +113,55 @@ export function moveTask(taskId, fromDate, toDate) {
|
|
|
113
113
|
return true;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Delete a single task by ID.
|
|
118
|
+
* @param {number} taskId
|
|
119
|
+
* @param {string} [date]
|
|
120
|
+
* @returns {boolean} success
|
|
121
|
+
*/
|
|
122
|
+
export function deleteTask(taskId, date) {
|
|
123
|
+
const data = loadDay(date);
|
|
124
|
+
const idx = data.tasks.findIndex(t => t.id === taskId);
|
|
125
|
+
if (idx === -1) return false;
|
|
126
|
+
data.tasks.splice(idx, 1);
|
|
127
|
+
saveDay(date, data);
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Clear all tasks for a date (delete completed, or all).
|
|
133
|
+
* @param {'done'|'all'} mode — 'done' removes only completed, 'all' removes everything
|
|
134
|
+
* @param {string} [date]
|
|
135
|
+
* @returns {number} count of removed tasks
|
|
136
|
+
*/
|
|
137
|
+
export function clearTasks(mode = 'all', date) {
|
|
138
|
+
const data = loadDay(date);
|
|
139
|
+
const before = data.tasks.length;
|
|
140
|
+
if (mode === 'done') {
|
|
141
|
+
data.tasks = data.tasks.filter(t => t.status !== 'done');
|
|
142
|
+
} else {
|
|
143
|
+
data.tasks = [];
|
|
144
|
+
}
|
|
145
|
+
saveDay(date, data);
|
|
146
|
+
return before - data.tasks.length;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Edit task priority.
|
|
151
|
+
* @param {number} taskId
|
|
152
|
+
* @param {string} priority
|
|
153
|
+
* @param {string} [date]
|
|
154
|
+
* @returns {boolean}
|
|
155
|
+
*/
|
|
156
|
+
export function editTaskPriority(taskId, priority, date) {
|
|
157
|
+
const data = loadDay(date);
|
|
158
|
+
const task = data.tasks.find(t => t.id === taskId);
|
|
159
|
+
if (!task) return false;
|
|
160
|
+
task.priority = priority;
|
|
161
|
+
saveDay(date, data);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
|
|
116
165
|
/**
|
|
117
166
|
* Get tasks for the week (Mon-Sun).
|
|
118
167
|
*/
|
|
@@ -36,6 +36,10 @@ import {
|
|
|
36
36
|
addTask,
|
|
37
37
|
completeTask,
|
|
38
38
|
moveTask,
|
|
39
|
+
deleteTask,
|
|
40
|
+
clearTasks,
|
|
41
|
+
editTask,
|
|
42
|
+
editTaskPriority,
|
|
39
43
|
} from './task-store.mjs';
|
|
40
44
|
|
|
41
45
|
import { notify } from './notification.mjs';
|
|
@@ -53,6 +57,8 @@ export const DESTRUCTIVE_ACTIONS = new Set([
|
|
|
53
57
|
'calendar_update',
|
|
54
58
|
'contact_delete',
|
|
55
59
|
'task_done',
|
|
60
|
+
'task_delete',
|
|
61
|
+
'task_clear',
|
|
56
62
|
'notify_remind',
|
|
57
63
|
'slack_send',
|
|
58
64
|
'github_create_issue',
|
|
@@ -157,6 +163,15 @@ TOOLS:
|
|
|
157
163
|
23. task_move(id: number, toDate: string)
|
|
158
164
|
Move a task to another date (YYYY-MM-DD).
|
|
159
165
|
|
|
166
|
+
24. task_delete(id: number)
|
|
167
|
+
Delete a specific task permanently. ALWAYS confirm before deleting.
|
|
168
|
+
|
|
169
|
+
25. task_clear(mode?: "all"|"done")
|
|
170
|
+
Clear tasks. mode="done" removes only completed tasks. mode="all" removes ALL tasks. Default: "all". ALWAYS confirm before clearing.
|
|
171
|
+
|
|
172
|
+
26. task_edit(id: number, description?: string, priority?: "low"|"medium"|"high"|"critical")
|
|
173
|
+
Edit a task's description and/or priority.
|
|
174
|
+
|
|
160
175
|
--- CONTACTS ---
|
|
161
176
|
|
|
162
177
|
24. contact_search(query: string)
|
|
@@ -381,6 +396,10 @@ export function describeAction(action, params) {
|
|
|
381
396
|
return `Delete contact "${params.query}"`;
|
|
382
397
|
case 'task_done':
|
|
383
398
|
return `Mark task #${params.id} as completed`;
|
|
399
|
+
case 'task_delete':
|
|
400
|
+
return `Delete task #${params.id} permanently`;
|
|
401
|
+
case 'task_clear':
|
|
402
|
+
return `Clear ${params.mode === 'done' ? 'completed' : 'ALL'} tasks`;
|
|
384
403
|
case 'notify_remind':
|
|
385
404
|
return `Set reminder: "${params.message}" at ${params.atTime}`;
|
|
386
405
|
case 'slack_send':
|
|
@@ -759,6 +778,32 @@ export async function executeTool(action, params, config) {
|
|
|
759
778
|
return success ? `Task #${params.id} moved to ${toDate}.` : `Task #${params.id} not found.`;
|
|
760
779
|
}
|
|
761
780
|
|
|
781
|
+
case 'task_delete': {
|
|
782
|
+
const success = deleteTask(params.id);
|
|
783
|
+
return success ? `Task #${params.id} deleted.` : `Task #${params.id} not found.`;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
case 'task_clear': {
|
|
787
|
+
const mode = params.mode || 'all';
|
|
788
|
+
const count = clearTasks(mode);
|
|
789
|
+
return count > 0
|
|
790
|
+
? `${count} task${count !== 1 ? 's' : ''} ${mode === 'done' ? 'completed' : ''} removed.`
|
|
791
|
+
: 'No tasks to remove.';
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
case 'task_edit': {
|
|
795
|
+
if (params.description) {
|
|
796
|
+
editTask(params.id, params.description);
|
|
797
|
+
}
|
|
798
|
+
if (params.priority) {
|
|
799
|
+
editTaskPriority(params.id, params.priority);
|
|
800
|
+
}
|
|
801
|
+
const parts = [];
|
|
802
|
+
if (params.description) parts.push(`description updated`);
|
|
803
|
+
if (params.priority) parts.push(`priority set to ${params.priority}`);
|
|
804
|
+
return parts.length > 0 ? `Task #${params.id}: ${parts.join(', ')}.` : `No changes specified for task #${params.id}.`;
|
|
805
|
+
}
|
|
806
|
+
|
|
762
807
|
// ── Notifications ─────────────────────────────────────────────────────
|
|
763
808
|
case 'notify_remind': {
|
|
764
809
|
const atTime = resolveTime(params.atTime);
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -360,10 +360,13 @@ function sendChat(){
|
|
|
360
360
|
function renderTasks(el){
|
|
361
361
|
var t=dash.tasks;
|
|
362
362
|
var h='<div class="task-bar"><input id="taskInput" placeholder="Add a new task..."><select id="taskPriority"><option value="medium">Medium</option><option value="high">High</option><option value="critical">Critical</option><option value="low">Low</option></select><button onclick="addTaskUI()">Add</button></div>';
|
|
363
|
+
if(t.length>0){
|
|
364
|
+
h+='<div style="display:flex;gap:8px;margin-bottom:12px"><button onclick="clearTasksUI(\\x27done\\x27)" style="background:var(--bg3);color:var(--dim);border:1px solid var(--border);padding:6px 12px;border-radius:var(--r);font-size:11px;cursor:pointer">Clear completed</button><button onclick="clearTasksUI(\\x27all\\x27)" style="background:var(--bg3);color:var(--red);border:1px solid var(--border);padding:6px 12px;border-radius:var(--r);font-size:11px;cursor:pointer">Clear all</button></div>';
|
|
365
|
+
}
|
|
363
366
|
t.sort(function(a,b){if(a.status==='done'&&b.status!=='done')return 1;if(a.status!=='done'&&b.status==='done')return -1;return 0});
|
|
364
367
|
t.forEach(function(x){
|
|
365
368
|
var isDone=x.status==='done';
|
|
366
|
-
h+='<div class="card task'+(isDone?' task--done':'')+'"
|
|
369
|
+
h+='<div class="card task'+(isDone?' task--done':'')+'"><span class="task__check'+(isDone?' task__check--done':'')+'" onclick="toggleTask('+x.id+')">'+(isDone?'\\u2713':'')+'</span><span class="task__desc" onclick="toggleTask('+x.id+')">'+esc(x.description)+'</span><span class="task__priority task__priority--'+esc(x.priority)+'">'+esc(x.priority)+'</span><span onclick="deleteTaskUI('+x.id+')" style="color:var(--dim);cursor:pointer;padding:4px 8px;font-size:14px;opacity:0.5" title="Delete task">×</span></div>';
|
|
367
370
|
});
|
|
368
371
|
el.innerHTML=h;
|
|
369
372
|
var inp=document.getElementById('taskInput');
|
|
@@ -377,7 +380,16 @@ function addTaskUI(){
|
|
|
377
380
|
});
|
|
378
381
|
}
|
|
379
382
|
function toggleTask(id){
|
|
380
|
-
apiPatch('/api/tasks/'+id+'/done').then(function(){loadDash().then(function(){if(currentView==='tasks')render()})});
|
|
383
|
+
apiPatch('/api/tasks/'+id+'/done').then(function(){loadDash().then(function(){if(currentView==='tasks'||currentView==='dashboard')render()})});
|
|
384
|
+
}
|
|
385
|
+
function deleteTaskUI(id){
|
|
386
|
+
if(!confirm('Delete task #'+id+'?'))return;
|
|
387
|
+
apiPost('/api/tasks/'+id+'/delete',{}).then(function(){loadDash().then(function(){render()})});
|
|
388
|
+
}
|
|
389
|
+
function clearTasksUI(mode){
|
|
390
|
+
var msg=mode==='all'?'Delete ALL tasks? This cannot be undone.':'Remove all completed tasks?';
|
|
391
|
+
if(!confirm(msg))return;
|
|
392
|
+
apiPost('/api/tasks/clear',{mode:mode}).then(function(){loadDash().then(function(){render()})});
|
|
381
393
|
}
|
|
382
394
|
|
|
383
395
|
// ---- PLAN ----
|
|
@@ -389,8 +401,8 @@ function renderPlan(el){
|
|
|
389
401
|
var h='<div class="plan-summary">'+esc(p.executive_summary||'No summary')+'</div>';
|
|
390
402
|
if(p.priority_actions&&p.priority_actions.length>0){h+='<div class="section-title">Priority Actions</div>';p.priority_actions.forEach(function(a){h+='<div class="card plan-action"><span class="plan-action__time">'+esc(a.time||'')+'</span><span class="plan-action__text">'+esc(a.action)+'</span></div>'})}
|
|
391
403
|
if(p.schedule&&p.schedule.length>0){h+='<div class="section-title">Schedule</div>';p.schedule.forEach(function(s){h+='<div class="card event"><span class="event__time">'+esc(s.time_start)+'-'+esc(s.time_end)+'</span><span class="event__title">'+esc(s.title)+'</span></div>'})}
|
|
392
|
-
if(p.security_alerts&&p.security_alerts.length>0){h+='<div class="section-title" style="color:var(--red)">Security Alerts</div>';p.security_alerts.forEach(function(a){h+='<div class="card" style="border-color:var(--red)"><span style="color:var(--red)">'+esc(typeof a==='
|
|
393
|
-
if(p.insights&&p.insights.length>0){h+='<div class="section-title">Insights</div>';p.insights.forEach(function(i){h+='<div style="color:var(--dim);padding:4px 0;font-size:12px">\\u2192 '+esc(
|
|
404
|
+
if(p.security_alerts&&p.security_alerts.length>0){h+='<div class="section-title" style="color:var(--red)">Security Alerts</div>';p.security_alerts.forEach(function(a){var txt=typeof a==='string'?a:(a.description||a.message||a.action_required||'Alert');var sev=typeof a==='object'&&a.severity?' ['+a.severity.toUpperCase()+']':'';h+='<div class="card" style="border-color:var(--red);padding:14px"><span style="color:var(--red);font-weight:700">!'+esc(sev)+'</span> '+esc(txt)+(typeof a==='object'&&a.action_required&&a.action_required!==txt?'<div style="color:var(--amber);font-size:11px;margin-top:6px">Action: '+esc(a.action_required)+'</div>':'')+'</div>'})}
|
|
405
|
+
if(p.insights&&p.insights.length>0){h+='<div class="section-title">Insights</div>';p.insights.forEach(function(i){var txt=typeof i==='string'?i:(i.message||i.insight||'');h+='<div style="color:var(--dim);padding:4px 0;font-size:12px">\\u2192 '+esc(txt)+'</div>'})}
|
|
394
406
|
h+='<div style="margin-top:16px;text-align:center"><button class="btn btn--secondary" onclick="refreshPlan()">Regenerate</button></div>';
|
|
395
407
|
el.innerHTML=h;
|
|
396
408
|
});
|