naisys 1.3.1 → 1.4.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 CHANGED
@@ -75,6 +75,10 @@ dreamModel: claude3opus
75
75
  # defaults to the shellModel if omitted
76
76
  webModel: gemini-pro
77
77
 
78
+ # The model used by the 'genimg' command. If not defined then the genimg command is not available to the LLM
79
+ # Valid values: dalle2-256, dalle2-512, dalle2-1024, dalle3-1024, dalle3-1024-HD
80
+ imageModel: dalle3-1024
81
+
78
82
  # A system like prompt explaining the agent's role and responsibilities
79
83
  # You can use config variables in this string
80
84
  agentPrompt: |
@@ -161,10 +165,11 @@ initialCommands:
161
165
  - `comment "<note>"` - The LLM is directed to use this for 'thinking out loud' which avoids 'invalid command' errors
162
166
  - `endsession "<note>"` - Clear the context and start a new session.
163
167
  - The LLM is directed to track it's context size and to end the session with a note before running over the context limit
164
- - `pause <seconds>` - Can be used by the debug agent or the LLM to pause execution indefinitely, or until a new message is received from another agent, or for a set number of seconds
168
+ - `pause <seconds>` - Can be used by the debug agent or the LLM to pause execution for a set number of seconds
165
169
  - NAISYS apps
166
170
  - `llmail` - A context friendly 'mail system' used for agent to agent communication
167
171
  - `llmynx` - A context friendly wrapping on the lynx browser that can use a separate LLM to reduce the size of a large webpage into something that can fit into the LLM's context
172
+ - `genimg "<description>" <filepath>` - Generates an image with the given description, save at the specified path
168
173
 
169
174
  ## Running NAISYS from Source
170
175
 
@@ -188,3 +193,11 @@ initialCommands:
188
193
  - If you want to use NAISYS for a website
189
194
  - Install a local web server, for example [XAMPP](https://www.apachefriends.org/) on Windows
190
195
  - Start the server and put the URL in the `.env` file
196
+
197
+ ## Changelog
198
+
199
+ - 1.4: `genimg` command for generating images
200
+ - 1.3: Post-session 'dreaming' as well as a mail 'blackout' period
201
+ - 1.2: Created stand-in shell commands for custom Naisys commands
202
+ - 1.1: Added command protection settings to prevent unwanted writes
203
+ - 1.0: Initial release
package/bin/genimg ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ echo "'genimg' cannot be used with other commands on the same prompt."
package/bin/naisys CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
 
3
- # Make sure to enable this script for execution with `chmod +x runteam.sh`
3
+ # Make sure to enable this script for execution with `chmod +x naisys`
4
4
 
5
5
  # Check if an argument is provided
6
6
  if [ $# -eq 0 ]; then
@@ -0,0 +1,97 @@
1
+ import * as fs from "fs";
2
+ import OpenAI from "openai";
3
+ import path from "path";
4
+ import sharp from "sharp";
5
+ import * as config from "../config.js";
6
+ import * as costTracker from "../llm/costTracker.js";
7
+ import * as output from "../utils/output.js";
8
+ import { unixToHostPath } from "../utils/utilities.js";
9
+ /** genimg "<description>" <filepath>: Generate an image with the description and save it to the file path */
10
+ export async function handleCommand(args) {
11
+ // genimg sholdn't even be presented as an available command unless it is defined in the config
12
+ if (!config.agent.imageModel) {
13
+ throw "Agent config: Error, 'imageModel' is not defined";
14
+ }
15
+ const description = args.split('"')[1].trim();
16
+ const filepath = args.split('"')[2].trim();
17
+ if (!description) {
18
+ throw "Error: Description is required";
19
+ }
20
+ if (!filepath) {
21
+ throw "Error: Filepath is required";
22
+ }
23
+ // Check directory exists
24
+ const hostpath = unixToHostPath(filepath);
25
+ const dirname = path.dirname(hostpath);
26
+ if (!fs.existsSync(dirname)) {
27
+ throw `Error: Directory does not exist`;
28
+ }
29
+ output.comment(`Generating image with ${config.agent.imageModel}...`);
30
+ const openai = new OpenAI();
31
+ const model = getImageModel(config.agent.imageModel);
32
+ const response = await openai.images.generate({
33
+ prompt: description,
34
+ model: model.name,
35
+ size: model.size,
36
+ quality: model.quality,
37
+ response_format: "b64_json",
38
+ });
39
+ // save to filepath
40
+ const base64Image = response.data[0].b64_json;
41
+ if (!base64Image) {
42
+ throw 'Error: "b64_json" not found in response';
43
+ }
44
+ // Convert the base64 string to a buffer
45
+ const imageBuffer = Buffer.from(base64Image, "base64");
46
+ // Use sharp to convert the buffer and save it as a JPG file
47
+ //const currentPath = unixToHostPath(await shellWrapper.getCurrentPath());
48
+ //const filepath = path.join(currentPath, filename);
49
+ const fileExtension = path.extname(filepath).substring(1);
50
+ await sharp(imageBuffer)
51
+ .toFormat(fileExtension)
52
+ .toFile(hostpath);
53
+ // Record the cost
54
+ await costTracker.recordCost(model.cost, "genimg", model.name);
55
+ return "Image generated and saved to " + filepath;
56
+ }
57
+ const imageModels = [
58
+ {
59
+ key: "dalle3-1024-HD",
60
+ name: "dall-e-3",
61
+ size: "1024x1024",
62
+ quality: "hd",
63
+ cost: 0.08,
64
+ },
65
+ {
66
+ key: "dalle3-1024",
67
+ name: "dall-e-3",
68
+ size: "1024x1024",
69
+ cost: 0.04,
70
+ },
71
+ {
72
+ key: "dalle2-1024",
73
+ name: "dall-e-2",
74
+ size: "1024x1024",
75
+ cost: 0.02,
76
+ },
77
+ {
78
+ key: "dalle2-512",
79
+ name: "dall-e-2",
80
+ size: "512x512",
81
+ cost: 0.018,
82
+ },
83
+ {
84
+ key: "dalle2-256",
85
+ name: "dall-e-2",
86
+ size: "256x256",
87
+ cost: 0.016,
88
+ },
89
+ ];
90
+ function getImageModel(key) {
91
+ const model = imageModels.find((m) => m.key === key);
92
+ if (!model) {
93
+ throw `Error, image model not found: ${key}`;
94
+ }
95
+ return model;
96
+ }
97
+ //# sourceMappingURL=genimg.js.map
@@ -3,8 +3,8 @@ import table from "text-table";
3
3
  import * as config from "../config.js";
4
4
  import * as dbUtils from "../utils/dbUtils.js";
5
5
  import * as utilities from "../utils/utilities.js";
6
- import { naisysToHostPath } from "../utils/utilities.js";
7
- const _dbFilePath = naisysToHostPath(`${config.naisysFolder}/lib/llmail.db`);
6
+ import { unixToHostPath } from "../utils/utilities.js";
7
+ const _dbFilePath = unixToHostPath(`${config.naisysFolder}/lib/llmail.db`);
8
8
  let _myUserId = -1;
9
9
  /** Threading is not currently used so this doesn't matter */
10
10
  const _threadTokenMax = config.mailMessageTokenMax * 5;
@@ -1,4 +1,5 @@
1
1
  import chalk from "chalk";
2
+ import * as genimg from "../apps/genimg.js";
2
3
  import * as llmail from "../apps/llmail.js";
3
4
  import * as llmynx from "../apps/llmynx.js";
4
5
  import * as config from "../config.js";
@@ -125,6 +126,11 @@ export async function processCommand(prompt, consoleInput) {
125
126
  }
126
127
  break;
127
128
  }
129
+ case "genimg": {
130
+ const genimgResponse = await genimg.handleCommand(cmdArgs);
131
+ await contextManager.append(genimgResponse);
132
+ break;
133
+ }
128
134
  case "context":
129
135
  contextManager.printContext();
130
136
  break;
@@ -199,7 +205,8 @@ async function splitMultipleInputCommands(nextInput) {
199
205
  }
200
206
  }
201
207
  // If the LLM forgets the quote on the comment, treat it as a single line comment
202
- else if (newLinePos > 0 && nextInput.startsWith("comment ")) {
208
+ else if (newLinePos > 0 &&
209
+ (nextInput.startsWith("comment ") || nextInput.startsWith("genimg "))) {
203
210
  input = nextInput.slice(0, newLinePos);
204
211
  nextInput = nextInput.slice(newLinePos).trim();
205
212
  }
@@ -47,6 +47,9 @@ export async function handleCommand(input) {
47
47
  if (outputLimitExceeded) {
48
48
  await contextManager.append(`\nThe shell command generated too much output (${tokenCount} tokens). Only 2,000 tokens worth are shown above.`);
49
49
  }
50
+ if (text.endsWith(": command not found")) {
51
+ await contextManager.append("Please enter a valid Linux or NAISYS command after the prompt. Use the 'comment' command for thoughts.");
52
+ }
50
53
  }
51
54
  response.hasErrors = output.hasErrors;
52
55
  return response;
@@ -3,7 +3,7 @@ import * as fs from "fs";
3
3
  import * as os from "os";
4
4
  import * as config from "../config.js";
5
5
  import * as output from "../utils/output.js";
6
- import { naisysToHostPath } from "../utils/utilities.js";
6
+ import { unixToHostPath } from "../utils/utilities.js";
7
7
  var ShellEvent;
8
8
  (function (ShellEvent) {
9
9
  ShellEvent["Ouptput"] = "stdout";
@@ -57,13 +57,13 @@ function errorIfNotEmpty(response) {
57
57
  output.error(response.value);
58
58
  }
59
59
  }
60
- export function processOutput(dataStr, eventType) {
60
+ function processOutput(dataStr, eventType) {
61
61
  if (!_resolveCurrentCommand) {
62
62
  output.comment(eventType + " without handler: " + dataStr);
63
63
  return;
64
64
  }
65
65
  if (eventType === ShellEvent.Exit) {
66
- output.error("SHELL EXITED. PID: " + (_process === null || _process === void 0 ? void 0 : _process.pid) + " CODE: " + dataStr);
66
+ output.error("SHELL EXITED. PID: " + _process?.pid + " CODE: " + dataStr);
67
67
  }
68
68
  else {
69
69
  //_log += "OUTPUT: " + dataStr;
@@ -127,7 +127,7 @@ export async function executeCommand(command) {
127
127
  _resolveCurrentCommand = resolve;
128
128
  const commandWithDelimiter = `${command.trim()}\necho "${_commandDelimiter} LINE:\${LINENO}"\n`;
129
129
  //_log += "INPUT: " + commandWithDelimiter;
130
- _process === null || _process === void 0 ? void 0 : _process.stdin.write(commandWithDelimiter);
130
+ _process?.stdin.write(commandWithDelimiter);
131
131
  // If no response, kill and reset the shell, often hanging on some unescaped input
132
132
  _currentCommandTimeout = setTimeout(resetShell, config.shellCommmandTimeoutSeconds * 1000);
133
133
  });
@@ -136,8 +136,8 @@ function resetShell() {
136
136
  if (!_resolveCurrentCommand) {
137
137
  return;
138
138
  }
139
- _process === null || _process === void 0 ? void 0 : _process.kill();
140
- output.error("SHELL TIMEMOUT/KILLED. PID: " + (_process === null || _process === void 0 ? void 0 : _process.pid));
139
+ _process?.kill();
140
+ output.error("SHELL TIMEMOUT/KILLED. PID: " + _process?.pid);
141
141
  const outputWithError = _commandOutput.trim() +
142
142
  `\nError: Command timed out after ${config.shellCommmandTimeoutSeconds} seconds.`;
143
143
  resetProcess();
@@ -163,7 +163,7 @@ function resetCommand() {
163
163
  }
164
164
  function resetProcess() {
165
165
  resetCommand();
166
- _process === null || _process === void 0 ? void 0 : _process.removeAllListeners();
166
+ _process?.removeAllListeners();
167
167
  _process = undefined;
168
168
  }
169
169
  /** Wraps multi line commands in a script to make it easier to diagnose the source of errors based on line number
@@ -176,7 +176,7 @@ set -e
176
176
  cd ${_currentPath}
177
177
  ${command.trim()}`;
178
178
  // create/writewrite file
179
- fs.writeFileSync(naisysToHostPath(scriptPath), scriptContent);
179
+ fs.writeFileSync(unixToHostPath(scriptPath), scriptContent);
180
180
  // `Path` is set to the ./bin folder because custom NAISYS commands that follow shell commands will be handled by the shell, which will fail
181
181
  // so we need to remind the LLM that 'naisys commands cannot be used with other commands on the same prompt'
182
182
  // `source` will run the script in the current shell, so any change directories in the script will persist in the current shell
package/dist/config.js CHANGED
@@ -1,18 +1,21 @@
1
1
  import { program } from "commander";
2
2
  import dotenv from "dotenv";
3
3
  import * as fs from "fs";
4
+ import { readFile } from "fs/promises";
4
5
  import yaml from "js-yaml";
6
+ import path from "path";
7
+ import { fileURLToPath } from "url";
5
8
  import { CommandProtection } from "./utils/enums.js";
6
- import { valueFromString } from "./utils/utilities.js";
9
+ import { hostToUnixPath, valueFromString } from "./utils/utilities.js";
7
10
  program.argument("<agent-path>", "Path to agent configuration file").parse();
8
11
  dotenv.config();
9
12
  /** The system name that shows after the @ in the command prompt */
10
13
  export const hostname = "naisys";
11
14
  /** Limits the size of files that can be read/wrote */
12
- export const shellOutputTokenMax = 2500; //
15
+ export const shellOutputTokenMax = 3000; //
13
16
  /** The number of seconds NAISYS will wait for a shell command to complete */
14
17
  export const shellCommmandTimeoutSeconds = 15;
15
- export const webTokenMax = 2500;
18
+ export const webTokenMax = 3000;
16
19
  export const mailMessageTokenMax = 400;
17
20
  /** Used to prevent the agent from constantly responding to mail and not getting any work done */
18
21
  export const mailBlackoutCycles = 3;
@@ -26,8 +29,9 @@ export const googleApiKey = getEnv("GOOGLE_API_KEY");
26
29
  export const anthropicApiKey = getEnv("ANTHROPIC_API_KEY");
27
30
  export const agent = loadAgentConfig();
28
31
  function loadAgentConfig() {
29
- const agentPath = program.args[0];
30
- const config = yaml.load(fs.readFileSync(agentPath, "utf8"));
32
+ const config = yaml.load(fs.readFileSync(program.args[0], "utf8"));
33
+ config.path = hostToUnixPath(path.resolve(program.args[0]));
34
+ config.directory = config.path.substring(0, config.path.lastIndexOf("/"));
31
35
  // throw if any property is undefined
32
36
  for (const key of [
33
37
  "username",
@@ -69,11 +73,14 @@ export const binPath = getBinPath();
69
73
  * otherwise need to rip it from the package ourselves relative to where this file is located */
70
74
  async function getVersion() {
71
75
  try {
72
- const packageJsonPath = new URL("../package.json", import.meta.url);
73
- const packageJson = await import(packageJsonPath.href, {
74
- assert: { type: "json" },
75
- });
76
- return packageJson.default.version;
76
+ /* Removed for compatibility with https://bundlephobia.com/package/naisys
77
+ const packageJson = await import(packageJsonUrl.href, {
78
+ assert: { type: "json" },
79
+ });*/
80
+ const packageJsonUrl = new URL("../package.json", import.meta.url);
81
+ const packageJsonPath = fileURLToPath(packageJsonUrl);
82
+ const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
83
+ return packageJson.version;
77
84
  }
78
85
  catch (e) {
79
86
  return "0.1";
@@ -18,6 +18,11 @@ export function getSystemMessage() {
18
18
  if (_cachedSystemMessage) {
19
19
  return _cachedSystemMessage;
20
20
  }
21
+ let genImgCmd = "";
22
+ if (config.agent.imageModel) {
23
+ genImgCmd = `
24
+ genimg "<description>" <filepath>: Generate an image with the description and save it to the given filename`;
25
+ }
21
26
  // Fill out the templates in the agent prompt and stick it to the front of the system message
22
27
  // A lot of the stipulations in here are to prevent common LLM mistakes
23
28
  // Like we can't jump between standard and special commands in a single prompt, which the LLM will try to do if not warned
@@ -31,6 +36,7 @@ Don't try to guess the output of commands. Don't put commands in \`\`\` blocks.
31
36
  For example when you run 'cat' or 'ls', don't write what you think the output will be. Let the system do that.
32
37
  Your role is that of the user. The system will provide responses and next command prompt. Don't output your own command prompt.
33
38
  Be careful when writing files through the command prompt with cat. Make sure to close and escape quotes properly.
39
+ Don't blindly overwrite existing files without reading them first.
34
40
 
35
41
  NAISYS ${config.packageVersion} Shell
36
42
  Welcome back ${config.agent.username}!
@@ -43,7 +49,7 @@ LINUX Commands:
43
49
  Do not input notes after the prompt. Only valid commands.
44
50
  NAISYS Commands: (cannot be used with other commands on the same prompt)
45
51
  llmail: A local mail system for communicating with your team
46
- llmynx: A context optimized web browser. Enter 'llmynx help' to learn how to use it
52
+ llmynx: A context optimized web browser. Enter 'llmynx help' to learn how to use it${genImgCmd}
47
53
  comment "<thought>": Any non-command output like thinking out loud, prefix with the 'comment' command
48
54
  pause <seconds>: Pause for <seconds>
49
55
  endsession "<note>": Ends this session, clears the console log and context.
@@ -1,7 +1,7 @@
1
1
  import * as config from "../config.js";
2
2
  import * as dbUtils from "../utils/dbUtils.js";
3
- import { naisysToHostPath } from "../utils/utilities.js";
4
- const _dbFilePath = naisysToHostPath(`${config.naisysFolder}/lib/costs.db`);
3
+ import { unixToHostPath } from "../utils/utilities.js";
4
+ const _dbFilePath = unixToHostPath(`${config.naisysFolder}/lib/costs.db`);
5
5
  await init();
6
6
  async function init() {
7
7
  const newDbCreated = await dbUtils.initDatabase(_dbFilePath);
@@ -1,11 +1,11 @@
1
1
  import * as config from "../config.js";
2
2
  import * as dbUtils from "../utils/dbUtils.js";
3
3
  import * as output from "../utils/output.js";
4
- import { naisysToHostPath } from "../utils/utilities.js";
4
+ import { unixToHostPath } from "../utils/utilities.js";
5
5
  import * as contextManager from "./contextManager.js";
6
6
  import { LlmRole } from "./llmDtos.js";
7
7
  import * as llmService from "./llmService.js";
8
- const _dbFilePath = naisysToHostPath(`${config.naisysFolder}/lib/dream.db`);
8
+ const _dbFilePath = unixToHostPath(`${config.naisysFolder}/lib/dream.db`);
9
9
  await init();
10
10
  async function init() {
11
11
  const newDbCreated = await dbUtils.initDatabase(_dbFilePath);
@@ -27,7 +27,7 @@ export async function goodmorning() {
27
27
  FROM DreamLog
28
28
  WHERE username = ?
29
29
  ORDER BY date DESC LIMIT 1`, config.agent.username);
30
- return row === null || row === void 0 ? void 0 : row.dream;
30
+ return row?.dream;
31
31
  });
32
32
  }
33
33
  export async function goodnight() {
@@ -39,8 +39,10 @@ export async function goodnight() {
39
39
  async function runDreamSequence() {
40
40
  const systemMessage = `You are ${config.agent.username}'s unconcious sleep process. You compile all ${config.agent.username}'s
41
41
  thoughts during the day and reduce them down to important things to remember - references, plans, project structure, schemas,
42
- file locations, urls, and more. You are the sleep process, and you are the most important process. Using your results,
43
- when ${config.agent.username} wakes up they'll know exactly what to do and how to do it.`;
42
+ file locations, urls, and more. You don't need to summarize what happened today, or what to do in the far future, just focus on the
43
+ near term. Check what happened during the day for inconsistencies, things to fix and/or check tomorrow. You are the sleep process,
44
+ and you are the most important process. Using your results, when ${config.agent.username} wakes up they'll know exactly what to do
45
+ and how to do it with minimal time spent scanning existing work because you've laid everything out so well.`;
44
46
  const allTheThings = contextManager.messages.map((m) => m.content).join("\n");
45
47
  return await llmService.query(config.agent.dreamModel, systemMessage, [
46
48
  {
@@ -68,7 +68,6 @@ async function sendWithOpenAiCompatible(modelKey, systemMessage, context, source
68
68
  return chatResponse.choices[0].message.content || "";
69
69
  }
70
70
  async function sendWithGoogle(modelKey, systemMessage, context, source) {
71
- var _a;
72
71
  if (!config.googleApiKey) {
73
72
  throw "Error, googleApiKey is not defined";
74
73
  }
@@ -116,7 +115,7 @@ async function sendWithGoogle(modelKey, systemMessage, context, source) {
116
115
  },
117
116
  });
118
117
  const result = await chat.sendMessage(lastMessage.content);
119
- if ((_a = result.response.promptFeedback) === null || _a === void 0 ? void 0 : _a.blockReason) {
118
+ if (result.response.promptFeedback?.blockReason) {
120
119
  throw `Google API Request Blocked, ${result.response.promptFeedback.blockReason}`;
121
120
  }
122
121
  const responseText = result.response.text();
@@ -131,7 +130,6 @@ async function sendWithGoogle(modelKey, systemMessage, context, source) {
131
130
  return responseText;
132
131
  }
133
132
  async function sendWithAnthropic(modelKey, systemMessage, context, source) {
134
- var _a;
135
133
  const model = getLLModel(modelKey);
136
134
  if (!config.anthropicApiKey) {
137
135
  throw "Error, anthropicApiKey is not defined";
@@ -171,6 +169,6 @@ async function sendWithAnthropic(modelKey, systemMessage, context, source) {
171
169
  else {
172
170
  throw "Error, no usage data returned from Anthropic API.";
173
171
  }
174
- return ((_a = msgResponse.content.find((c) => c.type == "text")) === null || _a === void 0 ? void 0 : _a.text) || "";
172
+ return msgResponse.content.find((c) => c.type == "text")?.text || "";
175
173
  }
176
174
  //# sourceMappingURL=llmService.js.map
@@ -3,10 +3,10 @@ import * as fs from "fs";
3
3
  import * as config from "../config.js";
4
4
  import { LlmRole } from "../llm/llmDtos.js";
5
5
  import * as dbUtils from "./dbUtils.js";
6
- import { ensureFileDirExists, naisysToHostPath } from "./utilities.js";
7
- const _dbFilePath = naisysToHostPath(`${config.naisysFolder}/lib/log.db`);
8
- const _combinedLogFilePath = naisysToHostPath(`${config.websiteFolder || config.naisysFolder}/logs/combined-log.html`);
9
- const _userLogFilePath = naisysToHostPath(`${config.websiteFolder || config.naisysFolder}/logs/${config.agent.username}-log.html`);
6
+ import { ensureFileDirExists, unixToHostPath } from "./utilities.js";
7
+ const _dbFilePath = unixToHostPath(`${config.naisysFolder}/lib/log.db`);
8
+ const _combinedLogFilePath = unixToHostPath(`${config.websiteFolder || config.naisysFolder}/logs/combined-log.html`);
9
+ const _userLogFilePath = unixToHostPath(`${config.websiteFolder || config.naisysFolder}/logs/${config.agent.username}-log.html`);
10
10
  await init();
11
11
  async function init() {
12
12
  initLogFile(_combinedLogFilePath);
@@ -1,17 +1,26 @@
1
1
  import * as fs from "fs";
2
2
  import * as os from "os";
3
+ import path from "path";
3
4
  import { get_encoding } from "tiktoken";
4
- /** Take a NAISYS path and convert to something that can be
5
+ /** Take a unix path and convert to something that can be
5
6
  * opened by the host with the native fs library and such */
6
- export function naisysToHostPath(filePath) {
7
- if (os.platform() === "win32" && filePath.startsWith("/mnt/")) {
8
- // "/mnt/c/" -> "c:/"
9
- filePath = filePath.substring(5);
10
- return filePath[0] + ":" + filePath.substring(1);
7
+ export function unixToHostPath(unixPath) {
8
+ const match = unixPath.match(/^\/mnt\/([a-zA-Z])\//);
9
+ if (os.platform() === "win32" && match) {
10
+ // Replace '/mnt/c/' with 'C:/' and convert forward slashes to backslashes
11
+ return unixPath
12
+ .replace(`/mnt/${match[1]}/`, `${match[1].toLowerCase()}:\\`)
13
+ .replace(/\//g, "\\");
11
14
  }
12
- else {
13
- return filePath;
15
+ return unixPath;
16
+ }
17
+ export function hostToUnixPath(hostPath) {
18
+ const match = hostPath.match(/^([a-zA-Z]):\\(.*)/);
19
+ if (os.platform() === "win32" && match) {
20
+ // Replace 'C:\' with '/mnt/c/' and convert backslashes to forward slashes
21
+ return `/mnt/${match[1].toLowerCase()}/${match[2].replace(/\\/g, "/")}`;
14
22
  }
23
+ return hostPath; // Return the original path if it doesn't match the pattern
15
24
  }
16
25
  export function valueFromString(obj, path, defaultValue) {
17
26
  if (!path) {
@@ -20,7 +29,7 @@ export function valueFromString(obj, path, defaultValue) {
20
29
  const keys = path.split(".");
21
30
  let result = obj;
22
31
  for (const key of keys) {
23
- result = result === null || result === void 0 ? void 0 : result[key];
32
+ result = result?.[key];
24
33
  if (result === undefined) {
25
34
  return defaultValue;
26
35
  }
@@ -32,9 +41,9 @@ export function getTokenCount(text) {
32
41
  return _gpt2encoding.encode(text).length;
33
42
  }
34
43
  export function ensureFileDirExists(filePath) {
35
- const dir = filePath.split("/").slice(0, -1).join("/");
36
- if (!fs.existsSync(dir)) {
37
- fs.mkdirSync(dir, { recursive: true });
44
+ const dirname = path.dirname(filePath);
45
+ if (!fs.existsSync(dirname)) {
46
+ fs.mkdirSync(dirname, { recursive: true });
38
47
  }
39
48
  }
40
49
  export function trimChars(text, charList) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "naisys",
3
3
  "description": "Node.js Autonomous Intelligence System",
4
- "version": "1.3.1",
4
+ "version": "1.4.0",
5
5
  "type": "module",
6
6
  "main": "dist/naisys.js",
7
7
  "preferGlobal": true,
@@ -9,10 +9,9 @@
9
9
  "naisys": "bin/naisys"
10
10
  },
11
11
  "scripts": {
12
- "compile/run/attachable": "tsc && node --inspect dist/naisys.js ./agents/juicer.yaml",
13
- "agent:dev": "node dist/naisys.js ./agents/3-team-dev-db-content/dev.yaml",
14
- "agent:db": "node dist/naisys.js ./agents/3-team-dev-db-content/db.yaml",
15
- "agent:content": "node dist/naisys.js ./agents/3-team-dev-db-content/content.yaml",
12
+ "compile/run/attachable": "tsc && node --inspect dist/naisys.js ./agents/mud/mud.yaml",
13
+ "agent:claude": "node dist/naisys.js ./agents/mud/battle-claude.yaml",
14
+ "agent:gpt": "node dist/naisys.js ./agents/mud/battle-gpt.yaml",
16
15
  "clean": "rm -rf dist",
17
16
  "compile": "tsc",
18
17
  "eslint": "npx eslint --rulesdir eslint-rules src",
@@ -22,7 +21,7 @@
22
21
  "detect-cycles": "madge --circular dist",
23
22
  "updates:check": "npm-check-updates",
24
23
  "updates:apply": "npm-check-updates -u && npm install",
25
- "npm:publish:dryrun": "npm run clean && npm install && npm run compile && npm publish --dry-run",
24
+ "npm:publish:dryrun": "npm run clean && npm ci && npm run compile && npm publish --dry-run",
26
25
  "postinstall": "chmod +x ./bin/*"
27
26
  },
28
27
  "repository": {
@@ -62,9 +61,10 @@
62
61
  "escape-html": "1.0.3",
63
62
  "js-yaml": "4.1.0",
64
63
  "openai": "4.29.1",
64
+ "sharp": "0.33.2",
65
65
  "sqlite": "5.1.1",
66
66
  "sqlite3": "5.1.7",
67
67
  "text-table": "0.2.0",
68
68
  "tiktoken": "1.0.13"
69
69
  }
70
- }
70
+ }