nothumanallowed 14.4.0 → 14.4.2
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/constants.mjs +1 -1
- package/src/server/routes/connectors.mjs +87 -0
- package/src/server/routes/webcraft.mjs +63 -48
- package/src/ui-dist/assets/{index-s28fgld9.js → index-CwBY0ynS.js} +4 -4
- package/src/ui-dist/assets/{index-DQV8GF5r.css → index-Xhsjp7vx.css} +1 -1
- package/src/ui-dist/index.html +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "14.4.
|
|
3
|
+
"version": "14.4.2",
|
|
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/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 = '14.4.
|
|
8
|
+
export const VERSION = '14.4.2';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -38,6 +38,92 @@ function deleteWorkflow(id) {
|
|
|
38
38
|
if (fs.existsSync(p)) fs.unlinkSync(p);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/** Seed example workflows on first run */
|
|
42
|
+
function seedExamples() {
|
|
43
|
+
ensureDir();
|
|
44
|
+
const marker = path.join(WORKFLOWS_DIR, '.examples-seeded');
|
|
45
|
+
if (fs.existsSync(marker)) return;
|
|
46
|
+
|
|
47
|
+
const examples = [
|
|
48
|
+
{
|
|
49
|
+
id: 'ex_email_digest', name: '📧 Daily Email Digest',
|
|
50
|
+
enabled: false,
|
|
51
|
+
nodes: [
|
|
52
|
+
{ id: 'n1', defId: 'trigger_cron', x: 40, y: 80, config: { schedule: '0 8 * * *' } },
|
|
53
|
+
{ id: 'n2', defId: 'ai_summarize', x: 200, y: 80, config: { prompt: 'Summarize the last 10 unread emails concisely: {{output}}' } },
|
|
54
|
+
{ id: 'n3', defId: 'action_slack', x: 400, y: 40, config: { channel: '#general', text: '📧 Morning Digest:\n{{output}}' } },
|
|
55
|
+
{ id: 'n4', defId: 'action_notify', x: 400, y: 140, config: { message: 'Email digest ready', channel: 'system' } },
|
|
56
|
+
],
|
|
57
|
+
edges: [{ from: 'n1', to: 'n2' }, { from: 'n2', to: 'n3' }, { from: 'n2', to: 'n4' }],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'ex_smart_router', name: '🔀 Smart Email Router',
|
|
61
|
+
enabled: false,
|
|
62
|
+
nodes: [
|
|
63
|
+
{ id: 'n1', defId: 'trigger_email', x: 40, y: 100, config: { filter: 'is:unread' } },
|
|
64
|
+
{ id: 'n2', defId: 'ai_classify', x: 200, y: 100, config: { categories: 'urgent, meeting, newsletter, spam', prompt: 'Classify this email: {{output}}' } },
|
|
65
|
+
{ id: 'n3', defId: 'logic_if', x: 380, y: 100, config: { condition: 'output.includes("urgent")' } },
|
|
66
|
+
{ id: 'n4', defId: 'action_notify', x: 560, y: 40, config: { message: '🚨 Urgent email: {{output}}', channel: 'telegram' } },
|
|
67
|
+
{ id: 'n5', defId: 'action_task', x: 560, y: 160, config: { title: 'Review: {{output}}', priority: 'low' } },
|
|
68
|
+
],
|
|
69
|
+
edges: [
|
|
70
|
+
{ from: 'n1', to: 'n2' }, { from: 'n2', to: 'n3' },
|
|
71
|
+
{ from: 'n3', to: 'n4', fromPort: 'true' },
|
|
72
|
+
{ from: 'n3', to: 'n5', fromPort: 'false' },
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: 'ex_content_pipeline', name: '📝 Content Pipeline',
|
|
77
|
+
enabled: false,
|
|
78
|
+
nodes: [
|
|
79
|
+
{ id: 'n1', defId: 'trigger_manual', x: 40, y: 100, config: { input: 'Write a blog post about AI agents' } },
|
|
80
|
+
{ id: 'n2', defId: 'ai_agent', x: 200, y: 100, config: { agent: 'quill', prompt: 'Write a professional blog post about: {{output}}' } },
|
|
81
|
+
{ id: 'n3', defId: 'ai_translate', x: 400, y: 40, config: { lang: 'Italian', prompt: '{{output}}' } },
|
|
82
|
+
{ id: 'n4', defId: 'action_drive', x: 600, y: 40, config: { name: 'blog-it.md', content: '{{output}}' } },
|
|
83
|
+
{ id: 'n5', defId: 'action_drive', x: 400, y: 160, config: { name: 'blog-en.md', content: '{{output}}' } },
|
|
84
|
+
],
|
|
85
|
+
edges: [{ from: 'n1', to: 'n2' }, { from: 'n2', to: 'n3' }, { from: 'n2', to: 'n5' }, { from: 'n3', to: 'n4' }],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'ex_meeting_prep', name: '📅 Meeting Prep Automation',
|
|
89
|
+
enabled: false,
|
|
90
|
+
nodes: [
|
|
91
|
+
{ id: 'n1', defId: 'trigger_cron', x: 40, y: 100, config: { schedule: '0 7 * * 1-5' } },
|
|
92
|
+
{ id: 'n2', defId: 'ai_agent', x: 200, y: 100, config: { agent: 'herald', prompt: 'List my meetings for today with details' } },
|
|
93
|
+
{ id: 'n3', defId: 'logic_if', x: 380, y: 100, config: { condition: 'output.length > 20' } },
|
|
94
|
+
{ id: 'n4', defId: 'ai_summarize', x: 540, y: 40, config: { prompt: 'Prepare a brief for each meeting. Include talking points: {{output}}' } },
|
|
95
|
+
{ id: 'n5', defId: 'action_email', x: 720, y: 40, config: { to: 'me', subject: '📅 Meeting Prep — Today', body: '{{output}}' } },
|
|
96
|
+
],
|
|
97
|
+
edges: [
|
|
98
|
+
{ from: 'n1', to: 'n2' }, { from: 'n2', to: 'n3' },
|
|
99
|
+
{ from: 'n3', to: 'n4', fromPort: 'true' },
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 'ex_web_monitor', name: '🌐 Website Monitor + Alert',
|
|
104
|
+
enabled: false,
|
|
105
|
+
nodes: [
|
|
106
|
+
{ id: 'n1', defId: 'trigger_cron', x: 40, y: 100, config: { schedule: '*/30 * * * *' } },
|
|
107
|
+
{ id: 'n2', defId: 'action_webhook', x: 200, y: 100, config: { url: 'https://nothumanallowed.com', method: 'GET' } },
|
|
108
|
+
{ id: 'n3', defId: 'logic_if', x: 380, y: 100, config: { condition: 'output.includes("Error") || output.length < 100' } },
|
|
109
|
+
{ id: 'n4', defId: 'action_notify', x: 560, y: 40, config: { message: '🚨 Website down or error detected!', channel: 'telegram' } },
|
|
110
|
+
{ id: 'n5', defId: 'logic_error', x: 560, y: 160, config: { retries: '2', fallback: 'Check failed — site may be unreachable' } },
|
|
111
|
+
],
|
|
112
|
+
edges: [
|
|
113
|
+
{ from: 'n1', to: 'n2' }, { from: 'n2', to: 'n3' },
|
|
114
|
+
{ from: 'n3', to: 'n4', fromPort: 'true' },
|
|
115
|
+
{ from: 'n3', to: 'n5', fromPort: 'false' },
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
for (const wf of examples) {
|
|
121
|
+
const p = path.join(WORKFLOWS_DIR, `${wf.id}.json`);
|
|
122
|
+
if (!fs.existsSync(p)) fs.writeFileSync(p, JSON.stringify(wf, null, 2));
|
|
123
|
+
}
|
|
124
|
+
fs.writeFileSync(marker, new Date().toISOString());
|
|
125
|
+
}
|
|
126
|
+
|
|
41
127
|
/** Substitute {{varName}} placeholders in a string using a context map */
|
|
42
128
|
function interpolate(str, ctx) {
|
|
43
129
|
if (typeof str !== 'string') return str;
|
|
@@ -278,6 +364,7 @@ export function register(router) {
|
|
|
278
364
|
// GET /api/workflows — list all workflows
|
|
279
365
|
router.get('/api/workflows', async (req, res) => {
|
|
280
366
|
try {
|
|
367
|
+
seedExamples();
|
|
281
368
|
sendJSON(res, 200, { workflows: listWorkflows() });
|
|
282
369
|
} catch (e) {
|
|
283
370
|
sendError(res, 500, e.message);
|
|
@@ -1031,41 +1031,40 @@ RULES:
|
|
|
1031
1031
|
|
|
1032
1032
|
// ── Generation pipeline (SSE) ─────────────────────────────────────────────────
|
|
1033
1033
|
|
|
1034
|
-
const FILE_PLAN_SYSTEM = `You are
|
|
1035
|
-
Output ONLY a JSON array: [{"name":"path/
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
-
|
|
1040
|
-
-
|
|
1041
|
-
-
|
|
1042
|
-
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
-
|
|
1058
|
-
- public/
|
|
1059
|
-
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
- No explanation, no markdown, ONLY the JSON array.`;
|
|
1034
|
+
const FILE_PLAN_SYSTEM = `You are a senior architect. Design a MINIMAL but COMPLETE working website.
|
|
1035
|
+
Output ONLY a JSON array: [{"name":"path/file.ext","purpose":"description","tokens":N}]
|
|
1036
|
+
|
|
1037
|
+
CRITICAL RULES:
|
|
1038
|
+
- Generate 8-15 files MAXIMUM — every file must be COMPLETE and WORKING
|
|
1039
|
+
- Each file should be 100-300 lines — substantial but not truncated
|
|
1040
|
+
- Token estimate per file: 500-2000 tokens (no file should need more than 2500)
|
|
1041
|
+
- The generated site must work IMMEDIATELY when you run "node server.js"
|
|
1042
|
+
- Users can add more features later via chat — start with a solid foundation
|
|
1043
|
+
|
|
1044
|
+
REQUIRED FILES:
|
|
1045
|
+
1. package.json — dependencies (express, helmet, cors, compression, morgan, bcryptjs, jsonwebtoken, dotenv, cookie-parser, express-rate-limit)
|
|
1046
|
+
2. .env.example — environment variables
|
|
1047
|
+
3. server.js — Express server with ALL middleware, routes, and static serving
|
|
1048
|
+
4. public/index.html — COMPLETE landing page (hero, features, footer — all CSS inline in <style>, all JS inline in <script>)
|
|
1049
|
+
5. public/login.html — Login + register page (complete with inline CSS/JS, form validation, API calls)
|
|
1050
|
+
6. public/css/style.css — ONE main stylesheet (variables, reset, layout, components, responsive — everything in one file)
|
|
1051
|
+
7. public/js/app.js — Main JS (SPA routing, auth, API client, dark mode, toasts, form validation)
|
|
1052
|
+
8. middleware/auth.js — JWT authentication middleware
|
|
1053
|
+
9. routes/auth.js — Auth routes (register, login, logout, refresh)
|
|
1054
|
+
10. models/user.js — User model with JSON file storage
|
|
1055
|
+
|
|
1056
|
+
OPTIONAL (only if the project type requires them):
|
|
1057
|
+
- routes/api.js — REST API routes for the specific project
|
|
1058
|
+
- public/dashboard.html — Protected dashboard page
|
|
1059
|
+
- Additional pages specific to the project type
|
|
1060
|
+
|
|
1061
|
+
DO NOT generate:
|
|
1062
|
+
- Separate CSS files per component (put everything in style.css)
|
|
1063
|
+
- Separate JS files per feature (put everything in app.js)
|
|
1064
|
+
- README.md, .gitignore (not essential for a working site)
|
|
1065
|
+
- Animation/responsive separate files
|
|
1066
|
+
|
|
1067
|
+
Output ONLY the JSON array, no explanation.`;
|
|
1069
1068
|
|
|
1070
1069
|
// Token counter — approximate based on character count (1 token ≈ 4 chars)
|
|
1071
1070
|
function countTokens(text) {
|
|
@@ -1192,20 +1191,36 @@ function _isSeverelyTruncated(content, filename) {
|
|
|
1192
1191
|
}
|
|
1193
1192
|
|
|
1194
1193
|
async function runGenerate(config, projectName, description, blocks, authFields, emit, abortSignal) {
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
.map(([key]) => key)
|
|
1198
|
-
.join(', ');
|
|
1194
|
+
// Blocks → write to memory.md as TODO features (NOT generated now)
|
|
1195
|
+
const enabledBlocks = Object.entries(blocks).filter(([, enabled]) => enabled).map(([key]) => key);
|
|
1199
1196
|
const authDesc = blocks.auth
|
|
1200
1197
|
? `Auth fields: ${authFields.map((f) => `${f.label}(${f.type}${f.required ? ',required' : ''})`).join(', ')}`
|
|
1201
1198
|
: '';
|
|
1202
1199
|
|
|
1200
|
+
// Save blocks as planned features in memory.md
|
|
1201
|
+
SkillStore.ensureDefaults(projectName, config);
|
|
1202
|
+
if (enabledBlocks.length > 0) {
|
|
1203
|
+
const ctxDir = SkillStore.dir(projectName);
|
|
1204
|
+
const memPath = path.join(ctxDir, 'memory.md');
|
|
1205
|
+
const blockInstructions = `# ${projectName} — Project Memory
|
|
1206
|
+
|
|
1207
|
+
## Planned Features (ask the AI agent to implement these one by one)
|
|
1208
|
+
${enabledBlocks.includes('auth') ? `- [ ] **Authentication** (register/login/JWT) — ${authDesc || 'email + password'}\n` : ''}${enabledBlocks.includes('cookieBanner') ? '- [ ] **GDPR Cookie Banner** — consent modal, localStorage tracking\n' : ''}${enabledBlocks.includes('securityMiddleware') ? '- [ ] **Security Middleware** — helmet CSP, rate limiting, CORS\n' : ''}${enabledBlocks.includes('emailVerification') ? '- [ ] **Email Verification** — send verification link, confirm endpoint\n' : ''}
|
|
1209
|
+
## How to implement
|
|
1210
|
+
Ask the AI in chat: "Add authentication" or "Add cookie banner" — the agent will modify your code.
|
|
1211
|
+
|
|
1212
|
+
## Architecture Decisions
|
|
1213
|
+
_Add notes here as you build._
|
|
1214
|
+
`;
|
|
1215
|
+
fs.writeFileSync(memPath, blockInstructions, 'utf-8');
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1203
1218
|
const planPrompt = `Project: ${projectName}
|
|
1204
1219
|
Description: ${description}
|
|
1205
|
-
${blocksDesc ? `Required blocks: ${blocksDesc}` : ''}
|
|
1206
|
-
${authDesc}
|
|
1207
1220
|
|
|
1208
|
-
Design a COMPLETE
|
|
1221
|
+
Design a MINIMAL but COMPLETE file structure for a working website.
|
|
1222
|
+
Focus on the core: a beautiful landing page, server, and main CSS/JS.
|
|
1223
|
+
The user will add features like auth, cookie banner, etc. later via chat.`;
|
|
1209
1224
|
|
|
1210
1225
|
// Emit immediately so the browser connection stays alive and the UI shows activity
|
|
1211
1226
|
emit({ type: 'processing', msg: 'Planning file structure...' });
|
|
@@ -1285,9 +1300,9 @@ Design a COMPLETE production-ready file structure. Include ALL files needed for
|
|
|
1285
1300
|
})
|
|
1286
1301
|
.join('\n\n');
|
|
1287
1302
|
|
|
1288
|
-
//
|
|
1289
|
-
const estimatedTokens = fileSpec.tokens ||
|
|
1290
|
-
const maxTokens = Math.min(Math.max(estimatedTokens * 3,
|
|
1303
|
+
// max_tokens — generous for fewer, more complete files
|
|
1304
|
+
const estimatedTokens = fileSpec.tokens || 1500;
|
|
1305
|
+
const maxTokens = Math.min(Math.max(estimatedTokens * 3, 3000), 12000);
|
|
1291
1306
|
|
|
1292
1307
|
const fileSys = `You are a team of 200 senior full-stack developers generating ENTERPRISE-GRADE production code.
|
|
1293
1308
|
|
|
@@ -1321,12 +1336,12 @@ FRONTEND STANDARDS:
|
|
|
1321
1336
|
- Accessible: aria-labels, focus styles, keyboard navigation, alt text
|
|
1322
1337
|
- Professional typography: system font stack, proper hierarchy (clamp() for fluid sizes)
|
|
1323
1338
|
- CSS Grid/Flexbox layouts — no floats
|
|
1324
|
-
-
|
|
1339
|
+
- Each file must be COMPLETE and SELF-CONTAINED — no truncation
|
|
1340
|
+
- Maximum 200 lines per file. If more content needed, split into separate files
|
|
1341
|
+
- HTML: external CSS/JS via link/script tags, NOT inline styles/scripts exceeding 20 lines`;
|
|
1325
1342
|
|
|
1326
1343
|
const filePrompt = `Project: ${projectName}
|
|
1327
1344
|
Description: ${description}
|
|
1328
|
-
${blocksDesc ? `Enabled blocks: ${blocksDesc}` : ''}
|
|
1329
|
-
${authDesc}
|
|
1330
1345
|
Full project file list: ${allFileNames}
|
|
1331
1346
|
|
|
1332
1347
|
NOW GENERATE: ${fileSpec.name}
|