daemora 1.0.4 → 1.0.6
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/LICENSE +663 -0
- package/README.md +69 -19
- package/SOUL.md +29 -26
- package/config/mcp.json +126 -66
- package/daemora-ui/README.md +11 -0
- package/package.json +12 -2
- package/skills/api-development.md +35 -0
- package/skills/artifacts-builder/SKILL.md +74 -0
- package/skills/artifacts-builder/scripts/bundle-artifact.sh +54 -0
- package/skills/artifacts-builder/scripts/init-artifact.sh +322 -0
- package/skills/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/skills/brand-guidelines.md +73 -0
- package/skills/browser.md +77 -0
- package/skills/changelog-generator.md +104 -0
- package/skills/coding.md +26 -10
- package/skills/content-research-writer.md +538 -0
- package/skills/data-analysis.md +27 -0
- package/skills/debugging.md +33 -0
- package/skills/devops.md +37 -0
- package/skills/document-docx.md +197 -0
- package/skills/document-pdf.md +294 -0
- package/skills/document-pptx.md +484 -0
- package/skills/document-xlsx.md +289 -0
- package/skills/domain-name-brainstormer.md +212 -0
- package/skills/file-organizer.md +433 -0
- package/skills/frontend-design.md +42 -0
- package/skills/image-enhancer.md +99 -0
- package/skills/invoice-organizer.md +446 -0
- package/skills/lead-research-assistant.md +199 -0
- package/skills/mcp-builder/SKILL.md +328 -0
- package/skills/mcp-builder/reference/evaluation.md +602 -0
- package/skills/mcp-builder/reference/mcp_best_practices.md +915 -0
- package/skills/mcp-builder/reference/node_mcp_server.md +916 -0
- package/skills/mcp-builder/reference/python_mcp_server.md +752 -0
- package/skills/mcp-builder/scripts/connections.py +151 -0
- package/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/skills/meeting-insights-analyzer.md +327 -0
- package/skills/orchestration.md +93 -0
- package/skills/raffle-winner-picker.md +159 -0
- package/skills/slack-gif-creator/SKILL.md +646 -0
- package/skills/slack-gif-creator/core/color_palettes.py +302 -0
- package/skills/slack-gif-creator/core/easing.py +230 -0
- package/skills/slack-gif-creator/core/frame_composer.py +469 -0
- package/skills/slack-gif-creator/core/gif_builder.py +246 -0
- package/skills/slack-gif-creator/core/typography.py +357 -0
- package/skills/slack-gif-creator/core/validators.py +264 -0
- package/skills/slack-gif-creator/core/visual_effects.py +494 -0
- package/skills/slack-gif-creator/requirements.txt +4 -0
- package/skills/slack-gif-creator/templates/bounce.py +106 -0
- package/skills/slack-gif-creator/templates/explode.py +331 -0
- package/skills/slack-gif-creator/templates/fade.py +329 -0
- package/skills/slack-gif-creator/templates/flip.py +291 -0
- package/skills/slack-gif-creator/templates/kaleidoscope.py +211 -0
- package/skills/slack-gif-creator/templates/morph.py +329 -0
- package/skills/slack-gif-creator/templates/move.py +293 -0
- package/skills/slack-gif-creator/templates/pulse.py +268 -0
- package/skills/slack-gif-creator/templates/shake.py +127 -0
- package/skills/slack-gif-creator/templates/slide.py +291 -0
- package/skills/slack-gif-creator/templates/spin.py +269 -0
- package/skills/slack-gif-creator/templates/wiggle.py +300 -0
- package/skills/slack-gif-creator/templates/zoom.py +312 -0
- package/skills/system-admin.md +44 -0
- package/skills/tailored-resume-generator.md +345 -0
- package/skills/theme-factory/SKILL.md +59 -0
- package/skills/theme-factory/theme-showcase.pdf +0 -0
- package/skills/theme-factory/themes/arctic-frost.md +19 -0
- package/skills/theme-factory/themes/botanical-garden.md +19 -0
- package/skills/theme-factory/themes/desert-rose.md +19 -0
- package/skills/theme-factory/themes/forest-canopy.md +19 -0
- package/skills/theme-factory/themes/golden-hour.md +19 -0
- package/skills/theme-factory/themes/midnight-galaxy.md +19 -0
- package/skills/theme-factory/themes/modern-minimalist.md +19 -0
- package/skills/theme-factory/themes/ocean-depths.md +19 -0
- package/skills/theme-factory/themes/sunset-boulevard.md +19 -0
- package/skills/theme-factory/themes/tech-innovation.md +19 -0
- package/skills/video-downloader.md +99 -0
- package/skills/web-development.md +32 -0
- package/skills/webapp-testing/SKILL.md +96 -0
- package/skills/webapp-testing/examples/console_logging.py +35 -0
- package/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/skills/webapp-testing/scripts/with_server.py +106 -0
- package/src/agents/SubAgentManager.js +134 -16
- package/src/agents/systemPrompt.js +427 -0
- package/src/api/openai-compat.js +212 -0
- package/src/channels/TelegramChannel.js +5 -2
- package/src/channels/index.js +7 -10
- package/src/cli.js +281 -55
- package/src/config/agentProfiles.js +1 -0
- package/src/config/default.js +15 -1
- package/src/config/models.js +314 -78
- package/src/config/permissions.js +12 -0
- package/src/core/AgentLoop.js +70 -50
- package/src/core/Compaction.js +111 -11
- package/src/core/MessageQueue.js +90 -0
- package/src/core/Task.js +13 -0
- package/src/core/TaskQueue.js +1 -1
- package/src/core/TaskRunner.js +81 -6
- package/src/index.js +725 -59
- package/src/mcp/MCPAgentRunner.js +48 -11
- package/src/mcp/MCPManager.js +40 -2
- package/src/models/ModelRouter.js +74 -4
- package/src/safety/DockerSandbox.js +212 -0
- package/src/safety/ExecApproval.js +118 -0
- package/src/scheduler/Heartbeat.js +56 -21
- package/src/services/cleanup.js +106 -0
- package/src/services/sessions.js +39 -1
- package/src/setup/wizard.js +125 -75
- package/src/skills/SkillLoader.js +132 -17
- package/src/storage/TaskStore.js +19 -1
- package/src/tools/browserAutomation.js +615 -104
- package/src/tools/executeCommand.js +19 -1
- package/src/tools/index.js +7 -1
- package/src/tools/manageAgents.js +55 -4
- package/src/tools/replyWithFile.js +62 -0
- package/src/tools/screenCapture.js +12 -1
- package/src/tools/taskManager.js +164 -0
- package/src/tools/useMCP.js +3 -1
- package/src/utils/Embeddings.js +236 -12
- package/src/webhooks/WebhookHandler.js +107 -0
- package/src/systemPrompt.js +0 -528
package/src/channels/index.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
// Anyone on the network could send arbitrary tasks to the agent.
|
|
3
|
-
// Uncomment only if you've added your own auth middleware.
|
|
4
|
-
// import { HttpChannel } from "./HttpChannel.js";
|
|
1
|
+
import { HttpChannel } from "./HttpChannel.js";
|
|
5
2
|
|
|
6
3
|
// ─── Core channels ─────────────────────────────────────────────────────────────
|
|
7
4
|
import { TelegramChannel } from "./TelegramChannel.js";
|
|
@@ -42,10 +39,10 @@ class ChannelRegistry {
|
|
|
42
39
|
* Initialize and start all enabled channels.
|
|
43
40
|
*/
|
|
44
41
|
async startAll() {
|
|
45
|
-
// ─── HTTP channel
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
// ─── HTTP channel (Securely handled by Express routes in index.js) ────────
|
|
43
|
+
const http = new HttpChannel(config.channels.http);
|
|
44
|
+
this.channels.set("http", http);
|
|
45
|
+
await http.start();
|
|
49
46
|
// ─────────────────────────────────────────────────────────────────────────
|
|
50
47
|
|
|
51
48
|
// ── Core channels ─────────────────────────────────────────────────────────
|
|
@@ -351,11 +348,11 @@ class ChannelRegistry {
|
|
|
351
348
|
eventBus.on("task:reply:needed", async ({ task }) => {
|
|
352
349
|
const channel = this.channels.get(task.channel);
|
|
353
350
|
if (!channel?.running) {
|
|
354
|
-
console.log(`[ChannelRegistry] Cannot send recovered reply
|
|
351
|
+
console.log(`[ChannelRegistry] Cannot send recovered reply \u2014 channel "${task.channel}" not running`);
|
|
355
352
|
return;
|
|
356
353
|
}
|
|
357
354
|
try {
|
|
358
|
-
const reply = task.result || "(Task completed
|
|
355
|
+
const reply = task.result || "(Task completed \u2014 no output)";
|
|
359
356
|
await channel.sendReply(task.channelMeta, reply);
|
|
360
357
|
console.log(`[ChannelRegistry] Recovered reply sent via ${task.channel} for task ${task.id}`);
|
|
361
358
|
} catch (e) {
|
package/src/cli.js
CHANGED
|
@@ -15,9 +15,10 @@ import chalk from "chalk";
|
|
|
15
15
|
import { config } from "./config/default.js";
|
|
16
16
|
import daemonManager from "./daemon/DaemonManager.js";
|
|
17
17
|
import secretVault from "./safety/SecretVault.js";
|
|
18
|
-
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
19
|
-
import { join } from "path";
|
|
18
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
19
|
+
import { join, dirname } from "path";
|
|
20
20
|
import { execSync } from "child_process";
|
|
21
|
+
import { randomBytes } from "crypto";
|
|
21
22
|
|
|
22
23
|
// ── Color palette — matches Daemora UI exactly ──────────────────────────────
|
|
23
24
|
const P = {
|
|
@@ -118,6 +119,10 @@ async function main() {
|
|
|
118
119
|
await handleDoctor();
|
|
119
120
|
break;
|
|
120
121
|
|
|
122
|
+
case "cleanup":
|
|
123
|
+
await handleCleanup(subcommand, rest);
|
|
124
|
+
break;
|
|
125
|
+
|
|
121
126
|
case "channels":
|
|
122
127
|
await handleChannels(subcommand);
|
|
123
128
|
break;
|
|
@@ -130,6 +135,14 @@ async function main() {
|
|
|
130
135
|
await handleTools(subcommand);
|
|
131
136
|
break;
|
|
132
137
|
|
|
138
|
+
case "config":
|
|
139
|
+
handleConfig(subcommand, rest);
|
|
140
|
+
break;
|
|
141
|
+
|
|
142
|
+
case "auth":
|
|
143
|
+
handleAuth(subcommand);
|
|
144
|
+
break;
|
|
145
|
+
|
|
133
146
|
case "setup":
|
|
134
147
|
const { runSetupWizard } = await import("./setup/wizard.js");
|
|
135
148
|
await runSetupWizard();
|
|
@@ -421,7 +434,7 @@ async function handleMCP(action, args) {
|
|
|
421
434
|
}));
|
|
422
435
|
if (needsEnv) {
|
|
423
436
|
serverConfig.env = {};
|
|
424
|
-
|
|
437
|
+
pi.log.info(` Tip: use \${MY_VAR} to reference existing env vars instead of pasting secrets`);
|
|
425
438
|
let more = true;
|
|
426
439
|
while (more) {
|
|
427
440
|
const key = pGuard(await pi.text({
|
|
@@ -645,6 +658,132 @@ async function handleMCP(action, args) {
|
|
|
645
658
|
}
|
|
646
659
|
}
|
|
647
660
|
|
|
661
|
+
// ── Config (env var management from CLI) ──────────────────────────────────────
|
|
662
|
+
|
|
663
|
+
function handleConfig(action, args) {
|
|
664
|
+
const header = `\n ${t.h("Daemora Config")} ${t.muted("Environment variable management")}\n`;
|
|
665
|
+
|
|
666
|
+
switch (action) {
|
|
667
|
+
case "set": {
|
|
668
|
+
const [key, ...valueParts] = args;
|
|
669
|
+
const value = valueParts.join(" ");
|
|
670
|
+
if (!key || !value) {
|
|
671
|
+
console.error(`\n ${S.cross} Usage: daemora config set ${t.dim("<KEY> <value>")}\n`);
|
|
672
|
+
console.log(` ${t.muted("Example:")} daemora config set OPENAI_API_KEY sk-...\n`);
|
|
673
|
+
process.exit(1);
|
|
674
|
+
}
|
|
675
|
+
writeEnvKey(key, value);
|
|
676
|
+
process.env[key] = value;
|
|
677
|
+
console.log(`${header} ${S.check} ${t.success(key)} = ${t.muted(value.length <= 8 ? value : value.slice(0, 4) + "****")}\n`);
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
case "get": {
|
|
681
|
+
const [key] = args;
|
|
682
|
+
if (!key) {
|
|
683
|
+
console.error(`\n ${S.cross} Usage: daemora config get ${t.dim("<KEY>")}\n`);
|
|
684
|
+
process.exit(1);
|
|
685
|
+
}
|
|
686
|
+
const env = readEnvFile();
|
|
687
|
+
const val = env[key];
|
|
688
|
+
if (val !== undefined) {
|
|
689
|
+
const masked = val.length <= 4 ? "****" : val.slice(0, 4) + "*".repeat(Math.min(val.length - 4, 20));
|
|
690
|
+
console.log(`${header} ${key} = ${t.muted(masked)}\n`);
|
|
691
|
+
} else {
|
|
692
|
+
console.log(`${header} ${S.cross} ${key} is not set\n`);
|
|
693
|
+
}
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
case "delete":
|
|
697
|
+
case "unset": {
|
|
698
|
+
const [key] = args;
|
|
699
|
+
if (!key) {
|
|
700
|
+
console.error(`\n ${S.cross} Usage: daemora config unset ${t.dim("<KEY>")}\n`);
|
|
701
|
+
process.exit(1);
|
|
702
|
+
}
|
|
703
|
+
deleteEnvKey(key);
|
|
704
|
+
delete process.env[key];
|
|
705
|
+
console.log(`${header} ${S.check} ${key} removed\n`);
|
|
706
|
+
break;
|
|
707
|
+
}
|
|
708
|
+
case "list":
|
|
709
|
+
default: {
|
|
710
|
+
const env = readEnvFile();
|
|
711
|
+
const keys = Object.keys(env);
|
|
712
|
+
console.log(header);
|
|
713
|
+
if (keys.length === 0) {
|
|
714
|
+
console.log(` ${t.muted("No env vars configured. Run:")} daemora config set <KEY> <value>\n`);
|
|
715
|
+
} else {
|
|
716
|
+
// Also read .env.example for available keys
|
|
717
|
+
const examplePath = join(config.rootDir, ".env.example");
|
|
718
|
+
const availableKeys = new Set();
|
|
719
|
+
if (existsSync(examplePath)) {
|
|
720
|
+
for (const line of readFileSync(examplePath, "utf-8").split("\n")) {
|
|
721
|
+
const trimmed = line.trim();
|
|
722
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
723
|
+
const eqIdx = trimmed.indexOf("=");
|
|
724
|
+
if (eqIdx > 0) availableKeys.add(trimmed.slice(0, eqIdx));
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Show configured keys
|
|
729
|
+
console.log(` ${t.muted("Configured")} (${keys.length} keys)\n`);
|
|
730
|
+
for (const key of keys) {
|
|
731
|
+
const val = env[key];
|
|
732
|
+
const masked = !val ? t.dim("(empty)") : val.length <= 4 ? "****" : val.slice(0, 4) + "*".repeat(Math.min(val.length - 4, 16));
|
|
733
|
+
console.log(` ${S.check} ${t.success(key.padEnd(30))} ${t.muted(masked)}`);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// Show unconfigured keys from .env.example
|
|
737
|
+
const unconfigured = [...availableKeys].filter(k => !env[k]);
|
|
738
|
+
if (unconfigured.length > 0) {
|
|
739
|
+
console.log(`\n ${t.muted("Available (not set)")} (${unconfigured.length} keys)\n`);
|
|
740
|
+
for (const key of unconfigured.slice(0, 20)) {
|
|
741
|
+
console.log(` ${S.cross} ${t.dim(key)}`);
|
|
742
|
+
}
|
|
743
|
+
if (unconfigured.length > 20) {
|
|
744
|
+
console.log(` ${t.dim(`... and ${unconfigured.length - 20} more`)}`);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
console.log("");
|
|
748
|
+
}
|
|
749
|
+
break;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// ── Auth (API token management) ───────────────────────────────────────────────
|
|
755
|
+
|
|
756
|
+
function handleAuth(action) {
|
|
757
|
+
const tokenPath = join(config.dataDir, "auth-token");
|
|
758
|
+
const header = `\n ${t.h("Daemora Auth")} ${t.muted("API token management")}\n`;
|
|
759
|
+
|
|
760
|
+
switch (action) {
|
|
761
|
+
case "token": {
|
|
762
|
+
if (!existsSync(tokenPath)) {
|
|
763
|
+
console.log(`${header} ${S.cross} No token yet. Start the server first or run: daemora auth reset\n`);
|
|
764
|
+
} else {
|
|
765
|
+
const token = readFileSync(tokenPath, "utf-8").trim();
|
|
766
|
+
console.log(`${header} ${t.muted("API Token:")}\n\n ${token}\n`);
|
|
767
|
+
console.log(` ${t.muted("Usage:")} curl -H "Authorization: Bearer ${token.slice(0, 8)}..." http://localhost:${config.port}/api/health\n`);
|
|
768
|
+
}
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
771
|
+
case "reset": {
|
|
772
|
+
const token = randomBytes(32).toString("hex");
|
|
773
|
+
mkdirSync(dirname(tokenPath), { recursive: true });
|
|
774
|
+
writeFileSync(tokenPath, token, { mode: 0o600 });
|
|
775
|
+
console.log(`${header} ${S.check} ${t.success("New token generated")}\n\n ${token}\n`);
|
|
776
|
+
console.log(` ${t.muted("Restart the server for the new token to take effect.")}\n`);
|
|
777
|
+
break;
|
|
778
|
+
}
|
|
779
|
+
default: {
|
|
780
|
+
console.log(`${header} ${t.cmd("daemora auth token")} Show current API token`);
|
|
781
|
+
console.log(` ${t.cmd("daemora auth reset")} Generate a new token\n`);
|
|
782
|
+
break;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
648
787
|
// ── Sandbox (filesystem scoping) helpers ──────────────────────────────────────
|
|
649
788
|
|
|
650
789
|
function readEnvFile() {
|
|
@@ -1281,6 +1420,71 @@ async function handleDoctor() {
|
|
|
1281
1420
|
}
|
|
1282
1421
|
}
|
|
1283
1422
|
|
|
1423
|
+
// ─── Cleanup ──────────────────────────────────────────────────────────────────
|
|
1424
|
+
|
|
1425
|
+
async function handleCleanup(subcommand, rest) {
|
|
1426
|
+
const { runCleanup, getStorageStats } = await import("./services/cleanup.js");
|
|
1427
|
+
const { readFileSync: rfs, writeFileSync: wfs, existsSync: exs } = await import("fs");
|
|
1428
|
+
const { join: pjoin } = await import("path");
|
|
1429
|
+
|
|
1430
|
+
if (subcommand === "stats") {
|
|
1431
|
+
const stats = getStorageStats();
|
|
1432
|
+
console.log(`\n ${t.h("Storage Stats")}\n`);
|
|
1433
|
+
console.log(` Tasks: ${t.bold(stats.tasks.files)} files (${stats.tasks.sizeKB} KB)`);
|
|
1434
|
+
console.log(` Audit: ${t.bold(stats.audit.files)} files (${stats.audit.sizeKB} KB)`);
|
|
1435
|
+
console.log(` Costs: ${t.bold(stats.costs.files)} files (${stats.costs.sizeKB} KB)`);
|
|
1436
|
+
console.log(` Sessions: ${t.bold(stats.sessions.files)} files (${stats.sessions.sizeKB} KB)`);
|
|
1437
|
+
console.log(`\n Retention: ${stats.retentionDays === "never" ? t.dim("never delete") : t.bold(stats.retentionDays + " days")}`);
|
|
1438
|
+
console.log(` ${t.dim("Set with: daemora cleanup set <days> (0 = never)")}\n`);
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
if (subcommand === "set") {
|
|
1443
|
+
const days = parseInt(rest[0], 10);
|
|
1444
|
+
if (isNaN(days) || days < 0) {
|
|
1445
|
+
console.log(`\n ${S.cross} Usage: daemora cleanup set <days> (0 = never delete)\n`);
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
// Update .env file
|
|
1450
|
+
const envPath = pjoin(config.rootDir, ".env");
|
|
1451
|
+
if (exs(envPath)) {
|
|
1452
|
+
let env = rfs(envPath, "utf-8");
|
|
1453
|
+
if (env.includes("CLEANUP_AFTER_DAYS=")) {
|
|
1454
|
+
env = env.replace(/CLEANUP_AFTER_DAYS=\d*/, `CLEANUP_AFTER_DAYS=${days}`);
|
|
1455
|
+
} else {
|
|
1456
|
+
env = env.trimEnd() + `\n\n# === Cleanup ===\nCLEANUP_AFTER_DAYS=${days}\n`;
|
|
1457
|
+
}
|
|
1458
|
+
wfs(envPath, env);
|
|
1459
|
+
} else {
|
|
1460
|
+
wfs(envPath, `CLEANUP_AFTER_DAYS=${days}\n`);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
if (days === 0) {
|
|
1464
|
+
console.log(`\n ${t.success("✔")} Auto-cleanup ${t.bold("disabled")}. Data will be kept forever.\n`);
|
|
1465
|
+
} else {
|
|
1466
|
+
console.log(`\n ${t.success("✔")} Auto-cleanup set to ${t.bold(days + " days")}. Old data deleted on each startup.\n`);
|
|
1467
|
+
}
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
// Default: run cleanup now
|
|
1472
|
+
const days = config.cleanupAfterDays || 30;
|
|
1473
|
+
console.log(`\n ${t.h("Cleanup")} ${t.muted(`Deleting data older than ${days} days`)}\n`);
|
|
1474
|
+
|
|
1475
|
+
const result = runCleanup(days);
|
|
1476
|
+
|
|
1477
|
+
if (result.total === 0) {
|
|
1478
|
+
console.log(` ${t.success("✔")} Nothing to clean up.\n`);
|
|
1479
|
+
} else {
|
|
1480
|
+
if (result.tasks > 0) console.log(` ${t.success("✔")} Tasks: ${result.tasks} deleted`);
|
|
1481
|
+
if (result.audit > 0) console.log(` ${t.success("✔")} Audit: ${result.audit} deleted`);
|
|
1482
|
+
if (result.costs > 0) console.log(` ${t.success("✔")} Costs: ${result.costs} deleted`);
|
|
1483
|
+
if (result.sessions > 0) console.log(` ${t.success("✔")} Sessions: ${result.sessions} deleted`);
|
|
1484
|
+
console.log(`\n Total: ${t.bold(result.total)} file(s) deleted.\n`);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1284
1488
|
// ─── Channels ─────────────────────────────────────────────────────────────────
|
|
1285
1489
|
|
|
1286
1490
|
const CHANNEL_DEFS = [
|
|
@@ -1675,60 +1879,66 @@ async function handleModels() {
|
|
|
1675
1879
|
{
|
|
1676
1880
|
name: "OpenAI", prefix: "openai", envKey: "OPENAI_API_KEY",
|
|
1677
1881
|
models: [
|
|
1678
|
-
// GPT-5
|
|
1679
|
-
{ id: "gpt-5.
|
|
1680
|
-
{ id: "gpt-5.
|
|
1681
|
-
|
|
1682
|
-
{ id: "gpt-5.
|
|
1683
|
-
{ id: "gpt-5.
|
|
1684
|
-
|
|
1685
|
-
{ id: "gpt-5",
|
|
1686
|
-
{ id: "gpt-5
|
|
1687
|
-
{ id: "gpt-5-
|
|
1882
|
+
// GPT-5.4
|
|
1883
|
+
{ id: "gpt-5.4", desc: "GPT-5.4 flagship", price: "$2.50/$15", isNew: true },
|
|
1884
|
+
{ id: "gpt-5.4-pro", desc: "GPT-5.4 Pro — highest capability", price: "$30/$180", isNew: true },
|
|
1885
|
+
// GPT-5.2
|
|
1886
|
+
{ id: "gpt-5.2", desc: "GPT-5.2 flagship (Dec 2025)", price: "$1.75/$14", isNew: true },
|
|
1887
|
+
{ id: "gpt-5.2-pro", desc: "GPT-5.2 Pro — extended reasoning", price: "$21/$168", isNew: true },
|
|
1888
|
+
// GPT-5.1 / 5
|
|
1889
|
+
{ id: "gpt-5.1", desc: "GPT-5.1 (Nov 2025)", price: "$1.25/$10", isNew: true },
|
|
1890
|
+
{ id: "gpt-5", desc: "GPT-5 flagship (Aug 2025)", price: "$1.25/$10" },
|
|
1891
|
+
{ id: "gpt-5-pro", desc: "GPT-5 Pro — most powerful", price: "$15/$120" },
|
|
1892
|
+
{ id: "gpt-5-mini", desc: "GPT-5 Mini — fast & cheap", price: "$0.25/$2" },
|
|
1893
|
+
{ id: "gpt-5-nano", desc: "GPT-5 Nano — cheapest GPT-5", price: "$0.05/$0.40" },
|
|
1894
|
+
// Codex
|
|
1895
|
+
{ id: "gpt-5.3-codex", desc: "Latest coding model (2025)", price: "$1.75/$14", isNew: true },
|
|
1896
|
+
{ id: "gpt-5.1-codex", desc: "GPT-5.1 Codex — coding", price: "$1.25/$10", isNew: true },
|
|
1897
|
+
{ id: "gpt-5-codex", desc: "GPT-5 Codex — coding", price: "$1.25/$10" },
|
|
1688
1898
|
// o-series reasoning
|
|
1689
|
-
{ id: "o3-pro", desc: "Best reasoning — most thorough" },
|
|
1690
|
-
{ id: "o3
|
|
1691
|
-
{ id: "o4-mini
|
|
1692
|
-
{ id: "
|
|
1693
|
-
{ id: "
|
|
1694
|
-
{ id: "
|
|
1695
|
-
{ id: "o1", desc: "o1 reasoning model" },
|
|
1696
|
-
{ id: "o3-mini", desc: "Lightweight reasoning" },
|
|
1899
|
+
{ id: "o3-pro", desc: "Best reasoning — most thorough", price: "$20/$80" },
|
|
1900
|
+
{ id: "o3", desc: "Advanced reasoning (Apr 2025)", price: "$2/$8" },
|
|
1901
|
+
{ id: "o4-mini", desc: "Fast reasoning (Apr 2025)", price: "$1.10/$4.40" },
|
|
1902
|
+
{ id: "o1-pro", desc: "o1 Pro — powerful reasoning", price: "$150/$600" },
|
|
1903
|
+
{ id: "o1", desc: "o1 reasoning model", price: "$15/$60" },
|
|
1904
|
+
{ id: "o3-mini", desc: "Lightweight reasoning", price: "$1.10/$4.40" },
|
|
1697
1905
|
// GPT-4.1 (1M context)
|
|
1698
|
-
{ id: "gpt-4.1", desc: "1M context, best instruction following" },
|
|
1699
|
-
{ id: "gpt-4.1-mini", desc: "1M context, fast & affordable (default)" },
|
|
1700
|
-
{ id: "gpt-4.1-nano", desc: "1M context, fastest & cheapest" },
|
|
1906
|
+
{ id: "gpt-4.1", desc: "1M context, best instruction following", price: "$2/$8" },
|
|
1907
|
+
{ id: "gpt-4.1-mini", desc: "1M context, fast & affordable (default)", price: "$0.40/$1.60" },
|
|
1908
|
+
{ id: "gpt-4.1-nano", desc: "1M context, fastest & cheapest", price: "$0.10/$0.40" },
|
|
1701
1909
|
// GPT-4o & specialized
|
|
1702
|
-
{ id: "gpt-4o", desc: "Vision + text (128K ctx)" },
|
|
1703
|
-
{ id: "gpt-4o-mini", desc: "GPT-4o Mini (128K ctx)" },
|
|
1704
|
-
{ id: "computer-use-preview", desc: "Computer use / GUI automation" },
|
|
1705
|
-
{ id: "gpt-4o-search-preview", desc: "Built-in live web search" },
|
|
1706
|
-
{ id: "gpt-image-1", desc: "Image generation (native API)" },
|
|
1910
|
+
{ id: "gpt-4o", desc: "Vision + text (128K ctx)", price: "$2.50/$10" },
|
|
1911
|
+
{ id: "gpt-4o-mini", desc: "GPT-4o Mini (128K ctx)", price: "$0.15/$0.60" },
|
|
1912
|
+
{ id: "computer-use-preview", desc: "Computer use / GUI automation", price: "$3/$12" },
|
|
1707
1913
|
],
|
|
1708
1914
|
},
|
|
1709
1915
|
{
|
|
1710
1916
|
name: "Anthropic", prefix: "anthropic", envKey: "ANTHROPIC_API_KEY",
|
|
1711
1917
|
models: [
|
|
1712
|
-
{ id: "claude-opus-4-6", desc: "Most intelligent — complex reasoning
|
|
1713
|
-
{ id: "claude-
|
|
1714
|
-
{ id: "claude-
|
|
1715
|
-
{ id: "claude-opus-4
|
|
1716
|
-
{ id: "claude-sonnet-4-
|
|
1717
|
-
{ id: "claude-
|
|
1718
|
-
{ id: "claude-
|
|
1719
|
-
{ id: "claude-
|
|
1918
|
+
{ id: "claude-opus-4-6", desc: "Most intelligent — complex reasoning", price: "$5/$25", isNew: true },
|
|
1919
|
+
{ id: "claude-opus-4-5", desc: "Opus 4.5 — complex multi-step tasks", price: "$5/$25", isNew: true },
|
|
1920
|
+
{ id: "claude-opus-4-1", desc: "Opus 4.1 — long-duration complex tasks", price: "$15/$75" },
|
|
1921
|
+
{ id: "claude-opus-4", desc: "Opus 4 — extended thinking", price: "$15/$75" },
|
|
1922
|
+
{ id: "claude-sonnet-4-6", desc: "Best speed/intelligence — coding & agents", price: "$3/$15", isNew: true },
|
|
1923
|
+
{ id: "claude-sonnet-4-5", desc: "Sonnet 4.5 — coding & agentic tasks", price: "$3/$15" },
|
|
1924
|
+
{ id: "claude-sonnet-4", desc: "Sonnet 4 — balanced performance", price: "$3/$15" },
|
|
1925
|
+
{ id: "claude-haiku-4-5", desc: "Fastest — high-volume, cost-sensitive", price: "$1/$5" },
|
|
1926
|
+
{ id: "claude-haiku-3-5", desc: "3.5 Haiku — fast previous gen", price: "$0.80/$4" },
|
|
1927
|
+
{ id: "claude-haiku-3", desc: "Haiku 3 — cheapest Claude", price: "$0.25/$1.25" },
|
|
1720
1928
|
],
|
|
1721
1929
|
},
|
|
1722
1930
|
{
|
|
1723
1931
|
name: "Google", prefix: "google", envKey: "GOOGLE_AI_API_KEY",
|
|
1724
1932
|
models: [
|
|
1725
|
-
{ id: "gemini-3.1-pro-preview",
|
|
1726
|
-
{ id: "gemini-3.1-flash-lite-preview",
|
|
1727
|
-
{ id: "gemini-
|
|
1728
|
-
{ id: "gemini-
|
|
1729
|
-
{ id: "gemini-2.5-
|
|
1730
|
-
{ id: "gemini-
|
|
1731
|
-
{ id: "gemini-2.
|
|
1933
|
+
{ id: "gemini-3.1-pro-preview", desc: "Latest — complex tasks, reasoning", price: "$2/$12", isNew: true },
|
|
1934
|
+
{ id: "gemini-3.1-flash-lite-preview", desc: "Latest — cost-efficient & fast", price: "$0.25/$1.50", isNew: true },
|
|
1935
|
+
{ id: "gemini-3-pro-preview", desc: "Gemini 3 Pro — advanced reasoning", price: "$2/$12", isNew: true },
|
|
1936
|
+
{ id: "gemini-3-flash-preview", desc: "Gemini 3 Flash — fast & cheap", price: "$0.50/$3", isNew: true },
|
|
1937
|
+
{ id: "gemini-2.5-pro", desc: "GA — complex reasoning & coding (1M)", price: "$1.25/$10" },
|
|
1938
|
+
{ id: "gemini-2.5-flash", desc: "Fast & cost-effective for high-volume", price: "$0.30/$2.50" },
|
|
1939
|
+
{ id: "gemini-2.5-flash-lite", desc: "Speed-optimised for high-throughput", price: "$0.10/$0.40" },
|
|
1940
|
+
{ id: "gemini-2.0-flash", desc: "Previous gen flash", price: "$0.15/$0.60" },
|
|
1941
|
+
{ id: "gemini-2.0-flash-lite", desc: "Cheapest Gemini", price: "$0.075/$0.30" },
|
|
1732
1942
|
],
|
|
1733
1943
|
},
|
|
1734
1944
|
{
|
|
@@ -1758,14 +1968,14 @@ async function handleModels() {
|
|
|
1758
1968
|
{
|
|
1759
1969
|
name: "Ollama (local)", prefix: "ollama", configured: true,
|
|
1760
1970
|
models: [
|
|
1761
|
-
{ id: "llama4-maverick", desc: "Llama 4 Maverick — 17B MoE, 1M ctx, multimodal", isNew: true },
|
|
1762
|
-
{ id: "llama4-scout", desc: "Llama 4 Scout — 17B MoE, 10M ctx", isNew: true },
|
|
1763
|
-
{ id: "llama3.3", desc: "Llama 3.3 70B — best open model (Dec 2024)" },
|
|
1764
|
-
{ id: "qwen2.5", desc: "Qwen 2.5 72B — strong coder" },
|
|
1765
|
-
{ id: "deepseek-r1", desc: "DeepSeek-R1 local — reasoning" },
|
|
1766
|
-
{ id: "mistral", desc: "Mistral 7B — fast small model" },
|
|
1767
|
-
{ id: "phi4", desc: "Phi-4 14B — Microsoft small model" },
|
|
1768
|
-
{ id: "codellama", desc: "CodeLlama — code specialised" },
|
|
1971
|
+
{ id: "llama4-maverick", desc: "Llama 4 Maverick — 17B MoE, 1M ctx, multimodal", price: "free", isNew: true },
|
|
1972
|
+
{ id: "llama4-scout", desc: "Llama 4 Scout — 17B MoE, 10M ctx", price: "free", isNew: true },
|
|
1973
|
+
{ id: "llama3.3", desc: "Llama 3.3 70B — best open model (Dec 2024)", price: "free" },
|
|
1974
|
+
{ id: "qwen2.5", desc: "Qwen 2.5 72B — strong coder", price: "free" },
|
|
1975
|
+
{ id: "deepseek-r1", desc: "DeepSeek-R1 local — reasoning", price: "free" },
|
|
1976
|
+
{ id: "mistral", desc: "Mistral 7B — fast small model", price: "free" },
|
|
1977
|
+
{ id: "phi4", desc: "Phi-4 14B — Microsoft small model", price: "free" },
|
|
1978
|
+
{ id: "codellama", desc: "CodeLlama — code specialised", price: "free" },
|
|
1769
1979
|
],
|
|
1770
1980
|
},
|
|
1771
1981
|
];
|
|
@@ -1792,7 +2002,8 @@ async function handleModels() {
|
|
|
1792
2002
|
for (const m of prov.models) {
|
|
1793
2003
|
const fullId = `${prov.prefix}:${m.id}`;
|
|
1794
2004
|
const newBadge = m.isNew ? chalk.hex(P.amber)(" [NEW]") : "";
|
|
1795
|
-
|
|
2005
|
+
const priceTag = m.price ? chalk.hex(P.muted)(` ${m.price} /MTok`) : "";
|
|
2006
|
+
console.log(` ${S.dot} ${chalk.hex(P.teal)(fullId.padEnd(44))}${priceTag}${newBadge}`);
|
|
1796
2007
|
console.log(` ${chalk.hex(P.dim)(m.desc)}`);
|
|
1797
2008
|
}
|
|
1798
2009
|
}
|
|
@@ -1984,6 +2195,15 @@ ${line}
|
|
|
1984
2195
|
${t.cmd("start")} Start the agent server
|
|
1985
2196
|
${t.cmd("setup")} Interactive setup wizard
|
|
1986
2197
|
|
|
2198
|
+
${t.cmd("auth token")} Show API auth token
|
|
2199
|
+
${t.cmd("auth reset")} Generate a new auth token
|
|
2200
|
+
|
|
2201
|
+
${t.cmd("config list")} List all configured env vars
|
|
2202
|
+
${t.cmd("config set")} ${t.dim("<KEY> <value>")} Set an env var (e.g. OPENAI_API_KEY)
|
|
2203
|
+
${t.cmd("config get")} ${t.dim("<KEY>")} Show an env var (masked)
|
|
2204
|
+
${t.cmd("config unset")} ${t.dim("<KEY>")} Remove an env var
|
|
2205
|
+
${t.dim(" Keys: DEFAULT_MODEL, SUB_AGENT_MODEL, CODE_MODEL, RESEARCH_MODEL ...")}
|
|
2206
|
+
|
|
1987
2207
|
${t.cmd("daemon install")} Install as OS service (auto-start)
|
|
1988
2208
|
${t.cmd("daemon uninstall")} Remove OS service
|
|
1989
2209
|
${t.cmd("daemon start")} Start the background daemon
|
|
@@ -2036,6 +2256,9 @@ ${line}
|
|
|
2036
2256
|
${t.cmd("tools")} ${t.dim("[filter]")} List all 50 built-in tools (filter by name/category)
|
|
2037
2257
|
|
|
2038
2258
|
${t.cmd("doctor")} Security audit - check for misconfigurations
|
|
2259
|
+
${t.cmd("cleanup")} Delete old tasks, logs, and sessions
|
|
2260
|
+
${t.cmd("cleanup set")} ${t.dim("<days>")} Set auto-cleanup retention (0 = never)
|
|
2261
|
+
${t.cmd("cleanup stats")} Show storage usage per directory
|
|
2039
2262
|
|
|
2040
2263
|
${t.cmd("help")} Show this help
|
|
2041
2264
|
|
|
@@ -2053,8 +2276,11 @@ ${line}
|
|
|
2053
2276
|
${t.dim("$")} daemora mcp list
|
|
2054
2277
|
${t.dim("$")} daemora mcp add github npx -y @modelcontextprotocol/server-github
|
|
2055
2278
|
${t.dim("$")} daemora mcp env github GITHUB_PERSONAL_ACCESS_TOKEN ghp_...
|
|
2056
|
-
${t.dim("$")} daemora mcp
|
|
2057
|
-
${t.dim("$")} daemora mcp
|
|
2279
|
+
${t.dim("$")} daemora mcp env notion NOTION_TOKEN ntn_...
|
|
2280
|
+
${t.dim("$")} daemora mcp env stripe STRIPE_SECRET_KEY sk_live_...
|
|
2281
|
+
${t.dim("$")} daemora mcp enable notion
|
|
2282
|
+
${t.dim("$")} daemora mcp add myserver https://api.example.com/mcp
|
|
2283
|
+
${t.dim("$")} daemora mcp add mysse https://api.example.com/sse --sse
|
|
2058
2284
|
${t.dim("$")} daemora mcp remove github
|
|
2059
2285
|
${t.dim("$")} daemora mcp add (interactive - prompts for everything)
|
|
2060
2286
|
${t.dim("$")} daemora mcp reload github (reconnects live if agent running)
|
package/src/config/default.js
CHANGED
|
@@ -28,12 +28,23 @@ export const config = {
|
|
|
28
28
|
memoryPath: join(ROOT_DIR, "MEMORY.md"),
|
|
29
29
|
|
|
30
30
|
// Default model (provider:model format)
|
|
31
|
-
defaultModel: process.env.DEFAULT_MODEL || "openai:gpt-
|
|
31
|
+
defaultModel: process.env.DEFAULT_MODEL || "openai:gpt-5.1-mini",
|
|
32
|
+
|
|
33
|
+
// Sub-agent model — used for all sub-agents when no profile-specific model is set.
|
|
34
|
+
// Falls between profile routing (CODE_MODEL etc.) and DEFAULT_MODEL in priority.
|
|
35
|
+
subAgentModel: process.env.SUB_AGENT_MODEL || null,
|
|
32
36
|
|
|
33
37
|
// Agent loop
|
|
34
38
|
maxLoops: 40,
|
|
35
39
|
maxSubAgentDepth: 3,
|
|
36
40
|
|
|
41
|
+
// Thinking level: "auto" | "off" | "minimal" | "low" | "medium" | "high" | "xhigh"
|
|
42
|
+
thinkingLevel: process.env.THINKING_LEVEL || "auto",
|
|
43
|
+
|
|
44
|
+
// Message queue mode: "steer" (inject into live loop) | "collect" (batch into follow-up) | "followup" (queue as separate)
|
|
45
|
+
queueMode: process.env.QUEUE_MODE || "steer",
|
|
46
|
+
debounceMs: parseInt(process.env.DEBOUNCE_MS || "1500", 10),
|
|
47
|
+
|
|
37
48
|
// Safety
|
|
38
49
|
permissionTier: process.env.PERMISSION_TIER || "standard",
|
|
39
50
|
|
|
@@ -41,6 +52,9 @@ export const config = {
|
|
|
41
52
|
maxCostPerTask: parseFloat(process.env.MAX_COST_PER_TASK || "0.50"),
|
|
42
53
|
maxDailyCost: parseFloat(process.env.MAX_DAILY_COST || "10.00"),
|
|
43
54
|
|
|
55
|
+
// Cleanup
|
|
56
|
+
cleanupAfterDays: parseInt(process.env.CLEANUP_AFTER_DAYS || "30", 10), // 0 = never
|
|
57
|
+
|
|
44
58
|
// Daemon
|
|
45
59
|
daemonMode: process.env.DAEMON_MODE === "true",
|
|
46
60
|
heartbeatIntervalMinutes: parseInt(process.env.HEARTBEAT_INTERVAL_MINUTES || "30", 10),
|