naisys 1.0.3 → 1.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 +7 -1
- package/dist/apps/llmail.js +6 -0
- package/dist/command/commandHandler.js +9 -1
- package/dist/command/commandLoop.js +15 -13
- package/dist/command/commandProtection.js +49 -0
- package/dist/command/promptBuilder.js +7 -0
- package/dist/command/shellCommand.js +15 -1
- package/dist/command/shellWrapper.js +21 -18
- package/dist/config.js +18 -9
- package/dist/utils/enums.js +9 -0
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ title: Software Engineer
|
|
|
61
61
|
|
|
62
62
|
# The model to use for console interactions
|
|
63
63
|
# (gpt4turbo, gpt4turbo, gemini-pro, claude3sonnet, claude3opus, local)
|
|
64
|
-
|
|
64
|
+
shellModel: claude3sonnet
|
|
65
65
|
|
|
66
66
|
# The model to use for llmynx, pre-processing websites to fit into a smaller context
|
|
67
67
|
webModel: gpt3turbo
|
|
@@ -92,6 +92,12 @@ wakeOnMessage: false
|
|
|
92
92
|
# The maximum amount to spend on LLM interactions
|
|
93
93
|
# Once reached the agent will stop and this value will need to be increased to continue
|
|
94
94
|
spendLimitDollars: 2.00
|
|
95
|
+
|
|
96
|
+
# None: Commands from the LLM run automatically, this is the default setting as well if the value is not set
|
|
97
|
+
# Manual: Every command the LLM wants you run you have to approve [y/n]
|
|
98
|
+
# Auto: All commands are run through the separate LLM instace, commands that look like they'll modify the system are blocked
|
|
99
|
+
commandProtection: 'none'
|
|
100
|
+
|
|
95
101
|
# Additional custom variables can be defined here and/or in the .env file to be loaded into the agent prompt
|
|
96
102
|
```
|
|
97
103
|
|
package/dist/apps/llmail.js
CHANGED
|
@@ -347,4 +347,10 @@ function validateMsgTokenCount(message) {
|
|
|
347
347
|
async function usingDatabase(run) {
|
|
348
348
|
return dbUtils.usingDatabase(_dbFilePath, run);
|
|
349
349
|
}
|
|
350
|
+
export async function hasMultipleUsers() {
|
|
351
|
+
return await usingDatabase(async (db) => {
|
|
352
|
+
const users = await db.all("SELECT * FROM Users");
|
|
353
|
+
return users.length > 1;
|
|
354
|
+
});
|
|
355
|
+
}
|
|
350
356
|
//# sourceMappingURL=llmail.js.map
|
|
@@ -11,6 +11,7 @@ import * as logService from "../utils/logService.js";
|
|
|
11
11
|
import * as output from "../utils/output.js";
|
|
12
12
|
import { OutputColor } from "../utils/output.js";
|
|
13
13
|
import * as utilities from "../utils/utilities.js";
|
|
14
|
+
import * as commandProtection from "./commandProtection.js";
|
|
14
15
|
import * as promptBuilder from "./promptBuilder.js";
|
|
15
16
|
import * as shellCommand from "./shellCommand.js";
|
|
16
17
|
export var NextCommandAction;
|
|
@@ -20,7 +21,7 @@ export var NextCommandAction;
|
|
|
20
21
|
NextCommandAction[NextCommandAction["ExitApplication"] = 2] = "ExitApplication";
|
|
21
22
|
})(NextCommandAction || (NextCommandAction = {}));
|
|
22
23
|
export let previousSessionNotes = await logService.getPreviousEndSessionNote();
|
|
23
|
-
export async function
|
|
24
|
+
export async function processCommand(prompt, consoleInput) {
|
|
24
25
|
// We process the lines one at a time so we can support multiple commands with line breaks
|
|
25
26
|
let firstLine = true;
|
|
26
27
|
let processNextLLMpromptBlock = true;
|
|
@@ -47,6 +48,13 @@ export async function consoleInput(prompt, consoleInput) {
|
|
|
47
48
|
await output.commentAndLog("Continuing with next command from same LLM response...");
|
|
48
49
|
await contextManager.append(input, ContentSource.LLM);
|
|
49
50
|
}
|
|
51
|
+
// Run write protection checks if enabled
|
|
52
|
+
const { commandAllowed, rejectReason } = await commandProtection.validateCommand(input);
|
|
53
|
+
if (!commandAllowed) {
|
|
54
|
+
await output.errorAndLog(`Write Protection Triggered`);
|
|
55
|
+
await contextManager.append(rejectReason || "Unknown");
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
50
58
|
}
|
|
51
59
|
const cmdParams = input.split(" ");
|
|
52
60
|
const cmdArgs = input.slice(cmdParams[0].length).trim();
|
|
@@ -18,7 +18,7 @@ import * as promptBuilder from "./promptBuilder.js";
|
|
|
18
18
|
const maxErrorCount = 5;
|
|
19
19
|
export async function run() {
|
|
20
20
|
// Show Agent Config exept the agent prompt
|
|
21
|
-
await output.commentAndLog(`Agent configured to use ${config.agent.
|
|
21
|
+
await output.commentAndLog(`Agent configured to use ${config.agent.shellModel} model`);
|
|
22
22
|
// Show System Message
|
|
23
23
|
await output.commentAndLog("System Message:");
|
|
24
24
|
const systemMessage = contextManager.getSystemMessage();
|
|
@@ -35,28 +35,30 @@ export async function run() {
|
|
|
35
35
|
await output.commentAndLog("Starting Context:");
|
|
36
36
|
await contextManager.append("Previous Session Note:");
|
|
37
37
|
await contextManager.append(commandHandler.previousSessionNotes || "None");
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
if (await llmail.hasMultipleUsers()) {
|
|
39
|
+
await commandHandler.processCommand(await promptBuilder.getPrompt(), "llmail help");
|
|
40
|
+
await commandHandler.processCommand(await promptBuilder.getPrompt(), "llmail users");
|
|
41
|
+
}
|
|
40
42
|
inputMode.toggle(InputMode.Debug);
|
|
41
43
|
let pauseSeconds = config.agent.debugPauseSeconds;
|
|
42
44
|
let wakeOnMessage = config.agent.wakeOnMessage;
|
|
43
45
|
while (nextCommandAction == NextCommandAction.Continue) {
|
|
44
46
|
const prompt = await promptBuilder.getPrompt(pauseSeconds, wakeOnMessage);
|
|
45
|
-
let
|
|
47
|
+
let consoleInput = "";
|
|
46
48
|
// Debug command prompt
|
|
47
49
|
if (inputMode.current === InputMode.Debug) {
|
|
48
|
-
|
|
50
|
+
consoleInput = await promptBuilder.getInput(`${prompt}`, pauseSeconds, wakeOnMessage);
|
|
49
51
|
}
|
|
50
52
|
// LLM command prompt
|
|
51
53
|
else if (inputMode.current === InputMode.LLM) {
|
|
52
54
|
const workingMsg = prompt +
|
|
53
|
-
chalk[output.OutputColor.loading](`LLM (${config.agent.
|
|
55
|
+
chalk[output.OutputColor.loading](`LLM (${config.agent.shellModel}) Working...`);
|
|
54
56
|
try {
|
|
55
|
-
await
|
|
56
|
-
await
|
|
57
|
+
await checkNewMailNotification();
|
|
58
|
+
await checkContextLimitWarning();
|
|
57
59
|
await contextManager.append(prompt, ContentSource.ConsolePrompt);
|
|
58
60
|
process.stdout.write(workingMsg);
|
|
59
|
-
|
|
61
|
+
consoleInput = await llmService.query(config.agent.shellModel, contextManager.getSystemMessage(), contextManager.messages, "console");
|
|
60
62
|
clearPromptMessage(workingMsg);
|
|
61
63
|
}
|
|
62
64
|
catch (e) {
|
|
@@ -73,7 +75,7 @@ export async function run() {
|
|
|
73
75
|
// Run the command
|
|
74
76
|
try {
|
|
75
77
|
({ nextCommandAction, pauseSeconds, wakeOnMessage } =
|
|
76
|
-
await commandHandler.
|
|
78
|
+
await commandHandler.processCommand(prompt, consoleInput));
|
|
77
79
|
if (inputMode.current == InputMode.LLM) {
|
|
78
80
|
llmErrorCount = 0;
|
|
79
81
|
}
|
|
@@ -85,7 +87,7 @@ export async function run() {
|
|
|
85
87
|
}
|
|
86
88
|
// If the user is in debug mode and they didn't enter anything, switch to LLM
|
|
87
89
|
// If in LLM mode, auto switch back to debug
|
|
88
|
-
if ((inputMode.current == InputMode.Debug && !
|
|
90
|
+
if ((inputMode.current == InputMode.Debug && !consoleInput) ||
|
|
89
91
|
inputMode.current == InputMode.LLM) {
|
|
90
92
|
inputMode.toggle();
|
|
91
93
|
}
|
|
@@ -136,7 +138,7 @@ async function handleErrorAndSwitchToDebugMode(e, llmErrorCount, addToContext) {
|
|
|
136
138
|
wakeOnMessage,
|
|
137
139
|
};
|
|
138
140
|
}
|
|
139
|
-
async function
|
|
141
|
+
async function checkNewMailNotification() {
|
|
140
142
|
// Check for unread threads
|
|
141
143
|
const unreadThreads = await llmail.getUnreadThreads();
|
|
142
144
|
if (!unreadThreads.length) {
|
|
@@ -174,7 +176,7 @@ async function displayNewMail() {
|
|
|
174
176
|
`Use llmail read <id>' to read the thread, but be mindful you are close to the token limit for the session.`, ContentSource.Console);
|
|
175
177
|
}
|
|
176
178
|
}
|
|
177
|
-
async function
|
|
179
|
+
async function checkContextLimitWarning() {
|
|
178
180
|
const tokenCount = contextManager.getTokenCount();
|
|
179
181
|
const tokenMax = config.agent.tokenMax;
|
|
180
182
|
if (tokenCount > tokenMax) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as config from "../config.js";
|
|
2
|
+
import { LlmRole } from "../llm/llmDtos.js";
|
|
3
|
+
import * as llmService from "../llm/llmService.js";
|
|
4
|
+
import { CommandProtection } from "../utils/enums.js";
|
|
5
|
+
import * as output from "../utils/output.js";
|
|
6
|
+
import * as promptBuilder from "./promptBuilder.js";
|
|
7
|
+
export async function validateCommand(command) {
|
|
8
|
+
switch (config.agent.commandProtection) {
|
|
9
|
+
case CommandProtection.None:
|
|
10
|
+
return {
|
|
11
|
+
commandAllowed: true,
|
|
12
|
+
};
|
|
13
|
+
case CommandProtection.Manual: {
|
|
14
|
+
const confirmation = await promptBuilder.getCommandConfirmation();
|
|
15
|
+
const commandAllowed = confirmation.toLowerCase() === "y";
|
|
16
|
+
return {
|
|
17
|
+
commandAllowed,
|
|
18
|
+
rejectReason: commandAllowed ? undefined : "Command denied by admin",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
case CommandProtection.Auto:
|
|
22
|
+
return await autoValidateCommand(command);
|
|
23
|
+
default:
|
|
24
|
+
throw "Write protection not configured correctly";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function autoValidateCommand(command) {
|
|
28
|
+
output.comment("Checking if command is allowed...");
|
|
29
|
+
const systemMessage = `You are a command validator that checks if shell commands are ok to run.
|
|
30
|
+
The user is 'junior admin' allowed to move around the system, anywhere, and read anything, list anything.
|
|
31
|
+
They are not allowed to execute programs that could modify the system.
|
|
32
|
+
Programs that just give information responses are ok.
|
|
33
|
+
The user is allowed to write to their home directory in ${config.naisysFolder}/home/${config.agent.username}
|
|
34
|
+
In addition to the commands you know are ok, these additional commands are whitelisted:
|
|
35
|
+
llmail, llmynx, comment, endsession, and pause
|
|
36
|
+
Reply with 'allow' to allow the command, otherwise you can give a reason for your rejection.`;
|
|
37
|
+
const response = await llmService.query(config.agent.shellModel, systemMessage, [
|
|
38
|
+
{
|
|
39
|
+
role: LlmRole.User,
|
|
40
|
+
content: command,
|
|
41
|
+
},
|
|
42
|
+
], "write-protection");
|
|
43
|
+
const commandAllowed = response.toLocaleLowerCase().startsWith("allow");
|
|
44
|
+
return {
|
|
45
|
+
commandAllowed,
|
|
46
|
+
rejectReason: commandAllowed ? undefined : "Command Rejected: " + response,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=commandProtection.js.map
|
|
@@ -130,4 +130,11 @@ export function getInput(commandPrompt, pauseSeconds, wakeOnMessage) {
|
|
|
130
130
|
}
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
|
+
export function getCommandConfirmation() {
|
|
134
|
+
return new Promise((resolve) => {
|
|
135
|
+
_readlineInterface.question(chalk.greenBright("Allow command to run? [y/n] "), (answer) => {
|
|
136
|
+
resolve(answer);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
}
|
|
133
140
|
//# sourceMappingURL=promptBuilder.js.map
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import * as config from "../config.js";
|
|
1
2
|
import * as contextManager from "../llm/contextManager.js";
|
|
2
3
|
import * as inputMode from "../utils/inputMode.js";
|
|
3
4
|
import { InputMode } from "../utils/inputMode.js";
|
|
5
|
+
import * as utilities from "../utils/utilities.js";
|
|
4
6
|
import * as shellWrapper from "./shellWrapper.js";
|
|
5
7
|
export async function handleCommand(input) {
|
|
6
8
|
const cmdParams = input.split(" ");
|
|
@@ -29,7 +31,19 @@ export async function handleCommand(input) {
|
|
|
29
31
|
}
|
|
30
32
|
const output = await shellWrapper.executeCommand(input);
|
|
31
33
|
if (output.value) {
|
|
32
|
-
|
|
34
|
+
let text = output.value;
|
|
35
|
+
let outputLimitExceeded = false;
|
|
36
|
+
const tokenCount = utilities.getTokenCount(text);
|
|
37
|
+
// Prevent too much output from blowing up the context
|
|
38
|
+
if (tokenCount > config.shellOutputTokenMax) {
|
|
39
|
+
outputLimitExceeded = true;
|
|
40
|
+
const trimLength = (text.length * config.shellOutputTokenMax) / tokenCount;
|
|
41
|
+
text = text.slice(0, trimLength);
|
|
42
|
+
}
|
|
43
|
+
await contextManager.append(text);
|
|
44
|
+
if (outputLimitExceeded) {
|
|
45
|
+
await contextManager.append(`\nThe shell command generated too much output (${tokenCount} tokens). Only 2,000 tokens worth are shown above.`);
|
|
46
|
+
}
|
|
33
47
|
}
|
|
34
48
|
response.hasErrors = output.hasErrors;
|
|
35
49
|
return response;
|
|
@@ -39,12 +39,12 @@ async function ensureOpen() {
|
|
|
39
39
|
// Init users home dir on first run, on shell crash/rerun go back to the current path
|
|
40
40
|
if (!_currentPath) {
|
|
41
41
|
output.comment("NEW SHELL OPENED. PID: " + _process.pid);
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
errorIfNotEmpty(await executeCommand(`mkdir -p ${config.naisysFolder}/home/` + config.agent.username));
|
|
43
|
+
errorIfNotEmpty(await executeCommand(`cd ${config.naisysFolder}/home/` + config.agent.username));
|
|
44
44
|
}
|
|
45
45
|
else {
|
|
46
46
|
output.comment("SHELL RESTORED. PID: " + _process.pid);
|
|
47
|
-
|
|
47
|
+
errorIfNotEmpty(await executeCommand("cd " + _currentPath));
|
|
48
48
|
}
|
|
49
49
|
// Stop running commands if one fails
|
|
50
50
|
// Often the LLM will give us back all kinds of invalid commands, we want to break on the first one
|
|
@@ -52,9 +52,9 @@ async function ensureOpen() {
|
|
|
52
52
|
//commentIfNotEmpty(await executeCommand("set -e"));
|
|
53
53
|
}
|
|
54
54
|
/** Basically don't show anything in the console unless there is an error */
|
|
55
|
-
function
|
|
55
|
+
function errorIfNotEmpty(response) {
|
|
56
56
|
if (response.value) {
|
|
57
|
-
output.
|
|
57
|
+
output.error(response.value);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
export function processOutput(dataStr, eventType) {
|
|
@@ -128,19 +128,22 @@ export async function executeCommand(command) {
|
|
|
128
128
|
const commandWithDelimiter = `${command.trim()}\necho "${_commandDelimiter} LINE:\${LINENO}"\n`;
|
|
129
129
|
//_log += "INPUT: " + commandWithDelimiter;
|
|
130
130
|
_process === null || _process === void 0 ? void 0 : _process.stdin.write(commandWithDelimiter);
|
|
131
|
-
// If no response
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
131
|
+
// If no response, kill and reset the shell, often hanging on some unescaped input
|
|
132
|
+
_currentCommandTimeout = setTimeout(resetShell, config.shellCommmandTimeoutSeconds * 1000);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function resetShell() {
|
|
136
|
+
if (!_resolveCurrentCommand) {
|
|
137
|
+
return;
|
|
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));
|
|
141
|
+
const outputWithError = _commandOutput.trim() +
|
|
142
|
+
`\nError: Command timed out after ${config.shellCommmandTimeoutSeconds} seconds.`;
|
|
143
|
+
resetProcess();
|
|
144
|
+
_resolveCurrentCommand({
|
|
145
|
+
value: outputWithError,
|
|
146
|
+
hasErrors: true,
|
|
144
147
|
});
|
|
145
148
|
}
|
|
146
149
|
export async function getCurrentPath() {
|
package/dist/config.js
CHANGED
|
@@ -2,11 +2,14 @@ import { program } from "commander";
|
|
|
2
2
|
import dotenv from "dotenv";
|
|
3
3
|
import * as fs from "fs";
|
|
4
4
|
import yaml from "js-yaml";
|
|
5
|
+
import { CommandProtection } from "./utils/enums.js";
|
|
5
6
|
import { valueFromString } from "./utils/utilities.js";
|
|
6
7
|
program.argument("<agent-path>", "Path to agent configuration file").parse();
|
|
7
8
|
dotenv.config();
|
|
8
9
|
/** The system name that shows after the @ in the command prompt */
|
|
9
10
|
export const hostname = "naisys";
|
|
11
|
+
export const shellOutputTokenMax = 2500;
|
|
12
|
+
export const shellCommmandTimeoutSeconds = 10;
|
|
10
13
|
/* .env is used for global configs across naisys, while agent configs are for the specific agent */
|
|
11
14
|
export const naisysFolder = getEnv("NAISYS_FOLDER", true);
|
|
12
15
|
export const websiteFolder = getEnv("WEBSITE_FOLDER");
|
|
@@ -16,13 +19,6 @@ export const openaiApiKey = getEnv("OPENAI_API_KEY");
|
|
|
16
19
|
export const googleApiKey = getEnv("GOOGLE_API_KEY");
|
|
17
20
|
export const anthropicApiKey = getEnv("ANTHROPIC_API_KEY");
|
|
18
21
|
export const agent = loadAgentConfig();
|
|
19
|
-
function getEnv(key, required) {
|
|
20
|
-
const value = process.env[key];
|
|
21
|
-
if (!value && required) {
|
|
22
|
-
throw `Config: Error, .env ${key} is not defined`;
|
|
23
|
-
}
|
|
24
|
-
return value;
|
|
25
|
-
}
|
|
26
22
|
function loadAgentConfig() {
|
|
27
23
|
const agentPath = program.args[0];
|
|
28
24
|
const checkAgentConfig = yaml.load(fs.readFileSync(agentPath, "utf8"));
|
|
@@ -30,17 +26,23 @@ function loadAgentConfig() {
|
|
|
30
26
|
for (const key of [
|
|
31
27
|
"username",
|
|
32
28
|
"title",
|
|
33
|
-
"
|
|
29
|
+
"shellModel",
|
|
34
30
|
"webModel",
|
|
35
31
|
"agentPrompt",
|
|
36
32
|
"spendLimitDollars",
|
|
37
33
|
"tokenMax",
|
|
38
|
-
//
|
|
34
|
+
// other properties can be undefined
|
|
39
35
|
]) {
|
|
40
36
|
if (!valueFromString(checkAgentConfig, key)) {
|
|
41
37
|
throw `Agent config: Error, ${key} is not defined`;
|
|
42
38
|
}
|
|
43
39
|
}
|
|
40
|
+
if (!checkAgentConfig.commandProtection) {
|
|
41
|
+
checkAgentConfig.commandProtection = CommandProtection.None;
|
|
42
|
+
}
|
|
43
|
+
if (!Object.values(CommandProtection).includes(checkAgentConfig.commandProtection)) {
|
|
44
|
+
throw `Agent config: Error, 'commandProtection' is not a valid value`;
|
|
45
|
+
}
|
|
44
46
|
return checkAgentConfig;
|
|
45
47
|
}
|
|
46
48
|
export const packageVersion = await getVersion();
|
|
@@ -58,4 +60,11 @@ async function getVersion() {
|
|
|
58
60
|
return "0.1";
|
|
59
61
|
}
|
|
60
62
|
}
|
|
63
|
+
function getEnv(key, required) {
|
|
64
|
+
const value = process.env[key];
|
|
65
|
+
if (!value && required) {
|
|
66
|
+
throw `Config: Error, .env ${key} is not defined`;
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
61
70
|
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* To separate enums from services which is useful for mocking where the enum
|
|
2
|
+
is used across the code base, but the service it originates from is mocked. */
|
|
3
|
+
export var CommandProtection;
|
|
4
|
+
(function (CommandProtection) {
|
|
5
|
+
CommandProtection["None"] = "none";
|
|
6
|
+
CommandProtection["Manual"] = "manual";
|
|
7
|
+
CommandProtection["Auto"] = "auto";
|
|
8
|
+
})(CommandProtection || (CommandProtection = {}));
|
|
9
|
+
//# sourceMappingURL=enums.js.map
|
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.0
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/naisys.js",
|
|
7
7
|
"preferGlobal": true,
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"naisys": "naisys.sh"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"compile/run/attachable": "tsc && node --inspect dist/naisys.js ./agents/
|
|
13
|
-
"run agent:dev": "node dist/naisys.js ./agents/
|
|
14
|
-
"run agent:admin": "node dist/naisys.js ./agents/
|
|
12
|
+
"compile/run/attachable": "tsc && node --inspect dist/naisys.js ./agents/webdev-fansite.yaml",
|
|
13
|
+
"run agent:dev": "node dist/naisys.js ./agents/2-team/dev.yaml",
|
|
14
|
+
"run agent:admin": "node dist/naisys.js ./agents/2-team/admin.yaml",
|
|
15
15
|
"clean": "rm -rf dist",
|
|
16
16
|
"clean:win": "wsl rm -rf dist",
|
|
17
17
|
"compile": "tsc",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"dependency-graph": "madge --image dependency-graph.png dist",
|
|
22
22
|
"detect-cycles": "madge --circular dist",
|
|
23
23
|
"updates:check": "npm-check-updates",
|
|
24
|
-
"updates:apply": "npm-check-updates -u && npm update"
|
|
24
|
+
"updates:apply": "npm-check-updates -u && npm update",
|
|
25
|
+
"npm:publish:dryrun": "npm run clean && npm run compile && npm publish --dry-run"
|
|
25
26
|
},
|
|
26
27
|
"repository": {
|
|
27
28
|
"type": "git",
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
],
|
|
38
39
|
"author": "John Marshall",
|
|
39
40
|
"license": "MIT",
|
|
41
|
+
"homepage": "https://naisys.org",
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@types/escape-html": "1.0.4",
|
|
42
44
|
"@types/js-yaml": "4.0.9",
|