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.
Files changed (123) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +69 -19
  3. package/SOUL.md +29 -26
  4. package/config/mcp.json +126 -66
  5. package/daemora-ui/README.md +11 -0
  6. package/package.json +12 -2
  7. package/skills/api-development.md +35 -0
  8. package/skills/artifacts-builder/SKILL.md +74 -0
  9. package/skills/artifacts-builder/scripts/bundle-artifact.sh +54 -0
  10. package/skills/artifacts-builder/scripts/init-artifact.sh +322 -0
  11. package/skills/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  12. package/skills/brand-guidelines.md +73 -0
  13. package/skills/browser.md +77 -0
  14. package/skills/changelog-generator.md +104 -0
  15. package/skills/coding.md +26 -10
  16. package/skills/content-research-writer.md +538 -0
  17. package/skills/data-analysis.md +27 -0
  18. package/skills/debugging.md +33 -0
  19. package/skills/devops.md +37 -0
  20. package/skills/document-docx.md +197 -0
  21. package/skills/document-pdf.md +294 -0
  22. package/skills/document-pptx.md +484 -0
  23. package/skills/document-xlsx.md +289 -0
  24. package/skills/domain-name-brainstormer.md +212 -0
  25. package/skills/file-organizer.md +433 -0
  26. package/skills/frontend-design.md +42 -0
  27. package/skills/image-enhancer.md +99 -0
  28. package/skills/invoice-organizer.md +446 -0
  29. package/skills/lead-research-assistant.md +199 -0
  30. package/skills/mcp-builder/SKILL.md +328 -0
  31. package/skills/mcp-builder/reference/evaluation.md +602 -0
  32. package/skills/mcp-builder/reference/mcp_best_practices.md +915 -0
  33. package/skills/mcp-builder/reference/node_mcp_server.md +916 -0
  34. package/skills/mcp-builder/reference/python_mcp_server.md +752 -0
  35. package/skills/mcp-builder/scripts/connections.py +151 -0
  36. package/skills/mcp-builder/scripts/evaluation.py +373 -0
  37. package/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  38. package/skills/mcp-builder/scripts/requirements.txt +2 -0
  39. package/skills/meeting-insights-analyzer.md +327 -0
  40. package/skills/orchestration.md +93 -0
  41. package/skills/raffle-winner-picker.md +159 -0
  42. package/skills/slack-gif-creator/SKILL.md +646 -0
  43. package/skills/slack-gif-creator/core/color_palettes.py +302 -0
  44. package/skills/slack-gif-creator/core/easing.py +230 -0
  45. package/skills/slack-gif-creator/core/frame_composer.py +469 -0
  46. package/skills/slack-gif-creator/core/gif_builder.py +246 -0
  47. package/skills/slack-gif-creator/core/typography.py +357 -0
  48. package/skills/slack-gif-creator/core/validators.py +264 -0
  49. package/skills/slack-gif-creator/core/visual_effects.py +494 -0
  50. package/skills/slack-gif-creator/requirements.txt +4 -0
  51. package/skills/slack-gif-creator/templates/bounce.py +106 -0
  52. package/skills/slack-gif-creator/templates/explode.py +331 -0
  53. package/skills/slack-gif-creator/templates/fade.py +329 -0
  54. package/skills/slack-gif-creator/templates/flip.py +291 -0
  55. package/skills/slack-gif-creator/templates/kaleidoscope.py +211 -0
  56. package/skills/slack-gif-creator/templates/morph.py +329 -0
  57. package/skills/slack-gif-creator/templates/move.py +293 -0
  58. package/skills/slack-gif-creator/templates/pulse.py +268 -0
  59. package/skills/slack-gif-creator/templates/shake.py +127 -0
  60. package/skills/slack-gif-creator/templates/slide.py +291 -0
  61. package/skills/slack-gif-creator/templates/spin.py +269 -0
  62. package/skills/slack-gif-creator/templates/wiggle.py +300 -0
  63. package/skills/slack-gif-creator/templates/zoom.py +312 -0
  64. package/skills/system-admin.md +44 -0
  65. package/skills/tailored-resume-generator.md +345 -0
  66. package/skills/theme-factory/SKILL.md +59 -0
  67. package/skills/theme-factory/theme-showcase.pdf +0 -0
  68. package/skills/theme-factory/themes/arctic-frost.md +19 -0
  69. package/skills/theme-factory/themes/botanical-garden.md +19 -0
  70. package/skills/theme-factory/themes/desert-rose.md +19 -0
  71. package/skills/theme-factory/themes/forest-canopy.md +19 -0
  72. package/skills/theme-factory/themes/golden-hour.md +19 -0
  73. package/skills/theme-factory/themes/midnight-galaxy.md +19 -0
  74. package/skills/theme-factory/themes/modern-minimalist.md +19 -0
  75. package/skills/theme-factory/themes/ocean-depths.md +19 -0
  76. package/skills/theme-factory/themes/sunset-boulevard.md +19 -0
  77. package/skills/theme-factory/themes/tech-innovation.md +19 -0
  78. package/skills/video-downloader.md +99 -0
  79. package/skills/web-development.md +32 -0
  80. package/skills/webapp-testing/SKILL.md +96 -0
  81. package/skills/webapp-testing/examples/console_logging.py +35 -0
  82. package/skills/webapp-testing/examples/element_discovery.py +40 -0
  83. package/skills/webapp-testing/examples/static_html_automation.py +33 -0
  84. package/skills/webapp-testing/scripts/with_server.py +106 -0
  85. package/src/agents/SubAgentManager.js +134 -16
  86. package/src/agents/systemPrompt.js +427 -0
  87. package/src/api/openai-compat.js +212 -0
  88. package/src/channels/TelegramChannel.js +5 -2
  89. package/src/channels/index.js +7 -10
  90. package/src/cli.js +281 -55
  91. package/src/config/agentProfiles.js +1 -0
  92. package/src/config/default.js +15 -1
  93. package/src/config/models.js +314 -78
  94. package/src/config/permissions.js +12 -0
  95. package/src/core/AgentLoop.js +70 -50
  96. package/src/core/Compaction.js +111 -11
  97. package/src/core/MessageQueue.js +90 -0
  98. package/src/core/Task.js +13 -0
  99. package/src/core/TaskQueue.js +1 -1
  100. package/src/core/TaskRunner.js +81 -6
  101. package/src/index.js +725 -59
  102. package/src/mcp/MCPAgentRunner.js +48 -11
  103. package/src/mcp/MCPManager.js +40 -2
  104. package/src/models/ModelRouter.js +74 -4
  105. package/src/safety/DockerSandbox.js +212 -0
  106. package/src/safety/ExecApproval.js +118 -0
  107. package/src/scheduler/Heartbeat.js +56 -21
  108. package/src/services/cleanup.js +106 -0
  109. package/src/services/sessions.js +39 -1
  110. package/src/setup/wizard.js +125 -75
  111. package/src/skills/SkillLoader.js +132 -17
  112. package/src/storage/TaskStore.js +19 -1
  113. package/src/tools/browserAutomation.js +615 -104
  114. package/src/tools/executeCommand.js +19 -1
  115. package/src/tools/index.js +7 -1
  116. package/src/tools/manageAgents.js +55 -4
  117. package/src/tools/replyWithFile.js +62 -0
  118. package/src/tools/screenCapture.js +12 -1
  119. package/src/tools/taskManager.js +164 -0
  120. package/src/tools/useMCP.js +3 -1
  121. package/src/utils/Embeddings.js +236 -12
  122. package/src/webhooks/WebhookHandler.js +107 -0
  123. package/src/systemPrompt.js +0 -528
@@ -1,7 +1,4 @@
1
- // HTTP channel is intentionally commented out - it has no authentication.
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 disabled (no authentication) ────────────────────────────
46
- // const http = new HttpChannel(config.channels.http);
47
- // this.channels.set("http", http);
48
- // await http.start();
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 channel "${task.channel}" not running`);
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 no output)";
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
- p.log.info(` Tip: use \${MY_VAR} to reference existing env vars instead of pasting secrets`);
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 family
1679
- { id: "gpt-5.3-codex", desc: "Latest coding model (2025)", isNew: true },
1680
- { id: "gpt-5.2-pro", desc: "GPT-5.2 Pro — highest capability", isNew: true },
1681
- { id: "gpt-5.2", desc: "GPT-5.2 flagship (Dec 2025)", isNew: true },
1682
- { id: "gpt-5.1-codex-max", desc: "GPT-5.1 Codex Max — coding (Nov 2025)", isNew: true },
1683
- { id: "gpt-5.1", desc: "GPT-5.1 (Nov 2025)", isNew: true },
1684
- { id: "gpt-5-pro", desc: "GPT-5 Pro — most powerful" },
1685
- { id: "gpt-5", desc: "GPT-5 flagship (Aug 2025)" },
1686
- { id: "gpt-5-mini", desc: "GPT-5 Mini fast & cheap" },
1687
- { id: "gpt-5-nano", desc: "GPT-5 Nanocheapest 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 Promost 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-deep-research", desc: "Deep research with web browsing" },
1691
- { id: "o4-mini-deep-research", desc: "Fast deep research" },
1692
- { id: "o3", desc: "Advanced reasoning (Apr 2025)" },
1693
- { id: "o4-mini", desc: "Fast reasoning (Apr 2025)" },
1694
- { id: "o1-pro", desc: "o1 Pro — powerful reasoning (Mar 2025)" },
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 + extended thinking", isNew: true },
1713
- { id: "claude-sonnet-4-6", desc: "Best speed/intelligencedaily coding & agents", isNew: true },
1714
- { id: "claude-haiku-4-5", desc: "Fastesthigh-volume, cost-sensitive tasks" },
1715
- { id: "claude-opus-4-5-20251101", desc: "Opus 4.5complex multi-step tasks (Nov 2025)" },
1716
- { id: "claude-sonnet-4-5-20250929", desc: "Sonnet 4.5 — coding & agentic tasks (200K ctx)" },
1717
- { id: "claude-opus-4-1-20250805", desc: "Opus 4.1long-duration complex tasks" },
1718
- { id: "claude-3-5-sonnet-latest", desc: "3.5 Sonnet — previous gen, widely used" },
1719
- { id: "claude-3-5-haiku-latest", desc: "3.5 Haiku fast previous gen" },
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.5complex 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.5coding & 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: "Fastesthigh-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", desc: "Latest — complex tasks, advanced reasoning", isNew: true },
1726
- { id: "gemini-3.1-flash-lite-preview", desc: "Latest — cost-efficient & fast", isNew: true },
1727
- { id: "gemini-2.5-pro", desc: "GAcomplex reasoning & coding (1M ctx)" },
1728
- { id: "gemini-2.5-flash", desc: "Fast & cost-effective for high-volume tasks" },
1729
- { id: "gemini-2.5-flash-lite", desc: "Speed-optimised for high-throughput" },
1730
- { id: "gemini-live-2.5-flash-native-audio", desc: "Real-time bidirectional audio/video agents" },
1731
- { id: "gemini-2.0-flash", desc: "Previous gen flash" },
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
- console.log(` ${S.dot} ${chalk.hex(P.teal)(fullId.padEnd(50))}${newBadge}`);
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 add notion http://localhost:3100/mcp
2057
- ${t.dim("$")} daemora mcp add myserver http://localhost:3100/sse --sse
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)
@@ -114,6 +114,7 @@ export const defaultSubAgentTools = [
114
114
  "searchMemory", "pruneMemory", "listMemoryCategories",
115
115
  // Project tracking
116
116
  "projectTracker",
117
+ "taskManager",
117
118
  // MCP (via specialist agent - no direct mcp__ tools)
118
119
  "manageMCP",
119
120
  "useMCP",
@@ -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-4.1-mini",
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),