@krmxd/onegpt 0.0.1-beta → 0.1.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.
- package/README.md +6 -0
- package/bin/ogpt.js +61 -2
- package/package.json +1 -1
- package/src/cli.js +51 -5
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ ogpt
|
|
|
24
24
|
git commit) - everything else just works
|
|
25
25
|
- Token dashboard with live tok/s charts at `http://127.0.0.1:8756` (`/dash`)
|
|
26
26
|
- Session history shared with the Python OGPT build (`/save`, `/load`, `/sessions`)
|
|
27
|
+
- resume where you left off: `ogpt --continue` (or `--session <id>`)
|
|
27
28
|
- Anti-sloth guardrails: tiny local models are kept on-task until every
|
|
28
29
|
requested file actually exists
|
|
29
30
|
|
|
@@ -37,5 +38,10 @@ ogpt
|
|
|
37
38
|
| `/auto` | toggle auto-approve |
|
|
38
39
|
| `/dash` | token dashboard |
|
|
39
40
|
| `/new` | fresh chat |
|
|
41
|
+
| `/export [md|json] [file]` | save the chat as Markdown or JSON |
|
|
42
|
+
| `/todos` | show the current todo list |
|
|
43
|
+
|
|
44
|
+
CLI flags: `ogpt -m <model>` · `-c/--continue` · `--session <id>` ·
|
|
45
|
+
`--auto` · `--no-stream`.
|
|
40
46
|
|
|
41
47
|
Config lives at `~/.config/ogpt/config.json`.
|
package/bin/ogpt.js
CHANGED
|
@@ -8,8 +8,30 @@ if (maj < 18) {
|
|
|
8
8
|
process.exit(1);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
let CLI, getConfig;
|
|
12
|
+
try {
|
|
13
|
+
({ CLI } = require("../src/cli"));
|
|
14
|
+
({ getConfig } = require("../src/config"));
|
|
15
|
+
} catch (e) {
|
|
16
|
+
console.error(`OGPT failed to start: ${e.message}`);
|
|
17
|
+
if (e.code === "MODULE_NOT_FOUND") {
|
|
18
|
+
console.error(`
|
|
19
|
+
The installation looks broken or out of date. Fix it with:
|
|
20
|
+
|
|
21
|
+
npm cache clean --force
|
|
22
|
+
npm i -g @krmxd/onegpt@latest --force
|
|
23
|
+
|
|
24
|
+
If you installed with 'npm link' and later moved or renamed the
|
|
25
|
+
source folder, re-link it:
|
|
26
|
+
|
|
27
|
+
cd <your-ogpt-repo>/nodejs && npm link
|
|
28
|
+
|
|
29
|
+
Or run straight from the repo without installing:
|
|
30
|
+
|
|
31
|
+
cd <your-ogpt-repo>/nodejs && node bin/ogpt.js`);
|
|
32
|
+
}
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
13
35
|
|
|
14
36
|
async function main() {
|
|
15
37
|
const args = process.argv.slice(2);
|
|
@@ -19,12 +41,18 @@ async function main() {
|
|
|
19
41
|
let prompt = [];
|
|
20
42
|
let noStream = false;
|
|
21
43
|
let autoApprove = false;
|
|
44
|
+
let continueLast = false;
|
|
45
|
+
let sessionId = "";
|
|
22
46
|
|
|
23
47
|
for (let i = 0; i < args.length; i++) {
|
|
24
48
|
if (args[i] === "--no-stream" || args[i] === "-s") {
|
|
25
49
|
noStream = true;
|
|
26
50
|
} else if (args[i] === "--auto") {
|
|
27
51
|
autoApprove = true;
|
|
52
|
+
} else if (args[i] === "--continue" || args[i] === "-c") {
|
|
53
|
+
continueLast = true;
|
|
54
|
+
} else if (args[i] === "--session") {
|
|
55
|
+
sessionId = args[++i] || "";
|
|
28
56
|
} else if (args[i] === "--model" || args[i] === "-m") {
|
|
29
57
|
const name = args[++i];
|
|
30
58
|
cfg.set("active_model", cfg.resolveModel(name));
|
|
@@ -37,6 +65,8 @@ async function main() {
|
|
|
37
65
|
Options:
|
|
38
66
|
-m, --model <oGPT-name|id> Override model (e.g. -m oGPT-2a)
|
|
39
67
|
-s, --no-stream Disable streaming
|
|
68
|
+
-c, --continue Resume your most recent chat
|
|
69
|
+
--session <id> Resume a specific session by ID
|
|
40
70
|
--auto Auto-approve all tools
|
|
41
71
|
-v, --version Show version
|
|
42
72
|
-h, --help Show help`);
|
|
@@ -53,6 +83,35 @@ Options:
|
|
|
53
83
|
if (autoApprove) {
|
|
54
84
|
cli.tools._autoApprove = true;
|
|
55
85
|
}
|
|
86
|
+
if (sessionId || continueLast) {
|
|
87
|
+
const fsMod = require("fs"), osMod = require("os"), pathMod = require("path");
|
|
88
|
+
const dir = pathMod.join(osMod.homedir(), ".config", "ogpt", "sessions");
|
|
89
|
+
let sid = sessionId;
|
|
90
|
+
if (!sid) {
|
|
91
|
+
try {
|
|
92
|
+
sid = fsMod.readdirSync(dir).filter((f) => f.endsWith(".meta.json"))
|
|
93
|
+
.map((f) => { try { return JSON.parse(fsMod.readFileSync(pathMod.join(dir, f), "utf-8")); } catch { return null; } })
|
|
94
|
+
.filter((m) => m && (m.msgs || 0) > 0)
|
|
95
|
+
.sort((a, b) => (b.updated || 0) - (a.updated || 0))[0]?.id || "";
|
|
96
|
+
} catch {}
|
|
97
|
+
}
|
|
98
|
+
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
99
|
+
let data = null;
|
|
100
|
+
if (sid) {
|
|
101
|
+
try { data = JSON.parse(fsMod.readFileSync(pathMod.join(dir, `${sid}.json`), "utf-8")); } catch {}
|
|
102
|
+
}
|
|
103
|
+
if (Array.isArray(data) && data.length) {
|
|
104
|
+
cli.agent.history = data.map((d) => ({
|
|
105
|
+
role: d.role || "user", content: d.content || "", ts: Date.now() / 1000 }));
|
|
106
|
+
cli._sessionId = sid;
|
|
107
|
+
console.log(dim(continueLast && !sessionId
|
|
108
|
+
? `Continued last chat: ${sid}` : `Resumed session: ${sid}`));
|
|
109
|
+
} else if (sessionId) {
|
|
110
|
+
console.error(`Session not found: ${sessionId}`);
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
56
115
|
|
|
57
116
|
if (prompt.length) {
|
|
58
117
|
await cli.runSingle(prompt.join(" "));
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -284,6 +284,10 @@ class CLI {
|
|
|
284
284
|
"List plugins", "/plugins", "system", true));
|
|
285
285
|
reg(new Command("/mcp", () => this.info("No MCP servers configured."),
|
|
286
286
|
"List MCP servers", "/mcp", "system", true));
|
|
287
|
+
reg(new Command("/export", (a) => this.cmdExport(a),
|
|
288
|
+
"Export the chat as Markdown or JSON", "/export [md|json] [file]", "general"));
|
|
289
|
+
reg(new Command("/todos", () => this.cmdTodos(),
|
|
290
|
+
"Show the current todo list", "/todos", "tools", true));
|
|
287
291
|
|
|
288
292
|
reg(new Command("/tools", () => this.cmdTools(), "List available tools", "/tools", "tools", true));
|
|
289
293
|
reg(new Command("/approve", (a) => { this.print(this.tools.toggleApprove(a[0] || "")); }, "Auto-approve a specific tool", "/approve <tool>", "tools"));
|
|
@@ -683,8 +687,46 @@ class CLI {
|
|
|
683
687
|
this.print(`## Project Structure\n\`\`\`\n${lines.join("\n")}\n\`\`\``);
|
|
684
688
|
}
|
|
685
689
|
|
|
686
|
-
|
|
687
|
-
const
|
|
690
|
+
cmdExport(args) {
|
|
691
|
+
const fmt = args && args[0] === "json" ? "json" : "md";
|
|
692
|
+
const file = (args && args[1]) ||
|
|
693
|
+
`ogpt-chat-${new Date().toISOString().slice(0, 19).replace(/[:T]/g, "-")}.${fmt}`;
|
|
694
|
+
try {
|
|
695
|
+
const msgs = this.agent.history.filter((m) => m.role !== "tool" &&
|
|
696
|
+
!String(m.content || "").startsWith("[Conversation summary]"));
|
|
697
|
+
if (!msgs.length) { this.info("Nothing to export - no conversation yet."); return; }
|
|
698
|
+
let body;
|
|
699
|
+
if (fmt === "json") {
|
|
700
|
+
body = JSON.stringify({ exported: new Date().toISOString(),
|
|
701
|
+
model: this.cfg.displayName(), messages: msgs }, null, 2);
|
|
702
|
+
} else {
|
|
703
|
+
body = `# OGPT chat export\n\n_${new Date().toLocaleString()} · ${this.cfg.displayName()} · ${msgs.length} messages_\n\n`
|
|
704
|
+
+ msgs.map((m) => `## ${m.role === "user" ? "You" : this.cfg.displayName()}\n\n${m.content}\n`).join("\n");
|
|
705
|
+
}
|
|
706
|
+
fs.writeFileSync(file, body);
|
|
707
|
+
this.success(`Exported ${msgs.length} messages to ${file}`);
|
|
708
|
+
} catch (e) {
|
|
709
|
+
this.error(`Export failed: ${e.message}`);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
_todosFile() {
|
|
714
|
+
return path.join(os.homedir(), ".config", "ogpt", "todos.json");
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
cmdTodos() {
|
|
718
|
+
let todos = [];
|
|
719
|
+
try {
|
|
720
|
+
const data = JSON.parse(fs.readFileSync(this._todosFile(), "utf-8"));
|
|
721
|
+
todos = Array.isArray(data) ? data : data.todos || [];
|
|
722
|
+
} catch {}
|
|
723
|
+
if (!todos.length) { this.info("No todos."); return; }
|
|
724
|
+
const rows = todos.map((t, i) =>
|
|
725
|
+
[String(i + 1), t.done ? "[x]" : "[ ]", String(t.text || "")]);
|
|
726
|
+
this._table("Todos", ["#", "Done", "Task"], rows);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
cmdSession(args) { const sub = (args && args[0]) || "list";
|
|
688
730
|
if (sub === "list") return this.cmdSessions();
|
|
689
731
|
if (sub === "save") return this.cmdSave();
|
|
690
732
|
if (sub === "new" || sub === "fresh") return this.cmdNew(args.slice(1));
|
|
@@ -716,12 +758,16 @@ class CLI {
|
|
|
716
758
|
const metaPath = path.join(dir, `${this._sessionId}.meta.json`);
|
|
717
759
|
try { meta = JSON.parse(fs.readFileSync(metaPath, "utf-8")); } catch {}
|
|
718
760
|
if (!meta.id) {
|
|
719
|
-
meta = { id: this._sessionId,
|
|
720
|
-
title: `Session ${new Date().toISOString().slice(0, 16).replace("T", " ")}`,
|
|
721
|
-
created: Date.now() / 1000, ...meta };
|
|
761
|
+
meta = { id: this._sessionId, title: "", created: Date.now() / 1000, ...meta };
|
|
722
762
|
}
|
|
723
763
|
meta.updated = Date.now() / 1000;
|
|
724
764
|
meta.msgs = data.length;
|
|
765
|
+
// Auto-title from the first real user message (same rule as Python).
|
|
766
|
+
const existing = (meta.title || "").trim();
|
|
767
|
+
if (!existing || existing.startsWith("Session ")) {
|
|
768
|
+
const first = data.find((m) => m.role === "user" && String(m.content || "").trim());
|
|
769
|
+
if (first) meta.title = String(first.content).trim().slice(0, 50);
|
|
770
|
+
}
|
|
725
771
|
fs.writeFileSync(metaPath, JSON.stringify(meta));
|
|
726
772
|
return this._sessionId;
|
|
727
773
|
} catch {
|