0agent 1.0.47 → 1.0.49

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/bin/chat.js CHANGED
@@ -31,6 +31,7 @@ const SLASH_COMMANDS = [
31
31
  { cmd: '/security-audit',desc: 'Security audit — find vulnerabilities' },
32
32
  { cmd: '/design-review', desc: 'Design review — architecture and patterns' },
33
33
  // Built-ins
34
+ { cmd: '/memory', desc: 'Show graph nodes and force-push to GitHub' },
34
35
  { cmd: '/telegram', desc: 'Connect Telegram bot — forward messages to 0agent'},
35
36
  { cmd: '/model', desc: 'Show or switch the LLM model' },
36
37
  { cmd: '/key', desc: 'Update a stored API key' },
@@ -902,6 +903,50 @@ async function handleCommand(input) {
902
903
  break;
903
904
  }
904
905
 
906
+ // /memory — inspect graph nodes + force GitHub sync
907
+ case '/memory': {
908
+ try {
909
+ const sub = parts[1]?.toLowerCase();
910
+
911
+ if (sub === 'sync' || sub === 'push') {
912
+ process.stdout.write(` ${fmt(C.dim, 'Pushing to GitHub...')}\n`);
913
+ const res = await fetch(`${BASE_URL}/api/memory/push`, { method: 'POST' }).catch(() => null);
914
+ const data = res?.ok ? await res.json().catch(() => null) : null;
915
+ if (data?.pushed) {
916
+ console.log(` ${fmt(C.green, '✓')} Pushed ${data.nodes_synced} nodes, ${data.edges_synced} edges to GitHub\n`);
917
+ } else {
918
+ console.log(` ${fmt(C.yellow, '⚠')} ${data?.error ?? 'Sync not configured or failed'}\n`);
919
+ }
920
+ break;
921
+ }
922
+
923
+ // Show memory nodes from graph
924
+ const res = await fetch(`${BASE_URL}/api/graph/nodes?limit=200`).then(r => r.json()).catch(() => []);
925
+ const nodes = Array.isArray(res) ? res : [];
926
+ const memNodes = nodes.filter(n => n.id?.startsWith('memory:') || n.type === 'context');
927
+ const total = nodes.length;
928
+
929
+ console.log(`\n ${fmt(C.bold, 'Knowledge graph')} — ${total} nodes total, ${memNodes.length} memory nodes\n`);
930
+
931
+ if (memNodes.length === 0) {
932
+ console.log(` ${fmt(C.dim, 'No memory nodes yet. Run a task — the agent will write facts here.')}\n`);
933
+ } else {
934
+ for (const n of memNodes.slice(0, 20)) {
935
+ const content = n.metadata?.content ?? n.label;
936
+ const type = n.metadata?.type ?? n.type;
937
+ console.log(` ${fmt(C.cyan, n.label.padEnd(28))} ${fmt(C.dim, String(content).slice(0, 50))}`);
938
+ console.log(` ${fmt(C.dim, ` ${n.id} [${type}]`)}`);
939
+ }
940
+ if (memNodes.length > 20) console.log(fmt(C.dim, `\n …and ${memNodes.length - 20} more`));
941
+ }
942
+ console.log();
943
+ console.log(` ${fmt(C.dim, 'Force sync: /memory sync · Dashboard: http://localhost:4200')}\n`);
944
+ } catch {
945
+ console.log(` ${fmt(C.red, '✗')} Daemon not running\n`);
946
+ }
947
+ break;
948
+ }
949
+
905
950
  // /telegram — configure Telegram bot token
906
951
  case '/telegram': {
907
952
  if (!cfg) { console.log(fmt(C.red, ' No config found. Run: 0agent init')); break; }
@@ -1002,51 +1047,55 @@ async function openPalette(initialFilter = '') {
1002
1047
 
1003
1048
  let filter = initialFilter.toLowerCase();
1004
1049
  let idx = 0;
1005
- let drawn = 0; // number of lines we've printed so far
1050
+ let scroll = 0; // top of the visible window
1051
+ let drawn = 0;
1052
+ const PAGE = 10; // visible rows at once
1006
1053
 
1007
1054
  const getItems = () => SLASH_COMMANDS.filter(c =>
1008
1055
  !filter || c.cmd.slice(1).startsWith(filter)
1009
1056
  );
1010
1057
 
1011
1058
  const paint = () => {
1012
- // Erase previous draw: move up `drawn` lines, clear everything below
1013
1059
  if (drawn > 0) process.stdout.write(`\x1b[${drawn}A\x1b[0J`);
1014
1060
 
1015
- const items = getItems();
1016
- const show = items.slice(0, 14);
1017
- if (idx >= items.length) idx = Math.max(0, items.length - 1);
1061
+ const items = getItems();
1062
+ if (items.length === 0) { idx = 0; scroll = 0; }
1063
+ else {
1064
+ idx = Math.max(0, Math.min(idx, items.length - 1));
1065
+ // Keep selected item inside the visible window
1066
+ if (idx < scroll) scroll = idx;
1067
+ if (idx >= scroll + PAGE) scroll = idx - PAGE + 1;
1068
+ }
1018
1069
 
1070
+ const show = items.slice(scroll, scroll + PAGE);
1019
1071
  const lines = [];
1020
1072
 
1021
- // Top border
1022
1073
  lines.push(` \x1b[2m${'─'.repeat(58)}\x1b[0m`);
1023
1074
 
1024
- if (show.length === 0) {
1075
+ if (items.length === 0) {
1025
1076
  lines.push(` \x1b[2m no commands match "/${filter}"\x1b[0m`);
1026
1077
  } else {
1027
1078
  for (let i = 0; i < show.length; i++) {
1028
1079
  const m = show[i];
1029
- const sel = i === idx;
1080
+ const sel = (scroll + i) === idx;
1030
1081
  if (sel) {
1031
- lines.push(
1032
- ` \x1b[36;1m›\x1b[0m \x1b[36;1m${m.cmd.padEnd(22)}\x1b[0m \x1b[0m${m.desc}\x1b[0m`
1033
- );
1082
+ lines.push(` \x1b[36;1m›\x1b[0m \x1b[36;1m${m.cmd.padEnd(22)}\x1b[0m ${m.desc}`);
1034
1083
  } else {
1035
- lines.push(
1036
- ` \x1b[36m${m.cmd.padEnd(22)}\x1b[0m \x1b[2m${m.desc}\x1b[0m`
1037
- );
1084
+ lines.push(` \x1b[36m${m.cmd.padEnd(22)}\x1b[0m \x1b[2m${m.desc}\x1b[0m`);
1038
1085
  }
1039
1086
  }
1040
1087
  }
1041
1088
 
1042
- if (items.length > 14) lines.push(` \x1b[2m …${items.length - 14} more\x1b[0m`);
1089
+ // Scroll indicator
1090
+ if (items.length > PAGE) {
1091
+ const pct = Math.round(((scroll + PAGE / 2) / items.length) * 100);
1092
+ lines.push(` \x1b[2m ${idx + 1} / ${items.length} (${pct}%)\x1b[0m`);
1093
+ }
1043
1094
 
1044
- // Bottom: search input line
1045
1095
  lines.push(` \x1b[2m${'─'.repeat(58)}\x1b[0m`);
1046
- lines.push(` ${fmt(C.cyan, '/')}${filter}\x1b[K \x1b[2m↑↓ navigate · Enter select · Esc cancel\x1b[0m`);
1096
+ lines.push(` ${fmt(C.cyan, '/')}${filter}\x1b[K \x1b[2m↑↓ scroll · Enter select · Esc cancel\x1b[0m`);
1047
1097
 
1048
- const out = lines.join('\n') + '\n';
1049
- process.stdout.write(out);
1098
+ process.stdout.write(lines.join('\n') + '\n');
1050
1099
  drawn = lines.length;
1051
1100
  };
1052
1101
 
@@ -1069,11 +1118,11 @@ async function openPalette(initialFilter = '') {
1069
1118
  paint();
1070
1119
  } else if (s === '\x7f' || s === '\x08') { // Backspace
1071
1120
  filter = filter.slice(0, -1);
1072
- idx = 0;
1121
+ idx = 0; scroll = 0;
1073
1122
  paint();
1074
1123
  } else if (/^[a-z0-9\-_]$/i.test(s)) { // Printable letter/digit/hyphen
1075
1124
  filter += s.toLowerCase();
1076
- idx = 0;
1125
+ idx = 0; scroll = 0;
1077
1126
  paint();
1078
1127
  }
1079
1128
  };
@@ -1410,17 +1459,19 @@ function isNewerVersion(a, b) {
1410
1459
 
1411
1460
  // ─── Message queue + serial executor ─────────────────────────────────────────
1412
1461
 
1413
- const COMMAND_PREFIXES = ['/model','/key','/status','/skills','/graph','/clear','/help','/schedule','/update'];
1462
+ // Only these exact prefixes are built-in commands handled by handleCommand().
1463
+ // Everything else starting with '/' is a skill → routed to runTask().
1464
+ const COMMAND_PREFIXES = ['/model','/key','/status','/skills','/graph','/clear',
1465
+ '/help','/schedule','/update','/telegram'];
1414
1466
 
1415
1467
  async function executeInput(line) {
1416
- const isCmd = line.startsWith('/') || COMMAND_PREFIXES.some(c => line.startsWith(c));
1468
+ const isCmd = COMMAND_PREFIXES.some(c => line === c || line.startsWith(c + ' '));
1417
1469
  if (isCmd) {
1418
1470
  await handleCommand(line);
1419
1471
  } else {
1420
1472
  lastFailedTask = null;
1421
1473
  await runTask(line);
1422
1474
  }
1423
- // After this input completes, drain the queue
1424
1475
  await drainQueue();
1425
1476
  }
1426
1477
 
package/dist/daemon.mjs CHANGED
@@ -4765,12 +4765,18 @@ Current task:`;
4765
4765
  anthropicContext,
4766
4766
  enrichedReq.context?.system_context ? String(enrichedReq.context.system_context) : void 0
4767
4767
  ].filter(Boolean).join("\n\n") || void 0;
4768
+ const fullConfig = {
4769
+ cwd: this.cwd,
4770
+ agent_root: this.agentRoot,
4771
+ graph: this.graph,
4772
+ onMemoryWrite: this.onMemoryWritten
4773
+ };
4768
4774
  let agentResult;
4769
4775
  try {
4770
4776
  const { SelfHealLoop: SelfHealLoop2 } = await Promise.resolve().then(() => (init_SelfHealLoop(), SelfHealLoop_exports));
4771
4777
  const healLoop = new SelfHealLoop2(
4772
4778
  activeLLM,
4773
- { cwd: this.cwd, agent_root: this.agentRoot },
4779
+ fullConfig,
4774
4780
  (step) => this.addStep(sessionId, step),
4775
4781
  (token) => this.emit({ type: "session.token", session_id: sessionId, token })
4776
4782
  );
@@ -4827,7 +4833,37 @@ Current task:`;
4827
4833
  this.addStep(sessionId, `Commands run: ${agentResult.commands_run.length}`);
4828
4834
  }
4829
4835
  this.addStep(sessionId, `Done (${agentResult.tokens_used} tokens, ${agentResult.iterations} LLM turns)`);
4830
- this._extractAndPersistFacts(enrichedReq.task, agentResult.output, activeLLM).catch(() => {
4836
+ if (this.graph) {
4837
+ try {
4838
+ const nodeId = `memory:session_${sessionId.slice(0, 8)}`;
4839
+ const label = enrichedReq.task.slice(0, 80);
4840
+ const existing = this.graph.getNode(nodeId);
4841
+ const meta = {
4842
+ task: enrichedReq.task.slice(0, 300),
4843
+ output: agentResult.output.slice(0, 300),
4844
+ type: "session_summary",
4845
+ tokens: agentResult.tokens_used,
4846
+ saved_at: (/* @__PURE__ */ new Date()).toISOString()
4847
+ };
4848
+ if (existing) {
4849
+ this.graph.updateNode(nodeId, { label, metadata: meta });
4850
+ } else {
4851
+ this.graph.addNode(createNode({
4852
+ id: nodeId,
4853
+ graph_id: "root",
4854
+ label,
4855
+ type: "context" /* CONTEXT */,
4856
+ metadata: meta
4857
+ }));
4858
+ }
4859
+ console.log(`[0agent] Graph: wrote session summary node (${nodeId})`);
4860
+ this.onMemoryWritten?.();
4861
+ } catch (err) {
4862
+ console.warn("[0agent] Graph: baseline write failed:", err instanceof Error ? err.message : err);
4863
+ }
4864
+ }
4865
+ this._extractAndPersistFacts(enrichedReq.task, agentResult.output, activeLLM).catch((err) => {
4866
+ console.warn("[0agent] Memory extraction outer error:", err instanceof Error ? err.message : err);
4831
4867
  });
4832
4868
  this.completeSession(sessionId, {
4833
4869
  output: agentResult.output,
@@ -7323,13 +7359,18 @@ var ZeroAgentDaemon = class {
7323
7359
  adapter: this.adapter,
7324
7360
  agentRoot,
7325
7361
  // agent source path — self-improvement tasks read the right files
7326
- // Push to GitHub immediately when facts are extracted from a session
7362
+ // Push to GitHub immediately when facts are written to the graph
7327
7363
  onMemoryWritten: () => {
7328
7364
  this.githubMemorySync?.markDirty();
7329
7365
  if (this.githubMemorySync) {
7330
7366
  this.githubMemorySync.push("sync: new facts learned").then((r) => {
7331
- if (r.pushed) console.log(`[0agent] Memory pushed: ${r.nodes_synced} nodes \u2192 github`);
7332
- }).catch(() => {
7367
+ if (r.pushed) {
7368
+ console.log(`[0agent] Memory pushed: ${r.nodes_synced} nodes, ${r.edges_synced} edges \u2192 github`);
7369
+ } else if (r.error) {
7370
+ console.warn(`[0agent] Memory push failed: ${r.error}`);
7371
+ }
7372
+ }).catch((err) => {
7373
+ console.warn("[0agent] Memory push exception:", err instanceof Error ? err.message : err);
7333
7374
  });
7334
7375
  }
7335
7376
  }
@@ -7338,9 +7379,14 @@ var ZeroAgentDaemon = class {
7338
7379
  if (this.githubMemorySync) {
7339
7380
  const memSync = this.githubMemorySync;
7340
7381
  this.memorySyncTimer = setInterval(async () => {
7341
- const result = await memSync.push().catch(() => null);
7342
- if (result?.pushed && result.nodes_synced > 0) {
7343
- console.log(`[0agent] Memory synced: ${result.nodes_synced} nodes \u2192 github`);
7382
+ const result = await memSync.push().catch((err) => {
7383
+ console.warn("[0agent] Memory timer push failed:", err instanceof Error ? err.message : err);
7384
+ return null;
7385
+ });
7386
+ if (result?.pushed) {
7387
+ console.log(`[0agent] Memory sync: ${result.nodes_synced} nodes \u2192 github`);
7388
+ } else if (result?.error) {
7389
+ console.warn(`[0agent] Memory sync error: ${result.error}`);
7344
7390
  }
7345
7391
  }, 2 * 60 * 1e3);
7346
7392
  if (typeof this.memorySyncTimer === "object") this.memorySyncTimer.unref?.();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0agent",
3
- "version": "1.0.47",
3
+ "version": "1.0.49",
4
4
  "description": "A persistent, learning AI agent that runs on your machine. An agent that learns.",
5
5
  "private": false,
6
6
  "license": "Apache-2.0",