@krmxd/onegpt 0.2.4-beta → 0.2.5-fix-beta

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krmxd/onegpt",
3
- "version": "0.2.4-beta",
3
+ "version": "0.2.5-fix-beta",
4
4
  "description": "OGPT - AI coding assistant for the terminal with a built-in local engine",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/agent.js CHANGED
@@ -112,6 +112,8 @@ const TOOL_GUIDANCE = (
112
112
  "- Call tools ONLY as exact JSON: {\"name\": \"write_file\", \"arguments\": {...}}. " +
113
113
  "NEVER invent formats like 'name_file:path' or bare '<html>' dumps - those are NOT " +
114
114
  "tool calls, they will be ignored, and you must redo them properly.\n" +
115
+ "- To add files use write_file (or create_project to scaffold a starter folder). " +
116
+ "Never copy_path/move_path from folders you have not created yourself.\n" +
115
117
  "- To act, output plain JSON tool calls (never shell commands in code fences):\n" +
116
118
  '{"name": "write_file", "arguments": {"path": "widgets/gadget.py", ' +
117
119
  '"content": "print(\'hi\')"}}\n' +
@@ -210,6 +212,14 @@ function degenerateRepeat(text, minLen = 12, maxHits = 4) {
210
212
  counts.set(line, n);
211
213
  if (n >= maxHits) return line;
212
214
  }
215
+ // Single-line degeneration: models spam JSON fragments like
216
+ // '"name":"name":"create"...' inside ONE line - count key markers.
217
+ const flat = String(text || "");
218
+ for (const marker of ['"name"', '"arguments"', '{"name"']) {
219
+ let hits = 0, i = -1;
220
+ while ((i = flat.indexOf(marker, i + 1)) !== -1 && hits < maxHits + 1) hits++;
221
+ if (hits >= maxHits) return `...${marker} x${hits}`;
222
+ }
213
223
  return null;
214
224
  }
215
225
 
@@ -781,7 +791,8 @@ class Agent {
781
791
  // A tool-call blob typed as plain text must not scroll into the
782
792
  // chat as garbage - hold it back; the executor prints chips.
783
793
  const acc = contentParts.join("");
784
- if (!jsonHold && ((/^\s*\{/.test(acc) && acc.includes('"name"'))
794
+ const lead = acc.trim().toLowerCase();
795
+ if (!jsonHold && (((/^\s*[{"]/.test(acc) || /^json/.test(lead)) && acc.includes('"name"'))
785
796
  || (/^\s*```/.test(acc) && (acc.includes('"name"') || acc.includes('"arguments"'))))) {
786
797
  jsonHold = true;
787
798
  }
package/src/tools.js CHANGED
@@ -71,6 +71,9 @@ const TOOL_ALIASES = {
71
71
  removefile: "delete_path", remove_file: "delete_path", deletefile: "delete_path",
72
72
  delete_file: "delete_path", deletefolder: "delete_path", delete_folder: "delete_path",
73
73
  rmdir: "delete_path", unlink: "delete_path", trash: "delete_path",
74
+ createproject: "create_project", new_project: "create_project", newproject: "create_project",
75
+ scaffold_project: "create_project", scaffoldproject: "create_project",
76
+ create_app: "create_project", createapp: "create_project", build_project: "create_project",
74
77
  // file writing
75
78
  writefile: "write_file", filewrite: "write_file", createfile: "write_file",
76
79
  create_file: "write_file", newfile: "write_file", new_file: "write_file",
@@ -581,6 +584,14 @@ const TOOLS = [
581
584
  new ToolDef("delete_path", "Delete a file or folder (recursive)", {
582
585
  type: "object", properties: { path: { type: "string" } }, required: ["path"],
583
586
  }, true),
587
+ new ToolDef("create_project", "Scaffold a new project folder with starter files", {
588
+ type: "object",
589
+ properties: {
590
+ path: { type: "string" }, template: { type: "string",
591
+ description: "'web' (html/css/js) or 'flask' (python)" },
592
+ },
593
+ required: ["path"],
594
+ }, true),
584
595
  new ToolDef("edit_file", "Replace exact text in file", {
585
596
  type: "object",
586
597
  properties: {
@@ -891,6 +902,55 @@ const IMPLEMENTATIONS = {
891
902
  return new ToolResult(`Deleted ${kind}: ${p}`);
892
903
  },
893
904
 
905
+ create_project(args) {
906
+ const raw = String(args.path || args.name || "").trim();
907
+ if (!raw) return new ToolResult("", "Empty path", false);
908
+ const p = path.resolve(raw.replace(/^~(?=$|\/)/, os.homedir()));
909
+ const template = String(args.template || "web").toLowerCase();
910
+ if (fs.existsSync(p) && fs.readdirSync(p).length) {
911
+ return new ToolResult("", `Folder not empty: ${p} - pick a new project name.`, false);
912
+ }
913
+ fs.mkdirSync(p, { recursive: true });
914
+ const wf = (rel, content) => {
915
+ const f = path.join(p, rel);
916
+ fs.mkdirSync(path.dirname(f), { recursive: true });
917
+ fs.writeFileSync(f, content, "utf-8");
918
+ return rel;
919
+ };
920
+ const made = [];
921
+ const title = path.basename(p).replace(/[-_]/g, " ");
922
+ if (template === "flask") {
923
+ made.push(wf("app.py",
924
+ "from flask import Flask, render_template\n\n" +
925
+ "app = Flask(__name__)\n\n\n" +
926
+ "@app.route(\"/\")\n" +
927
+ "def index():\n" +
928
+ ` return render_template(\"index.html\", title=\"${title}\")\n\n\n` +
929
+ "if __name__ == \"__main__\":\n" +
930
+ " app.run(debug=True)\n"));
931
+ made.push(wf("requirements.txt", "flask\n"));
932
+ made.push(wf("templates/index.html",
933
+ "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n" +
934
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
935
+ ` <title>${title}</title>\n</head>\n<body>\n <h1>${title}</h1>\n` +
936
+ " {% block content %}{% endblock %}\n</body>\n</html>\n"));
937
+ made.push(wf("static/style.css", "/* Styles */\nbody { font-family: system-ui; }\n"));
938
+ } else {
939
+ // web / website / static starter
940
+ made.push(wf("index.html",
941
+ "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n" +
942
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
943
+ ` <title>${title}</title>\n <link rel=\"stylesheet\" href=\"styles.css\">\n` +
944
+ "</head>\n<body>\n <script src=\"script.js\" defer></script>\n</body>\n</html>\n"));
945
+ this.write_file({ path: path.join(p, "styles.css"), content: "" });
946
+ this.write_file({ path: path.join(p, "script.js"), content: "" });
947
+ made.push("styles.css (starter)", "script.js (starter)");
948
+ }
949
+ return new ToolResult(
950
+ `Created ${template} project '${path.basename(p)}' with: ` +
951
+ made.join(", ") + ". Extend these files with write_file/edit_file next.");
952
+ },
953
+
894
954
  edit_file(args) {
895
955
  const p = path.resolve(anchorPath(String(args.path)).replace(/^~(?=$|\/)/, os.homedir()));
896
956
  if (!fs.existsSync(p)) return new ToolResult("", `Not found: ${p}`, false);