nestor-sh 3.5.0 → 3.5.1
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/dist/nestor.mjs
CHANGED
|
@@ -516,7 +516,22 @@ var init_encryption = __esm({
|
|
|
516
516
|
if (!secret || secret.length < 16) {
|
|
517
517
|
throw new Error("Encryption secret must be at least 16 characters");
|
|
518
518
|
}
|
|
519
|
-
const
|
|
519
|
+
const envSalt = process.env["NESTOR_ENCRYPTION_SALT"];
|
|
520
|
+
let saltSource;
|
|
521
|
+
if (envSalt) {
|
|
522
|
+
if (envSalt.length < 16) {
|
|
523
|
+
throw new Error(
|
|
524
|
+
`NESTOR_ENCRYPTION_SALT must be at least 16 characters. Generate one with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
saltSource = envSalt;
|
|
528
|
+
} else {
|
|
529
|
+
console.warn(
|
|
530
|
+
"[nestor:encryption] NESTOR_ENCRYPTION_SALT is not set. Falling back to the legacy hardcoded salt. This reduces security (deployments share key derivation). Set NESTOR_ENCRYPTION_SALT to a unique 32+ char random string. Support for the hardcoded fallback will be removed in v4.0."
|
|
531
|
+
);
|
|
532
|
+
saltSource = "nestor-field-encryption-v1";
|
|
533
|
+
}
|
|
534
|
+
const fixedSalt = Buffer.from(saltSource);
|
|
520
535
|
this.masterKey = scryptSync(secret, fixedSalt, KEY_LENGTH);
|
|
521
536
|
}
|
|
522
537
|
/** Encrypt a string value. Returns base64-encoded ciphertext. */
|
|
@@ -14952,7 +14967,7 @@ function isNativeAvailable() {
|
|
|
14952
14967
|
return nativeModule !== null;
|
|
14953
14968
|
}
|
|
14954
14969
|
function getNativeVersion() {
|
|
14955
|
-
return nativeModule ? "3.5.
|
|
14970
|
+
return nativeModule ? "3.5.1" : null;
|
|
14956
14971
|
}
|
|
14957
14972
|
function validateSsrf(url, allowPrivate = false) {
|
|
14958
14973
|
if (nativeModule) {
|
|
@@ -119701,7 +119716,7 @@ var SERVER_VERSION, startTime;
|
|
|
119701
119716
|
var init_health = __esm({
|
|
119702
119717
|
"../server/src/routes/health.ts"() {
|
|
119703
119718
|
"use strict";
|
|
119704
|
-
SERVER_VERSION = "3.5.
|
|
119719
|
+
SERVER_VERSION = "3.5.1";
|
|
119705
119720
|
startTime = Date.now();
|
|
119706
119721
|
}
|
|
119707
119722
|
});
|
|
@@ -121114,7 +121129,7 @@ var init_system = __esm({
|
|
|
121114
121129
|
init_error_handler();
|
|
121115
121130
|
init_broadcaster();
|
|
121116
121131
|
init_approval_service();
|
|
121117
|
-
SERVER_VERSION2 = "3.5.
|
|
121132
|
+
SERVER_VERSION2 = "3.5.1";
|
|
121118
121133
|
startTime2 = Date.now();
|
|
121119
121134
|
UpdateConfigSchema = z20.object({
|
|
121120
121135
|
server: z20.object({
|
|
@@ -158892,7 +158907,7 @@ var init_admin3 = __esm({
|
|
|
158892
158907
|
"../server/src/routes/admin.ts"() {
|
|
158893
158908
|
"use strict";
|
|
158894
158909
|
init_rate_limit();
|
|
158895
|
-
SERVER_VERSION3 = "3.5.
|
|
158910
|
+
SERVER_VERSION3 = "3.5.1";
|
|
158896
158911
|
startTime3 = Date.now();
|
|
158897
158912
|
}
|
|
158898
158913
|
});
|
|
@@ -162469,7 +162484,7 @@ var VERSION2, DATA_DIR3, TELEMETRY_ID_FILE, TELEMETRY_LOG_FILE, DEFAULT_FLUSH_TH
|
|
|
162469
162484
|
var init_telemetry2 = __esm({
|
|
162470
162485
|
"../server/src/services/telemetry.ts"() {
|
|
162471
162486
|
"use strict";
|
|
162472
|
-
VERSION2 = "3.5.
|
|
162487
|
+
VERSION2 = "3.5.1";
|
|
162473
162488
|
DATA_DIR3 = join27(homedir10(), ".nestor");
|
|
162474
162489
|
TELEMETRY_ID_FILE = join27(DATA_DIR3, "telemetry-id");
|
|
162475
162490
|
TELEMETRY_LOG_FILE = join27(DATA_DIR3, "telemetry.jsonl");
|
|
@@ -311692,7 +311707,7 @@ var init_src8 = __esm({
|
|
|
311692
311707
|
await this._handle.listen();
|
|
311693
311708
|
const authMode = config2.apiKey ? "API key" : "open (no auth)";
|
|
311694
311709
|
console.log(`
|
|
311695
|
-
Nestor Server v3.5.
|
|
311710
|
+
Nestor Server v3.5.1`);
|
|
311696
311711
|
console.log(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
|
|
311697
311712
|
console.log(` HTTP : http://${this._host}:${this._port}`);
|
|
311698
311713
|
console.log(` WS : ws://${this._host}:${this._port}/ws`);
|
|
@@ -321481,7 +321496,7 @@ var init_server = __esm({
|
|
|
321481
321496
|
MCP_PROTOCOL_VERSION = "2024-11-05";
|
|
321482
321497
|
SERVER_INFO = {
|
|
321483
321498
|
name: "nestor",
|
|
321484
|
-
version: "3.5.
|
|
321499
|
+
version: "3.5.1"
|
|
321485
321500
|
};
|
|
321486
321501
|
SERVER_CAPABILITIES = {
|
|
321487
321502
|
tools: { listChanged: false },
|
|
@@ -322202,7 +322217,7 @@ function printWelcome() {
|
|
|
322202
322217
|
console.log(chalk15.cyan(` | .\` | | _| \\__ \\ | | | (_) | | / _ \\__ \\ | __ |`));
|
|
322203
322218
|
console.log(chalk15.cyan(` |_|\\_| |___| |___/ |_| \\___/ |_|_\\ (_) |___/ |_||_|`));
|
|
322204
322219
|
console.log("");
|
|
322205
|
-
console.log(chalk15.dim(" Interactive Shell \u2014 v3.5.
|
|
322220
|
+
console.log(chalk15.dim(" Interactive Shell \u2014 v3.5.1"));
|
|
322206
322221
|
console.log(chalk15.dim(" Type /help for commands, /exit to quit."));
|
|
322207
322222
|
console.log(chalk15.dim(" Multiline: end a line with \\ or use ``` code blocks."));
|
|
322208
322223
|
console.log("");
|
|
@@ -322871,11 +322886,190 @@ var init_plan_undo_commands = __esm({
|
|
|
322871
322886
|
}
|
|
322872
322887
|
});
|
|
322873
322888
|
|
|
322874
|
-
// src/commands/shell/
|
|
322889
|
+
// src/commands/shell/pair-command.ts
|
|
322890
|
+
import "node:readline";
|
|
322891
|
+
import { randomUUID as randomUUID66 } from "node:crypto";
|
|
322875
322892
|
import chalk20 from "chalk";
|
|
322893
|
+
async function askSingleKey(prompt, rl) {
|
|
322894
|
+
return new Promise((res) => {
|
|
322895
|
+
process.stdout.write(prompt);
|
|
322896
|
+
rl.once("line", (line) => {
|
|
322897
|
+
res(line.trim().toLowerCase());
|
|
322898
|
+
});
|
|
322899
|
+
});
|
|
322900
|
+
}
|
|
322901
|
+
async function cmdPairMode(args, session, rl, importAgentModule2, executeAgentTask2) {
|
|
322902
|
+
if (args.length === 0) {
|
|
322903
|
+
console.log(chalk20.yellow("Usage: /pair <task description>"));
|
|
322904
|
+
return;
|
|
322905
|
+
}
|
|
322906
|
+
if (!session.activeAgent) {
|
|
322907
|
+
console.log(chalk20.yellow("No agent active. Use /use <name> first."));
|
|
322908
|
+
return;
|
|
322909
|
+
}
|
|
322910
|
+
const task = args.join(" ");
|
|
322911
|
+
const agent = session.activeAgent;
|
|
322912
|
+
console.log(chalk20.cyan("\n\u{1F4CB} Planning...\n"));
|
|
322913
|
+
const agentModule = await importAgentModule2();
|
|
322914
|
+
if (!agentModule) {
|
|
322915
|
+
console.log(chalk20.yellow("Agent runtime not available. Cannot use pair mode."));
|
|
322916
|
+
return;
|
|
322917
|
+
}
|
|
322918
|
+
const { AgentRuntime: AgentRuntime2, RuntimeEventBus: RuntimeEventBus2, ToolRegistry: ToolRegistry4, ToolExecutor: ToolExecutor2, registerBuiltinTools: registerBuiltinTools2 } = agentModule;
|
|
322919
|
+
let llmAdapter;
|
|
322920
|
+
try {
|
|
322921
|
+
const router = await agentModule.createDefaultRouter();
|
|
322922
|
+
const modelId = agent.adapterConfig.model ?? "claude-sonnet-4-20250514";
|
|
322923
|
+
llmAdapter = router.resolve(modelId);
|
|
322924
|
+
} catch {
|
|
322925
|
+
console.log(chalk20.yellow("Could not initialize LLM adapter."));
|
|
322926
|
+
return;
|
|
322927
|
+
}
|
|
322928
|
+
let DryRunInterceptorCls;
|
|
322929
|
+
try {
|
|
322930
|
+
const mod2 = await Promise.resolve().then(() => (init_src5(), src_exports5));
|
|
322931
|
+
DryRunInterceptorCls = mod2.DryRunInterceptor;
|
|
322932
|
+
} catch {
|
|
322933
|
+
console.log(chalk20.yellow("DryRunInterceptor not available."));
|
|
322934
|
+
return;
|
|
322935
|
+
}
|
|
322936
|
+
const events = new RuntimeEventBus2();
|
|
322937
|
+
const tools = new ToolRegistry4();
|
|
322938
|
+
registerBuiltinTools2(tools);
|
|
322939
|
+
const interceptor = new DryRunInterceptorCls();
|
|
322940
|
+
const dryExecutor = new ToolExecutor2();
|
|
322941
|
+
dryExecutor.execute = async (tool, rawInput, ctx) => {
|
|
322942
|
+
return interceptor.execute(tool, rawInput, ctx);
|
|
322943
|
+
};
|
|
322944
|
+
const dryRuntime = new AgentRuntime2({
|
|
322945
|
+
adapter: llmAdapter,
|
|
322946
|
+
tools,
|
|
322947
|
+
toolExecutor: dryExecutor,
|
|
322948
|
+
role: {
|
|
322949
|
+
name: agent.name,
|
|
322950
|
+
description: agent.description ?? `Agent: ${agent.name}`,
|
|
322951
|
+
instructions: agent.adapterConfig.instructions ?? "You are a helpful AI assistant.",
|
|
322952
|
+
constraints: []
|
|
322953
|
+
},
|
|
322954
|
+
workingDir: process.cwd(),
|
|
322955
|
+
events,
|
|
322956
|
+
maxIterations: 20,
|
|
322957
|
+
signal: new AbortController().signal
|
|
322958
|
+
});
|
|
322959
|
+
const taskId = randomUUID66();
|
|
322960
|
+
try {
|
|
322961
|
+
const dryResult = await dryRuntime.run({ prompt: task, agentId: agent.id, taskId });
|
|
322962
|
+
const plan = interceptor.getPlan();
|
|
322963
|
+
if (plan.length === 0) {
|
|
322964
|
+
console.log(chalk20.yellow("No tool calls planned. The agent would only respond with text."));
|
|
322965
|
+
console.log("\n" + dryResult.output + "\n");
|
|
322966
|
+
return;
|
|
322967
|
+
}
|
|
322968
|
+
console.log(chalk20.cyan.bold(`\u{1F4CB} PLAN (${plan.length} steps):`));
|
|
322969
|
+
for (const step of plan) {
|
|
322970
|
+
console.log(formatPlanStep(step));
|
|
322971
|
+
}
|
|
322972
|
+
console.log("");
|
|
322973
|
+
console.log(chalk20.dim(` Estimated cost: $${dryResult.usage.estimatedCostUsd.toFixed(4)} | Iterations: ${dryResult.iterations}`));
|
|
322974
|
+
console.log("");
|
|
322975
|
+
const choice = await askSingleKey(
|
|
322976
|
+
" " + chalk20.cyan("[E]") + "xecute all | " + chalk20.cyan("[S]") + "tep-by-step | " + chalk20.cyan("[C]") + "ancel | " + chalk20.cyan("[R]") + "e-plan > ",
|
|
322977
|
+
rl
|
|
322978
|
+
);
|
|
322979
|
+
if (choice === "c") {
|
|
322980
|
+
console.log(chalk20.dim("\n Cancelled.\n"));
|
|
322981
|
+
return;
|
|
322982
|
+
}
|
|
322983
|
+
if (choice === "r") {
|
|
322984
|
+
const feedback = await askSingleKey(chalk20.cyan(" Feedback for re-planning: "), rl);
|
|
322985
|
+
const newArgs = [...args, "\n\nUser feedback:", feedback];
|
|
322986
|
+
return cmdPairMode(newArgs, session, rl, importAgentModule2, executeAgentTask2);
|
|
322987
|
+
}
|
|
322988
|
+
if (choice === "e") {
|
|
322989
|
+
console.log(chalk20.cyan("\n Executing all steps...\n"));
|
|
322990
|
+
await executeAgentTask2(agent, task, session);
|
|
322991
|
+
return;
|
|
322992
|
+
}
|
|
322993
|
+
console.log(chalk20.cyan("\n Step-by-step execution:\n"));
|
|
322994
|
+
const realTools = new ToolRegistry4();
|
|
322995
|
+
registerBuiltinTools2(realTools);
|
|
322996
|
+
const realExecutor = new ToolExecutor2();
|
|
322997
|
+
for (let i = 0; i < plan.length; i++) {
|
|
322998
|
+
const step = plan[i];
|
|
322999
|
+
console.log(chalk20.cyan.bold(`
|
|
323000
|
+
Step ${i + 1}/${plan.length}: ${step.toolName}`));
|
|
323001
|
+
if (step.toolName === "file_write" && step.args.path) {
|
|
323002
|
+
showDiffForStep(String(step.args.path), String(step.args.content ?? ""));
|
|
323003
|
+
} else if (step.toolName === "shell_exec") {
|
|
323004
|
+
console.log(chalk20.dim(` Command: ${chalk20.white(String(step.args.command ?? ""))}`));
|
|
323005
|
+
} else {
|
|
323006
|
+
console.log(chalk20.dim(` Args: ${JSON.stringify(step.args).slice(0, 200)}`));
|
|
323007
|
+
}
|
|
323008
|
+
const decision = await askSingleKey(
|
|
323009
|
+
" " + chalk20.cyan("[A]") + "ccept " + chalk20.cyan("[R]") + "eject " + chalk20.cyan("[M]") + "odify " + chalk20.cyan("[F]") + "eedback " + chalk20.cyan("[S]") + "kip > ",
|
|
323010
|
+
rl
|
|
323011
|
+
);
|
|
323012
|
+
const tool = realTools.get(step.toolName);
|
|
323013
|
+
const toolCtx = { agentId: agent.id, taskId, workingDir: process.cwd() };
|
|
323014
|
+
switch (decision) {
|
|
323015
|
+
case "a": {
|
|
323016
|
+
if (!tool) {
|
|
323017
|
+
console.log(chalk20.red(` Tool '${step.toolName}' not found.`));
|
|
323018
|
+
break;
|
|
323019
|
+
}
|
|
323020
|
+
const result = await realExecutor.execute(tool, step.args, toolCtx);
|
|
323021
|
+
console.log(result.isError ? chalk20.red(` \u2717 Error: ${result.output.slice(0, 200)}`) : chalk20.green(` \u2713 Done: ${result.output.slice(0, 200)}`));
|
|
323022
|
+
break;
|
|
323023
|
+
}
|
|
323024
|
+
case "r":
|
|
323025
|
+
console.log(chalk20.red(" \u2717 Rejected"));
|
|
323026
|
+
break;
|
|
323027
|
+
case "m": {
|
|
323028
|
+
if (!tool) {
|
|
323029
|
+
console.log(chalk20.red(` Tool '${step.toolName}' not found.`));
|
|
323030
|
+
break;
|
|
323031
|
+
}
|
|
323032
|
+
const modStr = await askSingleKey(chalk20.cyan(` Modified args JSON: `), rl);
|
|
323033
|
+
let modArgs = step.args;
|
|
323034
|
+
try {
|
|
323035
|
+
if (modStr.trim()) modArgs = JSON.parse(modStr);
|
|
323036
|
+
} catch {
|
|
323037
|
+
console.log(chalk20.yellow(" Invalid JSON, using original."));
|
|
323038
|
+
}
|
|
323039
|
+
const modResult = await realExecutor.execute(tool, modArgs, toolCtx);
|
|
323040
|
+
console.log(modResult.isError ? chalk20.red(` \u2717 Error: ${modResult.output.slice(0, 200)}`) : chalk20.green(` \u2713 Done: ${modResult.output.slice(0, 200)}`));
|
|
323041
|
+
break;
|
|
323042
|
+
}
|
|
323043
|
+
case "f": {
|
|
323044
|
+
const fb = await askSingleKey(chalk20.cyan(" Feedback: "), rl);
|
|
323045
|
+
console.log(chalk20.dim(` Noted: "${fb}"`));
|
|
323046
|
+
break;
|
|
323047
|
+
}
|
|
323048
|
+
case "s":
|
|
323049
|
+
console.log(chalk20.yellow(" \u23ED Skipped"));
|
|
323050
|
+
break;
|
|
323051
|
+
default:
|
|
323052
|
+
console.log(chalk20.yellow(" \u23ED Skipped"));
|
|
323053
|
+
break;
|
|
323054
|
+
}
|
|
323055
|
+
}
|
|
323056
|
+
console.log(chalk20.green("\n\u2705 Pair programming session complete.\n"));
|
|
323057
|
+
} catch (err) {
|
|
323058
|
+
console.error(chalk20.red("Pair mode error:"), err instanceof Error ? err.message : String(err));
|
|
323059
|
+
}
|
|
323060
|
+
}
|
|
323061
|
+
var init_pair_command = __esm({
|
|
323062
|
+
"src/commands/shell/pair-command.ts"() {
|
|
323063
|
+
"use strict";
|
|
323064
|
+
init_diff();
|
|
323065
|
+
}
|
|
323066
|
+
});
|
|
323067
|
+
|
|
323068
|
+
// src/commands/shell/replay-command.ts
|
|
323069
|
+
import chalk21 from "chalk";
|
|
322876
323070
|
async function cmdReplay(args) {
|
|
322877
323071
|
if (args.length === 0) {
|
|
322878
|
-
console.log(
|
|
323072
|
+
console.log(chalk21.yellow("Usage: /replay <runId>"));
|
|
322879
323073
|
return;
|
|
322880
323074
|
}
|
|
322881
323075
|
const runId = args[0];
|
|
@@ -322883,14 +323077,14 @@ async function cmdReplay(args) {
|
|
|
322883
323077
|
try {
|
|
322884
323078
|
const events = store.listRunEvents(runId);
|
|
322885
323079
|
if (!events || events.length === 0) {
|
|
322886
|
-
console.log(
|
|
323080
|
+
console.log(chalk21.yellow(`No events found for run ${runId}.`));
|
|
322887
323081
|
return;
|
|
322888
323082
|
}
|
|
322889
323083
|
console.log("");
|
|
322890
323084
|
console.log(
|
|
322891
|
-
|
|
323085
|
+
chalk21.cyan.bold("\u25B6 Replaying run ") + chalk21.cyan(runId.slice(0, 12) + "...") + chalk21.dim(` (${events.length} events)`)
|
|
322892
323086
|
);
|
|
322893
|
-
console.log(
|
|
323087
|
+
console.log(chalk21.dim("\u2500".repeat(60)));
|
|
322894
323088
|
console.log("");
|
|
322895
323089
|
let prevTimestamp = null;
|
|
322896
323090
|
for (const event of events) {
|
|
@@ -322899,7 +323093,7 @@ async function cmdReplay(args) {
|
|
|
322899
323093
|
if (prevTimestamp !== null) {
|
|
322900
323094
|
const gap = ts - prevTimestamp;
|
|
322901
323095
|
if (gap > 100) {
|
|
322902
|
-
process.stdout.write(
|
|
323096
|
+
process.stdout.write(chalk21.dim(` ... +${formatReplayDuration(gap)}
|
|
322903
323097
|
`));
|
|
322904
323098
|
}
|
|
322905
323099
|
}
|
|
@@ -322912,78 +323106,78 @@ async function cmdReplay(args) {
|
|
|
322912
323106
|
switch (event.type) {
|
|
322913
323107
|
case "node_started":
|
|
322914
323108
|
process.stdout.write(
|
|
322915
|
-
|
|
323109
|
+
chalk21.dim(` [${timeStr}] `) + chalk21.blue("\u25B6 ") + chalk21.blue.bold(data.nodeName ?? event.nodeId ?? "Step") + chalk21.dim(" started") + "\n"
|
|
322916
323110
|
);
|
|
322917
323111
|
break;
|
|
322918
323112
|
case "node_completed":
|
|
322919
323113
|
process.stdout.write(
|
|
322920
|
-
|
|
323114
|
+
chalk21.dim(` [${timeStr}] `) + chalk21.green("\u2714 ") + chalk21.green.bold(data.nodeName ?? event.nodeId ?? "Step") + chalk21.dim(" completed") + (data.durationMs ? chalk21.dim(` (${formatReplayDuration(data.durationMs)})`) : "") + "\n"
|
|
322921
323115
|
);
|
|
322922
323116
|
break;
|
|
322923
323117
|
case "node_failed":
|
|
322924
323118
|
process.stdout.write(
|
|
322925
|
-
|
|
323119
|
+
chalk21.dim(` [${timeStr}] `) + chalk21.red("\u2718 ") + chalk21.red.bold(data.nodeName ?? event.nodeId ?? "Step") + chalk21.dim(" failed") + "\n"
|
|
322926
323120
|
);
|
|
322927
323121
|
if (data.error) {
|
|
322928
|
-
process.stdout.write(
|
|
323122
|
+
process.stdout.write(chalk21.red(` Error: ${String(data.error).slice(0, 200)}`) + "\n");
|
|
322929
323123
|
}
|
|
322930
323124
|
break;
|
|
322931
323125
|
case "tool_call_requested":
|
|
322932
323126
|
process.stdout.write(
|
|
322933
|
-
|
|
323127
|
+
chalk21.dim(` [${timeStr}] `) + chalk21.yellow("\u{1F527} ") + chalk21.yellow.bold(data.tool ?? "tool") + "\n"
|
|
322934
323128
|
);
|
|
322935
323129
|
if (data.args) {
|
|
322936
323130
|
const argsStr = JSON.stringify(data.args);
|
|
322937
323131
|
const preview = argsStr.length > 120 ? argsStr.slice(0, 120) + "..." : argsStr;
|
|
322938
|
-
process.stdout.write(
|
|
323132
|
+
process.stdout.write(chalk21.dim(` args: ${preview}`) + "\n");
|
|
322939
323133
|
}
|
|
322940
323134
|
break;
|
|
322941
323135
|
case "tool_call_completed":
|
|
322942
323136
|
process.stdout.write(
|
|
322943
|
-
|
|
323137
|
+
chalk21.dim(` [${timeStr}] `) + chalk21.green("\u2714 ") + chalk21.yellow.bold(data.tool ?? "tool") + chalk21.green(" completed") + "\n"
|
|
322944
323138
|
);
|
|
322945
323139
|
if (data.output) {
|
|
322946
323140
|
const output = String(data.output);
|
|
322947
323141
|
const preview = output.length > 200 ? output.slice(0, 200) + "..." : output;
|
|
322948
|
-
process.stdout.write(
|
|
323142
|
+
process.stdout.write(chalk21.dim(` ${preview}`) + "\n");
|
|
322949
323143
|
}
|
|
322950
323144
|
break;
|
|
322951
323145
|
case "approval_requested":
|
|
322952
323146
|
process.stdout.write(
|
|
322953
|
-
|
|
323147
|
+
chalk21.dim(` [${timeStr}] `) + chalk21.yellow("\u{1F6E1}\uFE0F ") + chalk21.yellow("Approval requested: ") + chalk21.white(data.command ?? data.tool ?? "") + "\n"
|
|
322954
323148
|
);
|
|
322955
323149
|
break;
|
|
322956
323150
|
case "budget_warning":
|
|
322957
323151
|
process.stdout.write(
|
|
322958
|
-
|
|
323152
|
+
chalk21.dim(` [${timeStr}] `) + chalk21.yellow("\u26A0 Budget warning: ") + chalk21.white(`${data.usedPct ?? "?"}% used`) + "\n"
|
|
322959
323153
|
);
|
|
322960
323154
|
break;
|
|
322961
323155
|
case "reasoning": {
|
|
322962
323156
|
const entry = data.entry ?? data;
|
|
322963
323157
|
if (entry.reasoning) {
|
|
322964
|
-
const phaseTag = entry.phase ?
|
|
323158
|
+
const phaseTag = entry.phase ? chalk21.dim(`[${entry.phase}] `) : "";
|
|
322965
323159
|
process.stdout.write(
|
|
322966
|
-
|
|
323160
|
+
chalk21.dim(` [${timeStr}] `) + chalk21.dim.italic(`\u{1F4AD} ${phaseTag}${entry.reasoning}`) + "\n"
|
|
322967
323161
|
);
|
|
322968
323162
|
}
|
|
322969
323163
|
break;
|
|
322970
323164
|
}
|
|
322971
323165
|
default:
|
|
322972
323166
|
process.stdout.write(
|
|
322973
|
-
|
|
323167
|
+
chalk21.dim(` [${timeStr}] `) + chalk21.dim(`[${event.type}] `) + chalk21.dim(JSON.stringify(data).slice(0, 100)) + "\n"
|
|
322974
323168
|
);
|
|
322975
323169
|
break;
|
|
322976
323170
|
}
|
|
322977
323171
|
await new Promise((resolve20) => setTimeout(resolve20, 30));
|
|
322978
323172
|
}
|
|
322979
323173
|
console.log("");
|
|
322980
|
-
console.log(
|
|
323174
|
+
console.log(chalk21.dim("\u2500".repeat(60)));
|
|
322981
323175
|
console.log(
|
|
322982
|
-
|
|
323176
|
+
chalk21.cyan.bold("\u23F9 Replay complete") + chalk21.dim(` (${events.length} events)`)
|
|
322983
323177
|
);
|
|
322984
323178
|
console.log("");
|
|
322985
323179
|
} catch (err) {
|
|
322986
|
-
console.error(
|
|
323180
|
+
console.error(chalk21.red("Replay failed:"), err instanceof Error ? err.message : String(err));
|
|
322987
323181
|
} finally {
|
|
322988
323182
|
store.close();
|
|
322989
323183
|
}
|
|
@@ -323001,12 +323195,12 @@ var shell_exports = {};
|
|
|
323001
323195
|
__export(shell_exports, {
|
|
323002
323196
|
registerShellCommand: () => registerShellCommand
|
|
323003
323197
|
});
|
|
323004
|
-
import * as
|
|
323198
|
+
import * as readline5 from "node:readline";
|
|
323005
323199
|
import { existsSync as existsSync24, mkdirSync as mkdirSync16 } from "node:fs";
|
|
323006
323200
|
import { join as join31 } from "node:path";
|
|
323007
323201
|
import "node:fs";
|
|
323008
|
-
import { randomUUID as
|
|
323009
|
-
import
|
|
323202
|
+
import { randomUUID as randomUUID67 } from "node:crypto";
|
|
323203
|
+
import chalk22 from "chalk";
|
|
323010
323204
|
import * as p5 from "@clack/prompts";
|
|
323011
323205
|
function registerShellCommand(program2) {
|
|
323012
323206
|
program2.command("shell").description("Start an interactive REPL session").option("--fresh", "Start with a clean context, ignoring accumulated history").option("--max-iterations <n>", "Default max iterations for /mission commands").option("--max-runtime <seconds>", "Default max runtime in seconds for /mission commands").option("--hat <id>", "Activate a specialized persona hat (e.g. coder, researcher, security, writer, osint)").action(async (opts) => {
|
|
@@ -323053,13 +323247,13 @@ async function startShell(options) {
|
|
|
323053
323247
|
session.activeHat = hat;
|
|
323054
323248
|
} else {
|
|
323055
323249
|
const available = listHatsFn().map((h) => h.id).join(", ");
|
|
323056
|
-
console.log(
|
|
323250
|
+
console.log(chalk22.yellow(`Hat '${options.hat}' not found. Available hats: ${available}`));
|
|
323057
323251
|
}
|
|
323058
323252
|
} else {
|
|
323059
|
-
console.log(
|
|
323253
|
+
console.log(chalk22.dim("Hat system not available in this version of @nestor/agent."));
|
|
323060
323254
|
}
|
|
323061
323255
|
} catch {
|
|
323062
|
-
console.log(
|
|
323256
|
+
console.log(chalk22.dim("Hat system not available \u2014 @nestor/agent could not be loaded."));
|
|
323063
323257
|
}
|
|
323064
323258
|
}
|
|
323065
323259
|
if (!existsSync24(NESTOR_DIR)) {
|
|
@@ -323069,13 +323263,13 @@ async function startShell(options) {
|
|
|
323069
323263
|
const history = options?.fresh ? [] : loadHistory2();
|
|
323070
323264
|
printWelcome();
|
|
323071
323265
|
if (session.activeHat) {
|
|
323072
|
-
console.log(
|
|
323266
|
+
console.log(chalk22.cyan(` \u{1F3A9} Hat: ${chalk22.bold(session.activeHat.name)}`) + chalk22.dim(` \u2014 ${session.activeHat.description}`));
|
|
323073
323267
|
if (session.activeHat.modelPreference) {
|
|
323074
|
-
console.log(
|
|
323268
|
+
console.log(chalk22.dim(` Model preference: ${session.activeHat.modelPreference}`));
|
|
323075
323269
|
}
|
|
323076
323270
|
console.log("");
|
|
323077
323271
|
}
|
|
323078
|
-
const rl =
|
|
323272
|
+
const rl = readline5.createInterface({
|
|
323079
323273
|
input: process.stdin,
|
|
323080
323274
|
output: process.stdout,
|
|
323081
323275
|
prompt: buildPrompt(session),
|
|
@@ -323091,11 +323285,11 @@ async function startShell(options) {
|
|
|
323091
323285
|
const lastUserMsg = session.conversationHistory.filter((e) => e.role === "user").pop();
|
|
323092
323286
|
session.interruptedContext = lastUserMsg ? { prompt: lastUserMsg.content } : null;
|
|
323093
323287
|
process.stdout.write("\n");
|
|
323094
|
-
process.stdout.write(
|
|
323288
|
+
process.stdout.write(chalk22.yellow("^C Agent interrupted.") + "\n");
|
|
323095
323289
|
process.stdout.write(
|
|
323096
|
-
" " +
|
|
323290
|
+
" " + chalk22.cyan("[R]") + "esume " + chalk22.cyan("[N]") + "ew instruction " + chalk22.cyan("[C]") + "ancel\n"
|
|
323097
323291
|
);
|
|
323098
|
-
process.stdout.write(
|
|
323292
|
+
process.stdout.write(chalk22.dim("> "));
|
|
323099
323293
|
const onLine = async (answer) => {
|
|
323100
323294
|
const choice = answer.trim().toLowerCase();
|
|
323101
323295
|
if (choice === "r" && session.interruptedContext && session.activeAgent) {
|
|
@@ -323112,20 +323306,20 @@ async function startShell(options) {
|
|
|
323112
323306
|
rl.once("line", onLine);
|
|
323113
323307
|
return;
|
|
323114
323308
|
}
|
|
323115
|
-
process.stdout.write("\n" +
|
|
323309
|
+
process.stdout.write("\n" + chalk22.dim("(Use /exit or Ctrl+D to quit)") + "\n");
|
|
323116
323310
|
rl.prompt();
|
|
323117
323311
|
});
|
|
323118
323312
|
rl.on("close", () => {
|
|
323119
323313
|
saveHistory2(rl);
|
|
323120
323314
|
clearStatusBar();
|
|
323121
|
-
process.stdout.write("\n" +
|
|
323315
|
+
process.stdout.write("\n" + chalk22.dim("Goodbye.") + "\n");
|
|
323122
323316
|
process.exit(0);
|
|
323123
323317
|
});
|
|
323124
323318
|
rl.on("line", async (line) => {
|
|
323125
323319
|
if (line.trim().startsWith("```") && !session.inCodeBlock) {
|
|
323126
323320
|
session.inCodeBlock = true;
|
|
323127
323321
|
session.multilineBuffer.push(line);
|
|
323128
|
-
rl.setPrompt(
|
|
323322
|
+
rl.setPrompt(chalk22.dim("... "));
|
|
323129
323323
|
rl.prompt();
|
|
323130
323324
|
return;
|
|
323131
323325
|
}
|
|
@@ -323139,13 +323333,13 @@ async function startShell(options) {
|
|
|
323139
323333
|
await processInput(fullInput, session, rl);
|
|
323140
323334
|
return;
|
|
323141
323335
|
}
|
|
323142
|
-
rl.setPrompt(
|
|
323336
|
+
rl.setPrompt(chalk22.dim("... "));
|
|
323143
323337
|
rl.prompt();
|
|
323144
323338
|
return;
|
|
323145
323339
|
}
|
|
323146
323340
|
if (line.endsWith("\\")) {
|
|
323147
323341
|
session.multilineBuffer.push(line.slice(0, -1));
|
|
323148
|
-
rl.setPrompt(
|
|
323342
|
+
rl.setPrompt(chalk22.dim("... "));
|
|
323149
323343
|
rl.prompt();
|
|
323150
323344
|
return;
|
|
323151
323345
|
}
|
|
@@ -323175,10 +323369,10 @@ async function processInput(line, session, rl) {
|
|
|
323175
323369
|
} else if (session.activeAgent) {
|
|
323176
323370
|
await handleAgentMessage(trimmed, session, rl);
|
|
323177
323371
|
} else {
|
|
323178
|
-
console.log(
|
|
323372
|
+
console.log(chalk22.yellow("No agent active. Use /use <name> to activate one, or /help for commands."));
|
|
323179
323373
|
}
|
|
323180
323374
|
} catch (err) {
|
|
323181
|
-
console.error(
|
|
323375
|
+
console.error(chalk22.red("Error:"), err instanceof Error ? err.message : String(err));
|
|
323182
323376
|
}
|
|
323183
323377
|
rl.setPrompt(buildPrompt(session));
|
|
323184
323378
|
renderStatusBar(session);
|
|
@@ -323247,7 +323441,13 @@ async function handleSlashCommand(input, session, rl) {
|
|
|
323247
323441
|
cmdExport(args, session);
|
|
323248
323442
|
break;
|
|
323249
323443
|
case "/pair":
|
|
323250
|
-
await cmdPairMode(
|
|
323444
|
+
await cmdPairMode(
|
|
323445
|
+
args,
|
|
323446
|
+
session,
|
|
323447
|
+
rl,
|
|
323448
|
+
importAgentModule,
|
|
323449
|
+
(agent, task, sess) => executeAgentTask(agent, task, sess)
|
|
323450
|
+
);
|
|
323251
323451
|
break;
|
|
323252
323452
|
case "/annotate":
|
|
323253
323453
|
await cmdAnnotate2(args, session);
|
|
@@ -323277,12 +323477,12 @@ async function handleSlashCommand(input, session, rl) {
|
|
|
323277
323477
|
case "/quit":
|
|
323278
323478
|
saveHistory2(rl);
|
|
323279
323479
|
clearStatusBar();
|
|
323280
|
-
process.stdout.write(
|
|
323480
|
+
process.stdout.write(chalk22.dim("Goodbye.") + "\n");
|
|
323281
323481
|
process.exit(0);
|
|
323282
323482
|
break;
|
|
323283
323483
|
default:
|
|
323284
|
-
console.log(
|
|
323285
|
-
console.log(
|
|
323484
|
+
console.log(chalk22.red(`Unknown command: ${cmd}`));
|
|
323485
|
+
console.log(chalk22.dim("Type /help for available commands."));
|
|
323286
323486
|
break;
|
|
323287
323487
|
}
|
|
323288
323488
|
}
|
|
@@ -323292,9 +323492,9 @@ function printHelp2() {
|
|
|
323292
323492
|
async function cmdUseAgent(args, session) {
|
|
323293
323493
|
if (args.length === 0) {
|
|
323294
323494
|
if (session.activeAgent) {
|
|
323295
|
-
console.log(
|
|
323495
|
+
console.log(chalk22.dim(`Currently using: ${chalk22.bold(session.activeAgent.name)}`));
|
|
323296
323496
|
} else {
|
|
323297
|
-
console.log(
|
|
323497
|
+
console.log(chalk22.yellow("Usage: /use <agent-name>"));
|
|
323298
323498
|
}
|
|
323299
323499
|
return;
|
|
323300
323500
|
}
|
|
@@ -323303,8 +323503,8 @@ async function cmdUseAgent(args, session) {
|
|
|
323303
323503
|
try {
|
|
323304
323504
|
const agent = store.getAgentByName(name);
|
|
323305
323505
|
if (!agent) {
|
|
323306
|
-
console.log(
|
|
323307
|
-
console.log(
|
|
323506
|
+
console.log(chalk22.red(`Agent '${name}' not found.`));
|
|
323507
|
+
console.log(chalk22.dim("Use /agents to see available agents."));
|
|
323308
323508
|
return;
|
|
323309
323509
|
}
|
|
323310
323510
|
session.activeAgent = agent;
|
|
@@ -323314,10 +323514,10 @@ async function cmdUseAgent(args, session) {
|
|
|
323314
323514
|
session.totalTokensOut = 0;
|
|
323315
323515
|
session.totalCostUsd = 0;
|
|
323316
323516
|
session.totalToolCalls = 0;
|
|
323317
|
-
console.log(
|
|
323318
|
-
console.log(
|
|
323517
|
+
console.log(chalk22.green(`Activated agent: ${chalk22.bold(agent.name)}`));
|
|
323518
|
+
console.log(chalk22.dim(` Adapter: ${agent.adapterType} | Model: ${agent.adapterConfig.model ?? "default"}`));
|
|
323319
323519
|
if (agent.description) {
|
|
323320
|
-
console.log(
|
|
323520
|
+
console.log(chalk22.dim(` ${agent.description}`));
|
|
323321
323521
|
}
|
|
323322
323522
|
} finally {
|
|
323323
323523
|
store.close();
|
|
@@ -323336,7 +323536,7 @@ async function cmdNewAgent(args, session) {
|
|
|
323336
323536
|
validate: (v) => v.trim().length === 0 ? "Name is required" : void 0
|
|
323337
323537
|
});
|
|
323338
323538
|
if (p5.isCancel(result)) {
|
|
323339
|
-
console.log(
|
|
323539
|
+
console.log(chalk22.dim("Cancelled."));
|
|
323340
323540
|
return;
|
|
323341
323541
|
}
|
|
323342
323542
|
agentName = result;
|
|
@@ -323350,7 +323550,7 @@ async function cmdNewAgent(args, session) {
|
|
|
323350
323550
|
]
|
|
323351
323551
|
});
|
|
323352
323552
|
if (p5.isCancel(adapterResult)) {
|
|
323353
|
-
console.log(
|
|
323553
|
+
console.log(chalk22.dim("Cancelled."));
|
|
323354
323554
|
return;
|
|
323355
323555
|
}
|
|
323356
323556
|
adapter = adapterResult;
|
|
@@ -323359,7 +323559,7 @@ async function cmdNewAgent(args, session) {
|
|
|
323359
323559
|
placeholder: "claude-sonnet-4-20250514"
|
|
323360
323560
|
});
|
|
323361
323561
|
if (p5.isCancel(modelResult)) {
|
|
323362
|
-
console.log(
|
|
323562
|
+
console.log(chalk22.dim("Cancelled."));
|
|
323363
323563
|
return;
|
|
323364
323564
|
}
|
|
323365
323565
|
model = modelResult;
|
|
@@ -323370,7 +323570,7 @@ async function cmdNewAgent(args, session) {
|
|
|
323370
323570
|
if (!p5.isCancel(descResult)) {
|
|
323371
323571
|
description = descResult || void 0;
|
|
323372
323572
|
}
|
|
323373
|
-
const id =
|
|
323573
|
+
const id = randomUUID67();
|
|
323374
323574
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
323375
323575
|
const agentConfig = {
|
|
323376
323576
|
id,
|
|
@@ -323385,24 +323585,24 @@ async function cmdNewAgent(args, session) {
|
|
|
323385
323585
|
const store = await getStore();
|
|
323386
323586
|
try {
|
|
323387
323587
|
store.createAgent(agentConfig);
|
|
323388
|
-
console.log(
|
|
323588
|
+
console.log(chalk22.green(`Agent '${agentName}' created.`));
|
|
323389
323589
|
session.activeAgent = agentConfig;
|
|
323390
323590
|
session.conversationHistory = [];
|
|
323391
323591
|
session.totalTokensIn = 0;
|
|
323392
323592
|
session.totalTokensOut = 0;
|
|
323393
323593
|
session.totalCostUsd = 0;
|
|
323394
323594
|
session.totalToolCalls = 0;
|
|
323395
|
-
console.log(
|
|
323595
|
+
console.log(chalk22.dim(`Activated agent: ${agentName}`));
|
|
323396
323596
|
refreshAgentNameCache(session);
|
|
323397
323597
|
} catch (err) {
|
|
323398
|
-
console.error(
|
|
323598
|
+
console.error(chalk22.red("Failed to create agent:"), err instanceof Error ? err.message : String(err));
|
|
323399
323599
|
} finally {
|
|
323400
323600
|
store.close();
|
|
323401
323601
|
}
|
|
323402
323602
|
}
|
|
323403
323603
|
async function cmdRunAgent(args, session) {
|
|
323404
323604
|
if (args.length < 2) {
|
|
323405
|
-
console.log(
|
|
323605
|
+
console.log(chalk22.yellow("Usage: /run <agent-name> <task>"));
|
|
323406
323606
|
return;
|
|
323407
323607
|
}
|
|
323408
323608
|
const agentName = args[0];
|
|
@@ -323411,11 +323611,11 @@ async function cmdRunAgent(args, session) {
|
|
|
323411
323611
|
try {
|
|
323412
323612
|
const agent = store.getAgentByName(agentName);
|
|
323413
323613
|
if (!agent) {
|
|
323414
|
-
console.log(
|
|
323614
|
+
console.log(chalk22.red(`Agent '${agentName}' not found.`));
|
|
323415
323615
|
return;
|
|
323416
323616
|
}
|
|
323417
|
-
console.log(
|
|
323418
|
-
console.log(
|
|
323617
|
+
console.log(chalk22.cyan(`Running agent '${agentName}' on task...`));
|
|
323618
|
+
console.log(chalk22.dim(` Task: ${task}`));
|
|
323419
323619
|
console.log("");
|
|
323420
323620
|
await executeAgentTask(agent, task, session);
|
|
323421
323621
|
} finally {
|
|
@@ -323424,13 +323624,13 @@ async function cmdRunAgent(args, session) {
|
|
|
323424
323624
|
}
|
|
323425
323625
|
function cmdSwitchModel(args, session) {
|
|
323426
323626
|
if (!session.activeAgent) {
|
|
323427
|
-
console.log(
|
|
323627
|
+
console.log(chalk22.yellow("No agent active. Use /use <name> to activate one first."));
|
|
323428
323628
|
return;
|
|
323429
323629
|
}
|
|
323430
323630
|
if (args.length === 0) {
|
|
323431
323631
|
const current = session.activeAgent.adapterConfig.model ?? "default";
|
|
323432
|
-
console.log(
|
|
323433
|
-
console.log(
|
|
323632
|
+
console.log(chalk22.dim(`Current model: ${chalk22.bold(current)}`));
|
|
323633
|
+
console.log(chalk22.dim("Usage: /model <model-name>"));
|
|
323434
323634
|
return;
|
|
323435
323635
|
}
|
|
323436
323636
|
const newModel = args.join(" ");
|
|
@@ -323442,16 +323642,16 @@ function cmdSwitchModel(args, session) {
|
|
|
323442
323642
|
const hotSwap = runtime.getHotSwap();
|
|
323443
323643
|
const result = hotSwap.swap(newAdapter, `user requested /model ${newModel}`);
|
|
323444
323644
|
session.activeAgent.adapterConfig.model = newModel;
|
|
323445
|
-
console.log(
|
|
323645
|
+
console.log(chalk22.green(`Model hot-swapped: ${chalk22.dim(result.previous)} ${chalk22.bold("\u2192")} ${chalk22.bold(result.current)}`));
|
|
323446
323646
|
return;
|
|
323447
323647
|
} catch (err) {
|
|
323448
323648
|
const msg = err instanceof Error ? err.message : String(err);
|
|
323449
|
-
console.log(
|
|
323450
|
-
console.log(
|
|
323649
|
+
console.log(chalk22.yellow(`Hot-swap unavailable: ${msg}`));
|
|
323650
|
+
console.log(chalk22.dim("Falling back to config-level switch (takes effect on next request)."));
|
|
323451
323651
|
}
|
|
323452
323652
|
}
|
|
323453
323653
|
session.activeAgent.adapterConfig.model = newModel;
|
|
323454
|
-
console.log(
|
|
323654
|
+
console.log(chalk22.green(`Model switched to ${chalk22.bold(newModel)} (takes effect on next request)`));
|
|
323455
323655
|
}
|
|
323456
323656
|
async function cmdListTools() {
|
|
323457
323657
|
try {
|
|
@@ -323461,16 +323661,16 @@ async function cmdListTools() {
|
|
|
323461
323661
|
agentModule.registerBuiltinTools(tools);
|
|
323462
323662
|
const allTools = tools.list();
|
|
323463
323663
|
if (allTools.length === 0) {
|
|
323464
|
-
console.log(
|
|
323664
|
+
console.log(chalk22.yellow("No tools registered."));
|
|
323465
323665
|
return;
|
|
323466
323666
|
}
|
|
323467
323667
|
console.log("");
|
|
323468
|
-
console.log(
|
|
323469
|
-
console.log(
|
|
323668
|
+
console.log(chalk22.bold("Available Tools"));
|
|
323669
|
+
console.log(chalk22.dim("\u2500".repeat(50)));
|
|
323470
323670
|
for (const tool of allTools) {
|
|
323471
323671
|
const name = typeof tool === "string" ? tool : tool.name;
|
|
323472
323672
|
const desc = typeof tool === "string" ? "" : tool.description ?? "";
|
|
323473
|
-
console.log(` ${
|
|
323673
|
+
console.log(` ${chalk22.cyan(name)}${desc ? " " + chalk22.dim(desc) : ""}`);
|
|
323474
323674
|
}
|
|
323475
323675
|
console.log("");
|
|
323476
323676
|
return;
|
|
@@ -323481,14 +323681,14 @@ async function cmdListTools() {
|
|
|
323481
323681
|
try {
|
|
323482
323682
|
const skills = store.listSkills();
|
|
323483
323683
|
if (skills.length === 0) {
|
|
323484
|
-
console.log(
|
|
323684
|
+
console.log(chalk22.yellow("No tools available. Install skills to add tools."));
|
|
323485
323685
|
return;
|
|
323486
323686
|
}
|
|
323487
323687
|
console.log("");
|
|
323488
|
-
console.log(
|
|
323489
|
-
console.log(
|
|
323688
|
+
console.log(chalk22.bold("Available Tools (from installed skills)"));
|
|
323689
|
+
console.log(chalk22.dim("\u2500".repeat(50)));
|
|
323490
323690
|
for (const skill of skills) {
|
|
323491
|
-
console.log(` ${
|
|
323691
|
+
console.log(` ${chalk22.cyan(skill.name)} ${chalk22.dim(`v${skill.version}`)}`);
|
|
323492
323692
|
}
|
|
323493
323693
|
console.log("");
|
|
323494
323694
|
} finally {
|
|
@@ -323498,22 +323698,22 @@ async function cmdListTools() {
|
|
|
323498
323698
|
function cmdApprove(args, session) {
|
|
323499
323699
|
const validModes = ["off", "smart", "manual"];
|
|
323500
323700
|
if (args.length === 0) {
|
|
323501
|
-
console.log(`Approval mode: ${
|
|
323502
|
-
console.log(
|
|
323701
|
+
console.log(`Approval mode: ${chalk22.bold(session.approvalMode)}`);
|
|
323702
|
+
console.log(chalk22.dim(`Usage: /approve ${validModes.join("|")}`));
|
|
323503
323703
|
return;
|
|
323504
323704
|
}
|
|
323505
323705
|
const mode = args[0].toLowerCase();
|
|
323506
323706
|
if (!validModes.includes(mode)) {
|
|
323507
|
-
console.log(
|
|
323508
|
-
console.log(
|
|
323707
|
+
console.log(chalk22.red(`Invalid mode: ${mode}`));
|
|
323708
|
+
console.log(chalk22.dim(`Valid modes: ${validModes.join(", ")}`));
|
|
323509
323709
|
return;
|
|
323510
323710
|
}
|
|
323511
323711
|
session.approvalMode = mode;
|
|
323512
|
-
console.log(
|
|
323712
|
+
console.log(chalk22.green(`Approval mode set to ${chalk22.bold(mode)}`));
|
|
323513
323713
|
}
|
|
323514
323714
|
function cmdBack(session) {
|
|
323515
323715
|
if (session.conversationHistory.length < 2) {
|
|
323516
|
-
console.log(
|
|
323716
|
+
console.log(chalk22.yellow("Nothing to undo."));
|
|
323517
323717
|
return;
|
|
323518
323718
|
}
|
|
323519
323719
|
const last2 = session.conversationHistory[session.conversationHistory.length - 1];
|
|
@@ -323530,8 +323730,8 @@ function cmdBack(session) {
|
|
|
323530
323730
|
} else {
|
|
323531
323731
|
session.llmMessages = [];
|
|
323532
323732
|
}
|
|
323533
|
-
console.log(
|
|
323534
|
-
console.log(
|
|
323733
|
+
console.log(chalk22.green("Undid last message pair."));
|
|
323734
|
+
console.log(chalk22.dim(`History now has ${session.conversationHistory.length} entries.`));
|
|
323535
323735
|
}
|
|
323536
323736
|
function cmdFork(session) {
|
|
323537
323737
|
const forkName = `fork-${session.forks.length + 1}`;
|
|
@@ -323541,8 +323741,8 @@ function cmdFork(session) {
|
|
|
323541
323741
|
llmMessages: [...session.llmMessages],
|
|
323542
323742
|
timestamp: Date.now()
|
|
323543
323743
|
});
|
|
323544
|
-
console.log(
|
|
323545
|
-
console.log(
|
|
323744
|
+
console.log(chalk22.green(`Conversation forked as "${forkName}".`));
|
|
323745
|
+
console.log(chalk22.dim(`You now have ${session.forks.length} saved fork(s). Continue chatting from this point.`));
|
|
323546
323746
|
}
|
|
323547
323747
|
function cmdExport(args, session) {
|
|
323548
323748
|
exportConversation(args, session, NESTOR_DIR);
|
|
@@ -323560,7 +323760,7 @@ async function executeAgentTask(agent, prompt, session) {
|
|
|
323560
323760
|
const abortController = new AbortController();
|
|
323561
323761
|
session.abortController = abortController;
|
|
323562
323762
|
session.lastResponseStartMs = Date.now();
|
|
323563
|
-
const spinner3 = createSpinner(`${
|
|
323763
|
+
const spinner3 = createSpinner(`${chalk22.dim("Thinking...")}`);
|
|
323564
323764
|
spinner3.start();
|
|
323565
323765
|
try {
|
|
323566
323766
|
const agentModule = await importAgentModule();
|
|
@@ -323577,7 +323777,7 @@ Agent execution is not yet connected. The agent runtime will process your messag
|
|
|
323577
323777
|
|
|
323578
323778
|
Connect the LLM adapter to enable real responses.`;
|
|
323579
323779
|
console.log("");
|
|
323580
|
-
console.log(
|
|
323780
|
+
console.log(chalk22.white(placeholderResponse));
|
|
323581
323781
|
console.log("");
|
|
323582
323782
|
const simTokensIn = Math.floor(prompt.length * 1.3);
|
|
323583
323783
|
const simTokensOut = Math.floor(placeholderResponse.length * 1.1);
|
|
@@ -323599,7 +323799,7 @@ Connect the LLM adapter to enable real responses.`;
|
|
|
323599
323799
|
spinner3.fail("Aborted by user");
|
|
323600
323800
|
} else {
|
|
323601
323801
|
spinner3.fail("Error");
|
|
323602
|
-
console.error(
|
|
323802
|
+
console.error(chalk22.red(err instanceof Error ? err.message : String(err)));
|
|
323603
323803
|
}
|
|
323604
323804
|
} finally {
|
|
323605
323805
|
session.abortController = null;
|
|
@@ -323614,7 +323814,7 @@ async function runWithAgentRuntime(agentModule, agent, prompt, session, abortCon
|
|
|
323614
323814
|
const modelId = agent.adapterConfig.model ?? "claude-sonnet-4-20250514";
|
|
323615
323815
|
adapter = router.resolve(modelId);
|
|
323616
323816
|
} catch {
|
|
323617
|
-
console.log(
|
|
323817
|
+
console.log(chalk22.yellow("Could not initialize LLM adapter. Is the API key configured?"));
|
|
323618
323818
|
return;
|
|
323619
323819
|
}
|
|
323620
323820
|
const events = new RuntimeEventBus2();
|
|
@@ -323647,9 +323847,9 @@ async function runWithAgentRuntime(agentModule, agent, prompt, session, abortCon
|
|
|
323647
323847
|
session.currentRuntime = runtime;
|
|
323648
323848
|
session.currentRouter = router;
|
|
323649
323849
|
events.on("budget:warning", (payload) => {
|
|
323650
|
-
process.stdout.write("\n" +
|
|
323850
|
+
process.stdout.write("\n" + chalk22.yellow(` Budget warning: ${payload.usedPct.toFixed(0)}% used`) + "\n");
|
|
323651
323851
|
});
|
|
323652
|
-
const taskId =
|
|
323852
|
+
const taskId = randomUUID67();
|
|
323653
323853
|
console.log("");
|
|
323654
323854
|
let streamedOutput = "";
|
|
323655
323855
|
let receivedFirstToken = false;
|
|
@@ -323672,7 +323872,7 @@ async function runWithAgentRuntime(agentModule, agent, prompt, session, abortCon
|
|
|
323672
323872
|
process.stdout.write("\n");
|
|
323673
323873
|
}
|
|
323674
323874
|
process.stdout.write(
|
|
323675
|
-
|
|
323875
|
+
chalk22.dim(" ") + chalk22.yellow("\u25B6") + chalk22.dim(" Calling ") + chalk22.yellow.bold(event.name) + chalk22.dim("...") + "\n"
|
|
323676
323876
|
);
|
|
323677
323877
|
break;
|
|
323678
323878
|
case "tool_result": {
|
|
@@ -323680,32 +323880,32 @@ async function runWithAgentRuntime(agentModule, agent, prompt, session, abortCon
|
|
|
323680
323880
|
const toolOutput = event.result ?? "";
|
|
323681
323881
|
if (event.success) {
|
|
323682
323882
|
process.stdout.write(
|
|
323683
|
-
|
|
323883
|
+
chalk22.dim(" ") + chalk22.green("\u2714") + chalk22.dim(" ") + chalk22.yellow.bold(event.name) + chalk22.green(" completed") + "\n"
|
|
323684
323884
|
);
|
|
323685
323885
|
formatToolOutput(event.name, toolOutput);
|
|
323686
323886
|
} else {
|
|
323687
323887
|
process.stdout.write(
|
|
323688
|
-
|
|
323888
|
+
chalk22.dim(" ") + chalk22.red("\u2718") + chalk22.dim(" ") + chalk22.yellow.bold(event.name) + chalk22.red(" failed") + "\n"
|
|
323689
323889
|
);
|
|
323690
323890
|
if (toolOutput) {
|
|
323691
323891
|
const preview = toolOutput.length > 200 ? toolOutput.substring(0, 200) + "..." : toolOutput;
|
|
323692
|
-
process.stdout.write(
|
|
323892
|
+
process.stdout.write(chalk22.dim(" ") + chalk22.red(preview) + "\n");
|
|
323693
323893
|
}
|
|
323694
323894
|
}
|
|
323695
323895
|
receivedFirstToken = false;
|
|
323696
323896
|
break;
|
|
323697
323897
|
}
|
|
323698
323898
|
case "thinking":
|
|
323699
|
-
process.stdout.write(
|
|
323899
|
+
process.stdout.write(chalk22.dim.italic(event.text));
|
|
323700
323900
|
break;
|
|
323701
323901
|
case "reasoning":
|
|
323702
323902
|
if (session.verbose) {
|
|
323703
323903
|
const entry = event.entry;
|
|
323704
323904
|
if (entry?.reasoning) {
|
|
323705
|
-
const phaseTag = entry.phase ?
|
|
323706
|
-
const confTag = entry.confidence != null ?
|
|
323905
|
+
const phaseTag = entry.phase ? chalk22.dim(`[${entry.phase}] `) : "";
|
|
323906
|
+
const confTag = entry.confidence != null ? chalk22.dim(` (${(entry.confidence * 100).toFixed(0)}%)`) : "";
|
|
323707
323907
|
process.stdout.write(
|
|
323708
|
-
|
|
323908
|
+
chalk22.dim.italic(`
|
|
323709
323909
|
\u{1F4AD} ${phaseTag}${entry.reasoning}${confTag}
|
|
323710
323910
|
`)
|
|
323711
323911
|
);
|
|
@@ -323716,7 +323916,7 @@ async function runWithAgentRuntime(agentModule, agent, prompt, session, abortCon
|
|
|
323716
323916
|
if (receivedFirstToken) {
|
|
323717
323917
|
process.stdout.write("\n");
|
|
323718
323918
|
}
|
|
323719
|
-
process.stdout.write(
|
|
323919
|
+
process.stdout.write(chalk22.red("Error: ") + event.message + "\n");
|
|
323720
323920
|
break;
|
|
323721
323921
|
case "done": {
|
|
323722
323922
|
const result = event.result;
|
|
@@ -323734,9 +323934,9 @@ async function runWithAgentRuntime(agentModule, agent, prompt, session, abortCon
|
|
|
323734
323934
|
});
|
|
323735
323935
|
session.llmMessages = runtime.getMessages().filter((m) => m.role !== "system");
|
|
323736
323936
|
if (result.exitReason !== "completed") {
|
|
323737
|
-
console.log(
|
|
323937
|
+
console.log(chalk22.yellow(`Exit reason: ${result.exitReason}`));
|
|
323738
323938
|
if (result.error) {
|
|
323739
|
-
console.log(
|
|
323939
|
+
console.log(chalk22.red(`Error: ${result.error}`));
|
|
323740
323940
|
}
|
|
323741
323941
|
}
|
|
323742
323942
|
const turnTokens = result.usage.inputTokens + result.usage.outputTokens;
|
|
@@ -323758,177 +323958,9 @@ async function runWithAgentRuntime(agentModule, agent, prompt, session, abortCon
|
|
|
323758
323958
|
function cmdToggleVerbose(session) {
|
|
323759
323959
|
session.verbose = !session.verbose;
|
|
323760
323960
|
if (session.verbose) {
|
|
323761
|
-
console.log(
|
|
323961
|
+
console.log(chalk22.green("Verbose mode: ON") + chalk22.dim(" \u2014 Reasoning steps will be shown during agent runs."));
|
|
323762
323962
|
} else {
|
|
323763
|
-
console.log(
|
|
323764
|
-
}
|
|
323765
|
-
}
|
|
323766
|
-
async function askSingleKey(prompt, rl) {
|
|
323767
|
-
return new Promise((res) => {
|
|
323768
|
-
process.stdout.write(prompt);
|
|
323769
|
-
rl.once("line", (line) => {
|
|
323770
|
-
res(line.trim().toLowerCase());
|
|
323771
|
-
});
|
|
323772
|
-
});
|
|
323773
|
-
}
|
|
323774
|
-
async function cmdPairMode(args, session, rl) {
|
|
323775
|
-
if (args.length === 0) {
|
|
323776
|
-
console.log(chalk21.yellow("Usage: /pair <task description>"));
|
|
323777
|
-
return;
|
|
323778
|
-
}
|
|
323779
|
-
if (!session.activeAgent) {
|
|
323780
|
-
console.log(chalk21.yellow("No agent active. Use /use <name> first."));
|
|
323781
|
-
return;
|
|
323782
|
-
}
|
|
323783
|
-
const task = args.join(" ");
|
|
323784
|
-
const agent = session.activeAgent;
|
|
323785
|
-
console.log(chalk21.cyan("\n\u{1F4CB} Planning...\n"));
|
|
323786
|
-
const agentModule = await importAgentModule();
|
|
323787
|
-
if (!agentModule) {
|
|
323788
|
-
console.log(chalk21.yellow("Agent runtime not available. Cannot use pair mode."));
|
|
323789
|
-
return;
|
|
323790
|
-
}
|
|
323791
|
-
const { AgentRuntime: AgentRuntime2, RuntimeEventBus: RuntimeEventBus2, ToolRegistry: ToolRegistry4, ToolExecutor: ToolExecutor2, registerBuiltinTools: registerBuiltinTools2 } = agentModule;
|
|
323792
|
-
let llmAdapter;
|
|
323793
|
-
try {
|
|
323794
|
-
const router = await agentModule.createDefaultRouter();
|
|
323795
|
-
const modelId = agent.adapterConfig.model ?? "claude-sonnet-4-20250514";
|
|
323796
|
-
llmAdapter = router.resolve(modelId);
|
|
323797
|
-
} catch {
|
|
323798
|
-
console.log(chalk21.yellow("Could not initialize LLM adapter."));
|
|
323799
|
-
return;
|
|
323800
|
-
}
|
|
323801
|
-
let DryRunInterceptorCls;
|
|
323802
|
-
try {
|
|
323803
|
-
const mod2 = await Promise.resolve().then(() => (init_src5(), src_exports5));
|
|
323804
|
-
DryRunInterceptorCls = mod2.DryRunInterceptor;
|
|
323805
|
-
} catch {
|
|
323806
|
-
console.log(chalk21.yellow("DryRunInterceptor not available."));
|
|
323807
|
-
return;
|
|
323808
|
-
}
|
|
323809
|
-
const events = new RuntimeEventBus2();
|
|
323810
|
-
const tools = new ToolRegistry4();
|
|
323811
|
-
registerBuiltinTools2(tools);
|
|
323812
|
-
const interceptor = new DryRunInterceptorCls();
|
|
323813
|
-
const dryExecutor = new ToolExecutor2();
|
|
323814
|
-
dryExecutor.execute = async (tool, rawInput, ctx) => {
|
|
323815
|
-
return interceptor.execute(tool, rawInput, ctx);
|
|
323816
|
-
};
|
|
323817
|
-
const dryRuntime = new AgentRuntime2({
|
|
323818
|
-
adapter: llmAdapter,
|
|
323819
|
-
tools,
|
|
323820
|
-
toolExecutor: dryExecutor,
|
|
323821
|
-
role: {
|
|
323822
|
-
name: agent.name,
|
|
323823
|
-
description: agent.description ?? `Agent: ${agent.name}`,
|
|
323824
|
-
instructions: agent.adapterConfig.instructions ?? "You are a helpful AI assistant.",
|
|
323825
|
-
constraints: []
|
|
323826
|
-
},
|
|
323827
|
-
workingDir: process.cwd(),
|
|
323828
|
-
events,
|
|
323829
|
-
maxIterations: 20,
|
|
323830
|
-
signal: new AbortController().signal
|
|
323831
|
-
});
|
|
323832
|
-
const taskId = randomUUID66();
|
|
323833
|
-
try {
|
|
323834
|
-
const dryResult = await dryRuntime.run({ prompt: task, agentId: agent.id, taskId });
|
|
323835
|
-
const plan = interceptor.getPlan();
|
|
323836
|
-
if (plan.length === 0) {
|
|
323837
|
-
console.log(chalk21.yellow("No tool calls planned. The agent would only respond with text."));
|
|
323838
|
-
console.log("\n" + dryResult.output + "\n");
|
|
323839
|
-
return;
|
|
323840
|
-
}
|
|
323841
|
-
console.log(chalk21.cyan.bold(`\u{1F4CB} PLAN (${plan.length} steps):`));
|
|
323842
|
-
for (const step of plan) {
|
|
323843
|
-
console.log(formatPlanStep(step));
|
|
323844
|
-
}
|
|
323845
|
-
console.log("");
|
|
323846
|
-
console.log(chalk21.dim(` Estimated cost: $${dryResult.usage.estimatedCostUsd.toFixed(4)} | Iterations: ${dryResult.iterations}`));
|
|
323847
|
-
console.log("");
|
|
323848
|
-
const choice = await askSingleKey(
|
|
323849
|
-
" " + chalk21.cyan("[E]") + "xecute all | " + chalk21.cyan("[S]") + "tep-by-step | " + chalk21.cyan("[C]") + "ancel | " + chalk21.cyan("[R]") + "e-plan > ",
|
|
323850
|
-
rl
|
|
323851
|
-
);
|
|
323852
|
-
if (choice === "c") {
|
|
323853
|
-
console.log(chalk21.dim("\n Cancelled.\n"));
|
|
323854
|
-
return;
|
|
323855
|
-
}
|
|
323856
|
-
if (choice === "r") {
|
|
323857
|
-
const feedback = await askSingleKey(chalk21.cyan(" Feedback for re-planning: "), rl);
|
|
323858
|
-
const newArgs = [...args, "\n\nUser feedback:", feedback];
|
|
323859
|
-
return cmdPairMode(newArgs, session, rl);
|
|
323860
|
-
}
|
|
323861
|
-
if (choice === "e") {
|
|
323862
|
-
console.log(chalk21.cyan("\n Executing all steps...\n"));
|
|
323863
|
-
await executeAgentTask(agent, task, session);
|
|
323864
|
-
return;
|
|
323865
|
-
}
|
|
323866
|
-
console.log(chalk21.cyan("\n Step-by-step execution:\n"));
|
|
323867
|
-
const realTools = new ToolRegistry4();
|
|
323868
|
-
registerBuiltinTools2(realTools);
|
|
323869
|
-
const realExecutor = new ToolExecutor2();
|
|
323870
|
-
for (let i = 0; i < plan.length; i++) {
|
|
323871
|
-
const step = plan[i];
|
|
323872
|
-
console.log(chalk21.cyan.bold(`
|
|
323873
|
-
Step ${i + 1}/${plan.length}: ${step.toolName}`));
|
|
323874
|
-
if (step.toolName === "file_write" && step.args.path) {
|
|
323875
|
-
showDiffForStep(String(step.args.path), String(step.args.content ?? ""));
|
|
323876
|
-
} else if (step.toolName === "shell_exec") {
|
|
323877
|
-
console.log(chalk21.dim(` Command: ${chalk21.white(String(step.args.command ?? ""))}`));
|
|
323878
|
-
} else {
|
|
323879
|
-
console.log(chalk21.dim(` Args: ${JSON.stringify(step.args).slice(0, 200)}`));
|
|
323880
|
-
}
|
|
323881
|
-
const decision = await askSingleKey(
|
|
323882
|
-
" " + chalk21.cyan("[A]") + "ccept " + chalk21.cyan("[R]") + "eject " + chalk21.cyan("[M]") + "odify " + chalk21.cyan("[F]") + "eedback " + chalk21.cyan("[S]") + "kip > ",
|
|
323883
|
-
rl
|
|
323884
|
-
);
|
|
323885
|
-
const tool = realTools.get(step.toolName);
|
|
323886
|
-
const toolCtx = { agentId: agent.id, taskId, workingDir: process.cwd() };
|
|
323887
|
-
switch (decision) {
|
|
323888
|
-
case "a": {
|
|
323889
|
-
if (!tool) {
|
|
323890
|
-
console.log(chalk21.red(` Tool '${step.toolName}' not found.`));
|
|
323891
|
-
break;
|
|
323892
|
-
}
|
|
323893
|
-
const result = await realExecutor.execute(tool, step.args, toolCtx);
|
|
323894
|
-
console.log(result.isError ? chalk21.red(` \u2717 Error: ${result.output.slice(0, 200)}`) : chalk21.green(` \u2713 Done: ${result.output.slice(0, 200)}`));
|
|
323895
|
-
break;
|
|
323896
|
-
}
|
|
323897
|
-
case "r":
|
|
323898
|
-
console.log(chalk21.red(" \u2717 Rejected"));
|
|
323899
|
-
break;
|
|
323900
|
-
case "m": {
|
|
323901
|
-
if (!tool) {
|
|
323902
|
-
console.log(chalk21.red(` Tool '${step.toolName}' not found.`));
|
|
323903
|
-
break;
|
|
323904
|
-
}
|
|
323905
|
-
const modStr = await askSingleKey(chalk21.cyan(` Modified args JSON: `), rl);
|
|
323906
|
-
let modArgs = step.args;
|
|
323907
|
-
try {
|
|
323908
|
-
if (modStr.trim()) modArgs = JSON.parse(modStr);
|
|
323909
|
-
} catch {
|
|
323910
|
-
console.log(chalk21.yellow(" Invalid JSON, using original."));
|
|
323911
|
-
}
|
|
323912
|
-
const modResult = await realExecutor.execute(tool, modArgs, toolCtx);
|
|
323913
|
-
console.log(modResult.isError ? chalk21.red(` \u2717 Error: ${modResult.output.slice(0, 200)}`) : chalk21.green(` \u2713 Done: ${modResult.output.slice(0, 200)}`));
|
|
323914
|
-
break;
|
|
323915
|
-
}
|
|
323916
|
-
case "f": {
|
|
323917
|
-
const fb = await askSingleKey(chalk21.cyan(" Feedback: "), rl);
|
|
323918
|
-
console.log(chalk21.dim(` Noted: "${fb}"`));
|
|
323919
|
-
break;
|
|
323920
|
-
}
|
|
323921
|
-
case "s":
|
|
323922
|
-
console.log(chalk21.yellow(" \u23ED Skipped"));
|
|
323923
|
-
break;
|
|
323924
|
-
default:
|
|
323925
|
-
console.log(chalk21.yellow(" \u23ED Skipped"));
|
|
323926
|
-
break;
|
|
323927
|
-
}
|
|
323928
|
-
}
|
|
323929
|
-
console.log(chalk21.green("\n\u2705 Pair programming session complete.\n"));
|
|
323930
|
-
} catch (err) {
|
|
323931
|
-
console.error(chalk21.red("Pair mode error:"), err instanceof Error ? err.message : String(err));
|
|
323963
|
+
console.log(chalk22.yellow("Verbose mode: OFF") + chalk22.dim(" \u2014 Reasoning steps will be hidden."));
|
|
323932
323964
|
}
|
|
323933
323965
|
}
|
|
323934
323966
|
async function cmdAnnotate2(args, session) {
|
|
@@ -324010,6 +324042,7 @@ var init_shell = __esm({
|
|
|
324010
324042
|
init_handoffs_commands();
|
|
324011
324043
|
init_prompt_command();
|
|
324012
324044
|
init_plan_undo_commands();
|
|
324045
|
+
init_pair_command();
|
|
324013
324046
|
init_replay_command();
|
|
324014
324047
|
NESTOR_DIR = getNestorHome2();
|
|
324015
324048
|
HISTORY_FILE = join31(NESTOR_DIR, "shell_history");
|
|
@@ -324103,7 +324136,7 @@ var BANNER = `
|
|
|
324103
324136
|
function registerStartCommand(program2) {
|
|
324104
324137
|
program2.command("start").description("Start the Nestor server").option("-p, --port <port>", "Server port").option("-H, --host <host>", "Server host").option("--no-studio", "Disable the Studio web UI").action(async (options) => {
|
|
324105
324138
|
console.log(chalk.cyan(BANNER));
|
|
324106
|
-
console.log(chalk.dim(` v3.5.
|
|
324139
|
+
console.log(chalk.dim(` v3.5.1
|
|
324107
324140
|
`));
|
|
324108
324141
|
let config2 = readConfigFile();
|
|
324109
324142
|
if (!config2) {
|
|
@@ -326100,7 +326133,7 @@ import {
|
|
|
326100
326133
|
import { join as join32 } from "node:path";
|
|
326101
326134
|
import { fork as fork2, execSync as execSync3 } from "node:child_process";
|
|
326102
326135
|
import "node:readline";
|
|
326103
|
-
import
|
|
326136
|
+
import chalk23 from "chalk";
|
|
326104
326137
|
function desktopNotify(title, message) {
|
|
326105
326138
|
try {
|
|
326106
326139
|
if (process.platform === "win32") {
|
|
@@ -326150,26 +326183,26 @@ function registerDaemonCommand(program2) {
|
|
|
326150
326183
|
async function startForeground() {
|
|
326151
326184
|
const existingPid = readPid();
|
|
326152
326185
|
if (existingPid && isProcessAlive(existingPid)) {
|
|
326153
|
-
console.log(
|
|
326154
|
-
console.log(
|
|
326186
|
+
console.log(chalk23.yellow(`Daemon is already running (PID: ${existingPid}).`));
|
|
326187
|
+
console.log(chalk23.dim("Use `npx nestor-sh daemon stop` to stop it first."));
|
|
326155
326188
|
return;
|
|
326156
326189
|
}
|
|
326157
326190
|
ensureDirs();
|
|
326158
326191
|
writePid(process.pid);
|
|
326159
326192
|
console.log("");
|
|
326160
|
-
console.log(
|
|
326161
|
-
console.log(
|
|
326162
|
-
console.log(
|
|
326163
|
-
console.log(
|
|
326193
|
+
console.log(chalk23.cyan(` _ _ ___ ___ _____ ___ ___ ___ _ _`));
|
|
326194
|
+
console.log(chalk23.cyan(` | \\| | | __| / __| |_ _| / _ \\ | _ \\ / __| | || |`));
|
|
326195
|
+
console.log(chalk23.cyan(` | .\` | | _| \\__ \\ | | | (_) | | / _ \\__ \\ | __ |`));
|
|
326196
|
+
console.log(chalk23.cyan(` |_|\\_| |___| |___/ |_| \\___/ |_|_\\ (_) |___/ |_||_|`));
|
|
326164
326197
|
console.log("");
|
|
326165
|
-
console.log(
|
|
326166
|
-
console.log(
|
|
326167
|
-
console.log(
|
|
326198
|
+
console.log(chalk23.dim(" Daemon Mode \u2014 v3.5.1"));
|
|
326199
|
+
console.log(chalk23.dim(` PID: ${process.pid}`));
|
|
326200
|
+
console.log(chalk23.dim(` Log: ${LOG_FILE}`));
|
|
326168
326201
|
console.log("");
|
|
326169
326202
|
const daemonRunner = new DaemonRunner();
|
|
326170
326203
|
const shutdown = async (signal) => {
|
|
326171
326204
|
daemonLog(`Received ${signal}, shutting down...`);
|
|
326172
|
-
console.log(
|
|
326205
|
+
console.log(chalk23.yellow(`
|
|
326173
326206
|
Received ${signal}. Shutting down gracefully...`));
|
|
326174
326207
|
await daemonRunner.stop();
|
|
326175
326208
|
cleanupPid();
|
|
@@ -326182,8 +326215,8 @@ Received ${signal}. Shutting down gracefully...`));
|
|
|
326182
326215
|
async function startDetached() {
|
|
326183
326216
|
const existingPid = readPid();
|
|
326184
326217
|
if (existingPid && isProcessAlive(existingPid)) {
|
|
326185
|
-
console.log(
|
|
326186
|
-
console.log(
|
|
326218
|
+
console.log(chalk23.yellow(`Daemon is already running (PID: ${existingPid}).`));
|
|
326219
|
+
console.log(chalk23.dim("Use `npx nestor-sh daemon stop` to stop it first."));
|
|
326187
326220
|
return;
|
|
326188
326221
|
}
|
|
326189
326222
|
ensureDirs();
|
|
@@ -326197,22 +326230,22 @@ async function startDetached() {
|
|
|
326197
326230
|
child.unref();
|
|
326198
326231
|
if (child.pid) {
|
|
326199
326232
|
writePid(child.pid);
|
|
326200
|
-
console.log(
|
|
326201
|
-
console.log(
|
|
326202
|
-
console.log(
|
|
326233
|
+
console.log(chalk23.green(`Daemon started in background (PID: ${child.pid}).`));
|
|
326234
|
+
console.log(chalk23.dim(` Logs: ${LOG_FILE}`));
|
|
326235
|
+
console.log(chalk23.dim(` Stop: npx nestor-sh daemon stop`));
|
|
326203
326236
|
} else {
|
|
326204
|
-
console.error(
|
|
326237
|
+
console.error(chalk23.red("Failed to start daemon process."));
|
|
326205
326238
|
process.exit(1);
|
|
326206
326239
|
}
|
|
326207
326240
|
}
|
|
326208
326241
|
async function stopDaemon() {
|
|
326209
326242
|
const pid = readPid();
|
|
326210
326243
|
if (!pid) {
|
|
326211
|
-
console.log(
|
|
326244
|
+
console.log(chalk23.yellow("No daemon PID file found. Daemon is not running."));
|
|
326212
326245
|
return;
|
|
326213
326246
|
}
|
|
326214
326247
|
if (!isProcessAlive(pid)) {
|
|
326215
|
-
console.log(
|
|
326248
|
+
console.log(chalk23.yellow(`Daemon process (PID: ${pid}) is not running. Cleaning up PID file.`));
|
|
326216
326249
|
cleanupPid();
|
|
326217
326250
|
return;
|
|
326218
326251
|
}
|
|
@@ -326246,9 +326279,9 @@ async function showStatus() {
|
|
|
326246
326279
|
console.log("");
|
|
326247
326280
|
if (!pid || !alive) {
|
|
326248
326281
|
printBox([
|
|
326249
|
-
`${
|
|
326250
|
-
`Status: ${
|
|
326251
|
-
pid ?
|
|
326282
|
+
`${chalk23.bold("Nestor Daemon")}`,
|
|
326283
|
+
`Status: ${chalk23.red("STOPPED")}`,
|
|
326284
|
+
pid ? chalk23.dim(`(stale PID file: ${pid})`) : chalk23.dim("No PID file found")
|
|
326252
326285
|
]);
|
|
326253
326286
|
if (pid && !alive) {
|
|
326254
326287
|
cleanupPid();
|
|
@@ -326259,8 +326292,8 @@ async function showStatus() {
|
|
|
326259
326292
|
const uptimeStr = formatDuration(uptimeMs);
|
|
326260
326293
|
const lastBeat = heartbeat?.lastBeat ? timeSince(heartbeat.lastBeat) : "unknown";
|
|
326261
326294
|
const lines = [
|
|
326262
|
-
|
|
326263
|
-
`Status: ${
|
|
326295
|
+
chalk23.bold("Nestor Daemon"),
|
|
326296
|
+
`Status: ${chalk23.green("RUNNING")}`,
|
|
326264
326297
|
`PID: ${pid}`,
|
|
326265
326298
|
`Uptime: ${uptimeStr}`,
|
|
326266
326299
|
`Last heartbeat: ${lastBeat}`
|
|
@@ -326277,13 +326310,13 @@ async function showStatus() {
|
|
|
326277
326310
|
const agents = store.listAgents();
|
|
326278
326311
|
if (agents.length > 0) {
|
|
326279
326312
|
console.log("");
|
|
326280
|
-
console.log(
|
|
326313
|
+
console.log(chalk23.bold("Registered Agents:"));
|
|
326281
326314
|
const headers = ["Name", "Adapter", "Model", "Status"];
|
|
326282
326315
|
const rows = agents.map((a) => [
|
|
326283
326316
|
a.name,
|
|
326284
326317
|
a.adapterType,
|
|
326285
326318
|
a.adapterConfig.model ?? "-",
|
|
326286
|
-
|
|
326319
|
+
chalk23.dim("idle")
|
|
326287
326320
|
// We don't have live status without connecting to daemon
|
|
326288
326321
|
]);
|
|
326289
326322
|
printTable(headers, rows);
|
|
@@ -326295,8 +326328,8 @@ async function showStatus() {
|
|
|
326295
326328
|
}
|
|
326296
326329
|
async function showLogs(follow, lineCount) {
|
|
326297
326330
|
if (!existsSync25(LOG_FILE)) {
|
|
326298
|
-
console.log(
|
|
326299
|
-
console.log(
|
|
326331
|
+
console.log(chalk23.yellow("No daemon log file found."));
|
|
326332
|
+
console.log(chalk23.dim(`Expected at: ${LOG_FILE}`));
|
|
326300
326333
|
return;
|
|
326301
326334
|
}
|
|
326302
326335
|
if (!follow) {
|
|
@@ -326304,7 +326337,7 @@ async function showLogs(follow, lineCount) {
|
|
|
326304
326337
|
const lines = content.split("\n").filter((l) => l.length > 0);
|
|
326305
326338
|
const lastLines = lines.slice(-lineCount);
|
|
326306
326339
|
if (lastLines.length === 0) {
|
|
326307
|
-
console.log(
|
|
326340
|
+
console.log(chalk23.dim("(log is empty)"));
|
|
326308
326341
|
return;
|
|
326309
326342
|
}
|
|
326310
326343
|
for (const line of lastLines) {
|
|
@@ -326312,7 +326345,7 @@ async function showLogs(follow, lineCount) {
|
|
|
326312
326345
|
}
|
|
326313
326346
|
return;
|
|
326314
326347
|
}
|
|
326315
|
-
console.log(
|
|
326348
|
+
console.log(chalk23.dim(`Following ${LOG_FILE}... (Ctrl+C to stop)`));
|
|
326316
326349
|
console.log("");
|
|
326317
326350
|
if (existsSync25(LOG_FILE)) {
|
|
326318
326351
|
const content = readFileSync26(LOG_FILE, "utf-8");
|
|
@@ -326405,7 +326438,7 @@ var DaemonRunner = class {
|
|
|
326405
326438
|
}
|
|
326406
326439
|
}
|
|
326407
326440
|
daemonLog("Entering main loop");
|
|
326408
|
-
console.log(
|
|
326441
|
+
console.log(chalk23.green("Daemon is running. Press Ctrl+C to stop."));
|
|
326409
326442
|
while (this.running) {
|
|
326410
326443
|
try {
|
|
326411
326444
|
await this.tick();
|
|
@@ -326602,9 +326635,9 @@ var DaemonRunner = class {
|
|
|
326602
326635
|
try {
|
|
326603
326636
|
const store = await getStore();
|
|
326604
326637
|
try {
|
|
326605
|
-
const { randomUUID:
|
|
326638
|
+
const { randomUUID: randomUUID69 } = await import("node:crypto");
|
|
326606
326639
|
store.createRun({
|
|
326607
|
-
id:
|
|
326640
|
+
id: randomUUID69(),
|
|
326608
326641
|
workflowId: `agent:${agentId}`,
|
|
326609
326642
|
workflowVersion: 1,
|
|
326610
326643
|
status: result.exitReason === "completed" ? "completed" : "failed",
|
|
@@ -326640,9 +326673,9 @@ var DaemonRunner = class {
|
|
|
326640
326673
|
try {
|
|
326641
326674
|
const store = await getStore();
|
|
326642
326675
|
try {
|
|
326643
|
-
const { randomUUID:
|
|
326676
|
+
const { randomUUID: randomUUID69 } = await import("node:crypto");
|
|
326644
326677
|
store.createRun({
|
|
326645
|
-
id:
|
|
326678
|
+
id: randomUUID69(),
|
|
326646
326679
|
workflowId: `agent:${agentId}`,
|
|
326647
326680
|
workflowVersion: 1,
|
|
326648
326681
|
status: "failed",
|
|
@@ -326934,17 +326967,17 @@ function daemonLog(message) {
|
|
|
326934
326967
|
}
|
|
326935
326968
|
function colorizeLogLine(line) {
|
|
326936
326969
|
if (line.includes("error") || line.includes("Error") || line.includes("ERROR")) {
|
|
326937
|
-
return
|
|
326970
|
+
return chalk23.red(line);
|
|
326938
326971
|
}
|
|
326939
326972
|
if (line.includes("warn") || line.includes("Warning") || line.includes("WARN")) {
|
|
326940
|
-
return
|
|
326973
|
+
return chalk23.yellow(line);
|
|
326941
326974
|
}
|
|
326942
326975
|
if (line.includes("started") || line.includes("Started") || line.includes("completed")) {
|
|
326943
|
-
return
|
|
326976
|
+
return chalk23.green(line);
|
|
326944
326977
|
}
|
|
326945
326978
|
const match = line.match(/^(\[.*?\])\s(.*)$/);
|
|
326946
326979
|
if (match) {
|
|
326947
|
-
return
|
|
326980
|
+
return chalk23.dim(match[1]) + " " + match[2];
|
|
326948
326981
|
}
|
|
326949
326982
|
return line;
|
|
326950
326983
|
}
|
|
@@ -326997,7 +327030,7 @@ init_paths();
|
|
|
326997
327030
|
init_db();
|
|
326998
327031
|
import { existsSync as existsSync26, readFileSync as readFileSync27 } from "node:fs";
|
|
326999
327032
|
import { join as join33 } from "node:path";
|
|
327000
|
-
import
|
|
327033
|
+
import chalk24 from "chalk";
|
|
327001
327034
|
var NESTOR_DIR3 = getNestorHome2();
|
|
327002
327035
|
var HEARTBEAT_FILE2 = join33(NESTOR_DIR3, "daemon.heartbeat");
|
|
327003
327036
|
var LOG_FILE2 = join33(NESTOR_DIR3, "logs", "daemon.log");
|
|
@@ -327116,12 +327149,12 @@ function render(state) {
|
|
|
327116
327149
|
const headerText = " NESTOR MONITOR";
|
|
327117
327150
|
const timerText = `\u23F1 ${elapsed} `;
|
|
327118
327151
|
const headerPad = width - stripAnsi3(headerText).length - stripAnsi3(timerText).length;
|
|
327119
|
-
writeLn(
|
|
327152
|
+
writeLn(chalk24.bold.cyan("\u2554" + "\u2550".repeat(width) + "\u2557"));
|
|
327120
327153
|
writeLn(
|
|
327121
|
-
|
|
327154
|
+
chalk24.bold.cyan("\u2551") + chalk24.bold(headerText) + " ".repeat(Math.max(0, headerPad)) + chalk24.dim(timerText) + chalk24.bold.cyan("\u2551")
|
|
327122
327155
|
);
|
|
327123
|
-
writeLn(
|
|
327124
|
-
const daemonStatus = state.daemonRunning ?
|
|
327156
|
+
writeLn(chalk24.bold.cyan("\u2560" + "\u2550".repeat(width) + "\u2563"));
|
|
327157
|
+
const daemonStatus = state.daemonRunning ? chalk24.green("\u25CF RUNNING") + chalk24.dim(` (PID: ${state.daemonPid})`) : chalk24.red("\u25CB STOPPED");
|
|
327125
327158
|
writePadded(` Daemon: ${daemonStatus}`, width);
|
|
327126
327159
|
const totalAgents = state.agents.length;
|
|
327127
327160
|
const activeAgents = state.daemonRunning ? 0 : 0;
|
|
@@ -327132,47 +327165,47 @@ function render(state) {
|
|
|
327132
327165
|
if (agent) {
|
|
327133
327166
|
renderAgentDetail(agent, width, state);
|
|
327134
327167
|
} else {
|
|
327135
|
-
writePadded(
|
|
327168
|
+
writePadded(chalk24.yellow(` Agent '${state.focusedAgent}' not found.`), width);
|
|
327136
327169
|
}
|
|
327137
327170
|
} else {
|
|
327138
327171
|
for (const agent of state.agents) {
|
|
327139
327172
|
renderAgentRow(agent, width, state);
|
|
327140
327173
|
}
|
|
327141
327174
|
if (state.agents.length === 0) {
|
|
327142
|
-
writePadded(
|
|
327175
|
+
writePadded(chalk24.dim(" No agents registered."), width);
|
|
327143
327176
|
}
|
|
327144
327177
|
}
|
|
327145
327178
|
writePadded("", width);
|
|
327146
|
-
writePadded(
|
|
327179
|
+
writePadded(chalk24.bold(" Recent Events:"), width);
|
|
327147
327180
|
if (state.recentEvents.length === 0) {
|
|
327148
|
-
writePadded(
|
|
327181
|
+
writePadded(chalk24.dim(" (no events)"), width);
|
|
327149
327182
|
} else {
|
|
327150
327183
|
const eventsToShow = state.recentEvents.slice(-8);
|
|
327151
327184
|
for (const event of eventsToShow) {
|
|
327152
|
-
const colorFn = event.type === "error" ?
|
|
327153
|
-
const agentStr = event.agent ?
|
|
327154
|
-
const line = ` ${
|
|
327185
|
+
const colorFn = event.type === "error" ? chalk24.red : event.type === "warning" ? chalk24.yellow : event.type === "success" ? chalk24.green : chalk24.dim;
|
|
327186
|
+
const agentStr = event.agent ? chalk24.cyan(event.agent) + " \u2192 " : "";
|
|
327187
|
+
const line = ` ${chalk24.dim(event.time)} ${agentStr}${colorFn(truncate(event.message, width - 25))}`;
|
|
327155
327188
|
writePadded(line, width);
|
|
327156
327189
|
}
|
|
327157
327190
|
}
|
|
327158
|
-
writeLn(
|
|
327191
|
+
writeLn(chalk24.bold.cyan("\u2560" + "\u2550".repeat(width) + "\u2563"));
|
|
327159
327192
|
const helpText = " q:quit a:cycle agent r:refresh";
|
|
327160
|
-
writePadded(
|
|
327161
|
-
writeLn(
|
|
327193
|
+
writePadded(chalk24.dim(helpText), width);
|
|
327194
|
+
writeLn(chalk24.bold.cyan("\u255A" + "\u2550".repeat(width) + "\u255D"));
|
|
327162
327195
|
}
|
|
327163
327196
|
function renderAgentRow(agent, width, state) {
|
|
327164
|
-
const statusIcon2 = state.daemonRunning ?
|
|
327165
|
-
const statusText =
|
|
327197
|
+
const statusIcon2 = state.daemonRunning ? chalk24.dim("\u25CB") : chalk24.dim("\u25CB");
|
|
327198
|
+
const statusText = chalk24.dim("IDLE");
|
|
327166
327199
|
const model = agent.adapterConfig.model ?? "default";
|
|
327167
327200
|
const budget = agent.adapterConfig.budgetPerRunUsd;
|
|
327168
327201
|
const budgetStr = budget !== void 0 ? `$0.00/$${budget.toFixed(2)}` : "";
|
|
327169
327202
|
const nameStr = agent.name.padEnd(16).substring(0, 16);
|
|
327170
|
-
const line = ` ${nameStr} ${statusIcon2} ${statusText.padEnd(12)} ${budgetStr.padEnd(16)} ${
|
|
327203
|
+
const line = ` ${nameStr} ${statusIcon2} ${statusText.padEnd(12)} ${budgetStr.padEnd(16)} ${chalk24.dim(model)}`;
|
|
327171
327204
|
writePadded(line, width);
|
|
327172
327205
|
}
|
|
327173
327206
|
function renderAgentDetail(agent, width, state) {
|
|
327174
|
-
writePadded(
|
|
327175
|
-
writePadded(
|
|
327207
|
+
writePadded(chalk24.bold(` Agent: ${agent.name}`), width);
|
|
327208
|
+
writePadded(chalk24.dim(" " + "\u2500".repeat(width - 4)), width);
|
|
327176
327209
|
writePadded(` ID: ${agent.id}`, width);
|
|
327177
327210
|
writePadded(` Adapter: ${agent.adapterType}`, width);
|
|
327178
327211
|
writePadded(` Model: ${agent.adapterConfig.model ?? "default"}`, width);
|
|
@@ -327184,7 +327217,7 @@ function renderAgentDetail(agent, width, state) {
|
|
|
327184
327217
|
if (budget !== void 0) {
|
|
327185
327218
|
writePadded(` Budget: $${budget.toFixed(2)} per run`, width);
|
|
327186
327219
|
}
|
|
327187
|
-
writePadded(` Status: ${state.daemonRunning ?
|
|
327220
|
+
writePadded(` Status: ${state.daemonRunning ? chalk24.yellow("idle") : chalk24.dim("stopped")}`, width);
|
|
327188
327221
|
writePadded(` Created: ${agent.createdAt.substring(0, 19)}`, width);
|
|
327189
327222
|
}
|
|
327190
327223
|
function cycleAgentFocus(state) {
|
|
@@ -327207,7 +327240,7 @@ function writePadded(text7, totalWidth) {
|
|
|
327207
327240
|
const visible = stripAnsi3(text7).length;
|
|
327208
327241
|
const pad6 = Math.max(0, totalWidth - visible);
|
|
327209
327242
|
process.stdout.write(
|
|
327210
|
-
|
|
327243
|
+
chalk24.bold.cyan("\u2551") + text7 + " ".repeat(pad6) + chalk24.bold.cyan("\u2551") + "\n"
|
|
327211
327244
|
);
|
|
327212
327245
|
}
|
|
327213
327246
|
function stripAnsi3(str) {
|
|
@@ -327246,7 +327279,7 @@ function isDaemonAlive(pid) {
|
|
|
327246
327279
|
// src/commands/studio.ts
|
|
327247
327280
|
init_config2();
|
|
327248
327281
|
init_config();
|
|
327249
|
-
import
|
|
327282
|
+
import chalk25 from "chalk";
|
|
327250
327283
|
async function tryApiCall(method, path32, body) {
|
|
327251
327284
|
try {
|
|
327252
327285
|
const config2 = readConfigFile() ?? mergeWithDefaults({});
|
|
@@ -327284,22 +327317,22 @@ function registerStudioCommand(program2) {
|
|
|
327284
327317
|
const studio = program2.command("studio").description("Manage the Nestor Studio web UI");
|
|
327285
327318
|
studio.command("enable").description("Enable the Studio web UI").action(async () => {
|
|
327286
327319
|
updateConfigStudio(true);
|
|
327287
|
-
console.log(
|
|
327320
|
+
console.log(chalk25.green(" [ok]"), "Studio enabled in config file.");
|
|
327288
327321
|
const result = await tryApiCall("POST", "/api/admin/studio/toggle", { enabled: true });
|
|
327289
327322
|
if (result.ok) {
|
|
327290
|
-
console.log(
|
|
327323
|
+
console.log(chalk25.green(" [ok]"), "Running server updated (hot-reload).");
|
|
327291
327324
|
} else {
|
|
327292
|
-
console.log(
|
|
327325
|
+
console.log(chalk25.yellow(" [info]"), "Server not running or unreachable. Change will take effect on next start.");
|
|
327293
327326
|
}
|
|
327294
327327
|
});
|
|
327295
327328
|
studio.command("disable").description("Disable the Studio web UI").action(async () => {
|
|
327296
327329
|
updateConfigStudio(false);
|
|
327297
|
-
console.log(
|
|
327330
|
+
console.log(chalk25.green(" [ok]"), "Studio disabled in config file.");
|
|
327298
327331
|
const result = await tryApiCall("POST", "/api/admin/studio/toggle", { enabled: false });
|
|
327299
327332
|
if (result.ok) {
|
|
327300
|
-
console.log(
|
|
327333
|
+
console.log(chalk25.green(" [ok]"), "Running server updated (hot-reload).");
|
|
327301
327334
|
} else {
|
|
327302
|
-
console.log(
|
|
327335
|
+
console.log(chalk25.yellow(" [info]"), "Server not running or unreachable. Change will take effect on next start.");
|
|
327303
327336
|
}
|
|
327304
327337
|
});
|
|
327305
327338
|
studio.command("status").description("Show Studio status").action(async () => {
|
|
@@ -327310,25 +327343,25 @@ function registerStudioCommand(program2) {
|
|
|
327310
327343
|
const config3 = readConfigFile() ?? mergeWithDefaults({});
|
|
327311
327344
|
const url = `http://${config3.server.host}:${config3.server.port}/studio`;
|
|
327312
327345
|
console.log("");
|
|
327313
|
-
console.log(
|
|
327314
|
-
console.log(
|
|
327315
|
-
console.log(` Runtime : ${enabled ?
|
|
327316
|
-
console.log(` Config : ${config3.server.studio.enabled ?
|
|
327317
|
-
console.log(` URL : ${
|
|
327346
|
+
console.log(chalk25.bold(" Nestor Studio Status"));
|
|
327347
|
+
console.log(chalk25.dim(" \u2500".repeat(20)));
|
|
327348
|
+
console.log(` Runtime : ${enabled ? chalk25.green("enabled") : chalk25.red("disabled")}`);
|
|
327349
|
+
console.log(` Config : ${config3.server.studio.enabled ? chalk25.green("enabled") : chalk25.red("disabled")}`);
|
|
327350
|
+
console.log(` URL : ${chalk25.cyan(url)}`);
|
|
327318
327351
|
console.log("");
|
|
327319
327352
|
return;
|
|
327320
327353
|
}
|
|
327321
327354
|
const config2 = readConfigFile();
|
|
327322
327355
|
if (!config2) {
|
|
327323
|
-
console.log(
|
|
327324
|
-
console.log(
|
|
327356
|
+
console.log(chalk25.yellow(" No config file found."));
|
|
327357
|
+
console.log(chalk25.dim(" Studio is enabled by default."));
|
|
327325
327358
|
return;
|
|
327326
327359
|
}
|
|
327327
327360
|
console.log("");
|
|
327328
|
-
console.log(
|
|
327329
|
-
console.log(
|
|
327330
|
-
console.log(` Config : ${config2.server.studio.enabled ?
|
|
327331
|
-
console.log(` Server : ${
|
|
327361
|
+
console.log(chalk25.bold(" Nestor Studio Status"));
|
|
327362
|
+
console.log(chalk25.dim(" \u2500".repeat(20)));
|
|
327363
|
+
console.log(` Config : ${config2.server.studio.enabled ? chalk25.green("enabled") : chalk25.red("disabled")}`);
|
|
327364
|
+
console.log(` Server : ${chalk25.dim("not running")}`);
|
|
327332
327365
|
console.log("");
|
|
327333
327366
|
});
|
|
327334
327367
|
studio.command("open").description("Open Studio in your default browser").action(async () => {
|
|
@@ -327338,12 +327371,12 @@ function registerStudioCommand(program2) {
|
|
|
327338
327371
|
if (apiResult.ok) {
|
|
327339
327372
|
const data = apiResult.data?.data;
|
|
327340
327373
|
if (data && !data.enabled) {
|
|
327341
|
-
console.log(
|
|
327342
|
-
console.log(
|
|
327374
|
+
console.log(chalk25.yellow(" Studio is currently disabled on the running server."));
|
|
327375
|
+
console.log(chalk25.dim(" Use `npx nestor-sh studio enable` to enable it first."));
|
|
327343
327376
|
return;
|
|
327344
327377
|
}
|
|
327345
327378
|
}
|
|
327346
|
-
console.log(
|
|
327379
|
+
console.log(chalk25.green(" Opening Studio:"), chalk25.cyan(url));
|
|
327347
327380
|
try {
|
|
327348
327381
|
const { exec: exec2 } = await import("node:child_process");
|
|
327349
327382
|
const platform = process.platform;
|
|
@@ -327357,12 +327390,12 @@ function registerStudioCommand(program2) {
|
|
|
327357
327390
|
}
|
|
327358
327391
|
exec2(cmd, (err) => {
|
|
327359
327392
|
if (err) {
|
|
327360
|
-
console.log(
|
|
327361
|
-
console.log(
|
|
327393
|
+
console.log(chalk25.yellow(" Could not open browser automatically."));
|
|
327394
|
+
console.log(chalk25.dim(` Please open ${url} manually.`));
|
|
327362
327395
|
}
|
|
327363
327396
|
});
|
|
327364
327397
|
} catch {
|
|
327365
|
-
console.log(
|
|
327398
|
+
console.log(chalk25.dim(` Open ${url} in your browser.`));
|
|
327366
327399
|
}
|
|
327367
327400
|
});
|
|
327368
327401
|
}
|
|
@@ -327371,7 +327404,7 @@ function registerStudioCommand(program2) {
|
|
|
327371
327404
|
init_config();
|
|
327372
327405
|
init_config2();
|
|
327373
327406
|
init_paths();
|
|
327374
|
-
import
|
|
327407
|
+
import chalk26 from "chalk";
|
|
327375
327408
|
import fs28 from "node:fs";
|
|
327376
327409
|
import { join as join34 } from "node:path";
|
|
327377
327410
|
function registerTelemetryCommand(program2) {
|
|
@@ -327379,55 +327412,55 @@ function registerTelemetryCommand(program2) {
|
|
|
327379
327412
|
telemetry.command("on").description("Enable anonymous telemetry").action(() => {
|
|
327380
327413
|
setTelemetryEnabled(true);
|
|
327381
327414
|
console.log("");
|
|
327382
|
-
console.log(
|
|
327415
|
+
console.log(chalk26.green(" Telemetry enabled."));
|
|
327383
327416
|
console.log("");
|
|
327384
|
-
console.log(
|
|
327385
|
-
console.log(
|
|
327386
|
-
console.log(
|
|
327387
|
-
console.log(
|
|
327388
|
-
console.log(
|
|
327417
|
+
console.log(chalk26.dim(" What we collect (anonymized, aggregate only):"));
|
|
327418
|
+
console.log(chalk26.dim(" - Adapter type (claude/openai/ollama), model name"));
|
|
327419
|
+
console.log(chalk26.dim(" - Run duration, token count, tool count"));
|
|
327420
|
+
console.log(chalk26.dim(" - Exit reason, error class (no messages)"));
|
|
327421
|
+
console.log(chalk26.dim(" - OS platform, Node.js version"));
|
|
327389
327422
|
console.log("");
|
|
327390
|
-
console.log(
|
|
327391
|
-
console.log(
|
|
327423
|
+
console.log(chalk26.dim(" What we NEVER collect:"));
|
|
327424
|
+
console.log(chalk26.dim(" - API keys, file contents, prompts, personal data"));
|
|
327392
327425
|
console.log("");
|
|
327393
|
-
console.log(
|
|
327426
|
+
console.log(chalk26.dim(" Run `npx nestor-sh telemetry off` to disable at any time."));
|
|
327394
327427
|
console.log("");
|
|
327395
327428
|
});
|
|
327396
327429
|
telemetry.command("off").description("Disable anonymous telemetry").action(() => {
|
|
327397
327430
|
setTelemetryEnabled(false);
|
|
327398
327431
|
console.log("");
|
|
327399
|
-
console.log(
|
|
327400
|
-
console.log(
|
|
327432
|
+
console.log(chalk26.yellow(" Telemetry disabled."));
|
|
327433
|
+
console.log(chalk26.dim(" No data will be collected or sent."));
|
|
327401
327434
|
console.log("");
|
|
327402
327435
|
});
|
|
327403
327436
|
telemetry.command("status").description("Show current telemetry status").action(() => {
|
|
327404
327437
|
const config2 = readConfigFile();
|
|
327405
327438
|
console.log("");
|
|
327406
|
-
console.log(
|
|
327407
|
-
console.log(
|
|
327439
|
+
console.log(chalk26.bold(" Telemetry Status"));
|
|
327440
|
+
console.log(chalk26.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
327408
327441
|
if (!config2) {
|
|
327409
|
-
console.log(` ${
|
|
327410
|
-
console.log(
|
|
327442
|
+
console.log(` ${chalk26.dim("Enabled:")} ${chalk26.yellow("unknown")} (no config file)`);
|
|
327443
|
+
console.log(chalk26.dim(" Run `npx nestor-sh config init` to create a configuration."));
|
|
327411
327444
|
} else {
|
|
327412
327445
|
const enabled = config2.telemetry?.enabled ?? false;
|
|
327413
|
-
console.log(` ${
|
|
327446
|
+
console.log(` ${chalk26.dim("Enabled:")} ${enabled ? chalk26.green("true") : chalk26.dim("false (default)")}`);
|
|
327414
327447
|
if (config2.telemetry?.endpoint) {
|
|
327415
|
-
console.log(` ${
|
|
327448
|
+
console.log(` ${chalk26.dim("Endpoint:")} ${config2.telemetry.endpoint}`);
|
|
327416
327449
|
}
|
|
327417
|
-
console.log(` ${
|
|
327450
|
+
console.log(` ${chalk26.dim("Flush:")} every ${(config2.telemetry?.flushIntervalMs ?? 6e4) / 1e3}s`);
|
|
327418
327451
|
}
|
|
327419
327452
|
const telemetryFile = join34(getNestorHome2(), "telemetry.jsonl");
|
|
327420
327453
|
const idFile = join34(getNestorHome2(), "telemetry-id");
|
|
327421
327454
|
if (fs28.existsSync(idFile)) {
|
|
327422
327455
|
const installId = fs28.readFileSync(idFile, "utf-8").trim();
|
|
327423
|
-
console.log(` ${
|
|
327456
|
+
console.log(` ${chalk26.dim("Install ID:")} ${installId.slice(0, 8)}...`);
|
|
327424
327457
|
}
|
|
327425
327458
|
if (fs28.existsSync(telemetryFile)) {
|
|
327426
327459
|
const content = fs28.readFileSync(telemetryFile, "utf-8").trim();
|
|
327427
327460
|
const lineCount = content ? content.split("\n").length : 0;
|
|
327428
|
-
console.log(` ${
|
|
327461
|
+
console.log(` ${chalk26.dim("Events:")} ${lineCount} recorded locally`);
|
|
327429
327462
|
} else {
|
|
327430
|
-
console.log(` ${
|
|
327463
|
+
console.log(` ${chalk26.dim("Events:")} none recorded`);
|
|
327431
327464
|
}
|
|
327432
327465
|
console.log("");
|
|
327433
327466
|
});
|
|
@@ -327448,7 +327481,7 @@ function setTelemetryEnabled(enabled) {
|
|
|
327448
327481
|
const merged = mergeWithDefaults(config2);
|
|
327449
327482
|
fs28.writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
327450
327483
|
} catch (err) {
|
|
327451
|
-
console.error(
|
|
327484
|
+
console.error(chalk26.red(`Failed to update config: ${err instanceof Error ? err.message : String(err)}`));
|
|
327452
327485
|
process.exit(1);
|
|
327453
327486
|
}
|
|
327454
327487
|
}
|
|
@@ -327456,7 +327489,7 @@ function setTelemetryEnabled(enabled) {
|
|
|
327456
327489
|
// src/commands/memory.ts
|
|
327457
327490
|
init_db();
|
|
327458
327491
|
init_table();
|
|
327459
|
-
import
|
|
327492
|
+
import chalk27 from "chalk";
|
|
327460
327493
|
import { readFileSync as readFileSync28, writeFileSync as writeFileSync18 } from "node:fs";
|
|
327461
327494
|
function registerMemoryCommand(program2) {
|
|
327462
327495
|
const memory = program2.command("memory").description("Manage agent persistent memories");
|
|
@@ -327468,7 +327501,7 @@ function registerMemoryCommand(program2) {
|
|
|
327468
327501
|
if (!agentId) {
|
|
327469
327502
|
const agents = store.listAgents();
|
|
327470
327503
|
if (agents.length === 0) {
|
|
327471
|
-
console.log(
|
|
327504
|
+
console.log(chalk27.yellow("No agents found."));
|
|
327472
327505
|
return;
|
|
327473
327506
|
}
|
|
327474
327507
|
const headers2 = ["Agent", "Memories", "Avg Importance", "By Type"];
|
|
@@ -327489,7 +327522,7 @@ function registerMemoryCommand(program2) {
|
|
|
327489
327522
|
limit
|
|
327490
327523
|
});
|
|
327491
327524
|
if (memories.length === 0) {
|
|
327492
|
-
console.log(
|
|
327525
|
+
console.log(chalk27.yellow("No memories found."));
|
|
327493
327526
|
return;
|
|
327494
327527
|
}
|
|
327495
327528
|
const headers = ["ID", "Type", "Imp.", "Content", "Tags", "Created"];
|
|
@@ -327524,7 +327557,7 @@ function registerMemoryCommand(program2) {
|
|
|
327524
327557
|
allRows.sort((a, b) => b.imp - a.imp);
|
|
327525
327558
|
const limited = allRows.slice(0, limit);
|
|
327526
327559
|
if (limited.length === 0) {
|
|
327527
|
-
console.log(
|
|
327560
|
+
console.log(chalk27.yellow("No matching memories found."));
|
|
327528
327561
|
return;
|
|
327529
327562
|
}
|
|
327530
327563
|
printTable(
|
|
@@ -327535,7 +327568,7 @@ function registerMemoryCommand(program2) {
|
|
|
327535
327568
|
}
|
|
327536
327569
|
const results = store.recallMemories(agentId, query, { limit });
|
|
327537
327570
|
if (results.length === 0) {
|
|
327538
|
-
console.log(
|
|
327571
|
+
console.log(chalk27.yellow("No matching memories found."));
|
|
327539
327572
|
return;
|
|
327540
327573
|
}
|
|
327541
327574
|
printTable(
|
|
@@ -327555,41 +327588,41 @@ function registerMemoryCommand(program2) {
|
|
|
327555
327588
|
if (!agentId) {
|
|
327556
327589
|
const agents = store.listAgents();
|
|
327557
327590
|
if (agents.length === 0) {
|
|
327558
|
-
console.log(
|
|
327591
|
+
console.log(chalk27.yellow("No agents found."));
|
|
327559
327592
|
return;
|
|
327560
327593
|
}
|
|
327561
327594
|
let totalMemories = 0;
|
|
327562
327595
|
for (const agent of agents) {
|
|
327563
327596
|
const stats2 = store.getMemoryStats(agent.id);
|
|
327564
327597
|
totalMemories += stats2.total;
|
|
327565
|
-
console.log(
|
|
327598
|
+
console.log(chalk27.bold.white(`
|
|
327566
327599
|
${agent.name} (${agent.id.slice(0, 8)}...)`));
|
|
327567
|
-
console.log(` Total memories: ${
|
|
327568
|
-
console.log(` Avg importance: ${
|
|
327569
|
-
console.log(` FTS5 available: ${store.hasFts5() ?
|
|
327600
|
+
console.log(` Total memories: ${chalk27.cyan(String(stats2.total))}`);
|
|
327601
|
+
console.log(` Avg importance: ${chalk27.cyan(stats2.avgImportance.toFixed(2))}`);
|
|
327602
|
+
console.log(` FTS5 available: ${store.hasFts5() ? chalk27.green("yes") : chalk27.yellow("no (LIKE fallback)")}`);
|
|
327570
327603
|
const typeEntries2 = Object.entries(stats2.byType);
|
|
327571
327604
|
if (typeEntries2.length > 0) {
|
|
327572
327605
|
console.log(" By type:");
|
|
327573
327606
|
for (const [type, count] of typeEntries2) {
|
|
327574
|
-
console.log(` ${type}: ${
|
|
327607
|
+
console.log(` ${type}: ${chalk27.cyan(String(count))}`);
|
|
327575
327608
|
}
|
|
327576
327609
|
}
|
|
327577
327610
|
}
|
|
327578
|
-
console.log(
|
|
327579
|
-
Total across all agents: ${
|
|
327611
|
+
console.log(chalk27.bold.white(`
|
|
327612
|
+
Total across all agents: ${chalk27.cyan(String(totalMemories))}`));
|
|
327580
327613
|
return;
|
|
327581
327614
|
}
|
|
327582
327615
|
const stats = store.getMemoryStats(agentId);
|
|
327583
|
-
console.log(
|
|
327616
|
+
console.log(chalk27.bold.white(`
|
|
327584
327617
|
Memory Statistics for ${agentId}`));
|
|
327585
|
-
console.log(`Total memories: ${
|
|
327586
|
-
console.log(`Avg importance: ${
|
|
327587
|
-
console.log(`FTS5 available: ${store.hasFts5() ?
|
|
327618
|
+
console.log(`Total memories: ${chalk27.cyan(String(stats.total))}`);
|
|
327619
|
+
console.log(`Avg importance: ${chalk27.cyan(stats.avgImportance.toFixed(2))}`);
|
|
327620
|
+
console.log(`FTS5 available: ${store.hasFts5() ? chalk27.green("yes") : chalk27.yellow("no (LIKE fallback)")}`);
|
|
327588
327621
|
const typeEntries = Object.entries(stats.byType);
|
|
327589
327622
|
if (typeEntries.length > 0) {
|
|
327590
327623
|
console.log("\nBy type:");
|
|
327591
327624
|
for (const [type, count] of typeEntries) {
|
|
327592
|
-
console.log(` ${type}: ${
|
|
327625
|
+
console.log(` ${type}: ${chalk27.cyan(String(count))}`);
|
|
327593
327626
|
}
|
|
327594
327627
|
}
|
|
327595
327628
|
});
|
|
@@ -327600,14 +327633,14 @@ Memory Statistics for ${agentId}`));
|
|
|
327600
327633
|
const minImportance = parseFloat(options.minImportance);
|
|
327601
327634
|
const expired = store.pruneExpiredMemories();
|
|
327602
327635
|
if (expired > 0) {
|
|
327603
|
-
console.log(
|
|
327636
|
+
console.log(chalk27.green(`Pruned ${expired} expired memories.`));
|
|
327604
327637
|
}
|
|
327605
327638
|
if (agentId) {
|
|
327606
327639
|
const pruned = store.pruneMemories(agentId, {
|
|
327607
327640
|
maxAge: maxAgeDays * 86400,
|
|
327608
327641
|
minImportance
|
|
327609
327642
|
});
|
|
327610
|
-
console.log(
|
|
327643
|
+
console.log(chalk27.green(`Pruned ${pruned} old/low-importance memories for agent ${agentId}.`));
|
|
327611
327644
|
} else {
|
|
327612
327645
|
const agents = store.listAgents();
|
|
327613
327646
|
let total = 0;
|
|
@@ -327618,7 +327651,7 @@ Memory Statistics for ${agentId}`));
|
|
|
327618
327651
|
});
|
|
327619
327652
|
total += pruned;
|
|
327620
327653
|
}
|
|
327621
|
-
console.log(
|
|
327654
|
+
console.log(chalk27.green(`Pruned ${total} old/low-importance memories across all agents.`));
|
|
327622
327655
|
}
|
|
327623
327656
|
});
|
|
327624
327657
|
memory.command("export").description("Export memories to JSON").option("-a, --agent <id>", "Agent ID").option("-o, --output <file>", "Output file path", "memories-export.json").action(async (options) => {
|
|
@@ -327662,7 +327695,7 @@ Memory Statistics for ${agentId}`));
|
|
|
327662
327695
|
}
|
|
327663
327696
|
const json = JSON.stringify(allMemories, null, 2);
|
|
327664
327697
|
writeFileSync18(outputFile, json, "utf-8");
|
|
327665
|
-
console.log(
|
|
327698
|
+
console.log(chalk27.green(`Exported ${allMemories.length} memories to ${outputFile}`));
|
|
327666
327699
|
});
|
|
327667
327700
|
memory.command("import <file>").description("Import memories from JSON").action(async (file) => {
|
|
327668
327701
|
const store = await getStore();
|
|
@@ -327670,13 +327703,13 @@ Memory Statistics for ${agentId}`));
|
|
|
327670
327703
|
const raw = readFileSync28(file, "utf-8");
|
|
327671
327704
|
const entries = JSON.parse(raw);
|
|
327672
327705
|
if (!Array.isArray(entries)) {
|
|
327673
|
-
console.error(
|
|
327706
|
+
console.error(chalk27.red("Invalid format: expected a JSON array of memory entries."));
|
|
327674
327707
|
return;
|
|
327675
327708
|
}
|
|
327676
327709
|
let imported = 0;
|
|
327677
327710
|
for (const entry of entries) {
|
|
327678
327711
|
if (!entry.agentId || !entry.content) {
|
|
327679
|
-
console.warn(
|
|
327712
|
+
console.warn(chalk27.yellow("Skipping entry without agentId or content."));
|
|
327680
327713
|
continue;
|
|
327681
327714
|
}
|
|
327682
327715
|
store.storeMemory({
|
|
@@ -327688,9 +327721,9 @@ Memory Statistics for ${agentId}`));
|
|
|
327688
327721
|
});
|
|
327689
327722
|
imported++;
|
|
327690
327723
|
}
|
|
327691
|
-
console.log(
|
|
327724
|
+
console.log(chalk27.green(`Imported ${imported} memories from ${file}`));
|
|
327692
327725
|
} catch (err) {
|
|
327693
|
-
console.error(
|
|
327726
|
+
console.error(chalk27.red(`Failed to import: ${err instanceof Error ? err.message : String(err)}`));
|
|
327694
327727
|
}
|
|
327695
327728
|
});
|
|
327696
327729
|
}
|
|
@@ -327699,7 +327732,7 @@ Memory Statistics for ${agentId}`));
|
|
|
327699
327732
|
init_config2();
|
|
327700
327733
|
init_spinner();
|
|
327701
327734
|
init_table();
|
|
327702
|
-
import
|
|
327735
|
+
import chalk28 from "chalk";
|
|
327703
327736
|
function registerSandboxCommand(program2) {
|
|
327704
327737
|
const sandbox = program2.command("sandbox").description("Manage sandbox execution backends (Docker, SSH, local)");
|
|
327705
327738
|
sandbox.command("status").description("Show current sandbox mode and status").action(async () => {
|
|
@@ -327717,20 +327750,20 @@ async function cmdSandboxStatus() {
|
|
|
327717
327750
|
const sandboxMode = config2?.security?.sandboxMode ?? "none";
|
|
327718
327751
|
const sshConfig = config2?.security?.ssh;
|
|
327719
327752
|
const lines = [
|
|
327720
|
-
`Mode: ${
|
|
327753
|
+
`Mode: ${chalk28.bold(sandboxMode)}`
|
|
327721
327754
|
];
|
|
327722
327755
|
const dockerAvailable = await checkDockerAvailable();
|
|
327723
|
-
lines.push(`Docker: ${dockerAvailable ?
|
|
327756
|
+
lines.push(`Docker: ${dockerAvailable ? chalk28.green("available") : chalk28.red("not available")}`);
|
|
327724
327757
|
if (sshConfig) {
|
|
327725
|
-
lines.push(`SSH: ${
|
|
327758
|
+
lines.push(`SSH: ${chalk28.cyan(sshConfig.username)}@${chalk28.cyan(sshConfig.host)}:${sshConfig.port}`);
|
|
327726
327759
|
if (sshConfig.workDir) {
|
|
327727
327760
|
lines.push(`SSH workdir: ${sshConfig.workDir}`);
|
|
327728
327761
|
}
|
|
327729
327762
|
} else {
|
|
327730
|
-
lines.push(`SSH: ${
|
|
327763
|
+
lines.push(`SSH: ${chalk28.dim("not configured")}`);
|
|
327731
327764
|
}
|
|
327732
327765
|
console.log("");
|
|
327733
|
-
console.log(
|
|
327766
|
+
console.log(chalk28.bold("Sandbox Status"));
|
|
327734
327767
|
printBox(lines);
|
|
327735
327768
|
console.log("");
|
|
327736
327769
|
}
|
|
@@ -327738,8 +327771,8 @@ async function cmdSandboxTest() {
|
|
|
327738
327771
|
const config2 = readConfigFile();
|
|
327739
327772
|
const sandboxMode = config2?.security?.sandboxMode ?? "none";
|
|
327740
327773
|
console.log("");
|
|
327741
|
-
console.log(
|
|
327742
|
-
console.log(
|
|
327774
|
+
console.log(chalk28.bold("Sandbox Connectivity Test"));
|
|
327775
|
+
console.log(chalk28.dim("\u2500".repeat(40)));
|
|
327743
327776
|
const dockerSpinner = createSpinner("Testing Docker...");
|
|
327744
327777
|
dockerSpinner.start();
|
|
327745
327778
|
const dockerAvailable = await checkDockerAvailable();
|
|
@@ -327747,7 +327780,7 @@ async function cmdSandboxTest() {
|
|
|
327747
327780
|
dockerSpinner.succeed("Docker is available");
|
|
327748
327781
|
const version = await getDockerVersion();
|
|
327749
327782
|
if (version) {
|
|
327750
|
-
console.log(
|
|
327783
|
+
console.log(chalk28.dim(` Version: ${version}`));
|
|
327751
327784
|
}
|
|
327752
327785
|
} else {
|
|
327753
327786
|
dockerSpinner.fail("Docker is not available");
|
|
@@ -327760,43 +327793,43 @@ async function cmdSandboxTest() {
|
|
|
327760
327793
|
if (sshResult.ok) {
|
|
327761
327794
|
sshSpinner.succeed(`SSH connected to ${sshConfig.host}`);
|
|
327762
327795
|
if (sshResult.info) {
|
|
327763
|
-
console.log(
|
|
327796
|
+
console.log(chalk28.dim(` ${sshResult.info}`));
|
|
327764
327797
|
}
|
|
327765
327798
|
} else {
|
|
327766
327799
|
sshSpinner.fail(`SSH connection failed: ${sshResult.error}`);
|
|
327767
327800
|
}
|
|
327768
327801
|
} else {
|
|
327769
|
-
console.log(
|
|
327802
|
+
console.log(chalk28.dim(" SSH: not configured (use `npx nestor-sh sandbox ssh <host>`)"));
|
|
327770
327803
|
}
|
|
327771
|
-
console.log(
|
|
327804
|
+
console.log(chalk28.green("\u2714") + " Local execution: always available");
|
|
327772
327805
|
console.log("");
|
|
327773
327806
|
if (sandboxMode === "docker" && !dockerAvailable) {
|
|
327774
|
-
console.log(
|
|
327775
|
-
console.log(
|
|
327807
|
+
console.log(chalk28.yellow('Warning: Sandbox mode is "docker" but Docker is not available.'));
|
|
327808
|
+
console.log(chalk28.dim('Consider switching to "none" or "auto" in your config.'));
|
|
327776
327809
|
} else if (sandboxMode === "ssh" && !sshConfig) {
|
|
327777
|
-
console.log(
|
|
327778
|
-
console.log(
|
|
327810
|
+
console.log(chalk28.yellow('Warning: Sandbox mode is "ssh" but no SSH config found.'));
|
|
327811
|
+
console.log(chalk28.dim("Run `npx nestor-sh sandbox ssh <host>` to configure."));
|
|
327779
327812
|
} else {
|
|
327780
|
-
console.log(
|
|
327813
|
+
console.log(chalk28.green("Sandbox configuration looks good."));
|
|
327781
327814
|
}
|
|
327782
327815
|
console.log("");
|
|
327783
327816
|
}
|
|
327784
327817
|
async function cmdSandboxSSH(host, opts) {
|
|
327785
327818
|
const port = parseInt(opts.port, 10);
|
|
327786
327819
|
if (isNaN(port) || port < 1 || port > 65535) {
|
|
327787
|
-
console.log(
|
|
327820
|
+
console.log(chalk28.red(`Invalid port: ${opts.port}`));
|
|
327788
327821
|
return;
|
|
327789
327822
|
}
|
|
327790
327823
|
console.log("");
|
|
327791
|
-
console.log(
|
|
327792
|
-
console.log(
|
|
327793
|
-
console.log(` Host: ${
|
|
327794
|
-
console.log(` Port: ${
|
|
327795
|
-
console.log(` User: ${
|
|
327824
|
+
console.log(chalk28.bold("Configuring SSH Sandbox"));
|
|
327825
|
+
console.log(chalk28.dim("\u2500".repeat(40)));
|
|
327826
|
+
console.log(` Host: ${chalk28.cyan(host)}`);
|
|
327827
|
+
console.log(` Port: ${chalk28.cyan(String(port))}`);
|
|
327828
|
+
console.log(` User: ${chalk28.cyan(opts.user)}`);
|
|
327796
327829
|
if (opts.key) {
|
|
327797
|
-
console.log(` Key: ${
|
|
327830
|
+
console.log(` Key: ${chalk28.cyan(opts.key)}`);
|
|
327798
327831
|
}
|
|
327799
|
-
console.log(` Dir: ${
|
|
327832
|
+
console.log(` Dir: ${chalk28.cyan(opts.workdir)}`);
|
|
327800
327833
|
console.log("");
|
|
327801
327834
|
const testSpinner = createSpinner("Testing SSH connection...");
|
|
327802
327835
|
testSpinner.start();
|
|
@@ -327812,7 +327845,7 @@ async function cmdSandboxSSH(host, opts) {
|
|
|
327812
327845
|
testSpinner.succeed("SSH connection successful");
|
|
327813
327846
|
} else {
|
|
327814
327847
|
testSpinner.fail(`SSH connection failed: ${result.error}`);
|
|
327815
|
-
console.log(
|
|
327848
|
+
console.log(chalk28.yellow("Configuration saved anyway. Fix the connection issue and run `npx nestor-sh sandbox test`."));
|
|
327816
327849
|
}
|
|
327817
327850
|
try {
|
|
327818
327851
|
const config2 = readConfigFile() ?? {};
|
|
@@ -327826,10 +327859,10 @@ async function cmdSandboxSSH(host, opts) {
|
|
|
327826
327859
|
};
|
|
327827
327860
|
config2.security = security;
|
|
327828
327861
|
writeConfigFile(config2);
|
|
327829
|
-
console.log(
|
|
327830
|
-
console.log(
|
|
327862
|
+
console.log(chalk28.green("SSH configuration saved."));
|
|
327863
|
+
console.log(chalk28.dim('To use SSH as the default sandbox, set security.sandboxMode to "ssh" in your config.'));
|
|
327831
327864
|
} catch (err) {
|
|
327832
|
-
console.error(
|
|
327865
|
+
console.error(chalk28.red("Failed to save config:"), err instanceof Error ? err.message : String(err));
|
|
327833
327866
|
}
|
|
327834
327867
|
console.log("");
|
|
327835
327868
|
}
|
|
@@ -327918,7 +327951,7 @@ async function testSSHWithCli(config2) {
|
|
|
327918
327951
|
// src/commands/template.ts
|
|
327919
327952
|
init_db();
|
|
327920
327953
|
import * as p6 from "@clack/prompts";
|
|
327921
|
-
import
|
|
327954
|
+
import chalk29 from "chalk";
|
|
327922
327955
|
import fs29 from "node:fs";
|
|
327923
327956
|
import path29 from "node:path";
|
|
327924
327957
|
function registerTemplateCommand(program2) {
|
|
@@ -327935,13 +327968,13 @@ function registerTemplateCommand(program2) {
|
|
|
327935
327968
|
if (builtIn.length === 0) {
|
|
327936
327969
|
p6.log.info("No built-in templates found.");
|
|
327937
327970
|
} else {
|
|
327938
|
-
p6.log.info(
|
|
327971
|
+
p6.log.info(chalk29.bold("Built-in Templates:"));
|
|
327939
327972
|
for (const tmpl of builtIn) {
|
|
327940
327973
|
console.log(
|
|
327941
|
-
` ${
|
|
327974
|
+
` ${chalk29.cyan(tmpl.name)} ${chalk29.gray(`v${tmpl.version}`)} \u2014 ${tmpl.description}`
|
|
327942
327975
|
);
|
|
327943
327976
|
console.log(
|
|
327944
|
-
` ${
|
|
327977
|
+
` ${chalk29.gray(`${tmpl.agentCount} agents | by ${tmpl.author}`)}`
|
|
327945
327978
|
);
|
|
327946
327979
|
}
|
|
327947
327980
|
}
|
|
@@ -327966,7 +327999,7 @@ function registerTemplateCommand(program2) {
|
|
|
327966
327999
|
if (opts.output) {
|
|
327967
328000
|
const outputPath = path29.resolve(opts.output);
|
|
327968
328001
|
fs29.writeFileSync(outputPath, json, "utf-8");
|
|
327969
|
-
s.stop(`Template exported to ${
|
|
328002
|
+
s.stop(`Template exported to ${chalk29.green(outputPath)}`);
|
|
327970
328003
|
} else {
|
|
327971
328004
|
s.stop("Template exported:");
|
|
327972
328005
|
console.log(json);
|
|
@@ -327995,7 +328028,7 @@ function registerTemplateCommand(program2) {
|
|
|
327995
328028
|
if (!validation2.valid) {
|
|
327996
328029
|
p6.log.error("Template validation failed:");
|
|
327997
328030
|
for (const err of validation2.errors) {
|
|
327998
|
-
console.log(` ${
|
|
328031
|
+
console.log(` ${chalk29.red("\u2717")} ${err}`);
|
|
327999
328032
|
}
|
|
328000
328033
|
store.close();
|
|
328001
328034
|
process.exit(1);
|
|
@@ -328007,15 +328040,15 @@ function registerTemplateCommand(program2) {
|
|
|
328007
328040
|
overwrite: opts.overwrite
|
|
328008
328041
|
});
|
|
328009
328042
|
s.stop(opts.dryRun ? "Dry run complete:" : "Import complete:");
|
|
328010
|
-
console.log(` ${
|
|
328043
|
+
console.log(` ${chalk29.green("Created:")} ${result.created.agents} agents, ${result.created.workflows} workflows, ${result.created.skills} skills`);
|
|
328011
328044
|
if (result.skipped.length > 0) {
|
|
328012
|
-
console.log(` ${
|
|
328045
|
+
console.log(` ${chalk29.yellow("Skipped:")}`);
|
|
328013
328046
|
for (const skip of result.skipped) {
|
|
328014
328047
|
console.log(` ${skip.item}: ${skip.reason}`);
|
|
328015
328048
|
}
|
|
328016
328049
|
}
|
|
328017
328050
|
if (result.conflicts.length > 0) {
|
|
328018
|
-
console.log(` ${
|
|
328051
|
+
console.log(` ${chalk29.cyan("Conflicts:")}`);
|
|
328019
328052
|
for (const conflict of result.conflicts) {
|
|
328020
328053
|
console.log(` ${conflict.item}: ${conflict.resolution}`);
|
|
328021
328054
|
}
|
|
@@ -328039,7 +328072,7 @@ function registerTemplateCommand(program2) {
|
|
|
328039
328072
|
p6.log.info("Available templates:");
|
|
328040
328073
|
const available = service.listBuiltIn();
|
|
328041
328074
|
for (const t of available) {
|
|
328042
|
-
console.log(` ${
|
|
328075
|
+
console.log(` ${chalk29.cyan(t.name)} \u2014 ${t.description}`);
|
|
328043
328076
|
}
|
|
328044
328077
|
store.close();
|
|
328045
328078
|
process.exit(1);
|
|
@@ -328049,9 +328082,9 @@ function registerTemplateCommand(program2) {
|
|
|
328049
328082
|
dryRun: opts.dryRun
|
|
328050
328083
|
});
|
|
328051
328084
|
s.stop(opts.dryRun ? "Dry run complete:" : `Template "${name}" applied:`);
|
|
328052
|
-
console.log(` ${
|
|
328085
|
+
console.log(` ${chalk29.green("Created:")} ${result.created.agents} agents, ${result.created.workflows} workflows, ${result.created.skills} skills`);
|
|
328053
328086
|
if (result.skipped.length > 0) {
|
|
328054
|
-
console.log(` ${
|
|
328087
|
+
console.log(` ${chalk29.yellow("Skipped:")} ${result.skipped.length} items (already exist)`);
|
|
328055
328088
|
}
|
|
328056
328089
|
store.close();
|
|
328057
328090
|
} catch (err) {
|
|
@@ -328067,7 +328100,7 @@ init_db();
|
|
|
328067
328100
|
init_config2();
|
|
328068
328101
|
init_spinner();
|
|
328069
328102
|
import { resolve as resolve18 } from "node:path";
|
|
328070
|
-
import
|
|
328103
|
+
import chalk30 from "chalk";
|
|
328071
328104
|
function registerRagCommand(program2) {
|
|
328072
328105
|
const rag = program2.command("rag").description("RAG (Retrieval-Augmented Generation) commands");
|
|
328073
328106
|
rag.command("index [path]").description("Index a directory for code-context retrieval").option("-t, --tenant <id>", "Tenant ID", "default").option("--include <patterns...>", "Glob patterns to include").option("--exclude <patterns...>", "Glob patterns to exclude").option("--reindex", "Only re-index modified files", false).action(async (path32, opts) => {
|
|
@@ -328097,7 +328130,7 @@ function registerRagCommand(program2) {
|
|
|
328097
328130
|
}
|
|
328098
328131
|
});
|
|
328099
328132
|
spinner3.succeed(
|
|
328100
|
-
`Indexed ${
|
|
328133
|
+
`Indexed ${chalk30.bold(result.filesIndexed)} files, ${chalk30.bold(result.chunksCreated)} chunks in ${chalk30.dim((result.duration / 1e3).toFixed(1) + "s")} (provider: ${chalk30.cyan(provider.name)})`
|
|
328101
328134
|
);
|
|
328102
328135
|
} catch (err) {
|
|
328103
328136
|
spinner3.fail(`Indexing failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -328124,25 +328157,25 @@ function registerRagCommand(program2) {
|
|
|
328124
328157
|
filePath: opts.file
|
|
328125
328158
|
});
|
|
328126
328159
|
if (results.length === 0) {
|
|
328127
|
-
console.log(
|
|
328160
|
+
console.log(chalk30.yellow("No results found. Try indexing first: npx nestor-sh rag index"));
|
|
328128
328161
|
return;
|
|
328129
328162
|
}
|
|
328130
|
-
console.log(
|
|
328163
|
+
console.log(chalk30.bold(`
|
|
328131
328164
|
${results.length} results for "${query}":
|
|
328132
328165
|
`));
|
|
328133
328166
|
for (const chunk of results) {
|
|
328134
|
-
const nameLabel = chunk.name ?
|
|
328135
|
-
const scoreLabel = chunk.score >= 0.7 ?
|
|
328167
|
+
const nameLabel = chunk.name ? chalk30.cyan(` (${chunk.name})`) : "";
|
|
328168
|
+
const scoreLabel = chunk.score >= 0.7 ? chalk30.green(chunk.score.toFixed(2)) : chalk30.yellow(chunk.score.toFixed(2));
|
|
328136
328169
|
console.log(
|
|
328137
|
-
|
|
328170
|
+
chalk30.dim(" ") + chalk30.bold(chunk.filePath) + chalk30.dim(`:${chunk.startLine}-${chunk.endLine}`) + nameLabel + chalk30.dim(" [") + scoreLabel + chalk30.dim("]")
|
|
328138
328171
|
);
|
|
328139
328172
|
const preview = chunk.content.split("\n").slice(0, 3).join("\n");
|
|
328140
|
-
const indented = preview.split("\n").map((l) =>
|
|
328173
|
+
const indented = preview.split("\n").map((l) => chalk30.dim(" ") + l).join("\n");
|
|
328141
328174
|
console.log(indented);
|
|
328142
328175
|
console.log("");
|
|
328143
328176
|
}
|
|
328144
328177
|
} catch (err) {
|
|
328145
|
-
console.error(
|
|
328178
|
+
console.error(chalk30.red(`Search failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
328146
328179
|
process.exit(1);
|
|
328147
328180
|
}
|
|
328148
328181
|
});
|
|
@@ -328160,14 +328193,14 @@ ${results.length} results for "${query}":
|
|
|
328160
328193
|
});
|
|
328161
328194
|
const indexer = new agentModule.RagIndexer(store, provider);
|
|
328162
328195
|
const status = await indexer.status(opts.tenant);
|
|
328163
|
-
console.log(
|
|
328164
|
-
console.log(` Chunks: ${
|
|
328165
|
-
console.log(` Files: ${
|
|
328166
|
-
console.log(` Provider: ${
|
|
328167
|
-
console.log(` Last index: ${status.lastIndexedAt ?
|
|
328196
|
+
console.log(chalk30.bold("\nRAG Index Status:\n"));
|
|
328197
|
+
console.log(` Chunks: ${chalk30.bold(status.totalChunks)}`);
|
|
328198
|
+
console.log(` Files: ${chalk30.bold(status.totalFiles)}`);
|
|
328199
|
+
console.log(` Provider: ${chalk30.cyan(status.embeddingProvider)}`);
|
|
328200
|
+
console.log(` Last index: ${status.lastIndexedAt ? chalk30.dim(status.lastIndexedAt) : chalk30.yellow("never")}`);
|
|
328168
328201
|
console.log("");
|
|
328169
328202
|
} catch (err) {
|
|
328170
|
-
console.error(
|
|
328203
|
+
console.error(chalk30.red(`Status check failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
328171
328204
|
process.exit(1);
|
|
328172
328205
|
}
|
|
328173
328206
|
});
|
|
@@ -328178,9 +328211,9 @@ ${results.length} results for "${query}":
|
|
|
328178
328211
|
const provider = new agentModule.LocalEmbeddings();
|
|
328179
328212
|
const indexer = new agentModule.RagIndexer(store, provider);
|
|
328180
328213
|
const deleted = await indexer.clear(void 0, opts.tenant);
|
|
328181
|
-
console.log(
|
|
328214
|
+
console.log(chalk30.green(`Cleared ${deleted} chunks from the RAG index.`));
|
|
328182
328215
|
} catch (err) {
|
|
328183
|
-
console.error(
|
|
328216
|
+
console.error(chalk30.red(`Clear failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
328184
328217
|
process.exit(1);
|
|
328185
328218
|
}
|
|
328186
328219
|
});
|
|
@@ -328189,7 +328222,7 @@ ${results.length} results for "${query}":
|
|
|
328189
328222
|
// src/commands/test.ts
|
|
328190
328223
|
import { resolve as resolve19, relative as relative5 } from "node:path";
|
|
328191
328224
|
import { readdirSync as readdirSync8, statSync as statSync8, existsSync as existsSync27 } from "node:fs";
|
|
328192
|
-
import
|
|
328225
|
+
import chalk31 from "chalk";
|
|
328193
328226
|
var TEST_FILE_PATTERNS = [
|
|
328194
328227
|
".nestor-test.yaml",
|
|
328195
328228
|
".nestor-test.yml",
|
|
@@ -328202,7 +328235,7 @@ function registerTestCommand(program2) {
|
|
|
328202
328235
|
if (opts.file) {
|
|
328203
328236
|
const filePath = resolve19(opts.file);
|
|
328204
328237
|
if (!existsSync27(filePath)) {
|
|
328205
|
-
console.error(
|
|
328238
|
+
console.error(chalk31.red(`File not found: ${opts.file}`));
|
|
328206
328239
|
process.exit(1);
|
|
328207
328240
|
}
|
|
328208
328241
|
await runSkillTests([filePath], opts.verbose, opts.json);
|
|
@@ -328215,7 +328248,7 @@ function registerTestCommand(program2) {
|
|
|
328215
328248
|
}
|
|
328216
328249
|
if (opts.record) {
|
|
328217
328250
|
if (!opts.prompt) {
|
|
328218
|
-
console.error(
|
|
328251
|
+
console.error(chalk31.red("--prompt is required when using --record"));
|
|
328219
328252
|
process.exit(1);
|
|
328220
328253
|
}
|
|
328221
328254
|
await recordFixture(opts.record, opts.prompt);
|
|
@@ -328238,9 +328271,9 @@ function registerTestCommand(program2) {
|
|
|
328238
328271
|
}
|
|
328239
328272
|
const uniqueFiles = [...new Set(allFiles)];
|
|
328240
328273
|
if (uniqueFiles.length === 0) {
|
|
328241
|
-
console.log(
|
|
328242
|
-
console.log(
|
|
328243
|
-
console.log(
|
|
328274
|
+
console.log(chalk31.yellow("No test files found."));
|
|
328275
|
+
console.log(chalk31.dim(" Create files ending with .test.yaml or .nestor-test.yaml"));
|
|
328276
|
+
console.log(chalk31.dim(" Default search paths: ./ and .nestor/tests/"));
|
|
328244
328277
|
process.exit(1);
|
|
328245
328278
|
}
|
|
328246
328279
|
await runSkillTests(uniqueFiles, opts.verbose, opts.json);
|
|
@@ -328289,14 +328322,14 @@ async function listTestFiles(dir) {
|
|
|
328289
328322
|
}
|
|
328290
328323
|
const unique = [...new Set(files)];
|
|
328291
328324
|
if (unique.length === 0) {
|
|
328292
|
-
console.log(
|
|
328325
|
+
console.log(chalk31.yellow("No test files found. Create files ending with .test.yaml"));
|
|
328293
328326
|
return;
|
|
328294
328327
|
}
|
|
328295
|
-
console.log(
|
|
328328
|
+
console.log(chalk31.bold(`
|
|
328296
328329
|
Discovered ${unique.length} test file(s):
|
|
328297
328330
|
`));
|
|
328298
328331
|
for (const file of unique) {
|
|
328299
|
-
console.log(
|
|
328332
|
+
console.log(chalk31.dim(" ") + chalk31.cyan(relative5(dir, file)));
|
|
328300
328333
|
}
|
|
328301
328334
|
console.log("");
|
|
328302
328335
|
}
|
|
@@ -328307,7 +328340,7 @@ async function runSkillTests(files, verbose, json) {
|
|
|
328307
328340
|
const reporter = new skillTester.TestReporter();
|
|
328308
328341
|
const allResults = [];
|
|
328309
328342
|
if (!json) {
|
|
328310
|
-
console.log(
|
|
328343
|
+
console.log(chalk31.bold(`
|
|
328311
328344
|
Running ${files.length} test suite(s)...
|
|
328312
328345
|
`));
|
|
328313
328346
|
}
|
|
@@ -328317,7 +328350,7 @@ Running ${files.length} test suite(s)...
|
|
|
328317
328350
|
allResults.push(...suiteResults);
|
|
328318
328351
|
} catch (err) {
|
|
328319
328352
|
if (!json) {
|
|
328320
|
-
console.log(
|
|
328353
|
+
console.log(chalk31.red(` FAIL `) + chalk31.dim(file) + chalk31.red(` (${err instanceof Error ? err.message : String(err)})`));
|
|
328321
328354
|
}
|
|
328322
328355
|
}
|
|
328323
328356
|
}
|
|
@@ -328349,14 +328382,14 @@ async function runSkillTestsByName(skillName, verbose, json) {
|
|
|
328349
328382
|
}
|
|
328350
328383
|
}
|
|
328351
328384
|
if (matchingFiles.length === 0) {
|
|
328352
|
-
console.log(
|
|
328353
|
-
console.log(
|
|
328385
|
+
console.log(chalk31.yellow(`No test files found for skill: ${skillName}`));
|
|
328386
|
+
console.log(chalk31.dim(" Searched in: .nestor/tests/, tests/"));
|
|
328354
328387
|
process.exit(1);
|
|
328355
328388
|
}
|
|
328356
328389
|
await runSkillTests(matchingFiles, verbose, json);
|
|
328357
328390
|
}
|
|
328358
328391
|
async function runLegacyTests(files, verbose) {
|
|
328359
|
-
console.log(
|
|
328392
|
+
console.log(chalk31.bold(`
|
|
328360
328393
|
Running ${files.length} test suite(s) (legacy runner)...
|
|
328361
328394
|
`));
|
|
328362
328395
|
const agentModule = await Promise.resolve().then(() => (init_src5(), src_exports5));
|
|
@@ -328371,38 +328404,38 @@ Running ${files.length} test suite(s) (legacy runner)...
|
|
|
328371
328404
|
try {
|
|
328372
328405
|
suite = agentModule.AgentTestRunner.loadSuite(file);
|
|
328373
328406
|
} catch (err) {
|
|
328374
|
-
console.log(
|
|
328407
|
+
console.log(chalk31.red(` FAIL `) + chalk31.dim(relPath) + chalk31.red(` (parse error: ${err instanceof Error ? err.message : String(err)})`));
|
|
328375
328408
|
totalFailed++;
|
|
328376
328409
|
totalTests++;
|
|
328377
328410
|
continue;
|
|
328378
328411
|
}
|
|
328379
|
-
console.log(
|
|
328412
|
+
console.log(chalk31.bold(chalk31.dim(" ") + `${suite.name}`) + chalk31.dim(` (${relPath})`));
|
|
328380
328413
|
const result = await runner.runSuite(suite);
|
|
328381
328414
|
for (const testResult of result.results) {
|
|
328382
328415
|
totalTests++;
|
|
328383
328416
|
if (testResult.passed) {
|
|
328384
328417
|
totalPassed++;
|
|
328385
|
-
console.log(
|
|
328418
|
+
console.log(chalk31.green(" \u2714 ") + testResult.testName + chalk31.dim(` (${testResult.durationMs}ms)`));
|
|
328386
328419
|
} else {
|
|
328387
328420
|
totalFailed++;
|
|
328388
|
-
console.log(
|
|
328421
|
+
console.log(chalk31.red(" \u2718 ") + testResult.testName + chalk31.dim(` (${testResult.durationMs}ms)`));
|
|
328389
328422
|
for (const failure of testResult.failures) {
|
|
328390
|
-
console.log(
|
|
328423
|
+
console.log(chalk31.red(" ") + chalk31.dim(failure));
|
|
328391
328424
|
}
|
|
328392
328425
|
}
|
|
328393
328426
|
if (verbose && testResult.result) {
|
|
328394
|
-
console.log(
|
|
328427
|
+
console.log(chalk31.dim(" ") + `iterations: ${testResult.result.iterations}, cost: $${testResult.result.costUsd.toFixed(4)}, exit: ${testResult.result.exitReason}`);
|
|
328395
328428
|
}
|
|
328396
328429
|
}
|
|
328397
328430
|
console.log("");
|
|
328398
328431
|
}
|
|
328399
328432
|
const duration = ((Date.now() - startTime4) / 1e3).toFixed(1);
|
|
328400
|
-
console.log(
|
|
328433
|
+
console.log(chalk31.bold("\u2500".repeat(50)));
|
|
328401
328434
|
if (totalFailed === 0) {
|
|
328402
|
-
console.log(
|
|
328435
|
+
console.log(chalk31.green.bold(` All ${totalPassed} tests passed`) + chalk31.dim(` (${duration}s)`));
|
|
328403
328436
|
} else {
|
|
328404
328437
|
console.log(
|
|
328405
|
-
|
|
328438
|
+
chalk31.bold(` Tests: `) + chalk31.green.bold(`${totalPassed} passed`) + chalk31.dim(", ") + chalk31.red.bold(`${totalFailed} failed`) + chalk31.dim(`, ${totalTests} total (${duration}s)`)
|
|
328406
328439
|
);
|
|
328407
328440
|
}
|
|
328408
328441
|
console.log("");
|
|
@@ -328411,7 +328444,7 @@ Running ${files.length} test suite(s) (legacy runner)...
|
|
|
328411
328444
|
}
|
|
328412
328445
|
}
|
|
328413
328446
|
async function recordFixture(outputPath, prompt) {
|
|
328414
|
-
console.log(
|
|
328447
|
+
console.log(chalk31.bold("\nRecording LLM responses...\n"));
|
|
328415
328448
|
try {
|
|
328416
328449
|
const agentModule = await Promise.resolve().then(() => (init_src5(), src_exports5));
|
|
328417
328450
|
const router = await agentModule.createDefaultRouter();
|
|
@@ -328421,12 +328454,12 @@ async function recordFixture(outputPath, prompt) {
|
|
|
328421
328454
|
prompt,
|
|
328422
328455
|
outputPath: resolve19(outputPath)
|
|
328423
328456
|
});
|
|
328424
|
-
console.log(
|
|
328425
|
-
console.log(
|
|
328426
|
-
console.log(
|
|
328457
|
+
console.log(chalk31.green(` Recorded ${result.recordings} responses to ${outputPath}`));
|
|
328458
|
+
console.log(chalk31.dim(` Output: ${result.output.slice(0, 100)}...`));
|
|
328459
|
+
console.log(chalk31.dim(` Duration: ${(result.durationMs / 1e3).toFixed(1)}s, Iterations: ${result.iterations}`));
|
|
328427
328460
|
console.log("");
|
|
328428
328461
|
} catch (err) {
|
|
328429
|
-
console.error(
|
|
328462
|
+
console.error(chalk31.red(`Recording failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
328430
328463
|
process.exit(1);
|
|
328431
328464
|
}
|
|
328432
328465
|
}
|
|
@@ -328434,7 +328467,7 @@ async function recordFixture(outputPath, prompt) {
|
|
|
328434
328467
|
// src/commands/guardrail.ts
|
|
328435
328468
|
init_db();
|
|
328436
328469
|
init_table();
|
|
328437
|
-
import
|
|
328470
|
+
import chalk32 from "chalk";
|
|
328438
328471
|
import * as p7 from "@clack/prompts";
|
|
328439
328472
|
import crypto21 from "node:crypto";
|
|
328440
328473
|
function registerGuardrailCommand(program2) {
|
|
@@ -328443,19 +328476,19 @@ function registerGuardrailCommand(program2) {
|
|
|
328443
328476
|
const store = await getStore();
|
|
328444
328477
|
const guardrails = store.listGuardrails();
|
|
328445
328478
|
if (guardrails.length === 0) {
|
|
328446
|
-
console.log(
|
|
328447
|
-
console.log(
|
|
328479
|
+
console.log(chalk32.dim("No guardrails configured."));
|
|
328480
|
+
console.log(chalk32.dim("Add one with: npx nestor-sh guardrail add"));
|
|
328448
328481
|
return;
|
|
328449
328482
|
}
|
|
328450
328483
|
printTable(
|
|
328451
328484
|
["ID", "Name", "Type", "Pattern", "Action", "Enabled"],
|
|
328452
328485
|
guardrails.map((g) => [
|
|
328453
|
-
|
|
328454
|
-
|
|
328455
|
-
|
|
328456
|
-
|
|
328457
|
-
g.action === "block" ?
|
|
328458
|
-
g.enabled ?
|
|
328486
|
+
chalk32.dim(g.id.slice(0, 12)),
|
|
328487
|
+
chalk32.white(g.name),
|
|
328488
|
+
chalk32.cyan(g.type),
|
|
328489
|
+
chalk32.dim(g.pattern.length > 30 ? g.pattern.slice(0, 30) + "..." : g.pattern),
|
|
328490
|
+
g.action === "block" ? chalk32.red(g.action) : g.action === "warn" ? chalk32.yellow(g.action) : chalk32.blue(g.action),
|
|
328491
|
+
g.enabled ? chalk32.green("yes") : chalk32.dim("no")
|
|
328459
328492
|
])
|
|
328460
328493
|
);
|
|
328461
328494
|
});
|
|
@@ -328512,35 +328545,35 @@ function registerGuardrailCommand(program2) {
|
|
|
328512
328545
|
config: config2,
|
|
328513
328546
|
enabled: true
|
|
328514
328547
|
});
|
|
328515
|
-
console.log(
|
|
328548
|
+
console.log(chalk32.green(`Guardrail "${name}" created (${id}).`));
|
|
328516
328549
|
});
|
|
328517
328550
|
guardrail.command("remove <id>").description("Remove a guardrail by ID").action(async (id) => {
|
|
328518
328551
|
const store = await getStore();
|
|
328519
328552
|
const deleted = store.deleteGuardrail(id);
|
|
328520
328553
|
if (deleted) {
|
|
328521
|
-
console.log(
|
|
328554
|
+
console.log(chalk32.green(`Guardrail ${id} removed.`));
|
|
328522
328555
|
} else {
|
|
328523
|
-
console.log(
|
|
328556
|
+
console.log(chalk32.red(`Guardrail ${id} not found.`));
|
|
328524
328557
|
}
|
|
328525
328558
|
});
|
|
328526
328559
|
guardrail.command("toggle <id>").description("Enable/disable a guardrail").action(async (id) => {
|
|
328527
328560
|
const store = await getStore();
|
|
328528
328561
|
const existing = store.getGuardrail(id);
|
|
328529
328562
|
if (!existing) {
|
|
328530
|
-
console.log(
|
|
328563
|
+
console.log(chalk32.red(`Guardrail ${id} not found.`));
|
|
328531
328564
|
return;
|
|
328532
328565
|
}
|
|
328533
328566
|
const newEnabled = !existing.enabled;
|
|
328534
328567
|
store.updateGuardrail(id, { enabled: newEnabled });
|
|
328535
|
-
console.log(
|
|
328568
|
+
console.log(chalk32.green(`Guardrail ${id} ${newEnabled ? "enabled" : "disabled"}.`));
|
|
328536
328569
|
});
|
|
328537
328570
|
}
|
|
328538
328571
|
|
|
328539
328572
|
// src/commands/loop.ts
|
|
328540
328573
|
init_db();
|
|
328541
328574
|
init_config2();
|
|
328542
|
-
import
|
|
328543
|
-
import { randomUUID as
|
|
328575
|
+
import chalk33 from "chalk";
|
|
328576
|
+
import { randomUUID as randomUUID68 } from "node:crypto";
|
|
328544
328577
|
import { readFileSync as readFileSync29, existsSync as existsSync28 } from "node:fs";
|
|
328545
328578
|
import { execSync as execSync4 } from "node:child_process";
|
|
328546
328579
|
function desktopNotify2(title, message) {
|
|
@@ -328634,13 +328667,13 @@ function registerLoopCommand(program2) {
|
|
|
328634
328667
|
let spec = opts.spec;
|
|
328635
328668
|
if (!spec && opts.specFile) {
|
|
328636
328669
|
if (!existsSync28(opts.specFile)) {
|
|
328637
|
-
console.error(
|
|
328670
|
+
console.error(chalk33.red(`Spec file not found: ${opts.specFile}`));
|
|
328638
328671
|
process.exit(1);
|
|
328639
328672
|
}
|
|
328640
328673
|
spec = readFileSync29(opts.specFile, "utf-8").trim();
|
|
328641
328674
|
}
|
|
328642
328675
|
if (!spec) {
|
|
328643
|
-
console.error(
|
|
328676
|
+
console.error(chalk33.red("Must provide --spec or --spec-file"));
|
|
328644
328677
|
process.exit(1);
|
|
328645
328678
|
}
|
|
328646
328679
|
const maxIterations = parseInt(opts.maxIterations, 10);
|
|
@@ -328663,27 +328696,27 @@ function registerLoopCommand(program2) {
|
|
|
328663
328696
|
} catch {
|
|
328664
328697
|
}
|
|
328665
328698
|
}
|
|
328666
|
-
console.log(
|
|
328667
|
-
console.log(
|
|
328668
|
-
console.log(
|
|
328669
|
-
console.log(
|
|
328670
|
-
console.log(
|
|
328699
|
+
console.log(chalk33.cyan("\n Ralph Fresh-Context Loop"));
|
|
328700
|
+
console.log(chalk33.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
328701
|
+
console.log(chalk33.white(" Spec:"), spec.slice(0, 100) + (spec.length > 100 ? "..." : ""));
|
|
328702
|
+
console.log(chalk33.white(" Agent:"), opts.agent);
|
|
328703
|
+
console.log(chalk33.white(" Max iterations:"), maxIterations);
|
|
328671
328704
|
if (maxRuntimeMs > 0) {
|
|
328672
|
-
console.log(
|
|
328705
|
+
console.log(chalk33.white(" Max runtime:"), `${maxRuntimeMs / 1e3}s`);
|
|
328673
328706
|
}
|
|
328674
|
-
console.log(
|
|
328707
|
+
console.log(chalk33.white(" Budget:"), `$${totalBudget}`);
|
|
328675
328708
|
if (gate) {
|
|
328676
|
-
console.log(
|
|
328677
|
-
console.log(
|
|
328709
|
+
console.log(chalk33.white(" Validators:"), validateCommands.join(", "));
|
|
328710
|
+
console.log(chalk33.white(" Strictness:"), `${opts.strictness} \u2192 strict (progressive)`);
|
|
328678
328711
|
} else if (opts.verify) {
|
|
328679
|
-
console.log(
|
|
328712
|
+
console.log(chalk33.white(" Verify cmd:"), opts.verify);
|
|
328680
328713
|
}
|
|
328681
328714
|
console.log("");
|
|
328682
328715
|
let agentModule;
|
|
328683
328716
|
try {
|
|
328684
328717
|
agentModule = await Promise.resolve().then(() => (init_src5(), src_exports5));
|
|
328685
328718
|
} catch {
|
|
328686
|
-
console.error(
|
|
328719
|
+
console.error(chalk33.red("Failed to import @nestor/agent. Is it installed?"));
|
|
328687
328720
|
process.exit(1);
|
|
328688
328721
|
}
|
|
328689
328722
|
const store = await getStore();
|
|
@@ -328694,7 +328727,7 @@ function registerLoopCommand(program2) {
|
|
|
328694
328727
|
} catch {
|
|
328695
328728
|
}
|
|
328696
328729
|
const agent = resolvedAgent ?? {
|
|
328697
|
-
id:
|
|
328730
|
+
id: randomUUID68(),
|
|
328698
328731
|
name: opts.agent,
|
|
328699
328732
|
adapterType: "claude",
|
|
328700
328733
|
adapterConfig: {
|
|
@@ -328709,7 +328742,7 @@ function registerLoopCommand(program2) {
|
|
|
328709
328742
|
try {
|
|
328710
328743
|
router = await agentModule.createDefaultRouter();
|
|
328711
328744
|
} catch {
|
|
328712
|
-
console.error(
|
|
328745
|
+
console.error(chalk33.red("Could not initialize LLM adapter. Is the API key configured?"));
|
|
328713
328746
|
process.exit(1);
|
|
328714
328747
|
}
|
|
328715
328748
|
const summary = {
|
|
@@ -328722,35 +328755,35 @@ function registerLoopCommand(program2) {
|
|
|
328722
328755
|
};
|
|
328723
328756
|
for (let i = 1; i <= maxIterations; i++) {
|
|
328724
328757
|
if (summary.totalCostUsd >= totalBudget) {
|
|
328725
|
-
console.log(
|
|
328758
|
+
console.log(chalk33.yellow(`
|
|
328726
328759
|
Budget exhausted ($${summary.totalCostUsd.toFixed(4)} / $${totalBudget}). Stopping.`));
|
|
328727
328760
|
break;
|
|
328728
328761
|
}
|
|
328729
328762
|
if (maxRuntimeMs > 0 && Date.now() - loopStartMs >= maxRuntimeMs) {
|
|
328730
|
-
console.log(
|
|
328763
|
+
console.log(chalk33.yellow(`
|
|
328731
328764
|
Max runtime reached (${maxRuntimeMs / 1e3}s). Stopping.`));
|
|
328732
328765
|
break;
|
|
328733
328766
|
}
|
|
328734
328767
|
const remainingBudget = totalBudget - summary.totalCostUsd;
|
|
328735
|
-
console.log(
|
|
328736
|
-
\u2500\u2500 Iteration ${i}/${maxIterations} `) +
|
|
328768
|
+
console.log(chalk33.cyan(`
|
|
328769
|
+
\u2500\u2500 Iteration ${i}/${maxIterations} `) + chalk33.dim(`(budget remaining: $${remainingBudget.toFixed(4)}) \u2500\u2500`));
|
|
328737
328770
|
let bpReport = null;
|
|
328738
328771
|
if (gate && i > 1) {
|
|
328739
328772
|
bpReport = gate.run();
|
|
328740
|
-
const strictTag =
|
|
328773
|
+
const strictTag = chalk33.dim(`[${bpReport.strictness}]`);
|
|
328741
328774
|
if (bpReport.passed && bpReport.score >= 0.95) {
|
|
328742
|
-
console.log(
|
|
328775
|
+
console.log(chalk33.green(` ${strictTag} All validators pass (score: ${(bpReport.score * 100).toFixed(0)}%). Specification met!`));
|
|
328743
328776
|
summary.specMet = true;
|
|
328744
328777
|
break;
|
|
328745
328778
|
}
|
|
328746
|
-
const passTag =
|
|
328747
|
-
const failTag = bpReport.failedCount > 0 ?
|
|
328748
|
-
const regTag = bpReport.regressionCount > 0 ?
|
|
328749
|
-
console.log(
|
|
328779
|
+
const passTag = chalk33.green(`${bpReport.passedCount} pass`);
|
|
328780
|
+
const failTag = bpReport.failedCount > 0 ? chalk33.red(` ${bpReport.failedCount} fail`) : "";
|
|
328781
|
+
const regTag = bpReport.regressionCount > 0 ? chalk33.bgRed(` ${bpReport.regressionCount} REGRESSION`) : "";
|
|
328782
|
+
console.log(chalk33.dim(` ${strictTag} Validators: ${passTag}${failTag}${regTag} (score: ${(bpReport.score * 100).toFixed(0)}%)`));
|
|
328750
328783
|
} else if (!gate && opts.verify && i > 1) {
|
|
328751
328784
|
const verifyResult = runShellCommand(opts.verify, cwd);
|
|
328752
328785
|
if (verifyResult.exitCode === 0) {
|
|
328753
|
-
console.log(
|
|
328786
|
+
console.log(chalk33.green(" Specification met! Verify command exited 0."));
|
|
328754
328787
|
summary.specMet = true;
|
|
328755
328788
|
break;
|
|
328756
328789
|
}
|
|
@@ -328790,7 +328823,7 @@ function registerLoopCommand(program2) {
|
|
|
328790
328823
|
contextRotation: { maxMessages: 40, maxTokensEstimate: 8e4 },
|
|
328791
328824
|
stuckDetection: { maxRepeatedCalls: 3, maxConsecutiveErrors: 3 }
|
|
328792
328825
|
});
|
|
328793
|
-
const taskId =
|
|
328826
|
+
const taskId = randomUUID68();
|
|
328794
328827
|
let iterOutput = "";
|
|
328795
328828
|
try {
|
|
328796
328829
|
for await (const event of runtime.runStreaming({
|
|
@@ -328804,16 +328837,16 @@ function registerLoopCommand(program2) {
|
|
|
328804
328837
|
iterOutput += event.text;
|
|
328805
328838
|
break;
|
|
328806
328839
|
case "tool_start":
|
|
328807
|
-
console.log(
|
|
328840
|
+
console.log(chalk33.dim(`
|
|
328808
328841
|
[tool] ${event.name}`));
|
|
328809
328842
|
break;
|
|
328810
328843
|
case "tool_result":
|
|
328811
328844
|
if (!event.success) {
|
|
328812
|
-
console.log(
|
|
328845
|
+
console.log(chalk33.red(` [tool error] ${event.name}: ${event.result.slice(0, 100)}`));
|
|
328813
328846
|
}
|
|
328814
328847
|
break;
|
|
328815
328848
|
case "error":
|
|
328816
|
-
console.log(
|
|
328849
|
+
console.log(chalk33.red(`
|
|
328817
328850
|
[error] ${event.message}`));
|
|
328818
328851
|
break;
|
|
328819
328852
|
case "done": {
|
|
@@ -328835,7 +328868,7 @@ function registerLoopCommand(program2) {
|
|
|
328835
328868
|
const postReport = gate.run();
|
|
328836
328869
|
iterResult.specMet = postReport.passed && postReport.score >= 0.95;
|
|
328837
328870
|
if (postReport.regressionCount > 0) {
|
|
328838
|
-
console.log(
|
|
328871
|
+
console.log(chalk33.bgRed(` REGRESSION detected in ${postReport.regressionCount} validator(s)`));
|
|
328839
328872
|
}
|
|
328840
328873
|
} else if (opts.verify) {
|
|
328841
328874
|
const postVerify = runShellCommand(opts.verify, cwd);
|
|
@@ -328843,9 +328876,9 @@ function registerLoopCommand(program2) {
|
|
|
328843
328876
|
}
|
|
328844
328877
|
summary.iterationResults.push(iterResult);
|
|
328845
328878
|
console.log("");
|
|
328846
|
-
console.log(
|
|
328879
|
+
console.log(chalk33.dim(` [${r.exitReason}] ${r.usage.totalTokens} tokens, $${r.usage.estimatedCostUsd.toFixed(4)}, ${(r.durationMs / 1e3).toFixed(1)}s`));
|
|
328847
328880
|
if (iterResult.specMet) {
|
|
328848
|
-
console.log(
|
|
328881
|
+
console.log(chalk33.green(" Specification met!"));
|
|
328849
328882
|
summary.specMet = true;
|
|
328850
328883
|
}
|
|
328851
328884
|
break;
|
|
@@ -328853,7 +328886,7 @@ function registerLoopCommand(program2) {
|
|
|
328853
328886
|
}
|
|
328854
328887
|
}
|
|
328855
328888
|
} catch (err) {
|
|
328856
|
-
console.error(
|
|
328889
|
+
console.error(chalk33.red(`
|
|
328857
328890
|
Iteration ${i} crashed: ${err instanceof Error ? err.message : String(err)}`));
|
|
328858
328891
|
summary.iterationResults.push({
|
|
328859
328892
|
iteration: i,
|
|
@@ -328867,14 +328900,14 @@ function registerLoopCommand(program2) {
|
|
|
328867
328900
|
}
|
|
328868
328901
|
if (summary.specMet) break;
|
|
328869
328902
|
}
|
|
328870
|
-
console.log(
|
|
328871
|
-
console.log(
|
|
328872
|
-
console.log(
|
|
328873
|
-
console.log(
|
|
328874
|
-
console.log(
|
|
328903
|
+
console.log(chalk33.cyan("\n \u2500\u2500 Loop Summary \u2500\u2500"));
|
|
328904
|
+
console.log(chalk33.white(" Iterations:"), summary.totalIterations);
|
|
328905
|
+
console.log(chalk33.white(" Total cost:"), `$${summary.totalCostUsd.toFixed(4)}`);
|
|
328906
|
+
console.log(chalk33.white(" Total tokens:"), summary.totalTokens.toLocaleString());
|
|
328907
|
+
console.log(chalk33.white(" Total time:"), `${(summary.totalDurationMs / 1e3).toFixed(1)}s`);
|
|
328875
328908
|
console.log(
|
|
328876
|
-
|
|
328877
|
-
summary.specMet ?
|
|
328909
|
+
chalk33.white(" Spec met:"),
|
|
328910
|
+
summary.specMet ? chalk33.green("YES") : chalk33.red("NO")
|
|
328878
328911
|
);
|
|
328879
328912
|
console.log("");
|
|
328880
328913
|
desktopNotify2(
|
|
@@ -328889,7 +328922,7 @@ function registerLoopCommand(program2) {
|
|
|
328889
328922
|
// src/commands/messaging.ts
|
|
328890
328923
|
init_config2();
|
|
328891
328924
|
init_config();
|
|
328892
|
-
import
|
|
328925
|
+
import chalk34 from "chalk";
|
|
328893
328926
|
function getAdapterEnvStatus2() {
|
|
328894
328927
|
return [
|
|
328895
328928
|
{
|
|
@@ -328921,25 +328954,25 @@ function registerMessagingCommand(program2) {
|
|
|
328921
328954
|
messaging.command("status").description("Show which messaging adapters are configured").action(async () => {
|
|
328922
328955
|
const config2 = readConfigFile() ?? mergeWithDefaults({});
|
|
328923
328956
|
console.log("");
|
|
328924
|
-
console.log(
|
|
328925
|
-
console.log(
|
|
328957
|
+
console.log(chalk34.bold(" Messaging Status"));
|
|
328958
|
+
console.log(chalk34.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
328926
328959
|
const msgConfig = config2.messaging;
|
|
328927
328960
|
const enabled = msgConfig?.enabled ?? false;
|
|
328928
|
-
console.log(` ${
|
|
328961
|
+
console.log(` ${chalk34.dim("Enabled:")} ${enabled ? chalk34.green("true") : chalk34.yellow("false")}`);
|
|
328929
328962
|
if (msgConfig?.defaultAgentId) {
|
|
328930
|
-
console.log(` ${
|
|
328963
|
+
console.log(` ${chalk34.dim("Default Agent:")} ${msgConfig.defaultAgentId}`);
|
|
328931
328964
|
}
|
|
328932
328965
|
console.log("");
|
|
328933
|
-
console.log(
|
|
328934
|
-
console.log(
|
|
328966
|
+
console.log(chalk34.bold(" Adapter Configuration"));
|
|
328967
|
+
console.log(chalk34.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
328935
328968
|
const envStatus = getAdapterEnvStatus2();
|
|
328936
328969
|
for (const adapter of envStatus) {
|
|
328937
|
-
const icon = adapter.configured ?
|
|
328938
|
-
const label = adapter.configured ?
|
|
328939
|
-
console.log(` ${icon} ${
|
|
328970
|
+
const icon = adapter.configured ? chalk34.green("\u25CF") : chalk34.dim("\u25CB");
|
|
328971
|
+
const label = adapter.configured ? chalk34.green("ready") : chalk34.dim("not configured");
|
|
328972
|
+
console.log(` ${icon} ${chalk34.bold(adapter.platform.padEnd(12))} ${label}`);
|
|
328940
328973
|
for (const [varName, found] of Object.entries(adapter.envVars)) {
|
|
328941
|
-
const varIcon = found ?
|
|
328942
|
-
console.log(` ${varIcon} ${
|
|
328974
|
+
const varIcon = found ? chalk34.green(" \u2713") : chalk34.red(" \u2717");
|
|
328975
|
+
console.log(` ${varIcon} ${chalk34.dim(varName)}`);
|
|
328943
328976
|
}
|
|
328944
328977
|
}
|
|
328945
328978
|
const configTokens = [];
|
|
@@ -328948,30 +328981,30 @@ function registerMessagingCommand(program2) {
|
|
|
328948
328981
|
if (msgConfig?.slack?.botToken && msgConfig.slack.appToken) configTokens.push("slack");
|
|
328949
328982
|
if (configTokens.length > 0) {
|
|
328950
328983
|
console.log("");
|
|
328951
|
-
console.log(
|
|
328984
|
+
console.log(chalk34.dim(` Tokens also found in config file for: ${configTokens.join(", ")}`));
|
|
328952
328985
|
}
|
|
328953
328986
|
console.log("");
|
|
328954
|
-
console.log(
|
|
328955
|
-
console.log(
|
|
328956
|
-
console.log(
|
|
328957
|
-
console.log(
|
|
328958
|
-
console.log(
|
|
328987
|
+
console.log(chalk34.dim(" Required environment variables:"));
|
|
328988
|
+
console.log(chalk34.dim(" TELEGRAM_BOT_TOKEN \u2014 Telegram BotFather token"));
|
|
328989
|
+
console.log(chalk34.dim(" DISCORD_BOT_TOKEN \u2014 Discord bot token"));
|
|
328990
|
+
console.log(chalk34.dim(" SLACK_BOT_TOKEN \u2014 Slack Bot User OAuth Token (xoxb-...)"));
|
|
328991
|
+
console.log(chalk34.dim(" SLACK_APP_TOKEN \u2014 Slack App-Level Token (xapp-...)"));
|
|
328959
328992
|
console.log("");
|
|
328960
|
-
console.log(
|
|
328993
|
+
console.log(chalk34.dim(" Set messaging.enabled=true in nestor.config.json to activate."));
|
|
328961
328994
|
console.log("");
|
|
328962
328995
|
});
|
|
328963
328996
|
messaging.command("test").description("Send a test message via an adapter").argument("<adapter>", "Adapter to test: telegram, discord, or slack").option("-c, --channel <id>", "Channel/chat ID to send the test message to").option("-m, --message <text>", "Custom test message text").action(async (adapter, options) => {
|
|
328964
328997
|
const validAdapters = ["telegram", "discord", "slack"];
|
|
328965
328998
|
if (!validAdapters.includes(adapter)) {
|
|
328966
|
-
console.error(
|
|
328999
|
+
console.error(chalk34.red(` Unknown adapter "${adapter}". Must be one of: ${validAdapters.join(", ")}`));
|
|
328967
329000
|
process.exit(1);
|
|
328968
329001
|
}
|
|
328969
329002
|
if (!options.channel) {
|
|
328970
|
-
console.error(
|
|
329003
|
+
console.error(chalk34.red(" --channel is required. Provide the target channel/chat ID."));
|
|
328971
329004
|
process.exit(1);
|
|
328972
329005
|
}
|
|
328973
329006
|
console.log("");
|
|
328974
|
-
console.log(
|
|
329007
|
+
console.log(chalk34.dim(` Testing ${adapter} adapter...`));
|
|
328975
329008
|
const config2 = readConfigFile() ?? mergeWithDefaults({});
|
|
328976
329009
|
const host = config2.server.host ?? "127.0.0.1";
|
|
328977
329010
|
const port = config2.server.port ?? 3100;
|
|
@@ -328989,22 +329022,22 @@ function registerMessagingCommand(program2) {
|
|
|
328989
329022
|
const result = await response.json();
|
|
328990
329023
|
if (!response.ok) {
|
|
328991
329024
|
const error = result.error;
|
|
328992
|
-
console.error(
|
|
329025
|
+
console.error(chalk34.red(` Failed: ${error?.message ?? response.statusText}`));
|
|
328993
329026
|
if (response.status === 503) {
|
|
328994
|
-
console.log(
|
|
328995
|
-
console.log(
|
|
329027
|
+
console.log(chalk34.dim(" Make sure the Nestor server is running with messaging enabled."));
|
|
329028
|
+
console.log(chalk34.dim(" Run: npx nestor-sh start"));
|
|
328996
329029
|
}
|
|
328997
329030
|
process.exit(1);
|
|
328998
329031
|
}
|
|
328999
329032
|
const data = result.data;
|
|
329000
|
-
console.log(
|
|
329001
|
-
console.log(` ${
|
|
329002
|
-
console.log(` ${
|
|
329003
|
-
console.log(` ${
|
|
329033
|
+
console.log(chalk34.green(` Message sent successfully!`));
|
|
329034
|
+
console.log(` ${chalk34.dim("Platform:")} ${data.platform}`);
|
|
329035
|
+
console.log(` ${chalk34.dim("Channel:")} ${data.channelId}`);
|
|
329036
|
+
console.log(` ${chalk34.dim("Message ID:")} ${data.messageId}`);
|
|
329004
329037
|
console.log("");
|
|
329005
329038
|
} catch (err) {
|
|
329006
|
-
console.error(
|
|
329007
|
-
console.log(
|
|
329039
|
+
console.error(chalk34.red(` Failed to connect to Nestor server at ${baseUrl}`));
|
|
329040
|
+
console.log(chalk34.dim(" Make sure the server is running: npx nestor-sh start"));
|
|
329008
329041
|
console.log("");
|
|
329009
329042
|
process.exit(1);
|
|
329010
329043
|
}
|
|
@@ -329012,11 +329045,11 @@ function registerMessagingCommand(program2) {
|
|
|
329012
329045
|
messaging.command("send").description("Send a message to a specific channel via an adapter").argument("<adapter>", "Adapter: telegram, discord, or slack").argument("<channel>", "Channel or chat ID to send to").argument("<message>", "Message text to send").action(async (adapter, channel, message) => {
|
|
329013
329046
|
const validAdapters = ["telegram", "discord", "slack"];
|
|
329014
329047
|
if (!validAdapters.includes(adapter)) {
|
|
329015
|
-
console.error(
|
|
329048
|
+
console.error(chalk34.red(` Unknown adapter "${adapter}". Must be one of: ${validAdapters.join(", ")}`));
|
|
329016
329049
|
process.exit(1);
|
|
329017
329050
|
}
|
|
329018
329051
|
console.log("");
|
|
329019
|
-
console.log(
|
|
329052
|
+
console.log(chalk34.dim(` Sending message via ${adapter}...`));
|
|
329020
329053
|
const config2 = readConfigFile() ?? mergeWithDefaults({});
|
|
329021
329054
|
const host = config2.server.host ?? "127.0.0.1";
|
|
329022
329055
|
const port = config2.server.port ?? 3100;
|
|
@@ -329034,39 +329067,39 @@ function registerMessagingCommand(program2) {
|
|
|
329034
329067
|
const result = await response.json();
|
|
329035
329068
|
if (!response.ok) {
|
|
329036
329069
|
const error = result.error;
|
|
329037
|
-
console.error(
|
|
329070
|
+
console.error(chalk34.red(` Failed: ${error?.message ?? response.statusText}`));
|
|
329038
329071
|
if (response.status === 503) {
|
|
329039
|
-
console.log(
|
|
329040
|
-
console.log(
|
|
329072
|
+
console.log(chalk34.dim(" Make sure the Nestor server is running with messaging enabled."));
|
|
329073
|
+
console.log(chalk34.dim(" Run: npx nestor-sh start"));
|
|
329041
329074
|
}
|
|
329042
329075
|
process.exit(1);
|
|
329043
329076
|
}
|
|
329044
329077
|
const data = result.data;
|
|
329045
|
-
console.log(
|
|
329046
|
-
console.log(` ${
|
|
329047
|
-
console.log(` ${
|
|
329048
|
-
console.log(` ${
|
|
329078
|
+
console.log(chalk34.green(` Message sent!`));
|
|
329079
|
+
console.log(` ${chalk34.dim("Platform:")} ${data.platform}`);
|
|
329080
|
+
console.log(` ${chalk34.dim("Channel:")} ${data.channelId}`);
|
|
329081
|
+
console.log(` ${chalk34.dim("Message ID:")} ${data.messageId}`);
|
|
329049
329082
|
console.log("");
|
|
329050
329083
|
} catch (err) {
|
|
329051
|
-
console.error(
|
|
329052
|
-
console.log(
|
|
329084
|
+
console.error(chalk34.red(` Failed to connect to Nestor server at ${baseUrl}`));
|
|
329085
|
+
console.log(chalk34.dim(" Make sure the server is running: npx nestor-sh start"));
|
|
329053
329086
|
console.log("");
|
|
329054
329087
|
process.exit(1);
|
|
329055
329088
|
}
|
|
329056
329089
|
});
|
|
329057
329090
|
messaging.command("listen").description("Start listening for incoming messages (starts messaging bridge)").action(async () => {
|
|
329058
329091
|
console.log("");
|
|
329059
|
-
console.log(
|
|
329092
|
+
console.log(chalk34.bold(" Starting messaging bridge..."));
|
|
329060
329093
|
console.log("");
|
|
329061
329094
|
let config2 = readConfigFile();
|
|
329062
329095
|
if (!config2) {
|
|
329063
|
-
console.log(
|
|
329096
|
+
console.log(chalk34.yellow(" [warn]"), "No config file found, using defaults");
|
|
329064
329097
|
config2 = mergeWithDefaults({});
|
|
329065
329098
|
}
|
|
329066
329099
|
const msgConfig = config2.messaging;
|
|
329067
329100
|
if (!msgConfig?.enabled) {
|
|
329068
|
-
console.error(
|
|
329069
|
-
console.log(
|
|
329101
|
+
console.error(chalk34.red(" Messaging is not enabled in your configuration."));
|
|
329102
|
+
console.log(chalk34.dim(" Set messaging.enabled=true in nestor.config.json"));
|
|
329070
329103
|
console.log("");
|
|
329071
329104
|
process.exit(1);
|
|
329072
329105
|
}
|
|
@@ -329078,12 +329111,12 @@ function registerMessagingCommand(program2) {
|
|
|
329078
329111
|
const { bootstrapMessagingBridge: bootstrapMessagingBridge2 } = await Promise.resolve().then(() => (init_src8(), src_exports6));
|
|
329079
329112
|
const bridge = bootstrapMessagingBridge2(store, msgConfig, logger);
|
|
329080
329113
|
if (!bridge) {
|
|
329081
|
-
console.error(
|
|
329114
|
+
console.error(chalk34.red(" No adapter tokens found. Configure at least one platform."));
|
|
329082
329115
|
console.log("");
|
|
329083
|
-
console.log(
|
|
329084
|
-
console.log(
|
|
329085
|
-
console.log(
|
|
329086
|
-
console.log(
|
|
329116
|
+
console.log(chalk34.dim(" Required environment variables:"));
|
|
329117
|
+
console.log(chalk34.dim(" TELEGRAM_BOT_TOKEN"));
|
|
329118
|
+
console.log(chalk34.dim(" DISCORD_BOT_TOKEN"));
|
|
329119
|
+
console.log(chalk34.dim(" SLACK_BOT_TOKEN + SLACK_APP_TOKEN"));
|
|
329087
329120
|
console.log("");
|
|
329088
329121
|
store.close();
|
|
329089
329122
|
process.exit(1);
|
|
@@ -329091,28 +329124,28 @@ function registerMessagingCommand(program2) {
|
|
|
329091
329124
|
try {
|
|
329092
329125
|
await bridge.startAll();
|
|
329093
329126
|
const adapters = bridge.getStatus();
|
|
329094
|
-
console.log(
|
|
329127
|
+
console.log(chalk34.green(" Messaging bridge started"));
|
|
329095
329128
|
console.log("");
|
|
329096
329129
|
for (const a of adapters) {
|
|
329097
|
-
const icon = a.healthy ?
|
|
329130
|
+
const icon = a.healthy ? chalk34.green("\u25CF") : chalk34.red("\u25CB");
|
|
329098
329131
|
const label = a.healthy ? "connected" : "disconnected";
|
|
329099
329132
|
console.log(` ${icon} ${a.platform}: ${label}`);
|
|
329100
329133
|
}
|
|
329101
329134
|
console.log("");
|
|
329102
|
-
console.log(
|
|
329135
|
+
console.log(chalk34.dim(" Listening for messages. Press Ctrl+C to stop."));
|
|
329103
329136
|
console.log("");
|
|
329104
329137
|
const shutdown = async (signal) => {
|
|
329105
329138
|
console.log("");
|
|
329106
|
-
console.log(
|
|
329139
|
+
console.log(chalk34.yellow(` Received ${signal}, stopping...`));
|
|
329107
329140
|
await bridge.stopAll();
|
|
329108
329141
|
store.close();
|
|
329109
|
-
console.log(
|
|
329142
|
+
console.log(chalk34.green(" Messaging bridge stopped."));
|
|
329110
329143
|
process.exit(0);
|
|
329111
329144
|
};
|
|
329112
329145
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
329113
329146
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
329114
329147
|
} catch (err) {
|
|
329115
|
-
console.error(
|
|
329148
|
+
console.error(chalk34.red(` Failed to start messaging bridge: ${err instanceof Error ? err.message : String(err)}`));
|
|
329116
329149
|
store.close();
|
|
329117
329150
|
process.exit(1);
|
|
329118
329151
|
}
|
|
@@ -329122,7 +329155,7 @@ function registerMessagingCommand(program2) {
|
|
|
329122
329155
|
// src/commands/schedule.ts
|
|
329123
329156
|
init_db();
|
|
329124
329157
|
init_config2();
|
|
329125
|
-
import
|
|
329158
|
+
import chalk35 from "chalk";
|
|
329126
329159
|
import fs30 from "node:fs";
|
|
329127
329160
|
import path30 from "node:path";
|
|
329128
329161
|
function legacyJsonPath() {
|
|
@@ -329185,7 +329218,7 @@ async function migrateLegacyJsonIfPresent() {
|
|
|
329185
329218
|
}
|
|
329186
329219
|
return;
|
|
329187
329220
|
}
|
|
329188
|
-
console.log(
|
|
329221
|
+
console.log(chalk35.dim(`Migrating ${legacy.length} legacy schedule(s) from ${jsonPath} to server DB...`));
|
|
329189
329222
|
let migrated = 0;
|
|
329190
329223
|
let failed = 0;
|
|
329191
329224
|
for (const entry of legacy) {
|
|
@@ -329194,7 +329227,7 @@ async function migrateLegacyJsonIfPresent() {
|
|
|
329194
329227
|
migrated++;
|
|
329195
329228
|
} catch (err) {
|
|
329196
329229
|
failed++;
|
|
329197
|
-
console.log(
|
|
329230
|
+
console.log(chalk35.yellow(
|
|
329198
329231
|
` ${entry.agentName}: migration failed (${err instanceof Error ? err.message : String(err)})`
|
|
329199
329232
|
));
|
|
329200
329233
|
}
|
|
@@ -329204,14 +329237,14 @@ async function migrateLegacyJsonIfPresent() {
|
|
|
329204
329237
|
fs30.unlinkSync(jsonPath);
|
|
329205
329238
|
} catch {
|
|
329206
329239
|
}
|
|
329207
|
-
console.log(
|
|
329240
|
+
console.log(chalk35.green(` Migrated ${migrated}/${legacy.length}. Legacy file removed.`));
|
|
329208
329241
|
} else {
|
|
329209
329242
|
const backup = jsonPath + ".bak";
|
|
329210
329243
|
try {
|
|
329211
329244
|
fs30.renameSync(jsonPath, backup);
|
|
329212
329245
|
} catch {
|
|
329213
329246
|
}
|
|
329214
|
-
console.log(
|
|
329247
|
+
console.log(chalk35.yellow(
|
|
329215
329248
|
` Migrated ${migrated}/${legacy.length}. ${failed} failed. Original kept as ${backup}.`
|
|
329216
329249
|
));
|
|
329217
329250
|
}
|
|
@@ -329269,8 +329302,8 @@ function pad4(s, width) {
|
|
|
329269
329302
|
return s + " ".repeat(width - s.length);
|
|
329270
329303
|
}
|
|
329271
329304
|
function handleServerError(err) {
|
|
329272
|
-
console.error(
|
|
329273
|
-
console.log(
|
|
329305
|
+
console.error(chalk35.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
329306
|
+
console.log(chalk35.dim(" Is the server running? Start it with: npx nestor-sh start"));
|
|
329274
329307
|
console.log("");
|
|
329275
329308
|
process.exit(1);
|
|
329276
329309
|
}
|
|
@@ -329281,8 +329314,8 @@ function registerScheduleCommand(program2) {
|
|
|
329281
329314
|
await migrateLegacyJsonIfPresent();
|
|
329282
329315
|
const schedules = await listSchedulesFromServer();
|
|
329283
329316
|
if (schedules.length === 0) {
|
|
329284
|
-
console.log(
|
|
329285
|
-
console.log(
|
|
329317
|
+
console.log(chalk35.yellow("No scheduled agents."));
|
|
329318
|
+
console.log(chalk35.dim("Use `npx nestor-sh schedule add <agent> <cron>` to schedule one."));
|
|
329286
329319
|
return;
|
|
329287
329320
|
}
|
|
329288
329321
|
if (options.json) {
|
|
@@ -329291,15 +329324,15 @@ function registerScheduleCommand(program2) {
|
|
|
329291
329324
|
}
|
|
329292
329325
|
const nameW = 20, cronW = 20, nextW = 25, lastW = 22, statusW = 10;
|
|
329293
329326
|
console.log("");
|
|
329294
|
-
console.log(
|
|
329327
|
+
console.log(chalk35.bold(
|
|
329295
329328
|
pad4("Agent", nameW) + pad4("Cron", cronW) + pad4("Next Run", nextW) + pad4("Last Run", lastW) + pad4("Status", statusW)
|
|
329296
329329
|
));
|
|
329297
|
-
console.log(
|
|
329330
|
+
console.log(chalk35.dim("-".repeat(nameW + cronW + nextW + lastW + statusW)));
|
|
329298
329331
|
for (const s of schedules) {
|
|
329299
|
-
const statusColor2 = s.enabled ?
|
|
329332
|
+
const statusColor2 = s.enabled ? chalk35.green : chalk35.yellow;
|
|
329300
329333
|
const statusLabel = s.enabled ? "active" : "paused";
|
|
329301
329334
|
const nextRun = computeNextRun(s.cron);
|
|
329302
|
-
const lastRun = s.lastRunAt ? s.lastRunAt.substring(0, 19).replace("T", " ") :
|
|
329335
|
+
const lastRun = s.lastRunAt ? s.lastRunAt.substring(0, 19).replace("T", " ") : chalk35.dim("never");
|
|
329303
329336
|
console.log(
|
|
329304
329337
|
pad4(s.agentName, nameW) + pad4(s.cron, cronW) + pad4(nextRun, nextW) + pad4(String(lastRun), lastW) + statusColor2(pad4(statusLabel, statusW))
|
|
329305
329338
|
);
|
|
@@ -329311,9 +329344,9 @@ function registerScheduleCommand(program2) {
|
|
|
329311
329344
|
});
|
|
329312
329345
|
schedule.command("add").description("Schedule an agent with a cron expression").argument("<agent>", "Agent name").argument("<cron>", 'Cron expression (5-field, e.g. "0 9 * * 1-5")').option("-p, --prompt <text>", "Prompt to run on each tick", "Execute scheduled task.").action(async (agentName, cronExpr, options) => {
|
|
329313
329346
|
if (!isValidCron(cronExpr)) {
|
|
329314
|
-
console.error(
|
|
329315
|
-
console.log(
|
|
329316
|
-
console.log(
|
|
329347
|
+
console.error(chalk35.red(`Invalid cron expression: "${cronExpr}"`));
|
|
329348
|
+
console.log(chalk35.dim(" Format: minute hour day-of-month month day-of-week"));
|
|
329349
|
+
console.log(chalk35.dim(' Examples: "0 9 * * 1-5" (weekdays at 9am), "*/15 * * * *" (every 15min)'));
|
|
329317
329350
|
process.exit(1);
|
|
329318
329351
|
}
|
|
329319
329352
|
const store = await getStore();
|
|
@@ -329321,8 +329354,8 @@ function registerScheduleCommand(program2) {
|
|
|
329321
329354
|
try {
|
|
329322
329355
|
const agentCfg = store.getAgentByName(agentName);
|
|
329323
329356
|
if (!agentCfg) {
|
|
329324
|
-
console.error(
|
|
329325
|
-
console.log(
|
|
329357
|
+
console.error(chalk35.red(`Agent '${agentName}' not found.`));
|
|
329358
|
+
console.log(chalk35.dim("Use `npx nestor-sh agent list` to see available agents."));
|
|
329326
329359
|
process.exit(1);
|
|
329327
329360
|
}
|
|
329328
329361
|
agentId = agentCfg.id;
|
|
@@ -329332,13 +329365,13 @@ function registerScheduleCommand(program2) {
|
|
|
329332
329365
|
try {
|
|
329333
329366
|
await migrateLegacyJsonIfPresent();
|
|
329334
329367
|
await setScheduleOnServer(agentId, cronExpr, options.prompt, true);
|
|
329335
|
-
console.log(
|
|
329336
|
-
console.log(` ${
|
|
329337
|
-
console.log(` ${
|
|
329338
|
-
console.log(` ${
|
|
329368
|
+
console.log(chalk35.green(`Agent '${agentName}' scheduled.`));
|
|
329369
|
+
console.log(` ${chalk35.dim("Cron:")} ${cronExpr}`);
|
|
329370
|
+
console.log(` ${chalk35.dim("Schedule:")} ${computeNextRun(cronExpr)}`);
|
|
329371
|
+
console.log(` ${chalk35.dim("Prompt:")} ${options.prompt}`);
|
|
329339
329372
|
console.log("");
|
|
329340
|
-
console.log(
|
|
329341
|
-
console.log(
|
|
329373
|
+
console.log(chalk35.dim(" The schedule fires when the server is running."));
|
|
329374
|
+
console.log(chalk35.dim(" Start it with: npx nestor-sh start"));
|
|
329342
329375
|
} catch (err) {
|
|
329343
329376
|
handleServerError(err);
|
|
329344
329377
|
}
|
|
@@ -329349,7 +329382,7 @@ function registerScheduleCommand(program2) {
|
|
|
329349
329382
|
try {
|
|
329350
329383
|
const agentCfg = store.getAgentByName(agentName);
|
|
329351
329384
|
if (!agentCfg) {
|
|
329352
|
-
console.error(
|
|
329385
|
+
console.error(chalk35.red(`Agent '${agentName}' not found.`));
|
|
329353
329386
|
process.exit(1);
|
|
329354
329387
|
}
|
|
329355
329388
|
agentId = agentCfg.id;
|
|
@@ -329359,7 +329392,7 @@ function registerScheduleCommand(program2) {
|
|
|
329359
329392
|
try {
|
|
329360
329393
|
await migrateLegacyJsonIfPresent();
|
|
329361
329394
|
await deleteScheduleOnServer(agentId);
|
|
329362
|
-
console.log(
|
|
329395
|
+
console.log(chalk35.green(`Schedule for '${agentName}' removed.`));
|
|
329363
329396
|
} catch (err) {
|
|
329364
329397
|
handleServerError(err);
|
|
329365
329398
|
}
|
|
@@ -329376,22 +329409,22 @@ function registerScheduleCommand(program2) {
|
|
|
329376
329409
|
const schedules = await listSchedulesFromServer();
|
|
329377
329410
|
const entry = schedules.find((s) => s.agentName === agentName);
|
|
329378
329411
|
if (!entry) {
|
|
329379
|
-
console.error(
|
|
329412
|
+
console.error(chalk35.red(`No schedule found for agent '${agentName}'.`));
|
|
329380
329413
|
process.exit(1);
|
|
329381
329414
|
}
|
|
329382
|
-
console.log(
|
|
329415
|
+
console.log(chalk35.cyan(` Triggering immediate run for '${agentName}'...`));
|
|
329383
329416
|
const res = await apiCall("POST", `/agents/${entry.agentId}/run`, {
|
|
329384
329417
|
prompt: entry.prompt ?? "Execute scheduled task."
|
|
329385
329418
|
});
|
|
329386
329419
|
if (!res.ok) {
|
|
329387
329420
|
const body2 = await res.json().catch(() => ({}));
|
|
329388
329421
|
const err = body2.error;
|
|
329389
|
-
console.error(
|
|
329422
|
+
console.error(chalk35.red(` Failed: ${err?.message ?? res.statusText}`));
|
|
329390
329423
|
process.exit(1);
|
|
329391
329424
|
}
|
|
329392
329425
|
const body = await res.json();
|
|
329393
|
-
console.log(
|
|
329394
|
-
if (body.data?.runId) console.log(` ${
|
|
329426
|
+
console.log(chalk35.green(` Agent '${agentName}' triggered successfully.`));
|
|
329427
|
+
if (body.data?.runId) console.log(` ${chalk35.dim("Run ID:")} ${String(body.data.runId)}`);
|
|
329395
329428
|
console.log("");
|
|
329396
329429
|
} catch (err) {
|
|
329397
329430
|
handleServerError(err);
|
|
@@ -329404,7 +329437,7 @@ async function setEnabledByName(agentName, enabled) {
|
|
|
329404
329437
|
try {
|
|
329405
329438
|
const agentCfg = store.getAgentByName(agentName);
|
|
329406
329439
|
if (!agentCfg) {
|
|
329407
|
-
console.error(
|
|
329440
|
+
console.error(chalk35.red(`Agent '${agentName}' not found.`));
|
|
329408
329441
|
process.exit(1);
|
|
329409
329442
|
}
|
|
329410
329443
|
agentId = agentCfg.id;
|
|
@@ -329416,15 +329449,15 @@ async function setEnabledByName(agentName, enabled) {
|
|
|
329416
329449
|
const schedules = await listSchedulesFromServer();
|
|
329417
329450
|
const current = schedules.find((s) => s.agentId === agentId);
|
|
329418
329451
|
if (!current) {
|
|
329419
|
-
console.error(
|
|
329452
|
+
console.error(chalk35.red(`No schedule found for agent '${agentName}'.`));
|
|
329420
329453
|
process.exit(1);
|
|
329421
329454
|
}
|
|
329422
329455
|
if (current.enabled === enabled) {
|
|
329423
|
-
console.log(
|
|
329456
|
+
console.log(chalk35.yellow(`Schedule for '${agentName}' is already ${enabled ? "active" : "paused"}.`));
|
|
329424
329457
|
return;
|
|
329425
329458
|
}
|
|
329426
329459
|
await setScheduleOnServer(agentId, current.cron, current.prompt ?? void 0, enabled);
|
|
329427
|
-
console.log(
|
|
329460
|
+
console.log(chalk35.green(`Schedule for '${agentName}' ${enabled ? "resumed" : "paused"}.`));
|
|
329428
329461
|
} catch (err) {
|
|
329429
329462
|
handleServerError(err);
|
|
329430
329463
|
}
|
|
@@ -329434,7 +329467,7 @@ async function setEnabledByName(agentName, enabled) {
|
|
|
329434
329467
|
init_db();
|
|
329435
329468
|
init_paths();
|
|
329436
329469
|
import * as p8 from "@clack/prompts";
|
|
329437
|
-
import
|
|
329470
|
+
import chalk36 from "chalk";
|
|
329438
329471
|
import fs31 from "node:fs";
|
|
329439
329472
|
import path31 from "node:path";
|
|
329440
329473
|
function getSkillsDir2() {
|
|
@@ -329455,36 +329488,36 @@ function truncate2(s, max) {
|
|
|
329455
329488
|
function statusColor(status) {
|
|
329456
329489
|
switch (status) {
|
|
329457
329490
|
case "pending":
|
|
329458
|
-
return
|
|
329491
|
+
return chalk36.yellow;
|
|
329459
329492
|
case "approved":
|
|
329460
329493
|
case "auto_approved":
|
|
329461
|
-
return
|
|
329494
|
+
return chalk36.green;
|
|
329462
329495
|
case "rejected":
|
|
329463
|
-
return
|
|
329496
|
+
return chalk36.red;
|
|
329464
329497
|
default:
|
|
329465
|
-
return
|
|
329498
|
+
return chalk36.dim;
|
|
329466
329499
|
}
|
|
329467
329500
|
}
|
|
329468
329501
|
function confidenceColor(confidence) {
|
|
329469
|
-
if (confidence >= 0.8) return
|
|
329470
|
-
if (confidence >= 0.5) return
|
|
329471
|
-
return
|
|
329502
|
+
if (confidence >= 0.8) return chalk36.green;
|
|
329503
|
+
if (confidence >= 0.5) return chalk36.yellow;
|
|
329504
|
+
return chalk36.red;
|
|
329472
329505
|
}
|
|
329473
329506
|
function formatCandidate(c) {
|
|
329474
329507
|
console.log("");
|
|
329475
|
-
console.log(
|
|
329476
|
-
console.log(
|
|
329477
|
-
console.log(` ${
|
|
329478
|
-
console.log(` ${
|
|
329479
|
-
console.log(` ${
|
|
329480
|
-
console.log(` ${
|
|
329481
|
-
console.log(` ${
|
|
329482
|
-
console.log(` ${
|
|
329508
|
+
console.log(chalk36.bold(` Candidate: ${c.skillName}`));
|
|
329509
|
+
console.log(chalk36.dim(" " + "\u2500".repeat(50)));
|
|
329510
|
+
console.log(` ${chalk36.cyan("ID:")} ${c.id}`);
|
|
329511
|
+
console.log(` ${chalk36.cyan("Pattern:")} ${truncate2(c.pattern, 60)}`);
|
|
329512
|
+
console.log(` ${chalk36.cyan("Description:")} ${truncate2(c.skillDescription, 60)}`);
|
|
329513
|
+
console.log(` ${chalk36.cyan("Confidence:")} ${confidenceColor(c.confidence)((c.confidence * 100).toFixed(0) + "%")}`);
|
|
329514
|
+
console.log(` ${chalk36.cyan("Status:")} ${statusColor(c.status)(c.status)}`);
|
|
329515
|
+
console.log(` ${chalk36.cyan("Created:")} ${c.createdAt}`);
|
|
329483
329516
|
if (c.sourceAgentId) {
|
|
329484
|
-
console.log(` ${
|
|
329517
|
+
console.log(` ${chalk36.cyan("Source Agent:")} ${c.sourceAgentId}`);
|
|
329485
329518
|
}
|
|
329486
329519
|
if (c.reviewedAt) {
|
|
329487
|
-
console.log(` ${
|
|
329520
|
+
console.log(` ${chalk36.cyan("Reviewed:")} ${c.reviewedAt} by ${c.reviewedBy ?? "unknown"}`);
|
|
329488
329521
|
}
|
|
329489
329522
|
}
|
|
329490
329523
|
function installCandidate(candidate) {
|
|
@@ -329509,8 +329542,8 @@ function registerEvolveCommand(program2) {
|
|
|
329509
329542
|
limit
|
|
329510
329543
|
});
|
|
329511
329544
|
if (candidates.length === 0) {
|
|
329512
|
-
console.log(
|
|
329513
|
-
console.log(
|
|
329545
|
+
console.log(chalk36.yellow("No skill candidates found."));
|
|
329546
|
+
console.log(chalk36.dim("Candidates are generated automatically during agent runs when evolve is enabled."));
|
|
329514
329547
|
return;
|
|
329515
329548
|
}
|
|
329516
329549
|
if (options.json) {
|
|
@@ -329524,22 +329557,22 @@ function registerEvolveCommand(program2) {
|
|
|
329524
329557
|
const patternW = 30;
|
|
329525
329558
|
console.log("");
|
|
329526
329559
|
console.log(
|
|
329527
|
-
|
|
329560
|
+
chalk36.bold(
|
|
329528
329561
|
pad5("ID", idW) + pad5("Skill Name", nameW) + pad5("Confidence", confW) + pad5("Status", statusW) + pad5("Pattern", patternW)
|
|
329529
329562
|
)
|
|
329530
329563
|
);
|
|
329531
|
-
console.log(
|
|
329564
|
+
console.log(chalk36.dim("-".repeat(idW + nameW + confW + statusW + patternW)));
|
|
329532
329565
|
for (const c of candidates) {
|
|
329533
329566
|
const shortId = c.id.substring(0, 8);
|
|
329534
329567
|
const confStr = (c.confidence * 100).toFixed(0) + "%";
|
|
329535
329568
|
console.log(
|
|
329536
|
-
pad5(shortId, idW) + pad5(c.skillName, nameW) + confidenceColor(c.confidence)(pad5(confStr, confW)) + statusColor(c.status)(pad5(c.status, statusW)) +
|
|
329569
|
+
pad5(shortId, idW) + pad5(c.skillName, nameW) + confidenceColor(c.confidence)(pad5(confStr, confW)) + statusColor(c.status)(pad5(c.status, statusW)) + chalk36.dim(pad5(truncate2(c.pattern, patternW - 1), patternW))
|
|
329537
329570
|
);
|
|
329538
329571
|
}
|
|
329539
329572
|
const pendingCount = candidates.filter((c) => c.status === "pending").length;
|
|
329540
329573
|
console.log("");
|
|
329541
329574
|
if (pendingCount > 0) {
|
|
329542
|
-
console.log(
|
|
329575
|
+
console.log(chalk36.dim(` ${pendingCount} pending candidate(s). Use \`npx nestor-sh evolve review\` to review them.`));
|
|
329543
329576
|
}
|
|
329544
329577
|
console.log("");
|
|
329545
329578
|
} finally {
|
|
@@ -329556,25 +329589,25 @@ function registerEvolveCommand(program2) {
|
|
|
329556
329589
|
if (matches.length === 1) {
|
|
329557
329590
|
candidate = matches[0];
|
|
329558
329591
|
} else if (matches.length > 1) {
|
|
329559
|
-
console.error(
|
|
329592
|
+
console.error(chalk36.red(`Ambiguous ID prefix '${candidateId}'. Matches ${matches.length} candidates.`));
|
|
329560
329593
|
for (const m of matches) {
|
|
329561
|
-
console.log(` ${
|
|
329594
|
+
console.log(` ${chalk36.dim(m.id)} \u2014 ${m.skillName}`);
|
|
329562
329595
|
}
|
|
329563
329596
|
process.exit(1);
|
|
329564
329597
|
}
|
|
329565
329598
|
}
|
|
329566
329599
|
if (!candidate) {
|
|
329567
|
-
console.error(
|
|
329600
|
+
console.error(chalk36.red(`Candidate '${candidateId}' not found.`));
|
|
329568
329601
|
process.exit(1);
|
|
329569
329602
|
}
|
|
329570
329603
|
if (candidate.status !== "pending") {
|
|
329571
|
-
console.error(
|
|
329604
|
+
console.error(chalk36.yellow(`Candidate is already ${candidate.status}.`));
|
|
329572
329605
|
process.exit(1);
|
|
329573
329606
|
}
|
|
329574
329607
|
const skillDir = installCandidate(candidate);
|
|
329575
329608
|
store.updateSkillCandidateStatus(candidate.id, "approved", "cli-user");
|
|
329576
|
-
console.log(
|
|
329577
|
-
console.log(` ${
|
|
329609
|
+
console.log(chalk36.green(`Candidate '${candidate.skillName}' approved and installed.`));
|
|
329610
|
+
console.log(` ${chalk36.dim("Skill path:")} ${skillDir}`);
|
|
329578
329611
|
console.log("");
|
|
329579
329612
|
} finally {
|
|
329580
329613
|
store.close();
|
|
@@ -329590,20 +329623,20 @@ function registerEvolveCommand(program2) {
|
|
|
329590
329623
|
if (matches.length === 1) {
|
|
329591
329624
|
candidate = matches[0];
|
|
329592
329625
|
} else if (matches.length > 1) {
|
|
329593
|
-
console.error(
|
|
329626
|
+
console.error(chalk36.red(`Ambiguous ID prefix '${candidateId}'. Matches ${matches.length} candidates.`));
|
|
329594
329627
|
process.exit(1);
|
|
329595
329628
|
}
|
|
329596
329629
|
}
|
|
329597
329630
|
if (!candidate) {
|
|
329598
|
-
console.error(
|
|
329631
|
+
console.error(chalk36.red(`Candidate '${candidateId}' not found.`));
|
|
329599
329632
|
process.exit(1);
|
|
329600
329633
|
}
|
|
329601
329634
|
if (candidate.status !== "pending") {
|
|
329602
|
-
console.error(
|
|
329635
|
+
console.error(chalk36.yellow(`Candidate is already ${candidate.status}.`));
|
|
329603
329636
|
process.exit(1);
|
|
329604
329637
|
}
|
|
329605
329638
|
store.updateSkillCandidateStatus(candidate.id, "rejected", "cli-user");
|
|
329606
|
-
console.log(
|
|
329639
|
+
console.log(chalk36.green(`Candidate '${candidate.skillName}' rejected.`));
|
|
329607
329640
|
} finally {
|
|
329608
329641
|
store.close();
|
|
329609
329642
|
}
|
|
@@ -329613,10 +329646,10 @@ function registerEvolveCommand(program2) {
|
|
|
329613
329646
|
try {
|
|
329614
329647
|
const candidates = store.listSkillCandidates({ status: "pending", limit: 100 });
|
|
329615
329648
|
if (candidates.length === 0) {
|
|
329616
|
-
console.log(
|
|
329649
|
+
console.log(chalk36.yellow("No pending candidates to review."));
|
|
329617
329650
|
return;
|
|
329618
329651
|
}
|
|
329619
|
-
p8.intro(
|
|
329652
|
+
p8.intro(chalk36.bgCyan(` Review ${candidates.length} Skill Candidate(s) `));
|
|
329620
329653
|
let approved = 0;
|
|
329621
329654
|
let rejected = 0;
|
|
329622
329655
|
for (let i = 0; i < candidates.length; i++) {
|
|
@@ -329625,12 +329658,12 @@ function registerEvolveCommand(program2) {
|
|
|
329625
329658
|
const lines = c.skillMd.split("\n");
|
|
329626
329659
|
const previewLines = lines.slice(0, 12);
|
|
329627
329660
|
console.log("");
|
|
329628
|
-
console.log(
|
|
329661
|
+
console.log(chalk36.dim(" SKILL.md preview:"));
|
|
329629
329662
|
for (const line of previewLines) {
|
|
329630
|
-
console.log(
|
|
329663
|
+
console.log(chalk36.dim(` ${line}`));
|
|
329631
329664
|
}
|
|
329632
329665
|
if (lines.length > 12) {
|
|
329633
|
-
console.log(
|
|
329666
|
+
console.log(chalk36.dim(` ... (${lines.length - 12} more lines)`));
|
|
329634
329667
|
}
|
|
329635
329668
|
console.log("");
|
|
329636
329669
|
const action = await p8.select({
|
|
@@ -329649,19 +329682,19 @@ function registerEvolveCommand(program2) {
|
|
|
329649
329682
|
if (action === "approve") {
|
|
329650
329683
|
const skillDir = installCandidate(c);
|
|
329651
329684
|
store.updateSkillCandidateStatus(c.id, "approved", "cli-user");
|
|
329652
|
-
console.log(
|
|
329685
|
+
console.log(chalk36.green(` Approved and installed to ${skillDir}`));
|
|
329653
329686
|
approved++;
|
|
329654
329687
|
} else if (action === "reject") {
|
|
329655
329688
|
store.updateSkillCandidateStatus(c.id, "rejected", "cli-user");
|
|
329656
|
-
console.log(
|
|
329689
|
+
console.log(chalk36.dim(` Rejected.`));
|
|
329657
329690
|
rejected++;
|
|
329658
329691
|
} else {
|
|
329659
|
-
console.log(
|
|
329692
|
+
console.log(chalk36.dim(` Skipped.`));
|
|
329660
329693
|
}
|
|
329661
329694
|
}
|
|
329662
329695
|
console.log("");
|
|
329663
329696
|
p8.outro(
|
|
329664
|
-
|
|
329697
|
+
chalk36.bold(`Review complete: ${chalk36.green(`${approved} approved`)}, ${chalk36.red(`${rejected} rejected`)}, ${candidates.length - approved - rejected} skipped`)
|
|
329665
329698
|
);
|
|
329666
329699
|
} finally {
|
|
329667
329700
|
store.close();
|
|
@@ -329671,7 +329704,7 @@ function registerEvolveCommand(program2) {
|
|
|
329671
329704
|
|
|
329672
329705
|
// src/index.ts
|
|
329673
329706
|
var program = new Command();
|
|
329674
|
-
program.name("nestor-sh").description("Nestor AI Agent Platform \u2014 orchestrate, secure and monitor AI agents").version("3.5.
|
|
329707
|
+
program.name("nestor-sh").description("Nestor AI Agent Platform \u2014 orchestrate, secure and monitor AI agents").version("3.5.1");
|
|
329675
329708
|
registerStartCommand(program);
|
|
329676
329709
|
registerInstallCommand(program);
|
|
329677
329710
|
registerAgentCommand(program);
|