mythos-code 1.0.0 → 1.2.0

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 (2) hide show
  1. package/bin/mythos.js +70 -16
  2. package/package.json +1 -1
package/bin/mythos.js CHANGED
@@ -4,7 +4,7 @@ import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import os from "node:os";
6
6
  import readline from "node:readline";
7
- import { execSync } from "node:child_process";
7
+ import { exec } from "node:child_process";
8
8
 
9
9
  const API = process.env.MYTHOS_API_URL || "https://rdxaqiacoitzeowehdts.supabase.co/functions/v1/v1-messages";
10
10
  const CFG = path.join(os.homedir(), ".mythos-code.json");
@@ -31,26 +31,75 @@ async function login() {
31
31
  cfg.key = k; save(cfg); console.log(C.g + "✓ Gespeichert in " + CFG + C.x);
32
32
  }
33
33
 
34
- async function call(messages) {
35
- const r = await fetch(API, {
36
- method: "POST",
37
- headers: { "content-type": "application/json", "x-api-key": cfg.key, "anthropic-version": "2023-06-01" },
38
- body: JSON.stringify({ model: cfg.model || "mythos-code", max_tokens: 8000, system: SYSTEM, messages }),
39
- });
40
- const j = await r.json().catch(() => ({}));
41
- if (!r.ok) throw new Error(j?.error?.message || ("HTTP " + r.status));
42
- return (j.content || []).map((p) => p.text || "").join("");
34
+ const fmt = (ms) => { const s = Math.floor(ms / 1000); return (s >= 60 ? Math.floor(s / 60) + "m " : "") + (s % 60) + "s"; };
35
+
36
+ // Live-Timer: läuft während der ganzen Aufgabe (auch während Befehle laufen), pausiert nur für Rückfragen.
37
+ let T0 = 0, tick = null;
38
+ const clearLine = () => process.stdout.write("\r\x1b[K");
39
+ const startTick = () => { if (tick) return; tick = setInterval(() => process.stdout.write("\r" + C.d + "⏳ Mythos arbeitet… " + fmt(Date.now() - T0) + C.x + " "), 250); };
40
+ const stopTick = () => { if (tick) { clearInterval(tick); tick = null; } clearLine(); };
41
+ const say = (s) => { const was = !!tick; stopTick(); console.log(s); if (was) startTick(); };
42
+
43
+ // Verlauf kürzen, damit lange Aufgaben nicht an zu großem Kontext scheitern. level 0 = mild, 2 = stark.
44
+ const shorten = (s, max) => s.length <= max ? s : s.slice(0, Math.floor(max * 0.7)) + "\n…[gekürzt]…\n" + s.slice(s.length - Math.floor(max * 0.3));
45
+ function compact(history, level) {
46
+ const keep = [6, 8, 4][level], recentMax = [20000, 3000, 1500][level], oldMax = [1500, 800, 400][level];
47
+ const cut = Math.max(0, history.length - keep);
48
+ const older = level === 0 ? history.slice(0, cut) : history.slice(0, Math.min(1, cut));
49
+ return older.map((m) => ({ role: m.role, content: shorten(m.content, oldMax) }))
50
+ .concat(history.slice(cut).map((m) => ({ role: m.role, content: shorten(m.content, recentMax) })));
51
+ }
52
+
53
+ async function once(messages) {
54
+ const ctl = new AbortController(); const to = setTimeout(() => ctl.abort(), 170000);
55
+ try {
56
+ const r = await fetch(API, {
57
+ method: "POST", signal: ctl.signal,
58
+ headers: { "content-type": "application/json", "x-api-key": cfg.key, "anthropic-version": "2023-06-01" },
59
+ body: JSON.stringify({ model: cfg.model || "mythos-code", max_tokens: 8000, system: SYSTEM, messages, stream: true }),
60
+ });
61
+ if (!r.ok) { const j = await r.json().catch(() => ({})); const e = new Error(j?.error?.message || ("HTTP " + r.status)); e.status = r.status; throw e; }
62
+ const reader = r.body.getReader(); const dec = new TextDecoder(); let buf = "", out = "";
63
+ while (true) {
64
+ const { done, value } = await reader.read(); if (done) break;
65
+ buf += dec.decode(value, { stream: true });
66
+ let i; while ((i = buf.indexOf("\n")) !== -1) {
67
+ const line = buf.slice(0, i).trim(); buf = buf.slice(i + 1);
68
+ if (!line.startsWith("data:")) continue;
69
+ let p; try { p = JSON.parse(line.slice(5)); } catch { continue; }
70
+ if (p.type === "error") { const e = new Error(p.error?.message || "Überlastet"); e.status = 529; throw e; }
71
+ if (p.delta?.text) out += p.delta.text;
72
+ }
73
+ }
74
+ if (!out.trim()) throw new Error("Leere Antwort");
75
+ return out;
76
+ } finally { clearTimeout(to); }
77
+ }
78
+
79
+ async function call(history) {
80
+ for (let a = 0; a < 6; a++) {
81
+ try { return await once(compact(history, Math.min(2, Math.floor(a / 2)))); }
82
+ catch (e) {
83
+ if (e.status === 401) throw new Error("API-Key ungültig – bitte neu anmelden: mythos login");
84
+ if (/Daily limit/i.test(e.message)) throw new Error("Tageslimit erreicht – mit Pro unbegrenzt.");
85
+ await new Promise((r) => setTimeout(r, Math.min(8000, 1500 * (a + 1))));
86
+ }
87
+ }
88
+ throw new Error("Mythos ist gerade nicht erreichbar – bitte gleich nochmal versuchen.");
43
89
  }
44
90
 
45
91
  async function runTool(t) {
46
92
  const show = t.name === "write" ? `write ${t.path} (${(t.content || "").length} Zeichen)` : `${t.name} ${t.cmd || t.path || ""}`;
47
- console.log(C.y + "⚙ " + show + C.x);
93
+ say(C.y + "⚙ " + show + C.x);
48
94
  if ((t.name === "run" || t.name === "write") && !autoYes) {
95
+ stopTick();
49
96
  const a = (await ask(C.d + " Erlauben? [j/N/a=immer] " + C.x)).trim().toLowerCase();
97
+ startTick();
50
98
  if (a === "a") autoYes = true; else if (a !== "j" && a !== "y") return "Vom Nutzer abgelehnt.";
51
99
  }
52
100
  try {
53
- if (t.name === "run") return execSync(t.cmd, { encoding: "utf8", stdio: "pipe", timeout: 120000, maxBuffer: 1e7 }).slice(-8000) || "(keine Ausgabe)";
101
+ if (t.name === "run") return await new Promise((res) => exec(t.cmd, { encoding: "utf8", timeout: 180000, maxBuffer: 1e7 },
102
+ (err, so, se) => res(((so || "") + (se || "") + (err ? "\nExit: " + (err.code ?? err.message) : "")).slice(-8000) || "(keine Ausgabe)")));
54
103
  if (t.name === "read") return fs.readFileSync(t.path, "utf8").slice(0, 20000);
55
104
  if (t.name === "write") { fs.mkdirSync(path.dirname(path.resolve(t.path)), { recursive: true }); fs.writeFileSync(t.path, t.content ?? ""); return "OK geschrieben: " + t.path; }
56
105
  if (t.name === "ls") return fs.readdirSync(t.path || ".", { withFileTypes: true }).map((e) => (e.isDirectory() ? "📁 " : " ") + e.name).join("\n");
@@ -59,14 +108,19 @@ async function runTool(t) {
59
108
  }
60
109
 
61
110
  async function turn(history, input) {
111
+ T0 = Date.now(); startTick();
112
+ try { await turnInner(history, input); }
113
+ catch (e) { say(C.r + "⚠ " + e.message + C.x); }
114
+ finally { stopTick(); console.log(C.g + "✓ Mythos hat " + fmt(Date.now() - T0) + " gearbeitet" + C.x + "\n"); }
115
+ }
116
+ async function turnInner(history, input) {
62
117
  history.push({ role: "user", content: input });
63
- for (let i = 0; i < 25; i++) {
64
- process.stdout.write(C.d + "… denkt" + C.x + "\r");
118
+ for (let i = 0; i < 40; i++) {
65
119
  const out = await call(history);
66
120
  history.push({ role: "assistant", content: out });
67
121
  const m = out.match(/<tool>([\s\S]*?)<\/tool>/);
68
122
  const text = out.replace(/<tool>[\s\S]*?<\/tool>/g, "").trim();
69
- if (text) console.log(C.b + "Mythos: " + C.x + text + "\n");
123
+ if (text) say(C.b + "Mythos: " + C.x + text + "\n");
70
124
  if (!m) return;
71
125
  let t; try { t = JSON.parse(m[1]); } catch { history.push({ role: "user", content: "Tool-JSON ungültig." }); continue; }
72
126
  const res = await runTool(t);
@@ -87,7 +141,7 @@ async function main() {
87
141
  if (!q) continue;
88
142
  if (q === "/exit") break;
89
143
  if (q === "/clear") { history.length = 0; console.log("Verlauf geleert."); continue; }
90
- try { await turn(history, q); } catch (e) { console.log(C.r + "Fehler: " + e.message + C.x); }
144
+ await turn(history, q);
91
145
  }
92
146
  rl.close();
93
147
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mythos-code",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Mythos Code – KI-Coding-Agent im Terminal (by Mythoscraft)",
5
5
  "bin": {
6
6
  "mythos": "bin/mythos.js",