nestor-sh 2.9.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/nestor.mjs CHANGED
@@ -7809,9 +7809,9 @@ var init_request_validator = __esm({
7809
7809
  });
7810
7810
 
7811
7811
  // ../server/src/security/input-sanitizer.ts
7812
- function resolvePath(base, relative6) {
7813
- if (relative6.startsWith("/")) return relative6;
7814
- const parts = (base + "/" + relative6).split("/");
7812
+ function resolvePath(base, relative7) {
7813
+ if (relative7.startsWith("/")) return relative7;
7814
+ const parts = (base + "/" + relative7).split("/");
7815
7815
  const resolved = [];
7816
7816
  for (const part of parts) {
7817
7817
  if (part === "..") {
@@ -9350,7 +9350,7 @@ import path from "node:path";
9350
9350
  import fs2 from "node:fs";
9351
9351
  function validateSkillFile(filePath, content) {
9352
9352
  const ext = path.extname(filePath).toLowerCase();
9353
- const basename5 = path.basename(filePath);
9353
+ const basename6 = path.basename(filePath);
9354
9354
  const extensionlessAllowed = /* @__PURE__ */ new Set([
9355
9355
  "LICENSE",
9356
9356
  "LICENCE",
@@ -9366,14 +9366,14 @@ function validateSkillFile(filePath, content) {
9366
9366
  ".prettierrc",
9367
9367
  ".eslintrc"
9368
9368
  ]);
9369
- if (!ext && !extensionlessAllowed.has(basename5)) {
9369
+ if (!ext && !extensionlessAllowed.has(basename6)) {
9370
9370
  return {
9371
9371
  valid: false,
9372
- reason: `File without extension is not in the allowlist: ${basename5}`,
9372
+ reason: `File without extension is not in the allowlist: ${basename6}`,
9373
9373
  extension: ""
9374
9374
  };
9375
9375
  }
9376
- if (!ext && extensionlessAllowed.has(basename5)) {
9376
+ if (!ext && extensionlessAllowed.has(basename6)) {
9377
9377
  if (content && content.length >= 4) {
9378
9378
  const binaryCheck = checkForBinaryContent(content, "");
9379
9379
  if (binaryCheck) {
@@ -11501,7 +11501,7 @@ var SERVER_VERSION, startTime;
11501
11501
  var init_health = __esm({
11502
11502
  "../server/src/routes/health.ts"() {
11503
11503
  "use strict";
11504
- SERVER_VERSION = "2.9.0";
11504
+ SERVER_VERSION = "3.0.0";
11505
11505
  startTime = Date.now();
11506
11506
  }
11507
11507
  });
@@ -12914,7 +12914,7 @@ var init_system = __esm({
12914
12914
  init_error_handler();
12915
12915
  init_broadcaster();
12916
12916
  init_approval_service();
12917
- SERVER_VERSION2 = "2.9.0";
12917
+ SERVER_VERSION2 = "3.0.0";
12918
12918
  startTime2 = Date.now();
12919
12919
  UpdateConfigSchema = z9.object({
12920
12920
  server: z9.object({
@@ -20344,7 +20344,7 @@ function isNativeAvailable() {
20344
20344
  return nativeModule !== null;
20345
20345
  }
20346
20346
  function getNativeVersion() {
20347
- return nativeModule ? "2.9.0" : null;
20347
+ return nativeModule ? "3.0.0" : null;
20348
20348
  }
20349
20349
  function validateSsrf(url, allowPrivate = false) {
20350
20350
  if (nativeModule) {
@@ -71110,7 +71110,7 @@ var require_util2 = __commonJS({
71110
71110
  return path30;
71111
71111
  }
71112
71112
  exports2.normalize = normalize4;
71113
- function join30(aRoot, aPath) {
71113
+ function join31(aRoot, aPath) {
71114
71114
  if (aRoot === "") {
71115
71115
  aRoot = ".";
71116
71116
  }
@@ -71142,11 +71142,11 @@ var require_util2 = __commonJS({
71142
71142
  }
71143
71143
  return joined;
71144
71144
  }
71145
- exports2.join = join30;
71145
+ exports2.join = join31;
71146
71146
  exports2.isAbsolute = function(aPath) {
71147
71147
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
71148
71148
  };
71149
- function relative6(aRoot, aPath) {
71149
+ function relative7(aRoot, aPath) {
71150
71150
  if (aRoot === "") {
71151
71151
  aRoot = ".";
71152
71152
  }
@@ -71165,7 +71165,7 @@ var require_util2 = __commonJS({
71165
71165
  }
71166
71166
  return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
71167
71167
  }
71168
- exports2.relative = relative6;
71168
+ exports2.relative = relative7;
71169
71169
  var supportsNullProto = function() {
71170
71170
  var obj = /* @__PURE__ */ Object.create(null);
71171
71171
  return !("__proto__" in obj);
@@ -71315,7 +71315,7 @@ var require_util2 = __commonJS({
71315
71315
  parsed.path = parsed.path.substring(0, index + 1);
71316
71316
  }
71317
71317
  }
71318
- sourceURL = join30(urlGenerate(parsed), sourceURL);
71318
+ sourceURL = join31(urlGenerate(parsed), sourceURL);
71319
71319
  }
71320
71320
  return normalize4(sourceURL);
71321
71321
  }
@@ -73117,7 +73117,7 @@ var require_escodegen = __commonJS({
73117
73117
  function noEmptySpace() {
73118
73118
  return space ? space : " ";
73119
73119
  }
73120
- function join30(left2, right2) {
73120
+ function join31(left2, right2) {
73121
73121
  var leftSource, rightSource, leftCharCode, rightCharCode;
73122
73122
  leftSource = toSourceNodeWhenNeeded(left2).toString();
73123
73123
  if (leftSource.length === 0) {
@@ -73448,8 +73448,8 @@ var require_escodegen = __commonJS({
73448
73448
  } else {
73449
73449
  result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
73450
73450
  }
73451
- result = join30(result, operator);
73452
- result = [join30(
73451
+ result = join31(result, operator);
73452
+ result = [join31(
73453
73453
  result,
73454
73454
  that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)
73455
73455
  ), ")"];
@@ -73592,11 +73592,11 @@ var require_escodegen = __commonJS({
73592
73592
  var result, fragment;
73593
73593
  result = ["class"];
73594
73594
  if (stmt.id) {
73595
- result = join30(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
73595
+ result = join31(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
73596
73596
  }
73597
73597
  if (stmt.superClass) {
73598
- fragment = join30("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
73599
- result = join30(result, fragment);
73598
+ fragment = join31("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
73599
+ result = join31(result, fragment);
73600
73600
  }
73601
73601
  result.push(space);
73602
73602
  result.push(this.generateStatement(stmt.body, S_TFFT));
@@ -73609,9 +73609,9 @@ var require_escodegen = __commonJS({
73609
73609
  return escapeDirective(stmt.directive) + this.semicolon(flags);
73610
73610
  },
73611
73611
  DoWhileStatement: function(stmt, flags) {
73612
- var result = join30("do", this.maybeBlock(stmt.body, S_TFFF));
73612
+ var result = join31("do", this.maybeBlock(stmt.body, S_TFFF));
73613
73613
  result = this.maybeBlockSuffix(stmt.body, result);
73614
- return join30(result, [
73614
+ return join31(result, [
73615
73615
  "while" + space + "(",
73616
73616
  this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
73617
73617
  ")" + this.semicolon(flags)
@@ -73647,11 +73647,11 @@ var require_escodegen = __commonJS({
73647
73647
  ExportDefaultDeclaration: function(stmt, flags) {
73648
73648
  var result = ["export"], bodyFlags;
73649
73649
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
73650
- result = join30(result, "default");
73650
+ result = join31(result, "default");
73651
73651
  if (isStatement(stmt.declaration)) {
73652
- result = join30(result, this.generateStatement(stmt.declaration, bodyFlags));
73652
+ result = join31(result, this.generateStatement(stmt.declaration, bodyFlags));
73653
73653
  } else {
73654
- result = join30(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
73654
+ result = join31(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
73655
73655
  }
73656
73656
  return result;
73657
73657
  },
@@ -73659,15 +73659,15 @@ var require_escodegen = __commonJS({
73659
73659
  var result = ["export"], bodyFlags, that = this;
73660
73660
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
73661
73661
  if (stmt.declaration) {
73662
- return join30(result, this.generateStatement(stmt.declaration, bodyFlags));
73662
+ return join31(result, this.generateStatement(stmt.declaration, bodyFlags));
73663
73663
  }
73664
73664
  if (stmt.specifiers) {
73665
73665
  if (stmt.specifiers.length === 0) {
73666
- result = join30(result, "{" + space + "}");
73666
+ result = join31(result, "{" + space + "}");
73667
73667
  } else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
73668
- result = join30(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
73668
+ result = join31(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
73669
73669
  } else {
73670
- result = join30(result, "{");
73670
+ result = join31(result, "{");
73671
73671
  withIndent(function(indent2) {
73672
73672
  var i, iz;
73673
73673
  result.push(newline);
@@ -73685,7 +73685,7 @@ var require_escodegen = __commonJS({
73685
73685
  result.push(base + "}");
73686
73686
  }
73687
73687
  if (stmt.source) {
73688
- result = join30(result, [
73688
+ result = join31(result, [
73689
73689
  "from" + space,
73690
73690
  // ModuleSpecifier
73691
73691
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -73773,7 +73773,7 @@ var require_escodegen = __commonJS({
73773
73773
  ];
73774
73774
  cursor = 0;
73775
73775
  if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
73776
- result = join30(result, [
73776
+ result = join31(result, [
73777
73777
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
73778
73778
  ]);
73779
73779
  ++cursor;
@@ -73783,7 +73783,7 @@ var require_escodegen = __commonJS({
73783
73783
  result.push(",");
73784
73784
  }
73785
73785
  if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
73786
- result = join30(result, [
73786
+ result = join31(result, [
73787
73787
  space,
73788
73788
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
73789
73789
  ]);
@@ -73812,7 +73812,7 @@ var require_escodegen = __commonJS({
73812
73812
  }
73813
73813
  }
73814
73814
  }
73815
- result = join30(result, [
73815
+ result = join31(result, [
73816
73816
  "from" + space,
73817
73817
  // ModuleSpecifier
73818
73818
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -73866,7 +73866,7 @@ var require_escodegen = __commonJS({
73866
73866
  return result;
73867
73867
  },
73868
73868
  ThrowStatement: function(stmt, flags) {
73869
- return [join30(
73869
+ return [join31(
73870
73870
  "throw",
73871
73871
  this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
73872
73872
  ), this.semicolon(flags)];
@@ -73877,7 +73877,7 @@ var require_escodegen = __commonJS({
73877
73877
  result = this.maybeBlockSuffix(stmt.block, result);
73878
73878
  if (stmt.handlers) {
73879
73879
  for (i = 0, iz = stmt.handlers.length; i < iz; ++i) {
73880
- result = join30(result, this.generateStatement(stmt.handlers[i], S_TFFF));
73880
+ result = join31(result, this.generateStatement(stmt.handlers[i], S_TFFF));
73881
73881
  if (stmt.finalizer || i + 1 !== iz) {
73882
73882
  result = this.maybeBlockSuffix(stmt.handlers[i].body, result);
73883
73883
  }
@@ -73885,7 +73885,7 @@ var require_escodegen = __commonJS({
73885
73885
  } else {
73886
73886
  guardedHandlers = stmt.guardedHandlers || [];
73887
73887
  for (i = 0, iz = guardedHandlers.length; i < iz; ++i) {
73888
- result = join30(result, this.generateStatement(guardedHandlers[i], S_TFFF));
73888
+ result = join31(result, this.generateStatement(guardedHandlers[i], S_TFFF));
73889
73889
  if (stmt.finalizer || i + 1 !== iz) {
73890
73890
  result = this.maybeBlockSuffix(guardedHandlers[i].body, result);
73891
73891
  }
@@ -73893,13 +73893,13 @@ var require_escodegen = __commonJS({
73893
73893
  if (stmt.handler) {
73894
73894
  if (Array.isArray(stmt.handler)) {
73895
73895
  for (i = 0, iz = stmt.handler.length; i < iz; ++i) {
73896
- result = join30(result, this.generateStatement(stmt.handler[i], S_TFFF));
73896
+ result = join31(result, this.generateStatement(stmt.handler[i], S_TFFF));
73897
73897
  if (stmt.finalizer || i + 1 !== iz) {
73898
73898
  result = this.maybeBlockSuffix(stmt.handler[i].body, result);
73899
73899
  }
73900
73900
  }
73901
73901
  } else {
73902
- result = join30(result, this.generateStatement(stmt.handler, S_TFFF));
73902
+ result = join31(result, this.generateStatement(stmt.handler, S_TFFF));
73903
73903
  if (stmt.finalizer) {
73904
73904
  result = this.maybeBlockSuffix(stmt.handler.body, result);
73905
73905
  }
@@ -73907,7 +73907,7 @@ var require_escodegen = __commonJS({
73907
73907
  }
73908
73908
  }
73909
73909
  if (stmt.finalizer) {
73910
- result = join30(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
73910
+ result = join31(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
73911
73911
  }
73912
73912
  return result;
73913
73913
  },
@@ -73941,7 +73941,7 @@ var require_escodegen = __commonJS({
73941
73941
  withIndent(function() {
73942
73942
  if (stmt.test) {
73943
73943
  result = [
73944
- join30("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
73944
+ join31("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
73945
73945
  ":"
73946
73946
  ];
73947
73947
  } else {
@@ -73989,9 +73989,9 @@ var require_escodegen = __commonJS({
73989
73989
  result.push(this.maybeBlock(stmt.consequent, S_TFFF));
73990
73990
  result = this.maybeBlockSuffix(stmt.consequent, result);
73991
73991
  if (stmt.alternate.type === Syntax.IfStatement) {
73992
- result = join30(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
73992
+ result = join31(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
73993
73993
  } else {
73994
- result = join30(result, join30("else", this.maybeBlock(stmt.alternate, bodyFlags)));
73994
+ result = join31(result, join31("else", this.maybeBlock(stmt.alternate, bodyFlags)));
73995
73995
  }
73996
73996
  } else {
73997
73997
  result.push(this.maybeBlock(stmt.consequent, bodyFlags));
@@ -74092,7 +74092,7 @@ var require_escodegen = __commonJS({
74092
74092
  },
74093
74093
  ReturnStatement: function(stmt, flags) {
74094
74094
  if (stmt.argument) {
74095
- return [join30(
74095
+ return [join31(
74096
74096
  "return",
74097
74097
  this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
74098
74098
  ), this.semicolon(flags)];
@@ -74181,14 +74181,14 @@ var require_escodegen = __commonJS({
74181
74181
  if (leftSource.charCodeAt(leftSource.length - 1) === 47 && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
74182
74182
  result = [fragment, noEmptySpace(), expr.operator];
74183
74183
  } else {
74184
- result = join30(fragment, expr.operator);
74184
+ result = join31(fragment, expr.operator);
74185
74185
  }
74186
74186
  fragment = this.generateExpression(expr.right, rightPrecedence, flags);
74187
74187
  if (expr.operator === "/" && fragment.toString().charAt(0) === "/" || expr.operator.slice(-1) === "<" && fragment.toString().slice(0, 3) === "!--") {
74188
74188
  result.push(noEmptySpace());
74189
74189
  result.push(fragment);
74190
74190
  } else {
74191
- result = join30(result, fragment);
74191
+ result = join31(result, fragment);
74192
74192
  }
74193
74193
  if (expr.operator === "in" && !(flags & F_ALLOW_IN)) {
74194
74194
  return ["(", result, ")"];
@@ -74228,7 +74228,7 @@ var require_escodegen = __commonJS({
74228
74228
  var result, length, i, iz, itemFlags;
74229
74229
  length = expr["arguments"].length;
74230
74230
  itemFlags = flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0 ? E_TFT : E_TFF;
74231
- result = join30(
74231
+ result = join31(
74232
74232
  "new",
74233
74233
  this.generateExpression(expr.callee, Precedence.New, itemFlags)
74234
74234
  );
@@ -74278,11 +74278,11 @@ var require_escodegen = __commonJS({
74278
74278
  var result, fragment, rightCharCode, leftSource, leftCharCode;
74279
74279
  fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
74280
74280
  if (space === "") {
74281
- result = join30(expr.operator, fragment);
74281
+ result = join31(expr.operator, fragment);
74282
74282
  } else {
74283
74283
  result = [expr.operator];
74284
74284
  if (expr.operator.length > 2) {
74285
- result = join30(result, fragment);
74285
+ result = join31(result, fragment);
74286
74286
  } else {
74287
74287
  leftSource = toSourceNodeWhenNeeded(result).toString();
74288
74288
  leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
@@ -74305,7 +74305,7 @@ var require_escodegen = __commonJS({
74305
74305
  result = "yield";
74306
74306
  }
74307
74307
  if (expr.argument) {
74308
- result = join30(
74308
+ result = join31(
74309
74309
  result,
74310
74310
  this.generateExpression(expr.argument, Precedence.Yield, E_TTT)
74311
74311
  );
@@ -74313,7 +74313,7 @@ var require_escodegen = __commonJS({
74313
74313
  return parenthesize(result, Precedence.Yield, precedence);
74314
74314
  },
74315
74315
  AwaitExpression: function(expr, precedence, flags) {
74316
- var result = join30(
74316
+ var result = join31(
74317
74317
  expr.all ? "await*" : "await",
74318
74318
  this.generateExpression(expr.argument, Precedence.Await, E_TTT)
74319
74319
  );
@@ -74396,11 +74396,11 @@ var require_escodegen = __commonJS({
74396
74396
  var result, fragment;
74397
74397
  result = ["class"];
74398
74398
  if (expr.id) {
74399
- result = join30(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
74399
+ result = join31(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
74400
74400
  }
74401
74401
  if (expr.superClass) {
74402
- fragment = join30("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
74403
- result = join30(result, fragment);
74402
+ fragment = join31("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
74403
+ result = join31(result, fragment);
74404
74404
  }
74405
74405
  result.push(space);
74406
74406
  result.push(this.generateStatement(expr.body, S_TFFT));
@@ -74415,7 +74415,7 @@ var require_escodegen = __commonJS({
74415
74415
  }
74416
74416
  if (expr.kind === "get" || expr.kind === "set") {
74417
74417
  fragment = [
74418
- join30(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
74418
+ join31(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
74419
74419
  this.generateFunctionBody(expr.value)
74420
74420
  ];
74421
74421
  } else {
@@ -74425,7 +74425,7 @@ var require_escodegen = __commonJS({
74425
74425
  this.generateFunctionBody(expr.value)
74426
74426
  ];
74427
74427
  }
74428
- return join30(result, fragment);
74428
+ return join31(result, fragment);
74429
74429
  },
74430
74430
  Property: function(expr, precedence, flags) {
74431
74431
  if (expr.kind === "get" || expr.kind === "set") {
@@ -74620,7 +74620,7 @@ var require_escodegen = __commonJS({
74620
74620
  for (i = 0, iz = expr.blocks.length; i < iz; ++i) {
74621
74621
  fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT);
74622
74622
  if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
74623
- result = join30(result, fragment);
74623
+ result = join31(result, fragment);
74624
74624
  } else {
74625
74625
  result.push(fragment);
74626
74626
  }
@@ -74628,13 +74628,13 @@ var require_escodegen = __commonJS({
74628
74628
  });
74629
74629
  }
74630
74630
  if (expr.filter) {
74631
- result = join30(result, "if" + space);
74631
+ result = join31(result, "if" + space);
74632
74632
  fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
74633
- result = join30(result, ["(", fragment, ")"]);
74633
+ result = join31(result, ["(", fragment, ")"]);
74634
74634
  }
74635
74635
  if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
74636
74636
  fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
74637
- result = join30(result, fragment);
74637
+ result = join31(result, fragment);
74638
74638
  }
74639
74639
  result.push(expr.type === Syntax.GeneratorExpression ? ")" : "]");
74640
74640
  return result;
@@ -74650,8 +74650,8 @@ var require_escodegen = __commonJS({
74650
74650
  } else {
74651
74651
  fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
74652
74652
  }
74653
- fragment = join30(fragment, expr.of ? "of" : "in");
74654
- fragment = join30(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
74653
+ fragment = join31(fragment, expr.of ? "of" : "in");
74654
+ fragment = join31(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
74655
74655
  return ["for" + space + "(", fragment, ")"];
74656
74656
  },
74657
74657
  SpreadElement: function(expr, precedence, flags) {
@@ -102210,8 +102210,8 @@ function findChromePath() {
102210
102210
  for (const p8 of paths) {
102211
102211
  if (p8) {
102212
102212
  try {
102213
- const { existsSync: existsSync27 } = __require("node:fs");
102214
- if (existsSync27(p8)) return p8;
102213
+ const { existsSync: existsSync28 } = __require("node:fs");
102214
+ if (existsSync28(p8)) return p8;
102215
102215
  } catch {
102216
102216
  }
102217
102217
  }
@@ -102226,8 +102226,8 @@ function findChromePath() {
102226
102226
  ];
102227
102227
  for (const p8 of paths) {
102228
102228
  try {
102229
- const { existsSync: existsSync27 } = __require("node:fs");
102230
- if (existsSync27(p8)) return p8;
102229
+ const { existsSync: existsSync28 } = __require("node:fs");
102230
+ if (existsSync28(p8)) return p8;
102231
102231
  } catch {
102232
102232
  }
102233
102233
  }
@@ -102242,8 +102242,8 @@ function findChromePath() {
102242
102242
  ];
102243
102243
  for (const p8 of linuxPaths) {
102244
102244
  try {
102245
- const { existsSync: existsSync27 } = __require("node:fs");
102246
- if (existsSync27(p8)) return p8;
102245
+ const { existsSync: existsSync28 } = __require("node:fs");
102246
+ if (existsSync28(p8)) return p8;
102247
102247
  } catch {
102248
102248
  }
102249
102249
  }
@@ -103615,11 +103615,197 @@ var init_layered_memory = __esm({
103615
103615
  }
103616
103616
  });
103617
103617
 
103618
+ // ../agent/src/integrations/obsidian.ts
103619
+ import { existsSync as existsSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync2, statSync as statSync3 } from "node:fs";
103620
+ import { join as join8, basename as basename3, relative as relative3 } from "node:path";
103621
+ var ObsidianIntegration;
103622
+ var init_obsidian = __esm({
103623
+ "../agent/src/integrations/obsidian.ts"() {
103624
+ "use strict";
103625
+ ObsidianIntegration = class {
103626
+ constructor(config2) {
103627
+ this.config = config2;
103628
+ this.nestorDir = join8(config2.vaultPath, config2.nestorFolder || "Nestor");
103629
+ if (!existsSync5(this.nestorDir)) {
103630
+ mkdirSync3(this.nestorDir, { recursive: true });
103631
+ }
103632
+ }
103633
+ nestorDir;
103634
+ /** Check if vault exists and is accessible */
103635
+ isAvailable() {
103636
+ return existsSync5(this.config.vaultPath);
103637
+ }
103638
+ /** Write a note to the vault */
103639
+ writeNote(opts) {
103640
+ const folder5 = opts.folder ? join8(this.nestorDir, opts.folder) : this.nestorDir;
103641
+ if (!existsSync5(folder5)) mkdirSync3(folder5, { recursive: true });
103642
+ const filename = this.sanitizeFilename(opts.title) + ".md";
103643
+ const filepath = join8(folder5, filename);
103644
+ const fm = {
103645
+ created: (/* @__PURE__ */ new Date()).toISOString(),
103646
+ source: "nestor",
103647
+ tags: [...this.config.defaultTags || [], ...opts.tags || []],
103648
+ ...opts.frontmatter
103649
+ };
103650
+ const frontmatter = `---
103651
+ ${Object.entries(fm).map(
103652
+ ([k, v]) => `${k}: ${typeof v === "object" ? JSON.stringify(v) : v}`
103653
+ ).join("\n")}
103654
+ ---
103655
+
103656
+ `;
103657
+ writeFileSync3(filepath, frontmatter + opts.content);
103658
+ return filepath;
103659
+ }
103660
+ /** Read a note from the vault */
103661
+ readNote(path30) {
103662
+ const fullPath = path30.startsWith("/") || path30.includes(":") ? path30 : join8(this.nestorDir, path30);
103663
+ if (!existsSync5(fullPath)) return null;
103664
+ const raw = readFileSync8(fullPath, "utf-8");
103665
+ const fmMatch = raw.match(/^---\n([\s\S]*?)\n---\n\n?([\s\S]*)$/);
103666
+ if (fmMatch) {
103667
+ const frontmatter = {};
103668
+ for (const line of fmMatch[1].split("\n")) {
103669
+ const [key, ...rest] = line.split(": ");
103670
+ if (key) frontmatter[key.trim()] = rest.join(": ").trim();
103671
+ }
103672
+ return { frontmatter, content: fmMatch[2] };
103673
+ }
103674
+ return { frontmatter: {}, content: raw };
103675
+ }
103676
+ /** Search notes in the vault */
103677
+ searchNotes(query, limit = 10) {
103678
+ const results = [];
103679
+ const q = query.toLowerCase();
103680
+ this.walkDir(this.nestorDir, (filepath) => {
103681
+ if (!filepath.endsWith(".md") || results.length >= limit) return;
103682
+ try {
103683
+ const content = readFileSync8(filepath, "utf-8");
103684
+ if (content.toLowerCase().includes(q)) {
103685
+ const relPath = relative3(this.nestorDir, filepath);
103686
+ const title = basename3(filepath, ".md");
103687
+ const idx = content.toLowerCase().indexOf(q);
103688
+ const snippet = content.substring(Math.max(0, idx - 50), idx + 100).replace(/\n/g, " ");
103689
+ results.push({ path: relPath, title, snippet });
103690
+ }
103691
+ } catch {
103692
+ }
103693
+ });
103694
+ return results;
103695
+ }
103696
+ /** List all notes in a folder */
103697
+ listNotes(folder5) {
103698
+ const dir = folder5 ? join8(this.nestorDir, folder5) : this.nestorDir;
103699
+ if (!existsSync5(dir)) return [];
103700
+ const notes = [];
103701
+ this.walkDir(dir, (filepath) => {
103702
+ if (!filepath.endsWith(".md")) return;
103703
+ const stat = statSync3(filepath);
103704
+ notes.push({
103705
+ path: relative3(this.nestorDir, filepath),
103706
+ title: basename3(filepath, ".md"),
103707
+ modified: stat.mtime
103708
+ });
103709
+ });
103710
+ return notes.sort((a, b) => b.modified.getTime() - a.modified.getTime());
103711
+ }
103712
+ /** Write a mission report to the vault */
103713
+ writeMissionReport(mission) {
103714
+ return this.writeNote({
103715
+ title: mission.title,
103716
+ content: mission.report,
103717
+ folder: `missions/${mission.type}`,
103718
+ tags: ["mission", mission.type],
103719
+ frontmatter: {
103720
+ type: mission.type,
103721
+ quality: mission.evaluation?.overall
103722
+ }
103723
+ });
103724
+ }
103725
+ sanitizeFilename(name) {
103726
+ return name.replace(/[<>:"/\\|?*]/g, "-").substring(0, 100);
103727
+ }
103728
+ walkDir(dir, callback) {
103729
+ if (!existsSync5(dir)) return;
103730
+ for (const entry of readdirSync2(dir, { withFileTypes: true })) {
103731
+ const fullPath = join8(dir, entry.name);
103732
+ if (entry.isDirectory()) {
103733
+ this.walkDir(fullPath, callback);
103734
+ } else {
103735
+ callback(fullPath);
103736
+ }
103737
+ }
103738
+ }
103739
+ };
103740
+ }
103741
+ });
103742
+
103743
+ // ../agent/src/integrations/n8n.ts
103744
+ var N8nIntegration;
103745
+ var init_n8n = __esm({
103746
+ "../agent/src/integrations/n8n.ts"() {
103747
+ "use strict";
103748
+ N8nIntegration = class {
103749
+ constructor(config2) {
103750
+ this.config = config2;
103751
+ }
103752
+ /** Check if n8n is accessible */
103753
+ async isAvailable() {
103754
+ try {
103755
+ const res = await fetch(`${this.config.baseUrl}/api/v1/workflows`, {
103756
+ headers: this.headers(),
103757
+ signal: AbortSignal.timeout(5e3)
103758
+ });
103759
+ return res.ok;
103760
+ } catch {
103761
+ return false;
103762
+ }
103763
+ }
103764
+ /** Trigger a webhook workflow */
103765
+ async triggerWebhook(webhookPath, data) {
103766
+ const url = `${this.config.baseUrl}/webhook/${webhookPath}`;
103767
+ const res = await fetch(url, {
103768
+ method: "POST",
103769
+ headers: { "Content-Type": "application/json" },
103770
+ body: JSON.stringify(data),
103771
+ signal: AbortSignal.timeout(3e4)
103772
+ });
103773
+ return res.json();
103774
+ }
103775
+ /** List workflows */
103776
+ async listWorkflows() {
103777
+ const res = await fetch(`${this.config.baseUrl}/api/v1/workflows`, {
103778
+ headers: this.headers(),
103779
+ signal: AbortSignal.timeout(1e4)
103780
+ });
103781
+ if (!res.ok) return [];
103782
+ const data = await res.json();
103783
+ return data.data || [];
103784
+ }
103785
+ /** Execute a workflow by ID */
103786
+ async executeWorkflow(id, data) {
103787
+ const res = await fetch(`${this.config.baseUrl}/api/v1/workflows/${id}/execute`, {
103788
+ method: "POST",
103789
+ headers: this.headers(),
103790
+ body: data ? JSON.stringify(data) : void 0,
103791
+ signal: AbortSignal.timeout(6e4)
103792
+ });
103793
+ return res.json();
103794
+ }
103795
+ headers() {
103796
+ const h = { "Content-Type": "application/json" };
103797
+ if (this.config.apiKey) h["X-N8N-API-KEY"] = this.config.apiKey;
103798
+ return h;
103799
+ }
103800
+ };
103801
+ }
103802
+ });
103803
+
103618
103804
  // ../agent/src/tools/system-tools.ts
103619
103805
  import { z as z28 } from "zod";
103620
103806
  import { randomUUID as randomUUID23 } from "node:crypto";
103621
- import { readFileSync as readFileSync8 } from "node:fs";
103622
- import { join as join8 } from "node:path";
103807
+ import { readFileSync as readFileSync9 } from "node:fs";
103808
+ import { join as join9 } from "node:path";
103623
103809
  import { homedir as homedir3 } from "node:os";
103624
103810
  function registerSystemTools(registry, store, defaultTenantId = "default") {
103625
103811
  const tid = defaultTenantId;
@@ -103859,9 +104045,9 @@ Direct sub-agent execution from chat is not yet supported. Use the Studio UI or
103859
104045
  description: "Read the current Nestor configuration from ~/.nestor/nestor.config.json.",
103860
104046
  inputSchema: emptySchema,
103861
104047
  handler: async (_input, _ctx) => {
103862
- const configPath = join8(homedir3(), ".nestor", "nestor.config.json");
104048
+ const configPath = join9(homedir3(), ".nestor", "nestor.config.json");
103863
104049
  try {
103864
- const config2 = readFileSync8(configPath, "utf-8");
104050
+ const config2 = readFileSync9(configPath, "utf-8");
103865
104051
  return { output: config2, isError: false };
103866
104052
  } catch {
103867
104053
  return { output: "No config file found at ~/.nestor/nestor.config.json", isError: false };
@@ -104124,12 +104310,245 @@ ${mission.report}`;
104124
104310
  }
104125
104311
  }
104126
104312
  });
104313
+ function loadIntegrationConfig() {
104314
+ const configPath = join9(homedir3(), ".nestor", "nestor.config.json");
104315
+ try {
104316
+ const raw = readFileSync9(configPath, "utf-8");
104317
+ const config2 = JSON.parse(raw);
104318
+ return {
104319
+ obsidian: config2.obsidian,
104320
+ n8n: config2.n8n
104321
+ };
104322
+ } catch {
104323
+ return {};
104324
+ }
104325
+ }
104326
+ const obsidianWriteNoteSchema = z28.object({
104327
+ title: z28.string().describe("Note title (used as filename)"),
104328
+ content: z28.string().describe("Markdown content of the note"),
104329
+ folder: z28.string().optional().describe('Subfolder within Nestor dir (e.g., "research", "missions/osint")'),
104330
+ tags: z28.array(z28.string()).optional().describe("Tags to add to the note frontmatter")
104331
+ });
104332
+ const obsidianSearchSchema = z28.object({
104333
+ query: z28.string().describe("Search query (full-text search across note titles and content)"),
104334
+ limit: z28.number().optional().describe("Max results (default: 10)")
104335
+ });
104336
+ const obsidianReadNoteSchema = z28.object({
104337
+ path: z28.string().describe('Relative path within the Nestor folder (e.g., "research/AI Frameworks.md") or absolute path')
104338
+ });
104339
+ const obsidianListNotesSchema = z28.object({
104340
+ folder: z28.string().optional().describe('Subfolder to list (e.g., "missions"). Omit for root Nestor folder.')
104341
+ });
104342
+ registry.register({
104343
+ name: "obsidian_write_note",
104344
+ description: 'Write a note to the connected Obsidian vault. Creates a .md file with YAML frontmatter in the Nestor subfolder. Configure vault path in nestor.config.json under "obsidian.vaultPath".',
104345
+ inputSchema: obsidianWriteNoteSchema,
104346
+ handler: async (input, _ctx) => {
104347
+ const args2 = input;
104348
+ const cfg = loadIntegrationConfig();
104349
+ if (!cfg.obsidian?.vaultPath) {
104350
+ return {
104351
+ output: 'Obsidian integration not configured. Add "obsidian": { "vaultPath": "/path/to/vault" } to ~/.nestor/nestor.config.json',
104352
+ isError: true
104353
+ };
104354
+ }
104355
+ try {
104356
+ const obsidian = new ObsidianIntegration(cfg.obsidian);
104357
+ if (!obsidian.isAvailable()) {
104358
+ return { output: `Obsidian vault not found at: ${cfg.obsidian.vaultPath}`, isError: true };
104359
+ }
104360
+ const filepath = obsidian.writeNote({
104361
+ title: args2.title,
104362
+ content: args2.content,
104363
+ folder: args2.folder,
104364
+ tags: args2.tags
104365
+ });
104366
+ return { output: `Note written: ${filepath}`, isError: false };
104367
+ } catch (err) {
104368
+ const msg = err instanceof Error ? err.message : String(err);
104369
+ return { output: `Failed to write note: ${msg}`, isError: true };
104370
+ }
104371
+ }
104372
+ });
104373
+ registry.register({
104374
+ name: "obsidian_search",
104375
+ description: "Search notes in the connected Obsidian vault. Full-text search across all .md files in the Nestor subfolder.",
104376
+ inputSchema: obsidianSearchSchema,
104377
+ handler: async (input, _ctx) => {
104378
+ const args2 = input;
104379
+ const cfg = loadIntegrationConfig();
104380
+ if (!cfg.obsidian?.vaultPath) {
104381
+ return {
104382
+ output: 'Obsidian integration not configured. Add "obsidian": { "vaultPath": "/path/to/vault" } to ~/.nestor/nestor.config.json',
104383
+ isError: true
104384
+ };
104385
+ }
104386
+ try {
104387
+ const obsidian = new ObsidianIntegration(cfg.obsidian);
104388
+ if (!obsidian.isAvailable()) {
104389
+ return { output: `Obsidian vault not found at: ${cfg.obsidian.vaultPath}`, isError: true };
104390
+ }
104391
+ const results = obsidian.searchNotes(args2.query, args2.limit ?? 10);
104392
+ if (results.length === 0) {
104393
+ return { output: `No notes found matching "${args2.query}".`, isError: false };
104394
+ }
104395
+ return { output: JSON.stringify(results, null, 2), isError: false };
104396
+ } catch (err) {
104397
+ const msg = err instanceof Error ? err.message : String(err);
104398
+ return { output: `Search failed: ${msg}`, isError: true };
104399
+ }
104400
+ }
104401
+ });
104402
+ registry.register({
104403
+ name: "obsidian_read_note",
104404
+ description: "Read a note from the connected Obsidian vault. Returns frontmatter and content.",
104405
+ inputSchema: obsidianReadNoteSchema,
104406
+ handler: async (input, _ctx) => {
104407
+ const args2 = input;
104408
+ const cfg = loadIntegrationConfig();
104409
+ if (!cfg.obsidian?.vaultPath) {
104410
+ return {
104411
+ output: 'Obsidian integration not configured. Add "obsidian": { "vaultPath": "/path/to/vault" } to ~/.nestor/nestor.config.json',
104412
+ isError: true
104413
+ };
104414
+ }
104415
+ try {
104416
+ const obsidian = new ObsidianIntegration(cfg.obsidian);
104417
+ const note2 = obsidian.readNote(args2.path);
104418
+ if (!note2) {
104419
+ return { output: `Note not found: ${args2.path}`, isError: true };
104420
+ }
104421
+ return { output: JSON.stringify(note2, null, 2), isError: false };
104422
+ } catch (err) {
104423
+ const msg = err instanceof Error ? err.message : String(err);
104424
+ return { output: `Failed to read note: ${msg}`, isError: true };
104425
+ }
104426
+ }
104427
+ });
104428
+ registry.register({
104429
+ name: "obsidian_list_notes",
104430
+ description: "List all notes in the Obsidian vault Nestor folder, sorted by most recently modified.",
104431
+ inputSchema: obsidianListNotesSchema,
104432
+ handler: async (input, _ctx) => {
104433
+ const args2 = input;
104434
+ const cfg = loadIntegrationConfig();
104435
+ if (!cfg.obsidian?.vaultPath) {
104436
+ return {
104437
+ output: 'Obsidian integration not configured. Add "obsidian": { "vaultPath": "/path/to/vault" } to ~/.nestor/nestor.config.json',
104438
+ isError: true
104439
+ };
104440
+ }
104441
+ try {
104442
+ const obsidian = new ObsidianIntegration(cfg.obsidian);
104443
+ if (!obsidian.isAvailable()) {
104444
+ return { output: `Obsidian vault not found at: ${cfg.obsidian.vaultPath}`, isError: true };
104445
+ }
104446
+ const notes = obsidian.listNotes(args2.folder);
104447
+ if (notes.length === 0) {
104448
+ return { output: "No notes found.", isError: false };
104449
+ }
104450
+ const list = notes.map((n) => `- ${n.title} (${n.path}) \u2014 modified: ${n.modified.toISOString()}`).join("\n");
104451
+ return { output: `Found ${notes.length} note(s):
104452
+ ${list}`, isError: false };
104453
+ } catch (err) {
104454
+ const msg = err instanceof Error ? err.message : String(err);
104455
+ return { output: `Failed to list notes: ${msg}`, isError: true };
104456
+ }
104457
+ }
104458
+ });
104459
+ const n8nTriggerSchema = z28.object({
104460
+ webhook: z28.string().describe('Webhook path (e.g., "nestor-report" \u2014 will call {baseUrl}/webhook/nestor-report)'),
104461
+ data: z28.record(z28.unknown()).optional().describe("JSON data to send to the webhook")
104462
+ });
104463
+ const n8nExecuteWorkflowSchema = z28.object({
104464
+ workflowId: z28.string().describe("n8n workflow ID to execute"),
104465
+ data: z28.record(z28.unknown()).optional().describe("Input data for the workflow")
104466
+ });
104467
+ registry.register({
104468
+ name: "n8n_trigger",
104469
+ description: 'Trigger an n8n webhook workflow. Sends JSON data to a webhook endpoint. Configure n8n in nestor.config.json under "n8n": { "baseUrl": "http://localhost:5678", "apiKey": "..." }.',
104470
+ inputSchema: n8nTriggerSchema,
104471
+ handler: async (input, _ctx) => {
104472
+ const args2 = input;
104473
+ const cfg = loadIntegrationConfig();
104474
+ if (!cfg.n8n?.baseUrl) {
104475
+ return {
104476
+ output: 'n8n integration not configured. Add "n8n": { "baseUrl": "http://localhost:5678" } to ~/.nestor/nestor.config.json',
104477
+ isError: true
104478
+ };
104479
+ }
104480
+ try {
104481
+ const n8n = new N8nIntegration(cfg.n8n);
104482
+ const result = await n8n.triggerWebhook(args2.webhook, args2.data || {});
104483
+ return { output: JSON.stringify(result, null, 2), isError: false };
104484
+ } catch (err) {
104485
+ const msg = err instanceof Error ? err.message : String(err);
104486
+ return { output: `n8n webhook trigger failed: ${msg}`, isError: true };
104487
+ }
104488
+ }
104489
+ });
104490
+ registry.register({
104491
+ name: "n8n_list_workflows",
104492
+ description: "List available n8n workflows with their ID, name, and active status.",
104493
+ inputSchema: emptySchema,
104494
+ handler: async (_input, _ctx) => {
104495
+ const cfg = loadIntegrationConfig();
104496
+ if (!cfg.n8n?.baseUrl) {
104497
+ return {
104498
+ output: 'n8n integration not configured. Add "n8n": { "baseUrl": "http://localhost:5678" } to ~/.nestor/nestor.config.json',
104499
+ isError: true
104500
+ };
104501
+ }
104502
+ try {
104503
+ const n8n = new N8nIntegration(cfg.n8n);
104504
+ const available = await n8n.isAvailable();
104505
+ if (!available) {
104506
+ return { output: `n8n is not reachable at: ${cfg.n8n.baseUrl}`, isError: true };
104507
+ }
104508
+ const workflows = await n8n.listWorkflows();
104509
+ if (workflows.length === 0) {
104510
+ return { output: "No workflows found.", isError: false };
104511
+ }
104512
+ const list = workflows.map((w) => `- [${w.active ? "ACTIVE" : "inactive"}] ${w.name} (id: ${w.id})`).join("\n");
104513
+ return { output: `Found ${workflows.length} workflow(s):
104514
+ ${list}`, isError: false };
104515
+ } catch (err) {
104516
+ const msg = err instanceof Error ? err.message : String(err);
104517
+ return { output: `Failed to list n8n workflows: ${msg}`, isError: true };
104518
+ }
104519
+ }
104520
+ });
104521
+ registry.register({
104522
+ name: "n8n_execute_workflow",
104523
+ description: "Execute an n8n workflow by its ID. Optionally pass input data.",
104524
+ inputSchema: n8nExecuteWorkflowSchema,
104525
+ handler: async (input, _ctx) => {
104526
+ const args2 = input;
104527
+ const cfg = loadIntegrationConfig();
104528
+ if (!cfg.n8n?.baseUrl) {
104529
+ return {
104530
+ output: 'n8n integration not configured. Add "n8n": { "baseUrl": "http://localhost:5678" } to ~/.nestor/nestor.config.json',
104531
+ isError: true
104532
+ };
104533
+ }
104534
+ try {
104535
+ const n8n = new N8nIntegration(cfg.n8n);
104536
+ const result = await n8n.executeWorkflow(args2.workflowId, args2.data);
104537
+ return { output: JSON.stringify(result, null, 2), isError: false };
104538
+ } catch (err) {
104539
+ const msg = err instanceof Error ? err.message : String(err);
104540
+ return { output: `n8n workflow execution failed: ${msg}`, isError: true };
104541
+ }
104542
+ }
104543
+ });
104127
104544
  }
104128
104545
  var emptySchema, createAgentSchema, runAgentSchema, deleteAgentSchema, createWorkflowSchema, searchMemorySchema, storeMemorySchema, createGuardrailSchema, createMissionSchema, missionIdSchema, queryMemorySchema;
104129
104546
  var init_system_tools = __esm({
104130
104547
  "../agent/src/tools/system-tools.ts"() {
104131
104548
  "use strict";
104132
104549
  init_layered_memory();
104550
+ init_obsidian();
104551
+ init_n8n();
104133
104552
  emptySchema = z28.object({}).passthrough();
104134
104553
  createAgentSchema = z28.object({
104135
104554
  name: z28.string().describe("Agent name"),
@@ -104187,7 +104606,7 @@ var init_system_tools = __esm({
104187
104606
  import { z as z29 } from "zod";
104188
104607
  import { promises as fs14 } from "node:fs";
104189
104608
  import { execFile as execFile6 } from "node:child_process";
104190
- import { resolve as resolve10, join as join9 } from "node:path";
104609
+ import { resolve as resolve10, join as join10 } from "node:path";
104191
104610
  function buildSandboxConfig(context3) {
104192
104611
  const s = context3.sandbox;
104193
104612
  return {
@@ -104468,11 +104887,11 @@ async function fileListHandler(input, context3) {
104468
104887
  const items = await fs14.readdir(dir, { withFileTypes: true });
104469
104888
  for (const item of items) {
104470
104889
  if (item.name.startsWith(".") || item.name === "node_modules") continue;
104471
- const relativePath = join9(dir, item.name).replace(absolutePath, "").replace(/^[/\\]/, "");
104890
+ const relativePath = join10(dir, item.name).replace(absolutePath, "").replace(/^[/\\]/, "");
104472
104891
  if (item.isDirectory()) {
104473
104892
  entries.push(`${relativePath}/`);
104474
104893
  if (recursive) {
104475
- await listDir(join9(dir, item.name), depth + 1);
104894
+ await listDir(join10(dir, item.name), depth + 1);
104476
104895
  }
104477
104896
  } else {
104478
104897
  entries.push(relativePath);
@@ -104565,32 +104984,19 @@ async function webFetchHandler(input, context3) {
104565
104984
  return { output: `Fetch failed: ${message}`, isError: true };
104566
104985
  }
104567
104986
  }
104568
- async function webSearchHandler(input, context3) {
104569
- const { query, engine, maxResults } = input;
104570
- const max = maxResults || 5;
104571
- const searchEngine = engine || "duckduckgo";
104572
- let searchUrl;
104573
- switch (searchEngine) {
104574
- case "google":
104575
- searchUrl = `https://www.google.com/search?q=${encodeURIComponent(query)}&num=${max}`;
104576
- break;
104577
- case "bing":
104578
- searchUrl = `https://www.bing.com/search?q=${encodeURIComponent(query)}&count=${max}`;
104579
- break;
104580
- case "duckduckgo":
104581
- default:
104582
- searchUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
104583
- break;
104987
+ function pickUserAgent(attempt = 0) {
104988
+ return SEARCH_USER_AGENTS[attempt % SEARCH_USER_AGENTS.length];
104989
+ }
104990
+ async function fetchSearchHtml(searchUrl, context3, userAgent, timeoutMs = 15e3) {
104991
+ const controller = new AbortController();
104992
+ const timer2 = setTimeout(() => controller.abort(), timeoutMs);
104993
+ if (context3.signal) {
104994
+ context3.signal.addEventListener("abort", () => controller.abort(), { once: true });
104584
104995
  }
104585
104996
  try {
104586
- const controller = new AbortController();
104587
- const timer2 = setTimeout(() => controller.abort(), 15e3);
104588
- if (context3.signal) {
104589
- context3.signal.addEventListener("abort", () => controller.abort(), { once: true });
104590
- }
104591
104997
  const resp = await fetch(searchUrl, {
104592
104998
  headers: {
104593
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
104999
+ "User-Agent": userAgent,
104594
105000
  "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
104595
105001
  "Accept-Language": "en-US,en;q=0.9,fr;q=0.8"
104596
105002
  },
@@ -104598,96 +105004,217 @@ async function webSearchHandler(input, context3) {
104598
105004
  redirect: "follow"
104599
105005
  });
104600
105006
  clearTimeout(timer2);
104601
- if (!resp.ok) {
104602
- return { output: `Search failed: HTTP ${resp.status}. Try a different search engine with engine:"google" or engine:"bing".`, isError: true };
104603
- }
104604
105007
  const html = await resp.text();
104605
- const results = [];
104606
- if (searchEngine === "duckduckgo") {
104607
- const linkRegex = /<a[^>]*class="result__a"[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi;
104608
- const snippetRegex = /<a[^>]*class="result__snippet"[^>]*>(.*?)<\/a>/gi;
104609
- let linkMatch;
104610
- const links = [];
104611
- while ((linkMatch = linkRegex.exec(html)) !== null && links.length < max) {
104612
- let url = linkMatch[1];
104613
- const uddg = url.match(/uddg=([^&]*)/);
104614
- if (uddg) url = decodeURIComponent(uddg[1]);
104615
- const title = linkMatch[2].replace(/<[^>]*>/g, "").trim();
104616
- if (url.startsWith("http") && !url.includes("duckduckgo.com/y.js") && !url.includes("ad_domain=")) {
104617
- links.push({ url, title });
104618
- }
104619
- }
104620
- let snippetMatch;
104621
- const snippets = [];
104622
- while ((snippetMatch = snippetRegex.exec(html)) !== null) {
104623
- snippets.push(snippetMatch[1].replace(/<[^>]*>/g, "").trim());
104624
- }
104625
- for (let i = 0; i < links.length; i++) {
104626
- results.push({
104627
- title: links[i].title,
104628
- url: links[i].url,
104629
- snippet: snippets[i] || ""
104630
- });
104631
- }
104632
- } else if (searchEngine === "google") {
104633
- const resultBlockRegex = /<div class="[^"]*g[^"]*"[^>]*>[\s\S]*?<a[^>]*href="(https?:\/\/[^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?(?:<span[^>]*>([\s\S]*?)<\/span>)?/gi;
104634
- let blockMatch;
104635
- while ((blockMatch = resultBlockRegex.exec(html)) !== null && results.length < max) {
104636
- const url = blockMatch[1];
104637
- const title = blockMatch[2].replace(/<[^>]*>/g, "").trim();
104638
- const snippet = (blockMatch[3] || "").replace(/<[^>]*>/g, "").trim();
104639
- if (title.length > 3 && !url.includes("google.com")) {
104640
- results.push({ title, url, snippet });
104641
- }
104642
- }
104643
- } else if (searchEngine === "bing") {
104644
- const bingRegex = /<li class="b_algo"[^>]*>[\s\S]*?<a[^>]*href="(https?:\/\/[^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<p[^>]*>([\s\S]*?)<\/p>/gi;
104645
- let bingMatch;
104646
- while ((bingMatch = bingRegex.exec(html)) !== null && results.length < max) {
104647
- const url = bingMatch[1];
104648
- const title = bingMatch[2].replace(/<[^>]*>/g, "").trim();
104649
- const snippet = bingMatch[3].replace(/<[^>]*>/g, "").trim();
104650
- if (title.length > 3) {
104651
- results.push({ title, url, snippet });
104652
- }
105008
+ return { ok: resp.ok, status: resp.status, html };
105009
+ } catch {
105010
+ clearTimeout(timer2);
105011
+ return { ok: false, status: 0, html: "" };
105012
+ }
105013
+ }
105014
+ function parseDuckDuckGo(html, max) {
105015
+ const results = [];
105016
+ const linkRegex = /<a[^>]*class="result__a"[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi;
105017
+ const snippetRegex = /<a[^>]*class="result__snippet"[^>]*>(.*?)<\/a>/gi;
105018
+ let linkMatch;
105019
+ const links = [];
105020
+ while ((linkMatch = linkRegex.exec(html)) !== null && links.length < max) {
105021
+ let url = linkMatch[1];
105022
+ const uddg = url.match(/uddg=([^&]*)/);
105023
+ if (uddg) url = decodeURIComponent(uddg[1]);
105024
+ const title = linkMatch[2].replace(/<[^>]*>/g, "").trim();
105025
+ if (url.startsWith("http") && !url.includes("duckduckgo.com/y.js") && !url.includes("ad_domain=")) {
105026
+ links.push({ url, title });
105027
+ }
105028
+ }
105029
+ let snippetMatch;
105030
+ const snippets = [];
105031
+ while ((snippetMatch = snippetRegex.exec(html)) !== null) {
105032
+ snippets.push(snippetMatch[1].replace(/<[^>]*>/g, "").trim());
105033
+ }
105034
+ for (let i = 0; i < links.length; i++) {
105035
+ results.push({
105036
+ title: links[i].title,
105037
+ url: links[i].url,
105038
+ snippet: snippets[i] || ""
105039
+ });
105040
+ }
105041
+ return results;
105042
+ }
105043
+ function parseGoogle(html, max) {
105044
+ const results = [];
105045
+ const googleRegex = /<a[^>]*href="(https?:\/\/[^"]*)"[^>]*><h3[^>]*>([^<]+)<\/h3>/gi;
105046
+ let gMatch;
105047
+ while ((gMatch = googleRegex.exec(html)) !== null && results.length < max) {
105048
+ const url = gMatch[1];
105049
+ const title = gMatch[2].trim();
105050
+ if (title.length > 3 && !url.includes("google.com")) {
105051
+ results.push({ title, url, snippet: "" });
105052
+ }
105053
+ }
105054
+ if (results.length > 0) {
105055
+ const snippetRegex = /<div[^>]*class="[^"]*VwiC3b[^"]*"[^>]*>([\s\S]*?)<\/div>/gi;
105056
+ let sMatch;
105057
+ let idx = 0;
105058
+ while ((sMatch = snippetRegex.exec(html)) !== null && idx < results.length) {
105059
+ const snippet = sMatch[1].replace(/<[^>]*>/g, "").trim();
105060
+ if (snippet.length > 10) {
105061
+ results[idx].snippet = snippet;
105062
+ idx++;
104653
105063
  }
104654
105064
  }
104655
- if (results.length === 0) {
104656
- const anyLinkRegex = /<a[^>]*href="(https?:\/\/[^"]*)"[^>]*>(.*?)<\/a>/gi;
104657
- let anyMatch;
104658
- while ((anyMatch = anyLinkRegex.exec(html)) !== null && results.length < max) {
104659
- const url = anyMatch[1];
104660
- const title = anyMatch[2].replace(/<[^>]*>/g, "").trim();
104661
- if (title.length > 5 && !url.includes("duckduckgo.com") && !url.includes("google.com") && !url.includes("bing.com")) {
104662
- results.push({ title, url, snippet: "" });
104663
- }
105065
+ return results;
105066
+ }
105067
+ const resultBlockRegex = /<div class="[^"]*g[^"]*"[^>]*>[\s\S]*?<a[^>]*href="(https?:\/\/[^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?(?:<span[^>]*>([\s\S]*?)<\/span>)?/gi;
105068
+ let blockMatch;
105069
+ while ((blockMatch = resultBlockRegex.exec(html)) !== null && results.length < max) {
105070
+ const url = blockMatch[1];
105071
+ const title = blockMatch[2].replace(/<[^>]*>/g, "").trim();
105072
+ const snippet = (blockMatch[3] || "").replace(/<[^>]*>/g, "").trim();
105073
+ if (title.length > 3 && !url.includes("google.com")) {
105074
+ results.push({ title, url, snippet });
105075
+ }
105076
+ }
105077
+ return results;
105078
+ }
105079
+ function parseBing(html, max) {
105080
+ const results = [];
105081
+ const bingRegex = /<li[^>]*class="b_algo"[^>]*>[\s\S]*?<a[^>]*href="([^"]*)"[^>]*>([^<]+)<\/a>[\s\S]*?<p[^>]*>([^<]*)/gi;
105082
+ let bingMatch;
105083
+ while ((bingMatch = bingRegex.exec(html)) !== null && results.length < max) {
105084
+ const url = bingMatch[1];
105085
+ const title = bingMatch[2].replace(/<[^>]*>/g, "").trim();
105086
+ const snippet = bingMatch[3].replace(/<[^>]*>/g, "").trim();
105087
+ if (title.length > 3) {
105088
+ results.push({ title, url, snippet });
105089
+ }
105090
+ }
105091
+ if (results.length === 0) {
105092
+ const fallbackRegex = /<li class="b_algo"[^>]*>[\s\S]*?<a[^>]*href="(https?:\/\/[^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<p[^>]*>([\s\S]*?)<\/p>/gi;
105093
+ let fbMatch;
105094
+ while ((fbMatch = fallbackRegex.exec(html)) !== null && results.length < max) {
105095
+ const url = fbMatch[1];
105096
+ const title = fbMatch[2].replace(/<[^>]*>/g, "").trim();
105097
+ const snippet = fbMatch[3].replace(/<[^>]*>/g, "").trim();
105098
+ if (title.length > 3) {
105099
+ results.push({ title, url, snippet });
104664
105100
  }
104665
105101
  }
105102
+ }
105103
+ return results;
105104
+ }
105105
+ function parseAnyLinks(html, max) {
105106
+ const results = [];
105107
+ const anyLinkRegex = /<a[^>]*href="(https?:\/\/[^"]*)"[^>]*>(.*?)<\/a>/gi;
105108
+ let anyMatch;
105109
+ while ((anyMatch = anyLinkRegex.exec(html)) !== null && results.length < max) {
105110
+ const url = anyMatch[1];
105111
+ const title = anyMatch[2].replace(/<[^>]*>/g, "").trim();
105112
+ if (title.length > 5 && !url.includes("duckduckgo.com") && !url.includes("google.com") && !url.includes("bing.com")) {
105113
+ results.push({ title, url, snippet: "" });
105114
+ }
105115
+ }
105116
+ return results;
105117
+ }
105118
+ async function searchSingleEngine(engineName, query, max, context3) {
105119
+ let searchUrl;
105120
+ let parser2;
105121
+ switch (engineName) {
105122
+ case "google":
105123
+ searchUrl = `https://www.google.com/search?q=${encodeURIComponent(query)}&num=${max}`;
105124
+ parser2 = parseGoogle;
105125
+ break;
105126
+ case "bing":
105127
+ searchUrl = `https://www.bing.com/search?q=${encodeURIComponent(query)}&count=${max}`;
105128
+ parser2 = parseBing;
105129
+ break;
105130
+ case "duckduckgo":
105131
+ default:
105132
+ searchUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
105133
+ parser2 = parseDuckDuckGo;
105134
+ break;
105135
+ }
105136
+ for (let attempt = 0; attempt < 2; attempt++) {
105137
+ const ua = pickUserAgent(attempt);
105138
+ const { ok, status, html } = await fetchSearchHtml(searchUrl, context3, ua);
105139
+ if (!ok) {
105140
+ if (attempt === 0) continue;
105141
+ return { results: [], engineUsed: engineName, error: `HTTP ${status}` };
105142
+ }
105143
+ let results = parser2(html, max);
104666
105144
  if (results.length === 0) {
105145
+ results = parseAnyLinks(html, max);
105146
+ }
105147
+ if (results.length > 0) {
105148
+ return { results, engineUsed: engineName };
105149
+ }
105150
+ }
105151
+ return { results: [], engineUsed: engineName, error: "0 results after UA rotation" };
105152
+ }
105153
+ async function webSearchHandler(input, context3) {
105154
+ const { query, engine, maxResults } = input;
105155
+ const max = maxResults || 5;
105156
+ const searchEngine = engine || "auto";
105157
+ if (searchEngine !== "auto") {
105158
+ try {
105159
+ const { results, error } = await searchSingleEngine(searchEngine, query, max, context3);
105160
+ if (results.length === 0) {
105161
+ return {
105162
+ output: `No results found for "${query}" on ${searchEngine}${error ? ` (${error})` : ""}. Try a different query or use engine:"auto" for multi-engine fallback. You can also try web_fetch directly on a relevant URL.`,
105163
+ isError: false
105164
+ };
105165
+ }
105166
+ const formatted = results.map(
105167
+ (r, i) => `${i + 1}. ${r.title}
105168
+ ${r.url}
105169
+ ${r.snippet}`
105170
+ ).join("\n\n");
104667
105171
  return {
104668
- output: `No results found for "${query}". Try a different query or use a different engine (engine:"google" or engine:"bing"). You can also try web_fetch directly on a relevant URL.`,
105172
+ output: `Search results for "${query}" (${searchEngine}):
105173
+
105174
+ ${formatted}
105175
+
105176
+ Use web_fetch on any URL above to get the full page content.`,
104669
105177
  isError: false
104670
105178
  };
105179
+ } catch (err) {
105180
+ if (err.name === "AbortError") {
105181
+ return { output: `Search timed out for "${query}". Try a simpler query or different engine.`, isError: true };
105182
+ }
105183
+ return { output: `Search error: ${err.message}. Try engine:"auto" for multi-engine fallback.`, isError: true };
104671
105184
  }
104672
- const formatted = results.map(
104673
- (r, i) => `${i + 1}. ${r.title}
105185
+ }
105186
+ const fallbackChain = ["duckduckgo", "google", "bing"];
105187
+ const errors = [];
105188
+ for (const eng of fallbackChain) {
105189
+ try {
105190
+ const { results, engineUsed, error } = await searchSingleEngine(eng, query, max, context3);
105191
+ if (results.length > 0) {
105192
+ const formatted = results.map(
105193
+ (r, i) => `${i + 1}. ${r.title}
104674
105194
  ${r.url}
104675
105195
  ${r.snippet}`
104676
- ).join("\n\n");
104677
- return {
104678
- output: `Search results for "${query}":
105196
+ ).join("\n\n");
105197
+ const fallbackNote = eng !== "duckduckgo" ? `
105198
+
105199
+ (Note: Results from ${engineUsed} \u2014 earlier engines returned 0 results)` : "";
105200
+ return {
105201
+ output: `Search results for "${query}" (${engineUsed}):
104679
105202
 
104680
105203
  ${formatted}
104681
105204
 
104682
- Use web_fetch on any URL above to get the full page content.`,
104683
- isError: false
104684
- };
104685
- } catch (err) {
104686
- if (err.name === "AbortError") {
104687
- return { output: `Search timed out for "${query}". Try a simpler query or different engine.`, isError: true };
105205
+ Use web_fetch on any URL above to get the full page content.${fallbackNote}`,
105206
+ isError: false
105207
+ };
105208
+ }
105209
+ errors.push(`${eng}: ${error || "0 results"}`);
105210
+ } catch (err) {
105211
+ errors.push(`${eng}: ${err.message || "unknown error"}`);
104688
105212
  }
104689
- return { output: `Search error: ${err.message}. Try a different search engine with engine:"google" or engine:"bing".`, isError: true };
104690
105213
  }
105214
+ return {
105215
+ output: `All search engines failed for "${query}". Tried: ${errors.join("; ")}. Try web_fetch directly on known URLs (e.g., Wikipedia, company sites, social profiles) instead of searching.`,
105216
+ isError: true
105217
+ };
104691
105218
  }
104692
105219
  async function messageSendHandler(input, context3) {
104693
105220
  const { to, subject, body } = input;
@@ -104826,7 +105353,7 @@ function registerBrowserTools(registry, config2) {
104826
105353
  }
104827
105354
  return manager;
104828
105355
  }
104829
- var shellExecSchema, sandboxCache, DANGEROUS_METACHARACTERS, shellExecTool, fileReadSchema, fileReadTool, fileWriteSchema, fileWriteTool, fileListSchema, fileListTool, webFetchSchema, webFetchTool, webSearchSchema, webSearchTool, messageSendSchema, messageSendTool, messageReadSchema, messageReadTool, handoffSchema, handoffTool, undoSchema;
105356
+ var shellExecSchema, sandboxCache, DANGEROUS_METACHARACTERS, shellExecTool, fileReadSchema, fileReadTool, fileWriteSchema, fileWriteTool, fileListSchema, fileListTool, webFetchSchema, webFetchTool, webSearchSchema, SEARCH_USER_AGENTS, webSearchTool, messageSendSchema, messageSendTool, messageReadSchema, messageReadTool, handoffSchema, handoffTool, undoSchema;
104830
105357
  var init_builtin = __esm({
104831
105358
  "../agent/src/tools/builtin.ts"() {
104832
105359
  "use strict";
@@ -104906,12 +105433,17 @@ var init_builtin = __esm({
104906
105433
  };
104907
105434
  webSearchSchema = z29.object({
104908
105435
  query: z29.string().describe("The search query"),
104909
- engine: z29.string().optional().describe("Search engine: google, duckduckgo, bing. Default: duckduckgo"),
105436
+ engine: z29.string().optional().describe('Search engine: google, duckduckgo, bing, or "auto" for multi-engine fallback (default). Default: auto'),
104910
105437
  maxResults: z29.number().optional().describe("Max results to return. Default: 5")
104911
105438
  });
105439
+ SEARCH_USER_AGENTS = [
105440
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
105441
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15",
105442
+ "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0"
105443
+ ];
104912
105444
  webSearchTool = {
104913
105445
  name: "web_search",
104914
- description: "Search the internet using DuckDuckGo, Google, or Bing. Returns titles, URLs, and snippets. Use web_fetch on result URLs to read full page content. Always try this FIRST when you need to find information online.",
105446
+ description: 'Search the internet using DuckDuckGo, Google, or Bing with automatic multi-engine fallback. Returns titles, URLs, and snippets. Use web_fetch on result URLs to read full page content. Default mode "auto" tries DuckDuckGo first, then Google, then Bing if previous engines return 0 results.',
104915
105447
  inputSchema: webSearchSchema,
104916
105448
  handler: webSearchHandler
104917
105449
  };
@@ -106835,8 +107367,8 @@ var init_store2 = __esm({
106835
107367
  });
106836
107368
 
106837
107369
  // ../agent/src/memory/files.ts
106838
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "node:fs";
106839
- import { join as join10, dirname as dirname5 } from "node:path";
107370
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "node:fs";
107371
+ import { join as join11, dirname as dirname5 } from "node:path";
106840
107372
  var MemoryFiles;
106841
107373
  var init_files = __esm({
106842
107374
  "../agent/src/memory/files.ts"() {
@@ -106844,8 +107376,8 @@ var init_files = __esm({
106844
107376
  MemoryFiles = class {
106845
107377
  constructor(workDir) {
106846
107378
  this.workDir = workDir;
106847
- this.memoryPath = join10(workDir, "MEMORY.md");
106848
- this.userPath = join10(workDir, "USER.md");
107379
+ this.memoryPath = join11(workDir, "MEMORY.md");
107380
+ this.userPath = join11(workDir, "USER.md");
106849
107381
  }
106850
107382
  memoryPath;
106851
107383
  userPath;
@@ -106854,8 +107386,8 @@ var init_files = __esm({
106854
107386
  */
106855
107387
  readMemoryFile() {
106856
107388
  try {
106857
- if (!existsSync5(this.memoryPath)) return null;
106858
- return readFileSync9(this.memoryPath, "utf-8");
107389
+ if (!existsSync6(this.memoryPath)) return null;
107390
+ return readFileSync10(this.memoryPath, "utf-8");
106859
107391
  } catch {
106860
107392
  return null;
106861
107393
  }
@@ -106865,8 +107397,8 @@ var init_files = __esm({
106865
107397
  */
106866
107398
  readUserFile() {
106867
107399
  try {
106868
- if (!existsSync5(this.userPath)) return null;
106869
- return readFileSync9(this.userPath, "utf-8");
107400
+ if (!existsSync6(this.userPath)) return null;
107401
+ return readFileSync10(this.userPath, "utf-8");
106870
107402
  } catch {
106871
107403
  return null;
106872
107404
  }
@@ -106876,16 +107408,16 @@ var init_files = __esm({
106876
107408
  */
106877
107409
  appendMemory(observation) {
106878
107410
  const dir = dirname5(this.memoryPath);
106879
- if (!existsSync5(dir)) {
106880
- mkdirSync3(dir, { recursive: true });
107411
+ if (!existsSync6(dir)) {
107412
+ mkdirSync4(dir, { recursive: true });
106881
107413
  }
106882
107414
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
106883
107415
  const entry = `
106884
107416
  - [${timestamp}] ${observation}
106885
107417
  `;
106886
- if (existsSync5(this.memoryPath)) {
106887
- const existing = readFileSync9(this.memoryPath, "utf-8");
106888
- writeFileSync3(this.memoryPath, existing + entry, "utf-8");
107418
+ if (existsSync6(this.memoryPath)) {
107419
+ const existing = readFileSync10(this.memoryPath, "utf-8");
107420
+ writeFileSync4(this.memoryPath, existing + entry, "utf-8");
106889
107421
  } else {
106890
107422
  const header = `# Agent Memory
106891
107423
 
@@ -106893,7 +107425,7 @@ Persistent observations and notes.
106893
107425
 
106894
107426
  ## Observations
106895
107427
  `;
106896
- writeFileSync3(this.memoryPath, header + entry, "utf-8");
107428
+ writeFileSync4(this.memoryPath, header + entry, "utf-8");
106897
107429
  }
106898
107430
  }
106899
107431
  /**
@@ -106901,8 +107433,8 @@ Persistent observations and notes.
106901
107433
  */
106902
107434
  updateUserProfile(info) {
106903
107435
  const dir = dirname5(this.userPath);
106904
- if (!existsSync5(dir)) {
106905
- mkdirSync3(dir, { recursive: true });
107436
+ if (!existsSync6(dir)) {
107437
+ mkdirSync4(dir, { recursive: true });
106906
107438
  }
106907
107439
  const lines = ["# User Profile\n"];
106908
107440
  for (const [key, value] of Object.entries(info)) {
@@ -106911,7 +107443,7 @@ Persistent observations and notes.
106911
107443
  }
106912
107444
  }
106913
107445
  lines.push("");
106914
- writeFileSync3(this.userPath, lines.join("\n"), "utf-8");
107446
+ writeFileSync4(this.userPath, lines.join("\n"), "utf-8");
106915
107447
  }
106916
107448
  /**
106917
107449
  * Parse MEMORY.md into structured entries.
@@ -111124,8 +111656,8 @@ var init_embeddings = __esm({
111124
111656
  });
111125
111657
 
111126
111658
  // ../agent/src/rag/indexer.ts
111127
- import { readFileSync as readFileSync10, statSync as statSync3, existsSync as existsSync6 } from "node:fs";
111128
- import { join as join11, relative as relative3, resolve as resolve11 } from "node:path";
111659
+ import { readFileSync as readFileSync11, statSync as statSync4, existsSync as existsSync7 } from "node:fs";
111660
+ import { join as join12, relative as relative4, resolve as resolve11 } from "node:path";
111129
111661
  function matchesGlob(filePath, pattern) {
111130
111662
  const regexStr = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
111131
111663
  return new RegExp(`^${regexStr}$`).test(filePath) || new RegExp(`(^|/)${regexStr}$`).test(filePath);
@@ -111151,14 +111683,14 @@ function walkDirectory2(dir, excludePatterns) {
111151
111683
  const currentDir = stack.pop();
111152
111684
  let entries;
111153
111685
  try {
111154
- const { readdirSync: readdirSync7 } = __require("node:fs");
111155
- entries = readdirSync7(currentDir);
111686
+ const { readdirSync: readdirSync8 } = __require("node:fs");
111687
+ entries = readdirSync8(currentDir);
111156
111688
  } catch {
111157
111689
  continue;
111158
111690
  }
111159
111691
  for (const entry of entries) {
111160
- const fullPath = join11(currentDir, entry);
111161
- const relFromRoot = relative3(dir, fullPath).replace(/\\/g, "/");
111692
+ const fullPath = join12(currentDir, entry);
111693
+ const relFromRoot = relative4(dir, fullPath).replace(/\\/g, "/");
111162
111694
  let excluded = false;
111163
111695
  for (const pattern of excludePatterns) {
111164
111696
  if (!pattern.includes("*") && !pattern.includes(".")) {
@@ -111170,7 +111702,7 @@ function walkDirectory2(dir, excludePatterns) {
111170
111702
  }
111171
111703
  if (excluded) continue;
111172
111704
  try {
111173
- const stat = statSync3(fullPath);
111705
+ const stat = statSync4(fullPath);
111174
111706
  if (stat.isDirectory()) {
111175
111707
  stack.push(fullPath);
111176
111708
  } else if (stat.isFile()) {
@@ -111262,13 +111794,13 @@ var init_indexer = __esm({
111262
111794
  const tenantId = opts?.tenantId ?? "default";
111263
111795
  const onProgress = opts?.onProgress;
111264
111796
  const absDir = resolve11(dir);
111265
- if (!existsSync6(absDir)) {
111797
+ if (!existsSync7(absDir)) {
111266
111798
  throw new Error(`Directory not found: ${absDir}`);
111267
111799
  }
111268
111800
  const allFiles = walkDirectory2(absDir, excludePatterns);
111269
111801
  const matchingFiles = [];
111270
111802
  for (const file of allFiles) {
111271
- const relPath = relative3(absDir, file).replace(/\\/g, "/");
111803
+ const relPath = relative4(absDir, file).replace(/\\/g, "/");
111272
111804
  if (shouldInclude(relPath, includePatterns, excludePatterns)) {
111273
111805
  matchingFiles.push(file);
111274
111806
  }
@@ -111284,11 +111816,11 @@ var init_indexer = __esm({
111284
111816
  let totalFilesIndexed = 0;
111285
111817
  const allChunks = [];
111286
111818
  for (const filePath of matchingFiles) {
111287
- const relPath = relative3(absDir, filePath).replace(/\\/g, "/");
111819
+ const relPath = relative4(absDir, filePath).replace(/\\/g, "/");
111288
111820
  progress.currentFile = relPath;
111289
111821
  onProgress?.(progress);
111290
111822
  try {
111291
- const content = readFileSync10(filePath, "utf-8");
111823
+ const content = readFileSync11(filePath, "utf-8");
111292
111824
  if (content.includes("\0")) {
111293
111825
  progress.processedFiles++;
111294
111826
  continue;
@@ -111297,7 +111829,7 @@ var init_indexer = __esm({
111297
111829
  progress.processedFiles++;
111298
111830
  continue;
111299
111831
  }
111300
- const mtime = statSync3(filePath).mtimeMs;
111832
+ const mtime = statSync4(filePath).mtimeMs;
111301
111833
  const chunks = this.chunker.chunk(relPath, content);
111302
111834
  for (const chunk of chunks) {
111303
111835
  allChunks.push({ ...chunk, fileMtime: Math.floor(mtime) });
@@ -111359,7 +111891,7 @@ ${c.content}`);
111359
111891
  const tenantId = opts?.tenantId ?? "default";
111360
111892
  const onProgress = opts?.onProgress;
111361
111893
  const absDir = resolve11(dir);
111362
- if (!existsSync6(absDir)) {
111894
+ if (!existsSync7(absDir)) {
111363
111895
  throw new Error(`Directory not found: ${absDir}`);
111364
111896
  }
111365
111897
  const existingMtimes = this.store.getChunkMtimes(tenantId);
@@ -111370,16 +111902,16 @@ ${c.content}`);
111370
111902
  const allFiles = walkDirectory2(absDir, excludePatterns);
111371
111903
  const matchingFiles = [];
111372
111904
  for (const file of allFiles) {
111373
- const relPath = relative3(absDir, file).replace(/\\/g, "/");
111905
+ const relPath = relative4(absDir, file).replace(/\\/g, "/");
111374
111906
  if (shouldInclude(relPath, includePatterns, excludePatterns)) {
111375
111907
  matchingFiles.push(file);
111376
111908
  }
111377
111909
  }
111378
111910
  const filesToProcess = [];
111379
111911
  for (const filePath of matchingFiles) {
111380
- const relPath = relative3(absDir, filePath).replace(/\\/g, "/");
111912
+ const relPath = relative4(absDir, filePath).replace(/\\/g, "/");
111381
111913
  try {
111382
- const mtime = Math.floor(statSync3(filePath).mtimeMs);
111914
+ const mtime = Math.floor(statSync4(filePath).mtimeMs);
111383
111915
  const existingMtime = mtimeMap.get(relPath);
111384
111916
  if (existingMtime === void 0 || mtime > existingMtime) {
111385
111917
  filesToProcess.push(filePath);
@@ -111401,16 +111933,16 @@ ${c.content}`);
111401
111933
  let totalChunksCreated = 0;
111402
111934
  let totalFilesIndexed = 0;
111403
111935
  for (const filePath of filesToProcess) {
111404
- const relPath = relative3(absDir, filePath).replace(/\\/g, "/");
111936
+ const relPath = relative4(absDir, filePath).replace(/\\/g, "/");
111405
111937
  progress.currentFile = relPath;
111406
111938
  onProgress?.(progress);
111407
111939
  try {
111408
- const content = readFileSync10(filePath, "utf-8");
111940
+ const content = readFileSync11(filePath, "utf-8");
111409
111941
  if (content.includes("\0") || content.length > 5e5) {
111410
111942
  progress.processedFiles++;
111411
111943
  continue;
111412
111944
  }
111413
- const mtime = Math.floor(statSync3(filePath).mtimeMs);
111945
+ const mtime = Math.floor(statSync4(filePath).mtimeMs);
111414
111946
  this.store.clearChunksByFile(relPath, tenantId);
111415
111947
  const chunks = this.chunker.chunk(relPath, content);
111416
111948
  const texts = chunks.map((c) => `${c.name ?? c.type} in ${c.filePath}
@@ -111593,8 +112125,8 @@ var init_search = __esm({
111593
112125
  });
111594
112126
 
111595
112127
  // ../agent/src/rag/mental-model.ts
111596
- import { readFileSync as readFileSync11, statSync as statSync4, readdirSync as readdirSync2, writeFileSync as writeFileSync4, existsSync as existsSync7 } from "node:fs";
111597
- import { join as join12, relative as relative4, resolve as resolve12, extname as extname3, basename as basename3, dirname as dirname6 } from "node:path";
112128
+ import { readFileSync as readFileSync12, statSync as statSync5, readdirSync as readdirSync3, writeFileSync as writeFileSync5, existsSync as existsSync8 } from "node:fs";
112129
+ import { join as join13, relative as relative5, resolve as resolve12, extname as extname3, basename as basename4, dirname as dirname6 } from "node:path";
111598
112130
  var EXCLUDE_DIRS, SOURCE_EXTENSIONS, MentalModelBuilder;
111599
112131
  var init_mental_model = __esm({
111600
112132
  "../agent/src/rag/mental-model.ts"() {
@@ -111658,10 +112190,10 @@ var init_mental_model = __esm({
111658
112190
  const files = await this.findSourceFiles(absRoot);
111659
112191
  const nodes = /* @__PURE__ */ new Map();
111660
112192
  for (const file of files) {
111661
- const relPath = relative4(absRoot, file).replace(/\\/g, "/");
112193
+ const relPath = relative5(absRoot, file).replace(/\\/g, "/");
111662
112194
  let content;
111663
112195
  try {
111664
- content = readFileSync11(file, "utf-8");
112196
+ content = readFileSync12(file, "utf-8");
111665
112197
  } catch {
111666
112198
  continue;
111667
112199
  }
@@ -111669,14 +112201,14 @@ var init_mental_model = __esm({
111669
112201
  const imports = this.extractImports(content, file, absRoot);
111670
112202
  let mtime;
111671
112203
  try {
111672
- mtime = statSync4(file).mtimeMs;
112204
+ mtime = statSync5(file).mtimeMs;
111673
112205
  } catch {
111674
112206
  mtime = Date.now();
111675
112207
  }
111676
112208
  nodes.set(relPath, {
111677
112209
  path: relPath,
111678
112210
  type: "file",
111679
- name: basename3(file),
112211
+ name: basename4(file),
111680
112212
  dependencies: imports,
111681
112213
  dependents: [],
111682
112214
  lastModified: mtime,
@@ -111709,7 +112241,7 @@ var init_mental_model = __esm({
111709
112241
  );
111710
112242
  const hubs = [...graph.nodes.values()].sort((a, b) => b.dependents.length - a.dependents.length).slice(0, 5);
111711
112243
  const lines = [];
111712
- lines.push(`Project: ${basename3(graph.rootDir)}`);
112244
+ lines.push(`Project: ${basename4(graph.rootDir)}`);
111713
112245
  lines.push(`Language: ${graph.language}`);
111714
112246
  if (graph.framework) lines.push(`Framework: ${graph.framework}`);
111715
112247
  lines.push(`Files: ${moduleCount}`);
@@ -111796,15 +112328,15 @@ var init_mental_model = __esm({
111796
112328
  */
111797
112329
  save(graph, filePath) {
111798
112330
  const json = this.toJson(graph);
111799
- writeFileSync4(filePath, JSON.stringify(json, null, 2), "utf-8");
112331
+ writeFileSync5(filePath, JSON.stringify(json, null, 2), "utf-8");
111800
112332
  }
111801
112333
  /**
111802
112334
  * Load a graph from a JSON file.
111803
112335
  */
111804
112336
  load(filePath) {
111805
- if (!existsSync7(filePath)) return null;
112337
+ if (!existsSync8(filePath)) return null;
111806
112338
  try {
111807
- const content = readFileSync11(filePath, "utf-8");
112339
+ const content = readFileSync12(filePath, "utf-8");
111808
112340
  const json = JSON.parse(content);
111809
112341
  return this.fromJson(json);
111810
112342
  } catch {
@@ -111883,7 +112415,7 @@ var init_mental_model = __esm({
111883
112415
  }
111884
112416
  const fromDir = dirname6(fromFile);
111885
112417
  const resolved = resolve12(fromDir, specifier);
111886
- const relPath = relative4(rootDir, resolved).replace(/\\/g, "/");
112418
+ const relPath = relative5(rootDir, resolved).replace(/\\/g, "/");
111887
112419
  const candidates = [
111888
112420
  relPath,
111889
112421
  relPath + ".ts",
@@ -111904,7 +112436,7 @@ var init_mental_model = __esm({
111904
112436
  for (const candidate of candidates) {
111905
112437
  const fullPath = resolve12(rootDir, candidate);
111906
112438
  try {
111907
- const stat = statSync4(fullPath);
112439
+ const stat = statSync5(fullPath);
111908
112440
  if (stat.isFile()) {
111909
112441
  return candidate;
111910
112442
  }
@@ -111914,7 +112446,7 @@ var init_mental_model = __esm({
111914
112446
  return relPath;
111915
112447
  }
111916
112448
  resolveRelativePy(modulePath, fromFile, rootDir) {
111917
- const relPath = relative4(rootDir, resolve12(dirname6(fromFile), modulePath)).replace(/\\/g, "/");
112449
+ const relPath = relative5(rootDir, resolve12(dirname6(fromFile), modulePath)).replace(/\\/g, "/");
111918
112450
  const candidates = [
111919
112451
  relPath + ".py",
111920
112452
  relPath + "/__init__.py"
@@ -111922,7 +112454,7 @@ var init_mental_model = __esm({
111922
112454
  for (const candidate of candidates) {
111923
112455
  const fullPath = resolve12(rootDir, candidate);
111924
112456
  try {
111925
- if (statSync4(fullPath).isFile()) return candidate;
112457
+ if (statSync5(fullPath).isFile()) return candidate;
111926
112458
  } catch {
111927
112459
  }
111928
112460
  }
@@ -111997,10 +112529,10 @@ var init_mental_model = __esm({
111997
112529
  return "Unknown";
111998
112530
  }
111999
112531
  detectFramework(rootDir) {
112000
- const pkgPath = join12(rootDir, "package.json");
112001
- if (existsSync7(pkgPath)) {
112532
+ const pkgPath = join13(rootDir, "package.json");
112533
+ if (existsSync8(pkgPath)) {
112002
112534
  try {
112003
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
112535
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
112004
112536
  const deps = {
112005
112537
  ...pkg.dependencies ?? {},
112006
112538
  ...pkg.devDependencies ?? {}
@@ -112019,10 +112551,10 @@ var init_mental_model = __esm({
112019
112551
  } catch {
112020
112552
  }
112021
112553
  }
112022
- const cargoPath = join12(rootDir, "Cargo.toml");
112023
- if (existsSync7(cargoPath)) {
112554
+ const cargoPath = join13(rootDir, "Cargo.toml");
112555
+ if (existsSync8(cargoPath)) {
112024
112556
  try {
112025
- const cargo = readFileSync11(cargoPath, "utf-8");
112557
+ const cargo = readFileSync12(cargoPath, "utf-8");
112026
112558
  if (cargo.includes("actix-web")) return "Actix";
112027
112559
  if (cargo.includes("axum")) return "Axum";
112028
112560
  if (cargo.includes("rocket")) return "Rocket";
@@ -112030,10 +112562,10 @@ var init_mental_model = __esm({
112030
112562
  } catch {
112031
112563
  }
112032
112564
  }
112033
- const goModPath = join12(rootDir, "go.mod");
112034
- if (existsSync7(goModPath)) {
112565
+ const goModPath = join13(rootDir, "go.mod");
112566
+ if (existsSync8(goModPath)) {
112035
112567
  try {
112036
- const goMod = readFileSync11(goModPath, "utf-8");
112568
+ const goMod = readFileSync12(goModPath, "utf-8");
112037
112569
  if (goMod.includes("gin-gonic")) return "Gin";
112038
112570
  if (goMod.includes("echo")) return "Echo";
112039
112571
  if (goMod.includes("fiber")) return "Fiber";
@@ -112041,10 +112573,10 @@ var init_mental_model = __esm({
112041
112573
  }
112042
112574
  }
112043
112575
  for (const pyFile of ["requirements.txt", "pyproject.toml"]) {
112044
- const pyPath = join12(rootDir, pyFile);
112045
- if (existsSync7(pyPath)) {
112576
+ const pyPath = join13(rootDir, pyFile);
112577
+ if (existsSync8(pyPath)) {
112046
112578
  try {
112047
- const content = readFileSync11(pyPath, "utf-8");
112579
+ const content = readFileSync12(pyPath, "utf-8");
112048
112580
  if (content.includes("django")) return "Django";
112049
112581
  if (content.includes("flask")) return "Flask";
112050
112582
  if (content.includes("fastapi")) return "FastAPI";
@@ -112098,16 +112630,16 @@ var init_mental_model = __esm({
112098
112630
  const currentDir = stack.pop();
112099
112631
  let entries;
112100
112632
  try {
112101
- entries = readdirSync2(currentDir);
112633
+ entries = readdirSync3(currentDir);
112102
112634
  } catch {
112103
112635
  continue;
112104
112636
  }
112105
112637
  for (const entry of entries) {
112106
112638
  if (EXCLUDE_DIRS.has(entry)) continue;
112107
112639
  if (entry.startsWith(".") && entry !== ".") continue;
112108
- const fullPath = join12(currentDir, entry);
112640
+ const fullPath = join13(currentDir, entry);
112109
112641
  try {
112110
- const stat = statSync4(fullPath);
112642
+ const stat = statSync5(fullPath);
112111
112643
  if (stat.isDirectory()) {
112112
112644
  stack.push(fullPath);
112113
112645
  } else if (stat.isFile()) {
@@ -112140,7 +112672,7 @@ var init_rag = __esm({
112140
112672
  });
112141
112673
 
112142
112674
  // ../agent/src/testing/mock-adapter.ts
112143
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "node:fs";
112675
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "node:fs";
112144
112676
  var MockLlmAdapter, RecordingAdapter;
112145
112677
  var init_mock_adapter = __esm({
112146
112678
  "../agent/src/testing/mock-adapter.ts"() {
@@ -112192,7 +112724,7 @@ var init_mock_adapter = __esm({
112192
112724
  }
112193
112725
  /** Create from a JSON file of recorded responses. */
112194
112726
  static fromFile(filePath) {
112195
- const data = JSON.parse(readFileSync12(filePath, "utf-8"));
112727
+ const data = JSON.parse(readFileSync13(filePath, "utf-8"));
112196
112728
  return new _MockLlmAdapter2(data);
112197
112729
  }
112198
112730
  };
@@ -112224,11 +112756,11 @@ var init_mock_adapter = __esm({
112224
112756
  /** Save recordings to a JSON file. */
112225
112757
  save(filePath) {
112226
112758
  const responses = this.recordings.map((r) => r.response);
112227
- writeFileSync5(filePath, JSON.stringify(responses, null, 2), "utf-8");
112759
+ writeFileSync6(filePath, JSON.stringify(responses, null, 2), "utf-8");
112228
112760
  }
112229
112761
  /** Load responses from a JSON file (returns the responses array for MockLlmAdapter). */
112230
112762
  static load(filePath) {
112231
- return JSON.parse(readFileSync12(filePath, "utf-8"));
112763
+ return JSON.parse(readFileSync13(filePath, "utf-8"));
112232
112764
  }
112233
112765
  /** Get just the response objects for replaying. */
112234
112766
  getResponses() {
@@ -112390,8 +112922,8 @@ var init_assertions = __esm({
112390
112922
  });
112391
112923
 
112392
112924
  // ../agent/src/testing/runner.ts
112393
- import { readFileSync as readFileSync13, mkdirSync as mkdirSync4, writeFileSync as writeFileSync6, rmSync, existsSync as existsSync8 } from "node:fs";
112394
- import { join as join13 } from "node:path";
112925
+ import { readFileSync as readFileSync14, mkdirSync as mkdirSync5, writeFileSync as writeFileSync7, rmSync, existsSync as existsSync9 } from "node:fs";
112926
+ import { join as join14 } from "node:path";
112395
112927
  import { tmpdir as tmpdir3 } from "node:os";
112396
112928
  import { randomUUID as randomUUID27 } from "node:crypto";
112397
112929
  function parseYaml(content) {
@@ -112493,7 +113025,7 @@ var init_runner = __esm({
112493
113025
  AgentTestRunner = class {
112494
113026
  /** Load test suite from a YAML or JSON file. */
112495
113027
  static loadSuite(filePath) {
112496
- const content = readFileSync13(filePath, "utf-8");
113028
+ const content = readFileSync14(filePath, "utf-8");
112497
113029
  const parsed = parseYaml(content);
112498
113030
  return {
112499
113031
  name: parsed.name ?? "Unnamed Suite",
@@ -112516,18 +113048,18 @@ var init_runner = __esm({
112516
113048
  async runTest(testCase) {
112517
113049
  const startTime4 = Date.now();
112518
113050
  try {
112519
- const tempDir = join13(tmpdir3(), `nestor-test-${randomUUID27()}`);
112520
- mkdirSync4(tempDir, { recursive: true });
113051
+ const tempDir = join14(tmpdir3(), `nestor-test-${randomUUID27()}`);
113052
+ mkdirSync5(tempDir, { recursive: true });
112521
113053
  if (testCase.files) {
112522
113054
  for (const [path30, content] of Object.entries(testCase.files)) {
112523
- const fullPath = join13(tempDir, path30);
112524
- mkdirSync4(join13(fullPath, ".."), { recursive: true });
112525
- writeFileSync6(fullPath, content, "utf-8");
113055
+ const fullPath = join14(tempDir, path30);
113056
+ mkdirSync5(join14(fullPath, ".."), { recursive: true });
113057
+ writeFileSync7(fullPath, content, "utf-8");
112526
113058
  }
112527
113059
  }
112528
113060
  let responses;
112529
- if (testCase.recordings && existsSync8(testCase.recordings)) {
112530
- responses = JSON.parse(readFileSync13(testCase.recordings, "utf-8"));
113061
+ if (testCase.recordings && existsSync9(testCase.recordings)) {
113062
+ responses = JSON.parse(readFileSync14(testCase.recordings, "utf-8"));
112531
113063
  } else {
112532
113064
  responses = [{
112533
113065
  content: "Test completed successfully.",
@@ -115301,11 +115833,11 @@ var init_safety = __esm({
115301
115833
 
115302
115834
  // ../agent/src/mission/tool-factory.ts
115303
115835
  import { randomUUID as randomUUID33 } from "node:crypto";
115304
- import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync5, existsSync as existsSync10 } from "node:fs";
115836
+ import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, existsSync as existsSync11 } from "node:fs";
115305
115837
  import { homedir as homedir4 } from "node:os";
115306
- import { join as join16 } from "node:path";
115838
+ import { join as join17 } from "node:path";
115307
115839
  function getDefaultToolsDir() {
115308
- return join16(homedir4(), ".nestor", "tools");
115840
+ return join17(homedir4(), ".nestor", "tools");
115309
115841
  }
115310
115842
  function createDefaultToolFactory(adapter, toolsDir) {
115311
115843
  return new ToolFactory(adapter, toolsDir ?? getDefaultToolsDir());
@@ -115318,7 +115850,7 @@ var init_tool_factory = __esm({
115318
115850
  constructor(adapter, toolsDir) {
115319
115851
  this.adapter = adapter;
115320
115852
  this.toolsDir = toolsDir;
115321
- if (!existsSync10(toolsDir)) mkdirSync5(toolsDir, { recursive: true });
115853
+ if (!existsSync11(toolsDir)) mkdirSync6(toolsDir, { recursive: true });
115322
115854
  }
115323
115855
  /**
115324
115856
  * Generate a new tool from a natural language description.
@@ -115495,13 +116027,13 @@ Fix the tool code so it passes its test. Respond ONLY with valid JSON:
115495
116027
  * Save tool to disk: source, compiled JS, test, and manifest.
115496
116028
  */
115497
116029
  saveTool(tool) {
115498
- const toolDir = join16(this.toolsDir, tool.name);
115499
- if (!existsSync10(toolDir)) mkdirSync5(toolDir, { recursive: true });
115500
- writeFileSync7(join16(toolDir, "tool.ts"), tool.code);
115501
- writeFileSync7(join16(toolDir, "tool.js"), tool.compiledCode);
115502
- writeFileSync7(join16(toolDir, "test.js"), tool.testCode);
115503
- writeFileSync7(
115504
- join16(toolDir, "manifest.json"),
116030
+ const toolDir = join17(this.toolsDir, tool.name);
116031
+ if (!existsSync11(toolDir)) mkdirSync6(toolDir, { recursive: true });
116032
+ writeFileSync8(join17(toolDir, "tool.ts"), tool.code);
116033
+ writeFileSync8(join17(toolDir, "tool.js"), tool.compiledCode);
116034
+ writeFileSync8(join17(toolDir, "test.js"), tool.testCode);
116035
+ writeFileSync8(
116036
+ join17(toolDir, "manifest.json"),
115505
116037
  JSON.stringify(
115506
116038
  {
115507
116039
  id: tool.id,
@@ -116076,13 +116608,172 @@ Analyze and return the JSON structure described in the system prompt.`;
116076
116608
  }
116077
116609
  });
116078
116610
 
116611
+ // ../agent/src/mission/capability-research.ts
116612
+ var capability_research_exports = {};
116613
+ __export(capability_research_exports, {
116614
+ CapabilityResearchEngine: () => CapabilityResearchEngine
116615
+ });
116616
+ var CapabilityResearchEngine;
116617
+ var init_capability_research = __esm({
116618
+ "../agent/src/mission/capability-research.ts"() {
116619
+ "use strict";
116620
+ CapabilityResearchEngine = class {
116621
+ constructor(adapter, orchestratorStore) {
116622
+ this.adapter = adapter;
116623
+ this.orchestratorStore = orchestratorStore;
116624
+ }
116625
+ cache = /* @__PURE__ */ new Map();
116626
+ /**
116627
+ * Research capabilities for a mission type.
116628
+ * Returns cached results if still valid, otherwise does fresh research.
116629
+ */
116630
+ async research(type, objective) {
116631
+ const cached = this.cache.get(type);
116632
+ if (cached && Date.now() - cached.timestamp < cached.ttlMs) {
116633
+ return cached;
116634
+ }
116635
+ if (this.orchestratorStore) {
116636
+ const orch = this.orchestratorStore.get(type);
116637
+ if (orch.toolRecommendations.length > 0 && orch.missionCount > 3) {
116638
+ const fromOrch = {
116639
+ domain: type,
116640
+ recommendedTools: orch.toolRecommendations.map((t) => ({
116641
+ name: t,
116642
+ description: "",
116643
+ source: "builtin",
116644
+ priority: "recommended"
116645
+ })),
116646
+ methodologies: [],
116647
+ pitfalls: orch.knowledgeBase.failedPatterns.map(
116648
+ (p8) => `Previously failed pattern: ${p8.subObjectiveNames.join(" \u2192 ")} (used ${p8.usageCount} time${p8.usageCount > 1 ? "s" : ""}, score: ${p8.score.toFixed(2)})`
116649
+ ),
116650
+ resources: [],
116651
+ timestamp: Date.now(),
116652
+ ttlMs: 7 * 24 * 60 * 60 * 1e3
116653
+ };
116654
+ this.cache.set(type, fromOrch);
116655
+ return fromOrch;
116656
+ }
116657
+ }
116658
+ const result = await this.doResearch(type, objective);
116659
+ this.cache.set(type, result);
116660
+ return result;
116661
+ }
116662
+ async doResearch(type, objective) {
116663
+ const domainHints = this.getDomainHints(type);
116664
+ const prompt = `You are a capability researcher for an AI agent platform.
116665
+ Given a mission type and objective, recommend the best tools, methodologies, and resources.
116666
+
116667
+ Mission type: ${type}
116668
+ Objective: ${objective}
116669
+
116670
+ Based on your knowledge of ${type} best practices, respond with JSON:
116671
+ {
116672
+ "recommendedTools": [
116673
+ { "name": "tool_name", "description": "what it does", "source": "builtin|npm|github|api", "url": "optional", "priority": "essential|recommended|optional" }
116674
+ ],
116675
+ "methodologies": [
116676
+ { "name": "method name", "description": "brief description", "steps": ["step1", "step2"] }
116677
+ ],
116678
+ "pitfalls": ["common mistake 1", "common mistake 2"],
116679
+ "resources": [
116680
+ { "title": "resource title", "url": "https://...", "type": "article|repo|docs|tutorial" }
116681
+ ]
116682
+ }
116683
+
116684
+ ${domainHints}
116685
+
116686
+ Focus on tools that work locally (no cloud-only services) and can be used by an AI agent.
116687
+ Respond ONLY with JSON.`;
116688
+ try {
116689
+ const response = await this.adapter.chat([
116690
+ {
116691
+ role: "system",
116692
+ content: "You are a capability researcher. Respond only with JSON."
116693
+ },
116694
+ { role: "user", content: prompt }
116695
+ ]);
116696
+ let jsonStr = response.content;
116697
+ const codeBlockMatch = jsonStr.match(/```(?:json)?\s*([\s\S]*?)```/);
116698
+ if (codeBlockMatch) jsonStr = codeBlockMatch[1].trim();
116699
+ const match = jsonStr.match(/\{[\s\S]*\}/);
116700
+ if (match) jsonStr = match[0];
116701
+ const parsed = JSON.parse(jsonStr);
116702
+ return {
116703
+ domain: type,
116704
+ recommendedTools: Array.isArray(parsed.recommendedTools) ? parsed.recommendedTools : [],
116705
+ methodologies: Array.isArray(parsed.methodologies) ? parsed.methodologies : [],
116706
+ pitfalls: Array.isArray(parsed.pitfalls) ? parsed.pitfalls : [],
116707
+ resources: Array.isArray(parsed.resources) ? parsed.resources : [],
116708
+ timestamp: Date.now(),
116709
+ ttlMs: 7 * 24 * 60 * 60 * 1e3
116710
+ // 7 days
116711
+ };
116712
+ } catch {
116713
+ return {
116714
+ domain: type,
116715
+ recommendedTools: [],
116716
+ methodologies: [],
116717
+ pitfalls: [],
116718
+ resources: [],
116719
+ timestamp: Date.now(),
116720
+ ttlMs: 24 * 60 * 60 * 1e3
116721
+ // retry after 1 day on failure
116722
+ };
116723
+ }
116724
+ }
116725
+ /**
116726
+ * Inject research results into the mission planning context.
116727
+ * Returns a context block to prepend to the decomposition prompt.
116728
+ */
116729
+ toContextBlock(result) {
116730
+ if (result.recommendedTools.length === 0 && result.methodologies.length === 0) {
116731
+ return "";
116732
+ }
116733
+ const sections = ["CAPABILITY RESEARCH (pre-mission analysis):"];
116734
+ if (result.recommendedTools.length > 0) {
116735
+ sections.push("Recommended tools:");
116736
+ for (const t of result.recommendedTools.slice(0, 8)) {
116737
+ sections.push(` - ${t.name} (${t.priority}): ${t.description}`);
116738
+ }
116739
+ }
116740
+ if (result.methodologies.length > 0) {
116741
+ sections.push("Recommended methodology:");
116742
+ const best = result.methodologies[0];
116743
+ sections.push(` ${best.name}: ${best.steps.join(" \u2192 ")}`);
116744
+ }
116745
+ if (result.pitfalls.length > 0) {
116746
+ sections.push("Known pitfalls to avoid:");
116747
+ for (const p8 of result.pitfalls.slice(0, 5)) {
116748
+ sections.push(` - ${p8}`);
116749
+ }
116750
+ }
116751
+ return sections.join("\n");
116752
+ }
116753
+ // ─── Private Helpers ────────────────────────────────────────────────
116754
+ getDomainHints(type) {
116755
+ const hints = {
116756
+ osint: "For osint missions, consider: OSINT tools like Maltego alternatives, Wayback Machine, WHOIS, social media scrapers, SIRENE, public records databases",
116757
+ research: "For research missions, consider: Google Scholar, arxiv, Semantic Scholar, news aggregators, RSS feeds, citation graphs",
116758
+ code: "For code missions, consider: linters, formatters, test frameworks, build tools, CI/CD, static analysis",
116759
+ audit: "For audit missions, consider: static analyzers, dependency checkers, fuzzing tools, CVE databases, SAST/DAST",
116760
+ creation: "For creation missions, consider: writing assistants, image generators, template engines, CMS tools, Markdown processors",
116761
+ analysis: "For analysis missions, consider: data processing libraries, visualization tools, statistical frameworks, ML frameworks",
116762
+ custom: "Consider what specialized tools and methods would best serve this specific objective."
116763
+ };
116764
+ return hints[type] || hints.custom;
116765
+ }
116766
+ };
116767
+ }
116768
+ });
116769
+
116079
116770
  // ../agent/src/mission/orchestrator-store.ts
116080
116771
  var orchestrator_store_exports = {};
116081
116772
  __export(orchestrator_store_exports, {
116082
116773
  OrchestratorStore: () => OrchestratorStore
116083
116774
  });
116084
- import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
116085
- import { join as join17 } from "node:path";
116775
+ import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
116776
+ import { join as join18 } from "node:path";
116086
116777
  import { homedir as homedir5 } from "node:os";
116087
116778
  function arraysEqual(a, b) {
116088
116779
  if (a.length !== b.length) return false;
@@ -116092,11 +116783,11 @@ var ORCHESTRATORS_DIR, OrchestratorStore;
116092
116783
  var init_orchestrator_store = __esm({
116093
116784
  "../agent/src/mission/orchestrator-store.ts"() {
116094
116785
  "use strict";
116095
- ORCHESTRATORS_DIR = join17(homedir5(), ".nestor", "orchestrators");
116786
+ ORCHESTRATORS_DIR = join18(homedir5(), ".nestor", "orchestrators");
116096
116787
  OrchestratorStore = class {
116097
116788
  constructor(baseDir = ORCHESTRATORS_DIR) {
116098
116789
  this.baseDir = baseDir;
116099
- if (!existsSync11(baseDir)) mkdirSync6(baseDir, { recursive: true });
116790
+ if (!existsSync12(baseDir)) mkdirSync7(baseDir, { recursive: true });
116100
116791
  }
116101
116792
  cache = /* @__PURE__ */ new Map();
116102
116793
  /**
@@ -116106,9 +116797,9 @@ var init_orchestrator_store = __esm({
116106
116797
  get(type) {
116107
116798
  if (this.cache.has(type)) return this.cache.get(type);
116108
116799
  const filePath = this.filePath(type);
116109
- if (existsSync11(filePath)) {
116800
+ if (existsSync12(filePath)) {
116110
116801
  try {
116111
- const data = JSON.parse(readFileSync15(filePath, "utf-8"));
116802
+ const data = JSON.parse(readFileSync16(filePath, "utf-8"));
116112
116803
  this.cache.set(type, data);
116113
116804
  return data;
116114
116805
  } catch {
@@ -116206,7 +116897,7 @@ var init_orchestrator_store = __esm({
116206
116897
  ];
116207
116898
  return types.map((type) => {
116208
116899
  const filePath = this.filePath(type);
116209
- if (!existsSync11(filePath)) return null;
116900
+ if (!existsSync12(filePath)) return null;
116210
116901
  const orch = this.get(type);
116211
116902
  return {
116212
116903
  type: orch.type,
@@ -116243,12 +116934,12 @@ var init_orchestrator_store = __esm({
116243
116934
  }
116244
116935
  // ─── Private ──────────────────────────────────────────────────────────
116245
116936
  filePath(type) {
116246
- return join17(this.baseDir, type, "orchestrator.json");
116937
+ return join18(this.baseDir, type, "orchestrator.json");
116247
116938
  }
116248
116939
  save(orch) {
116249
- const dir = join17(this.baseDir, orch.type);
116250
- if (!existsSync11(dir)) mkdirSync6(dir, { recursive: true });
116251
- writeFileSync8(this.filePath(orch.type), JSON.stringify(orch, null, 2));
116940
+ const dir = join18(this.baseDir, orch.type);
116941
+ if (!existsSync12(dir)) mkdirSync7(dir, { recursive: true });
116942
+ writeFileSync9(this.filePath(orch.type), JSON.stringify(orch, null, 2));
116252
116943
  this.cache.set(orch.type, orch);
116253
116944
  }
116254
116945
  createDefault(type) {
@@ -116463,8 +117154,19 @@ var init_controller = __esm({
116463
117154
  async plan(input, options) {
116464
117155
  const tenantId = options?.tenantId ?? "default";
116465
117156
  const type = this.detectMissionType(input);
117157
+ let capabilityContext = "";
117158
+ try {
117159
+ const { CapabilityResearchEngine: CapabilityResearchEngine2 } = await Promise.resolve().then(() => (init_capability_research(), capability_research_exports));
117160
+ const researcher = new CapabilityResearchEngine2(
117161
+ this.agentFactory.getDefaultAdapter()
117162
+ // orchestratorStore could be wired here if available on the controller
117163
+ );
117164
+ const research = await researcher.research(type, input);
117165
+ capabilityContext = researcher.toContextBlock(research);
117166
+ } catch {
117167
+ }
116466
117168
  const similar = await this.inventory.findSimilarMissions(input);
116467
- const decomposition = await this.decompose(input, type, similar);
117169
+ const decomposition = await this.decompose(input, type, similar, capabilityContext);
116468
117170
  const defaultMaxIterations = (() => {
116469
117171
  switch (type) {
116470
117172
  case "osint":
@@ -116832,7 +117534,7 @@ Report generation failed. Mission completed with ${mission.findings.length} find
116832
117534
  return "custom";
116833
117535
  }
116834
117536
  // ─── Decompose ─────────────────────────────────────────────────────
116835
- async decompose(input, type, similar) {
117537
+ async decompose(input, type, similar, capabilityContext) {
116836
117538
  const methodGuide = {
116837
117539
  osint: `For OSINT missions, structure sub-objectives by METHOD, not by category:
116838
117540
  1. Entity disambiguation \u2014 multi-engine search to find the correct subject among homonyms
@@ -116895,7 +117597,8 @@ ${methodGuide[type] || methodGuide.custom}
116895
117597
  ${similar.length > 0 ? `Similar past missions found (learn from their structure):
116896
117598
  ${similar.map((m) => `- ${m.title} (${m.subObjectives.length} sub-objectives, score: ${m.evaluation?.overall ?? "N/A"})`).join("\n")}` : "No similar past missions found."}
116897
117599
 
116898
- The "type" field of each sub-objective should be one of:
117600
+ ${capabilityContext ? `${capabilityContext}
117601
+ ` : ""}The "type" field of each sub-objective should be one of:
116899
117602
  search \u2014 broad web search with multiple engines
116900
117603
  scrape \u2014 detailed scrape of specific page(s)
116901
117604
  analyze \u2014 analysis of data already collected (no external fetch)
@@ -117710,8 +118413,8 @@ var init_inventory = __esm({
117710
118413
  });
117711
118414
 
117712
118415
  // ../agent/src/mission/mcp-factory.ts
117713
- import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync7, existsSync as existsSync12 } from "node:fs";
117714
- import { join as join18 } from "node:path";
118416
+ import { writeFileSync as writeFileSync10, mkdirSync as mkdirSync8, existsSync as existsSync13 } from "node:fs";
118417
+ import { join as join19 } from "node:path";
117715
118418
  var McpFactory;
117716
118419
  var init_mcp_factory = __esm({
117717
118420
  "../agent/src/mission/mcp-factory.ts"() {
@@ -117719,7 +118422,7 @@ var init_mcp_factory = __esm({
117719
118422
  McpFactory = class {
117720
118423
  constructor(mcpDir) {
117721
118424
  this.mcpDir = mcpDir;
117722
- if (!existsSync12(mcpDir)) mkdirSync7(mcpDir, { recursive: true });
118425
+ if (!existsSync13(mcpDir)) mkdirSync8(mcpDir, { recursive: true });
117723
118426
  }
117724
118427
  /**
117725
118428
  * Generate an MCP server that exposes one or more custom tools.
@@ -117727,13 +118430,13 @@ var init_mcp_factory = __esm({
117727
118430
  */
117728
118431
  generate(tools, serverName) {
117729
118432
  const safeName = this.sanitizeName(serverName);
117730
- const serverDir = join18(this.mcpDir, safeName);
117731
- if (!existsSync12(serverDir)) mkdirSync7(serverDir, { recursive: true });
118433
+ const serverDir = join19(this.mcpDir, safeName);
118434
+ if (!existsSync13(serverDir)) mkdirSync8(serverDir, { recursive: true });
117732
118435
  const serverCode = this.generateServerCode(tools, safeName);
117733
- const entrypoint = join18(serverDir, "server.mjs");
117734
- writeFileSync9(entrypoint, serverCode);
117735
- writeFileSync9(
117736
- join18(serverDir, "package.json"),
118436
+ const entrypoint = join19(serverDir, "server.mjs");
118437
+ writeFileSync10(entrypoint, serverCode);
118438
+ writeFileSync10(
118439
+ join19(serverDir, "package.json"),
117737
118440
  JSON.stringify(
117738
118441
  {
117739
118442
  name: `@nestor/mcp-${safeName}`,
@@ -117747,11 +118450,11 @@ var init_mcp_factory = __esm({
117747
118450
  2
117748
118451
  )
117749
118452
  );
117750
- writeFileSync9(join18(serverDir, "Dockerfile"), this.generateDockerfile(safeName));
117751
- writeFileSync9(join18(serverDir, "README.md"), this.generateReadme(tools, safeName));
118453
+ writeFileSync10(join19(serverDir, "Dockerfile"), this.generateDockerfile(safeName));
118454
+ writeFileSync10(join19(serverDir, "README.md"), this.generateReadme(tools, safeName));
117752
118455
  for (const tool of tools) {
117753
118456
  const toolModuleCode = this.wrapToolAsModule(tool);
117754
- writeFileSync9(join18(serverDir, `${tool.name}.js`), toolModuleCode);
118457
+ writeFileSync10(join19(serverDir, `${tool.name}.js`), toolModuleCode);
117755
118458
  }
117756
118459
  return {
117757
118460
  id: safeName,
@@ -117985,8 +118688,8 @@ npx nestor-sh mcp add ${serverName} --command "node ${serverName}/server.mjs"
117985
118688
  // ../agent/src/mission/docker-deployer.ts
117986
118689
  import { execFile as execFile7 } from "node:child_process";
117987
118690
  import { promisify as promisify5 } from "node:util";
117988
- import { existsSync as existsSync13 } from "node:fs";
117989
- import { join as join19 } from "node:path";
118691
+ import { existsSync as existsSync14 } from "node:fs";
118692
+ import { join as join20 } from "node:path";
117990
118693
  var execFileAsync4, DockerDeployer;
117991
118694
  var init_docker_deployer = __esm({
117992
118695
  "../agent/src/mission/docker-deployer.ts"() {
@@ -118023,9 +118726,9 @@ var init_docker_deployer = __esm({
118023
118726
  * Returns the image name (tag).
118024
118727
  */
118025
118728
  async build(server) {
118026
- const serverDir = join19(server.entrypoint, "..");
118729
+ const serverDir = join20(server.entrypoint, "..");
118027
118730
  const imageName = `nestor-mcp-${server.name}:latest`;
118028
- if (!existsSync13(join19(serverDir, "Dockerfile"))) {
118731
+ if (!existsSync14(join20(serverDir, "Dockerfile"))) {
118029
118732
  throw new Error(`No Dockerfile found in ${serverDir}`);
118030
118733
  }
118031
118734
  const container = {
@@ -118248,6 +118951,7 @@ var init_mission = __esm({
118248
118951
  init_mcp_factory();
118249
118952
  init_docker_deployer();
118250
118953
  init_orchestrator_store();
118954
+ init_capability_research();
118251
118955
  }
118252
118956
  });
118253
118957
 
@@ -118498,6 +119202,15 @@ var init_intent = __esm({
118498
119202
  }
118499
119203
  });
118500
119204
 
119205
+ // ../agent/src/integrations/index.ts
119206
+ var init_integrations = __esm({
119207
+ "../agent/src/integrations/index.ts"() {
119208
+ "use strict";
119209
+ init_obsidian();
119210
+ init_n8n();
119211
+ }
119212
+ });
119213
+
118501
119214
  // ../agent/src/index.ts
118502
119215
  var src_exports3 = {};
118503
119216
  __export(src_exports3, {
@@ -118512,6 +119225,7 @@ __export(src_exports3, {
118512
119225
  AutoDowngradeAdapter: () => AutoDowngradeAdapter,
118513
119226
  AutoDowngradeMonitor: () => AutoDowngradeMonitor,
118514
119227
  BrowserManager: () => BrowserManager,
119228
+ CapabilityResearchEngine: () => CapabilityResearchEngine,
118515
119229
  CircuitBreaker: () => CircuitBreaker,
118516
119230
  ClaudeAdapter: () => ClaudeAdapter,
118517
119231
  CodeChunker: () => CodeChunker,
@@ -118547,6 +119261,8 @@ __export(src_exports3, {
118547
119261
  MistralAdapter: () => MistralAdapter,
118548
119262
  MockLlmAdapter: () => MockLlmAdapter,
118549
119263
  ModelRouter: () => ModelRouter,
119264
+ N8nIntegration: () => N8nIntegration,
119265
+ ObsidianIntegration: () => ObsidianIntegration,
118550
119266
  OllamaAdapter: () => OllamaAdapter,
118551
119267
  OllamaEmbeddingProvider: () => OllamaEmbeddingProvider,
118552
119268
  OllamaEmbeddings: () => OllamaEmbeddings,
@@ -118702,6 +119418,7 @@ var init_src5 = __esm({
118702
119418
  init_mission();
118703
119419
  init_meta_tool_factory();
118704
119420
  init_intent();
119421
+ init_integrations();
118705
119422
  }
118706
119423
  });
118707
119424
 
@@ -119971,8 +120688,8 @@ var init_experiments = __esm({
119971
120688
 
119972
120689
  // ../server/src/services/telemetry-anon.ts
119973
120690
  import { randomUUID as randomUUID38 } from "node:crypto";
119974
- import { existsSync as existsSync14, readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync8 } from "node:fs";
119975
- import { join as join20 } from "node:path";
120691
+ import { existsSync as existsSync15, readFileSync as readFileSync17, writeFileSync as writeFileSync11, mkdirSync as mkdirSync9 } from "node:fs";
120692
+ import { join as join21 } from "node:path";
119976
120693
  import { homedir as homedir6 } from "node:os";
119977
120694
  function getAnonTelemetry(config2) {
119978
120695
  if (!_anonInstance) {
@@ -119988,8 +120705,8 @@ var init_telemetry_anon = __esm({
119988
120705
  "../server/src/services/telemetry-anon.ts"() {
119989
120706
  "use strict";
119990
120707
  NESTOR_VERSION = "0.4.1";
119991
- DATA_DIR2 = join20(homedir6(), ".nestor");
119992
- ANON_ID_FILE = join20(DATA_DIR2, "anon-telemetry-id");
120708
+ DATA_DIR2 = join21(homedir6(), ".nestor");
120709
+ ANON_ID_FILE = join21(DATA_DIR2, "anon-telemetry-id");
119993
120710
  DEFAULT_ENDPOINT = "https://telemetry.nestor.sh/v1/events";
119994
120711
  FLUSH_BATCH_SIZE = 25;
119995
120712
  AnonTelemetryService = class {
@@ -120093,18 +120810,18 @@ var init_telemetry_anon = __esm({
120093
120810
  // ─── Private ──────────────────────────────────────────────────────────
120094
120811
  getOrCreateInstallId() {
120095
120812
  try {
120096
- if (existsSync14(ANON_ID_FILE)) {
120097
- const id = readFileSync16(ANON_ID_FILE, "utf-8").trim();
120813
+ if (existsSync15(ANON_ID_FILE)) {
120814
+ const id = readFileSync17(ANON_ID_FILE, "utf-8").trim();
120098
120815
  if (id.length > 0) return id;
120099
120816
  }
120100
120817
  } catch {
120101
120818
  }
120102
120819
  const newId = randomUUID38();
120103
120820
  try {
120104
- if (!existsSync14(DATA_DIR2)) {
120105
- mkdirSync8(DATA_DIR2, { recursive: true });
120821
+ if (!existsSync15(DATA_DIR2)) {
120822
+ mkdirSync9(DATA_DIR2, { recursive: true });
120106
120823
  }
120107
- writeFileSync10(ANON_ID_FILE, newId + "\n", "utf-8");
120824
+ writeFileSync11(ANON_ID_FILE, newId + "\n", "utf-8");
120108
120825
  } catch {
120109
120826
  }
120110
120827
  return newId;
@@ -150434,7 +151151,7 @@ var init_admin2 = __esm({
150434
151151
  "../server/src/routes/admin.ts"() {
150435
151152
  "use strict";
150436
151153
  init_rate_limit();
150437
- SERVER_VERSION3 = "2.9.0";
151154
+ SERVER_VERSION3 = "3.0.0";
150438
151155
  startTime3 = Date.now();
150439
151156
  }
150440
151157
  });
@@ -152122,19 +152839,19 @@ var init_providers = __esm({
152122
152839
 
152123
152840
  // ../server/src/services/key-vault.ts
152124
152841
  import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes7, scryptSync as scryptSync2 } from "node:crypto";
152125
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, existsSync as existsSync15, mkdirSync as mkdirSync9 } from "node:fs";
152126
- import { join as join21, dirname as dirname8 } from "node:path";
152842
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync16, mkdirSync as mkdirSync10 } from "node:fs";
152843
+ import { join as join22, dirname as dirname8 } from "node:path";
152127
152844
  import { homedir as homedir7 } from "node:os";
152128
152845
  function getVaultKey() {
152129
- if (!existsSync15(KEY_FILE)) {
152846
+ if (!existsSync16(KEY_FILE)) {
152130
152847
  const dir = dirname8(KEY_FILE);
152131
- if (!existsSync15(dir)) {
152132
- mkdirSync9(dir, { recursive: true });
152848
+ if (!existsSync16(dir)) {
152849
+ mkdirSync10(dir, { recursive: true });
152133
152850
  }
152134
152851
  const masterSecret = randomBytes7(32).toString("hex");
152135
- writeFileSync11(KEY_FILE, masterSecret, { mode: 384 });
152852
+ writeFileSync12(KEY_FILE, masterSecret, { mode: 384 });
152136
152853
  }
152137
- const secret = readFileSync17(KEY_FILE, "utf-8").trim();
152854
+ const secret = readFileSync18(KEY_FILE, "utf-8").trim();
152138
152855
  return scryptSync2(secret, "nestor-vault-salt", 32);
152139
152856
  }
152140
152857
  function encryptApiKey(plainKey) {
@@ -152186,7 +152903,7 @@ var init_key_vault = __esm({
152186
152903
  "../server/src/services/key-vault.ts"() {
152187
152904
  "use strict";
152188
152905
  ALGORITHM2 = "aes-256-gcm";
152189
- KEY_FILE = join21(homedir7(), ".nestor", ".vault-key");
152906
+ KEY_FILE = join22(homedir7(), ".nestor", ".vault-key");
152190
152907
  PROVIDER_ENV_MAP = {
152191
152908
  claude: "ANTHROPIC_API_KEY",
152192
152909
  openai: "OPENAI_API_KEY",
@@ -153171,8 +153888,8 @@ var init_seed_defaults = __esm({
153171
153888
 
153172
153889
  // ../server/src/app.ts
153173
153890
  import express from "express";
153174
- import { resolve as resolve13, join as join22 } from "node:path";
153175
- import { existsSync as existsSync16 } from "node:fs";
153891
+ import { resolve as resolve13, join as join23 } from "node:path";
153892
+ import { existsSync as existsSync17 } from "node:fs";
153176
153893
  import compression from "compression";
153177
153894
  import cors from "cors";
153178
153895
  function getStudioState() {
@@ -153502,7 +154219,7 @@ function createApp(config2) {
153502
154219
  }
153503
154220
  for (const dir of candidateDirs) {
153504
154221
  try {
153505
- if (existsSync16(join22(dir, "index.html"))) {
154222
+ if (existsSync17(join23(dir, "index.html"))) {
153506
154223
  studioDistDir = dir;
153507
154224
  break;
153508
154225
  }
@@ -153526,7 +154243,7 @@ function createApp(config2) {
153526
154243
  if (!studioState.enabled) {
153527
154244
  return res.status(403).json({ error: { code: "STUDIO_DISABLED", message: "Studio is disabled." } });
153528
154245
  }
153529
- res.sendFile(join22(studioDistDir, "index.html"));
154246
+ res.sendFile(join23(studioDistDir, "index.html"));
153530
154247
  });
153531
154248
  app.use("/studio", express.static(studioDistDir, { index: false }));
153532
154249
  app.use(express.static(studioDistDir, { index: false }));
@@ -153534,7 +154251,7 @@ function createApp(config2) {
153534
154251
  if (!studioState.enabled) {
153535
154252
  return res.status(403).json({ error: { code: "STUDIO_DISABLED", message: "Studio is disabled." } });
153536
154253
  }
153537
- res.sendFile(join22(studioDistDir, "index.html"));
154254
+ res.sendFile(join23(studioDistDir, "index.html"));
153538
154255
  });
153539
154256
  } else {
153540
154257
  app.get("/studio", (_req, res) => {
@@ -153562,7 +154279,7 @@ function createApp(config2) {
153562
154279
  if (!studioState.enabled) {
153563
154280
  return res.status(403).json({ error: { code: "STUDIO_DISABLED", message: "Studio is disabled." } });
153564
154281
  }
153565
- res.sendFile(join22(studioDistDir, "index.html"));
154282
+ res.sendFile(join23(studioDistDir, "index.html"));
153566
154283
  });
153567
154284
  }
153568
154285
  app.use(errorHandler());
@@ -153641,7 +154358,7 @@ var init_app = __esm({
153641
154358
  });
153642
154359
 
153643
154360
  // ../server/src/services/config-watcher.ts
153644
- import { watch, existsSync as existsSync17 } from "node:fs";
154361
+ import { watch, existsSync as existsSync18 } from "node:fs";
153645
154362
  import { readFile as readFile2 } from "node:fs/promises";
153646
154363
  var ConfigWatcher;
153647
154364
  var init_config_watcher = __esm({
@@ -153665,7 +154382,7 @@ var init_config_watcher = __esm({
153665
154382
  */
153666
154383
  async start() {
153667
154384
  await this.reload();
153668
- if (existsSync17(this.configPath)) {
154385
+ if (existsSync18(this.configPath)) {
153669
154386
  this.watcher = watch(this.configPath, { persistent: false }, (eventType) => {
153670
154387
  if (eventType === "change") {
153671
154388
  if (this.debounceTimer) clearTimeout(this.debounceTimer);
@@ -153701,7 +154418,7 @@ var init_config_watcher = __esm({
153701
154418
  // ─── Internal ───────────────────────────────────────────────────────
153702
154419
  async reload() {
153703
154420
  try {
153704
- if (!existsSync17(this.configPath)) {
154421
+ if (!existsSync18(this.configPath)) {
153705
154422
  console.warn("[config-watcher] Config file not found, keeping current config.");
153706
154423
  return;
153707
154424
  }
@@ -153745,8 +154462,8 @@ __export(telemetry_exports, {
153745
154462
  resetTelemetry: () => resetTelemetry
153746
154463
  });
153747
154464
  import { randomUUID as randomUUID42 } from "node:crypto";
153748
- import { existsSync as existsSync18, readFileSync as readFileSync18, writeFileSync as writeFileSync12, appendFileSync as appendFileSync2, mkdirSync as mkdirSync10 } from "node:fs";
153749
- import { join as join23 } from "node:path";
154465
+ import { existsSync as existsSync19, readFileSync as readFileSync19, writeFileSync as writeFileSync13, appendFileSync as appendFileSync2, mkdirSync as mkdirSync11 } from "node:fs";
154466
+ import { join as join24 } from "node:path";
153750
154467
  import { homedir as homedir8 } from "node:os";
153751
154468
  function getTelemetry(config2) {
153752
154469
  if (!_instance2) {
@@ -153761,10 +154478,10 @@ var VERSION2, DATA_DIR3, TELEMETRY_ID_FILE, TELEMETRY_LOG_FILE, DEFAULT_FLUSH_TH
153761
154478
  var init_telemetry2 = __esm({
153762
154479
  "../server/src/services/telemetry.ts"() {
153763
154480
  "use strict";
153764
- VERSION2 = "2.9.0";
153765
- DATA_DIR3 = join23(homedir8(), ".nestor");
153766
- TELEMETRY_ID_FILE = join23(DATA_DIR3, "telemetry-id");
153767
- TELEMETRY_LOG_FILE = join23(DATA_DIR3, "telemetry.jsonl");
154481
+ VERSION2 = "3.0.0";
154482
+ DATA_DIR3 = join24(homedir8(), ".nestor");
154483
+ TELEMETRY_ID_FILE = join24(DATA_DIR3, "telemetry-id");
154484
+ TELEMETRY_LOG_FILE = join24(DATA_DIR3, "telemetry.jsonl");
153768
154485
  DEFAULT_FLUSH_THRESHOLD = 10;
153769
154486
  TelemetryService = class {
153770
154487
  enabled;
@@ -153857,8 +154574,8 @@ var init_telemetry2 = __esm({
153857
154574
  // ─── Private ─────────────────────────────────────────────────────────
153858
154575
  getOrCreateInstallId() {
153859
154576
  try {
153860
- if (existsSync18(TELEMETRY_ID_FILE)) {
153861
- const id = readFileSync18(TELEMETRY_ID_FILE, "utf-8").trim();
154577
+ if (existsSync19(TELEMETRY_ID_FILE)) {
154578
+ const id = readFileSync19(TELEMETRY_ID_FILE, "utf-8").trim();
153862
154579
  if (id.length > 0) return id;
153863
154580
  }
153864
154581
  } catch {
@@ -153866,14 +154583,14 @@ var init_telemetry2 = __esm({
153866
154583
  const newId = randomUUID42();
153867
154584
  try {
153868
154585
  this.ensureDataDir();
153869
- writeFileSync12(TELEMETRY_ID_FILE, newId + "\n", "utf-8");
154586
+ writeFileSync13(TELEMETRY_ID_FILE, newId + "\n", "utf-8");
153870
154587
  } catch {
153871
154588
  }
153872
154589
  return newId;
153873
154590
  }
153874
154591
  ensureDataDir() {
153875
- if (!existsSync18(DATA_DIR3)) {
153876
- mkdirSync10(DATA_DIR3, { recursive: true });
154592
+ if (!existsSync19(DATA_DIR3)) {
154593
+ mkdirSync11(DATA_DIR3, { recursive: true });
153877
154594
  }
153878
154595
  }
153879
154596
  startFlushTimer() {
@@ -158080,7 +158797,7 @@ var init_src6 = __esm({
158080
158797
  await this._handle.listen();
158081
158798
  const authMode = config2.apiKey ? "API key" : "open (no auth)";
158082
158799
  console.log(`
158083
- Nestor Server v2.9.0`);
158800
+ Nestor Server v3.0.0`);
158084
158801
  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`);
158085
158802
  console.log(` HTTP : http://${this._host}:${this._port}`);
158086
158803
  console.log(` WS : ws://${this._host}:${this._port}/ws`);
@@ -165459,7 +166176,7 @@ var require_dist12 = __commonJS({
165459
166176
  });
165460
166177
 
165461
166178
  // ../skill-tester/src/yaml-loader.ts
165462
- import { readFileSync as readFileSync19 } from "node:fs";
166179
+ import { readFileSync as readFileSync20 } from "node:fs";
165463
166180
  function parseYamlContent(content) {
165464
166181
  try {
165465
166182
  return JSON.parse(content);
@@ -165575,7 +166292,7 @@ var init_yaml_loader = __esm({
165575
166292
  * Load a YAML test suite from a file path.
165576
166293
  */
165577
166294
  static loadFile(filePath) {
165578
- const content = readFileSync19(filePath, "utf-8");
166295
+ const content = readFileSync20(filePath, "utf-8");
165579
166296
  return _YamlTestLoader.parse(content);
165580
166297
  }
165581
166298
  /**
@@ -165654,8 +166371,8 @@ var init_yaml_loader = __esm({
165654
166371
  });
165655
166372
 
165656
166373
  // ../skill-tester/src/runner.ts
165657
- import { readFileSync as readFileSync20, readdirSync as readdirSync4, statSync as statSync5, existsSync as existsSync20, mkdirSync as mkdirSync12, rmSync as rmSync2 } from "node:fs";
165658
- import { join as join25, resolve as resolve14 } from "node:path";
166374
+ import { readFileSync as readFileSync21, readdirSync as readdirSync5, statSync as statSync6, existsSync as existsSync21, mkdirSync as mkdirSync13, rmSync as rmSync2 } from "node:fs";
166375
+ import { join as join26, resolve as resolve14 } from "node:path";
165659
166376
  import { tmpdir as tmpdir4 } from "node:os";
165660
166377
  import { randomUUID as randomUUID44 } from "node:crypto";
165661
166378
  var SequentialMockAdapter, SkillTestRunner;
@@ -165730,25 +166447,25 @@ var init_runner2 = __esm({
165730
166447
  try {
165731
166448
  const mockResponses = test.mockResponses.length > 0 ? test.mockResponses : [{ content: "Test completed." }];
165732
166449
  const adapter = new SequentialMockAdapter(mockResponses);
165733
- const tempDir = join25(tmpdir4(), `nestor-skill-test-${randomUUID44()}`);
165734
- mkdirSync12(tempDir, { recursive: true });
166450
+ const tempDir = join26(tmpdir4(), `nestor-skill-test-${randomUUID44()}`);
166451
+ mkdirSync13(tempDir, { recursive: true });
165735
166452
  try {
165736
166453
  const agentModule = await Promise.resolve().then(() => (init_src5(), src_exports3));
165737
166454
  const events = new agentModule.RuntimeEventBus();
165738
166455
  const tools = new agentModule.ToolRegistry();
165739
166456
  const toolExecutor = new agentModule.ToolExecutor();
165740
166457
  let instructions = "You are a helpful AI assistant.";
165741
- if (test.skill && existsSync20(test.skill)) {
165742
- instructions = readFileSync20(test.skill, "utf-8");
166458
+ if (test.skill && existsSync21(test.skill)) {
166459
+ instructions = readFileSync21(test.skill, "utf-8");
165743
166460
  } else if (test.skill) {
165744
166461
  const skillPaths = [
165745
- join25(process.cwd(), ".nestor", "skills", test.skill, "SKILL.md"),
165746
- join25(process.cwd(), "skills", test.skill, "SKILL.md"),
165747
- join25(process.cwd(), "skills-registry", test.skill, "SKILL.md")
166462
+ join26(process.cwd(), ".nestor", "skills", test.skill, "SKILL.md"),
166463
+ join26(process.cwd(), "skills", test.skill, "SKILL.md"),
166464
+ join26(process.cwd(), "skills-registry", test.skill, "SKILL.md")
165748
166465
  ];
165749
166466
  for (const p8 of skillPaths) {
165750
- if (existsSync20(p8)) {
165751
- instructions = readFileSync20(p8, "utf-8");
166467
+ if (existsSync21(p8)) {
166468
+ instructions = readFileSync21(p8, "utf-8");
165752
166469
  break;
165753
166470
  }
165754
166471
  }
@@ -165958,23 +166675,23 @@ var init_runner2 = __esm({
165958
166675
  discoverTestFiles(dir) {
165959
166676
  const files = [];
165960
166677
  const resolvedDir = resolve14(dir);
165961
- if (!existsSync20(resolvedDir)) return files;
165962
- const stat = statSync5(resolvedDir);
166678
+ if (!existsSync21(resolvedDir)) return files;
166679
+ const stat = statSync6(resolvedDir);
165963
166680
  if (!stat.isDirectory()) {
165964
166681
  return [resolvedDir];
165965
166682
  }
165966
166683
  function walk(current) {
165967
166684
  let entries;
165968
166685
  try {
165969
- entries = readdirSync4(current);
166686
+ entries = readdirSync5(current);
165970
166687
  } catch {
165971
166688
  return;
165972
166689
  }
165973
166690
  for (const entry of entries) {
165974
166691
  if (entry === "node_modules" || entry === ".git" || entry === "dist") continue;
165975
- const fullPath = join25(current, entry);
166692
+ const fullPath = join26(current, entry);
165976
166693
  try {
165977
- const s = statSync5(fullPath);
166694
+ const s = statSync6(fullPath);
165978
166695
  if (s.isDirectory()) {
165979
166696
  walk(fullPath);
165980
166697
  } else if (s.isFile() && entry.endsWith(".test.yaml")) {
@@ -167842,7 +168559,7 @@ var init_server = __esm({
167842
168559
  MCP_PROTOCOL_VERSION = "2024-11-05";
167843
168560
  SERVER_INFO = {
167844
168561
  name: "nestor",
167845
- version: "2.9.0"
168562
+ version: "3.0.0"
167846
168563
  };
167847
168564
  SERVER_CAPABILITIES = {
167848
168565
  tools: { listChanged: false },
@@ -168028,10 +168745,10 @@ __export(shell_exports, {
168028
168745
  registerShellCommand: () => registerShellCommand
168029
168746
  });
168030
168747
  import * as readline3 from "node:readline";
168031
- import { existsSync as existsSync21, readFileSync as readFileSync21, writeFileSync as writeFileSync14, mkdirSync as mkdirSync13, appendFileSync as appendFileSync3 } from "node:fs";
168032
- import { join as join26, resolve as resolve15, dirname as dirname10, basename as basename4 } from "node:path";
168748
+ import { existsSync as existsSync22, readFileSync as readFileSync22, writeFileSync as writeFileSync15, mkdirSync as mkdirSync14, appendFileSync as appendFileSync3 } from "node:fs";
168749
+ import { join as join27, resolve as resolve15, dirname as dirname10, basename as basename5 } from "node:path";
168033
168750
  import { homedir as homedir9 } from "node:os";
168034
- import { readdirSync as readdirSync5 } from "node:fs";
168751
+ import { readdirSync as readdirSync6 } from "node:fs";
168035
168752
  import { randomUUID as randomUUID50 } from "node:crypto";
168036
168753
  import chalk11 from "chalk";
168037
168754
  import * as p5 from "@clack/prompts";
@@ -168062,8 +168779,8 @@ async function startShell() {
168062
168779
  currentRouter: null,
168063
168780
  verbose: false
168064
168781
  };
168065
- if (!existsSync21(NESTOR_DIR)) {
168066
- mkdirSync13(NESTOR_DIR, { recursive: true });
168782
+ if (!existsSync22(NESTOR_DIR)) {
168783
+ mkdirSync14(NESTOR_DIR, { recursive: true });
168067
168784
  }
168068
168785
  refreshAgentNameCache(session);
168069
168786
  const history = loadHistory();
@@ -168286,7 +169003,7 @@ function printWelcome() {
168286
169003
  console.log(chalk11.cyan(` | .\` | | _| \\__ \\ | | | (_) | | / _ \\__ \\ | __ |`));
168287
169004
  console.log(chalk11.cyan(` |_|\\_| |___| |___/ |_| \\___/ |_|_\\ (_) |___/ |_||_|`));
168288
169005
  console.log("");
168289
- console.log(chalk11.dim(" Interactive Shell \u2014 v2.9.0"));
169006
+ console.log(chalk11.dim(" Interactive Shell \u2014 v3.0.0"));
168290
169007
  console.log(chalk11.dim(" Type /help for commands, /exit to quit."));
168291
169008
  console.log(chalk11.dim(" Multiline: end a line with \\ or use ``` code blocks."));
168292
169009
  console.log("");
@@ -168783,8 +169500,8 @@ function cmdExport(args2, session) {
168783
169500
  timestamp: new Date(e.timestamp).toISOString()
168784
169501
  }))
168785
169502
  };
168786
- const filename = join26(NESTOR_DIR, `conversation-${timestamp}.json`);
168787
- writeFileSync14(filename, JSON.stringify(data, null, 2), "utf-8");
169503
+ const filename = join27(NESTOR_DIR, `conversation-${timestamp}.json`);
169504
+ writeFileSync15(filename, JSON.stringify(data, null, 2), "utf-8");
168788
169505
  console.log(chalk11.green(`Exported to: ${filename}`));
168789
169506
  return;
168790
169507
  }
@@ -168808,8 +169525,8 @@ function cmdExport(args2, session) {
168808
169525
  lines.push(entry.content);
168809
169526
  lines.push("");
168810
169527
  }
168811
- const filename = join26(NESTOR_DIR, `conversation-${timestamp}.md`);
168812
- writeFileSync14(filename, lines.join("\n"), "utf-8");
169528
+ const filename = join27(NESTOR_DIR, `conversation-${timestamp}.md`);
169529
+ writeFileSync15(filename, lines.join("\n"), "utf-8");
168813
169530
  console.log(chalk11.green(`Exported to: ${filename}`));
168814
169531
  return;
168815
169532
  }
@@ -168845,8 +169562,8 @@ ${rows}
168845
169562
  <div class="stats">Tokens: ${fmtNum(session.totalTokensIn)} in / ${fmtNum(session.totalTokensOut)} out | Cost: $${session.totalCostUsd.toFixed(4)} | Tool calls: ${session.totalToolCalls}</div>
168846
169563
  </body>
168847
169564
  </html>`;
168848
- const filename = join26(NESTOR_DIR, `conversation-${timestamp}.html`);
168849
- writeFileSync14(filename, html, "utf-8");
169565
+ const filename = join27(NESTOR_DIR, `conversation-${timestamp}.html`);
169566
+ writeFileSync15(filename, html, "utf-8");
168850
169567
  console.log(chalk11.green(`Exported to: ${filename}`));
168851
169568
  }
168852
169569
  }
@@ -169353,7 +170070,7 @@ function createUnifiedDiff(oldText, newText, fileName) {
169353
170070
  function showDiffForStep(filePath, newContent) {
169354
170071
  try {
169355
170072
  const absolutePath = resolve15(process.cwd(), filePath);
169356
- const oldContent = readFileSync21(absolutePath, "utf-8");
170073
+ const oldContent = readFileSync22(absolutePath, "utf-8");
169357
170074
  const diff = createUnifiedDiff(oldContent, newContent, filePath);
169358
170075
  for (const line of diff.split("\n")) {
169359
170076
  if (line.startsWith("+") && !line.startsWith("+++")) {
@@ -169766,8 +170483,8 @@ function completeFilePath(partial) {
169766
170483
  dir = dirname10(resolved);
169767
170484
  prefix = partial.substring(0, Math.max(partial.lastIndexOf("/"), partial.lastIndexOf("\\")) + 1);
169768
170485
  }
169769
- const entries = readdirSync5(dir, { withFileTypes: true });
169770
- const base = basename4(partial);
170486
+ const entries = readdirSync6(dir, { withFileTypes: true });
170487
+ const base = basename5(partial);
169771
170488
  const matches = [];
169772
170489
  for (const entry of entries) {
169773
170490
  if (entry.name.startsWith(".")) continue;
@@ -169797,8 +170514,8 @@ function refreshAgentNameCache(session) {
169797
170514
  }
169798
170515
  function loadHistory() {
169799
170516
  try {
169800
- if (existsSync21(HISTORY_FILE)) {
169801
- const raw = readFileSync21(HISTORY_FILE, "utf-8");
170517
+ if (existsSync22(HISTORY_FILE)) {
170518
+ const raw = readFileSync22(HISTORY_FILE, "utf-8");
169802
170519
  return raw.split("\n").filter((l) => l.trim().length > 0).slice(-MAX_HISTORY);
169803
170520
  }
169804
170521
  } catch {
@@ -169809,8 +170526,8 @@ function saveHistory(rl) {
169809
170526
  }
169810
170527
  function appendToHistoryFile(line) {
169811
170528
  try {
169812
- if (!existsSync21(NESTOR_DIR)) {
169813
- mkdirSync13(NESTOR_DIR, { recursive: true });
170529
+ if (!existsSync22(NESTOR_DIR)) {
170530
+ mkdirSync14(NESTOR_DIR, { recursive: true });
169814
170531
  }
169815
170532
  appendFileSync3(HISTORY_FILE, line + "\n", "utf-8");
169816
170533
  } catch {
@@ -170152,8 +170869,8 @@ var init_shell = __esm({
170152
170869
  init_config2();
170153
170870
  init_spinner();
170154
170871
  init_table();
170155
- NESTOR_DIR = join26(homedir9(), ".nestor");
170156
- HISTORY_FILE = join26(NESTOR_DIR, "shell_history");
170872
+ NESTOR_DIR = join27(homedir9(), ".nestor");
170873
+ HISTORY_FILE = join27(NESTOR_DIR, "shell_history");
170157
170874
  MAX_HISTORY = 1e3;
170158
170875
  SLASH_COMMANDS = {
170159
170876
  "/help": { description: "Show all commands", usage: "/help" },
@@ -170205,8 +170922,8 @@ var init_shell = __esm({
170205
170922
 
170206
170923
  // src/index.ts
170207
170924
  import { Command } from "commander";
170208
- import { existsSync as existsSync26, readFileSync as readFileSync26 } from "node:fs";
170209
- import { join as join29 } from "node:path";
170925
+ import { existsSync as existsSync27, readFileSync as readFileSync27 } from "node:fs";
170926
+ import { join as join30 } from "node:path";
170210
170927
  import { homedir as homedir12 } from "node:os";
170211
170928
 
170212
170929
  // src/commands/start.ts
@@ -170226,7 +170943,7 @@ var BANNER = `
170226
170943
  function registerStartCommand(program2) {
170227
170944
  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) => {
170228
170945
  console.log(chalk.cyan(BANNER));
170229
- console.log(chalk.dim(` v2.9.0
170946
+ console.log(chalk.dim(` v3.0.0
170230
170947
  `));
170231
170948
  let config2 = readConfigFile();
170232
170949
  if (!config2) {
@@ -170351,8 +171068,8 @@ init_config();
170351
171068
  init_config2();
170352
171069
  import * as p from "@clack/prompts";
170353
171070
  import chalk2 from "chalk";
170354
- import { mkdirSync as mkdirSync11, existsSync as existsSync19 } from "node:fs";
170355
- import { join as join24 } from "node:path";
171071
+ import { mkdirSync as mkdirSync12, existsSync as existsSync20 } from "node:fs";
171072
+ import { join as join25 } from "node:path";
170356
171073
  import { randomBytes as randomBytes8 } from "node:crypto";
170357
171074
  function generateApiKey() {
170358
171075
  return `nst_${randomBytes8(32).toString("hex")}`;
@@ -170371,7 +171088,7 @@ function generateBetaKey() {
170371
171088
  }
170372
171089
  async function initializeDatabase(dataDir) {
170373
171090
  const { NestorStore: NestorStore2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
170374
- const dbPath = join24(dataDir, "nestor.db");
171091
+ const dbPath = join25(dataDir, "nestor.db");
170375
171092
  const store = await NestorStore2.open(dbPath);
170376
171093
  store.close();
170377
171094
  }
@@ -170419,31 +171136,31 @@ async function runNonInteractiveInstall() {
170419
171136
  console.log();
170420
171137
  const config2 = buildConfigFromDefaults();
170421
171138
  const dataDir = expandPath(config2.server.dataDir);
170422
- if (!existsSync19(dataDir)) {
170423
- mkdirSync11(dataDir, { recursive: true });
171139
+ if (!existsSync20(dataDir)) {
171140
+ mkdirSync12(dataDir, { recursive: true });
170424
171141
  console.log(chalk2.green(" Created data directory:"), dataDir);
170425
171142
  }
170426
171143
  for (const sub of ["adapters", "skills", "plugins", "logs"]) {
170427
- const subDir = join24(dataDir, sub);
170428
- if (!existsSync19(subDir)) {
170429
- mkdirSync11(subDir, { recursive: true });
171144
+ const subDir = join25(dataDir, sub);
171145
+ if (!existsSync20(subDir)) {
171146
+ mkdirSync12(subDir, { recursive: true });
170430
171147
  }
170431
171148
  }
170432
171149
  writeConfigFile(config2);
170433
171150
  console.log(chalk2.green(" Configuration saved:"), getConfigPath());
170434
171151
  try {
170435
171152
  await initializeDatabase(dataDir);
170436
- console.log(chalk2.green(" Database initialized:"), join24(dataDir, "nestor.db"));
171153
+ console.log(chalk2.green(" Database initialized:"), join25(dataDir, "nestor.db"));
170437
171154
  } catch (err) {
170438
171155
  console.log(chalk2.yellow(" Database initialization skipped (install @nestor/db first)"));
170439
171156
  }
170440
171157
  const apiKey = generateApiKey();
170441
- const apiKeyPath = join24(dataDir, ".api-keys");
170442
- const { writeFileSync: writeFileSync17 } = await import("node:fs");
170443
- writeFileSync17(apiKeyPath, JSON.stringify({ admin: apiKey }, null, 2) + "\n", "utf-8");
171158
+ const apiKeyPath = join25(dataDir, ".api-keys");
171159
+ const { writeFileSync: writeFileSync18 } = await import("node:fs");
171160
+ writeFileSync18(apiKeyPath, JSON.stringify({ admin: apiKey }, null, 2) + "\n", "utf-8");
170444
171161
  console.log(chalk2.green(" Admin API key created"));
170445
171162
  const betaKey = generateBetaKey();
170446
- writeFileSync17(join24(dataDir, "license.key"), betaKey, "utf-8");
171163
+ writeFileSync18(join25(dataDir, "license.key"), betaKey, "utf-8");
170447
171164
  console.log(chalk2.green(" Beta key created"));
170448
171165
  console.log();
170449
171166
  console.log(chalk2.bold("Admin API Key:"), chalk2.yellow(apiKey));
@@ -170539,9 +171256,9 @@ async function runInteractiveInstall() {
170539
171256
  const dataDir = expandPath(config2.server.dataDir);
170540
171257
  const spinner3 = p.spinner();
170541
171258
  spinner3.start("Creating directories...");
170542
- for (const dir of [dataDir, join24(dataDir, "adapters"), join24(dataDir, "skills"), join24(dataDir, "plugins"), join24(dataDir, "logs")]) {
170543
- if (!existsSync19(dir)) {
170544
- mkdirSync11(dir, { recursive: true });
171259
+ for (const dir of [dataDir, join25(dataDir, "adapters"), join25(dataDir, "skills"), join25(dataDir, "plugins"), join25(dataDir, "logs")]) {
171260
+ if (!existsSync20(dir)) {
171261
+ mkdirSync12(dir, { recursive: true });
170545
171262
  }
170546
171263
  }
170547
171264
  spinner3.stop("Directories created");
@@ -170566,14 +171283,14 @@ async function runInteractiveInstall() {
170566
171283
  const spinner4 = p.spinner();
170567
171284
  spinner4.start("Generating admin API key...");
170568
171285
  const apiKey = generateApiKey();
170569
- const apiKeyPath = join24(dataDir, ".api-keys");
170570
- const { writeFileSync: writeFileSync17 } = await import("node:fs");
170571
- writeFileSync17(apiKeyPath, JSON.stringify({ admin: apiKey }, null, 2) + "\n", "utf-8");
171286
+ const apiKeyPath = join25(dataDir, ".api-keys");
171287
+ const { writeFileSync: writeFileSync18 } = await import("node:fs");
171288
+ writeFileSync18(apiKeyPath, JSON.stringify({ admin: apiKey }, null, 2) + "\n", "utf-8");
170572
171289
  spinner4.stop("Admin API key created!");
170573
171290
  const spinner5 = p.spinner();
170574
171291
  spinner5.start("Generating beta key...");
170575
171292
  const betaKey = generateBetaKey();
170576
- writeFileSync17(join24(dataDir, "license.key"), betaKey, "utf-8");
171293
+ writeFileSync18(join25(dataDir, "license.key"), betaKey, "utf-8");
170577
171294
  spinner5.stop("Beta key created!");
170578
171295
  p.note(
170579
171296
  `Config file: ${getConfigPath()}
@@ -171866,23 +172583,23 @@ init_db();
171866
172583
  init_spinner();
171867
172584
  init_table();
171868
172585
  import {
171869
- existsSync as existsSync22,
171870
- readFileSync as readFileSync22,
171871
- writeFileSync as writeFileSync15,
171872
- mkdirSync as mkdirSync14,
172586
+ existsSync as existsSync23,
172587
+ readFileSync as readFileSync23,
172588
+ writeFileSync as writeFileSync16,
172589
+ mkdirSync as mkdirSync15,
171873
172590
  unlinkSync,
171874
172591
  appendFileSync as appendFileSync4
171875
172592
  } from "node:fs";
171876
- import { join as join27 } from "node:path";
172593
+ import { join as join28 } from "node:path";
171877
172594
  import { homedir as homedir10 } from "node:os";
171878
172595
  import { fork as fork2 } from "node:child_process";
171879
172596
  import "node:readline";
171880
172597
  import chalk12 from "chalk";
171881
- var NESTOR_DIR2 = join27(homedir10(), ".nestor");
171882
- var PID_FILE = join27(NESTOR_DIR2, "daemon.pid");
171883
- var LOG_DIR = join27(NESTOR_DIR2, "logs");
171884
- var LOG_FILE = join27(LOG_DIR, "daemon.log");
171885
- var HEARTBEAT_FILE = join27(NESTOR_DIR2, "daemon.heartbeat");
172598
+ var NESTOR_DIR2 = join28(homedir10(), ".nestor");
172599
+ var PID_FILE = join28(NESTOR_DIR2, "daemon.pid");
172600
+ var LOG_DIR = join28(NESTOR_DIR2, "logs");
172601
+ var LOG_FILE = join28(LOG_DIR, "daemon.log");
172602
+ var HEARTBEAT_FILE = join28(NESTOR_DIR2, "daemon.heartbeat");
171886
172603
  var HEARTBEAT_INTERVAL_MS2 = 3e4;
171887
172604
  function registerDaemonCommand(program2) {
171888
172605
  const daemon = program2.command("daemon").description("Manage the Nestor background daemon");
@@ -171918,7 +172635,7 @@ async function startForeground() {
171918
172635
  console.log(chalk12.cyan(` | .\` | | _| \\__ \\ | | | (_) | | / _ \\__ \\ | __ |`));
171919
172636
  console.log(chalk12.cyan(` |_|\\_| |___| |___/ |_| \\___/ |_|_\\ (_) |___/ |_||_|`));
171920
172637
  console.log("");
171921
- console.log(chalk12.dim(" Daemon Mode \u2014 v2.9.0"));
172638
+ console.log(chalk12.dim(" Daemon Mode \u2014 v3.0.0"));
171922
172639
  console.log(chalk12.dim(` PID: ${process.pid}`));
171923
172640
  console.log(chalk12.dim(` Log: ${LOG_FILE}`));
171924
172641
  console.log("");
@@ -172050,13 +172767,13 @@ async function showStatus() {
172050
172767
  console.log("");
172051
172768
  }
172052
172769
  async function showLogs(follow, lineCount) {
172053
- if (!existsSync22(LOG_FILE)) {
172770
+ if (!existsSync23(LOG_FILE)) {
172054
172771
  console.log(chalk12.yellow("No daemon log file found."));
172055
172772
  console.log(chalk12.dim(`Expected at: ${LOG_FILE}`));
172056
172773
  return;
172057
172774
  }
172058
172775
  if (!follow) {
172059
- const content = readFileSync22(LOG_FILE, "utf-8");
172776
+ const content = readFileSync23(LOG_FILE, "utf-8");
172060
172777
  const lines = content.split("\n").filter((l) => l.length > 0);
172061
172778
  const lastLines = lines.slice(-lineCount);
172062
172779
  if (lastLines.length === 0) {
@@ -172070,19 +172787,19 @@ async function showLogs(follow, lineCount) {
172070
172787
  }
172071
172788
  console.log(chalk12.dim(`Following ${LOG_FILE}... (Ctrl+C to stop)`));
172072
172789
  console.log("");
172073
- if (existsSync22(LOG_FILE)) {
172074
- const content = readFileSync22(LOG_FILE, "utf-8");
172790
+ if (existsSync23(LOG_FILE)) {
172791
+ const content = readFileSync23(LOG_FILE, "utf-8");
172075
172792
  const lines = content.split("\n").filter((l) => l.length > 0);
172076
172793
  const lastLines = lines.slice(-10);
172077
172794
  for (const line of lastLines) {
172078
172795
  console.log(colorizeLogLine(line));
172079
172796
  }
172080
172797
  }
172081
- let lastSize = existsSync22(LOG_FILE) ? readFileSync22(LOG_FILE).length : 0;
172798
+ let lastSize = existsSync23(LOG_FILE) ? readFileSync23(LOG_FILE).length : 0;
172082
172799
  const watcher = setInterval(() => {
172083
172800
  try {
172084
- if (!existsSync22(LOG_FILE)) return;
172085
- const content = readFileSync22(LOG_FILE, "utf-8");
172801
+ if (!existsSync23(LOG_FILE)) return;
172802
+ const content = readFileSync23(LOG_FILE, "utf-8");
172086
172803
  if (content.length > lastSize) {
172087
172804
  const newContent = content.substring(lastSize);
172088
172805
  const newLines = newContent.split("\n").filter((l) => l.length > 0);
@@ -172394,7 +173111,7 @@ var DaemonRunner = class {
172394
173111
  activeAgents: this.runningAgents.size,
172395
173112
  nextScheduledRun: void 0
172396
173113
  };
172397
- writeFileSync15(HEARTBEAT_FILE, JSON.stringify(data), "utf-8");
173114
+ writeFileSync16(HEARTBEAT_FILE, JSON.stringify(data), "utf-8");
172398
173115
  } catch {
172399
173116
  }
172400
173117
  }
@@ -172412,8 +173129,8 @@ async function importDaemonAgentModule() {
172412
173129
  }
172413
173130
  function readHeartbeat() {
172414
173131
  try {
172415
- if (existsSync22(HEARTBEAT_FILE)) {
172416
- const raw = readFileSync22(HEARTBEAT_FILE, "utf-8");
173132
+ if (existsSync23(HEARTBEAT_FILE)) {
173133
+ const raw = readFileSync23(HEARTBEAT_FILE, "utf-8");
172417
173134
  return JSON.parse(raw);
172418
173135
  }
172419
173136
  } catch {
@@ -172422,8 +173139,8 @@ function readHeartbeat() {
172422
173139
  }
172423
173140
  function readPid() {
172424
173141
  try {
172425
- if (existsSync22(PID_FILE)) {
172426
- const raw = readFileSync22(PID_FILE, "utf-8").trim();
173142
+ if (existsSync23(PID_FILE)) {
173143
+ const raw = readFileSync23(PID_FILE, "utf-8").trim();
172427
173144
  const pid = parseInt(raw, 10);
172428
173145
  return isNaN(pid) ? null : pid;
172429
173146
  }
@@ -172433,11 +173150,11 @@ function readPid() {
172433
173150
  }
172434
173151
  function writePid(pid) {
172435
173152
  ensureDirs();
172436
- writeFileSync15(PID_FILE, String(pid), "utf-8");
173153
+ writeFileSync16(PID_FILE, String(pid), "utf-8");
172437
173154
  }
172438
173155
  function cleanupPid() {
172439
173156
  try {
172440
- if (existsSync22(PID_FILE)) {
173157
+ if (existsSync23(PID_FILE)) {
172441
173158
  unlinkSync(PID_FILE);
172442
173159
  }
172443
173160
  } catch {
@@ -172477,11 +173194,11 @@ function colorizeLogLine(line) {
172477
173194
  return line;
172478
173195
  }
172479
173196
  function ensureDirs() {
172480
- if (!existsSync22(NESTOR_DIR2)) {
172481
- mkdirSync14(NESTOR_DIR2, { recursive: true });
173197
+ if (!existsSync23(NESTOR_DIR2)) {
173198
+ mkdirSync15(NESTOR_DIR2, { recursive: true });
172482
173199
  }
172483
- if (!existsSync22(LOG_DIR)) {
172484
- mkdirSync14(LOG_DIR, { recursive: true });
173200
+ if (!existsSync23(LOG_DIR)) {
173201
+ mkdirSync15(LOG_DIR, { recursive: true });
172485
173202
  }
172486
173203
  }
172487
173204
  function delay(ms) {
@@ -172522,13 +173239,13 @@ if (process.argv[2] === "__daemon_child__" || process.env.NESTOR_DAEMON_MODE ===
172522
173239
 
172523
173240
  // src/commands/watch.ts
172524
173241
  init_db();
172525
- import { existsSync as existsSync23, readFileSync as readFileSync23 } from "node:fs";
172526
- import { join as join28 } from "node:path";
173242
+ import { existsSync as existsSync24, readFileSync as readFileSync24 } from "node:fs";
173243
+ import { join as join29 } from "node:path";
172527
173244
  import { homedir as homedir11 } from "node:os";
172528
173245
  import chalk13 from "chalk";
172529
- var NESTOR_DIR3 = join28(homedir11(), ".nestor");
172530
- var HEARTBEAT_FILE2 = join28(NESTOR_DIR3, "daemon.heartbeat");
172531
- var LOG_FILE2 = join28(NESTOR_DIR3, "logs", "daemon.log");
173246
+ var NESTOR_DIR3 = join29(homedir11(), ".nestor");
173247
+ var HEARTBEAT_FILE2 = join29(NESTOR_DIR3, "daemon.heartbeat");
173248
+ var LOG_FILE2 = join29(NESTOR_DIR3, "logs", "daemon.log");
172532
173249
  var REFRESH_INTERVAL_MS = 1e3;
172533
173250
  var MAX_EVENTS = 12;
172534
173251
  function registerWatchCommand(program2) {
@@ -172596,8 +173313,8 @@ async function refreshData(state) {
172596
173313
  } catch {
172597
173314
  }
172598
173315
  try {
172599
- if (existsSync23(HEARTBEAT_FILE2)) {
172600
- const raw = readFileSync23(HEARTBEAT_FILE2, "utf-8");
173316
+ if (existsSync24(HEARTBEAT_FILE2)) {
173317
+ const raw = readFileSync24(HEARTBEAT_FILE2, "utf-8");
172601
173318
  const heartbeat = JSON.parse(raw);
172602
173319
  state.daemonRunning = isDaemonAlive(heartbeat.pid);
172603
173320
  state.daemonPid = heartbeat.pid;
@@ -172614,8 +173331,8 @@ async function refreshData(state) {
172614
173331
  }
172615
173332
  function loadRecentEvents(state) {
172616
173333
  try {
172617
- if (!existsSync23(LOG_FILE2)) return;
172618
- const content = readFileSync23(LOG_FILE2, "utf-8");
173334
+ if (!existsSync24(LOG_FILE2)) return;
173335
+ const content = readFileSync24(LOG_FILE2, "utf-8");
172619
173336
  const lines = content.split("\n").filter((l) => l.length > 0);
172620
173337
  const recent = lines.slice(-MAX_EVENTS);
172621
173338
  state.recentEvents = recent.map((line) => {
@@ -172941,10 +173658,10 @@ function registerTelemetryCommand(program2) {
172941
173658
  }
172942
173659
  console.log(` ${chalk15.dim("Flush:")} every ${(config2.telemetry?.flushIntervalMs ?? 6e4) / 1e3}s`);
172943
173660
  }
172944
- const { join: join30 } = __require("node:path");
173661
+ const { join: join31 } = __require("node:path");
172945
173662
  const { homedir: homedir13 } = __require("node:os");
172946
- const telemetryFile = join30(homedir13(), ".nestor", "telemetry.jsonl");
172947
- const idFile = join30(homedir13(), ".nestor", "telemetry-id");
173663
+ const telemetryFile = join31(homedir13(), ".nestor", "telemetry.jsonl");
173664
+ const idFile = join31(homedir13(), ".nestor", "telemetry-id");
172948
173665
  if (fs28.existsSync(idFile)) {
172949
173666
  const installId = fs28.readFileSync(idFile, "utf-8").trim();
172950
173667
  console.log(` ${chalk15.dim("Install ID:")} ${installId.slice(0, 8)}...`);
@@ -172985,7 +173702,7 @@ function setTelemetryEnabled(enabled) {
172985
173702
  init_db();
172986
173703
  init_table();
172987
173704
  import chalk16 from "chalk";
172988
- import { readFileSync as readFileSync24, writeFileSync as writeFileSync16 } from "node:fs";
173705
+ import { readFileSync as readFileSync25, writeFileSync as writeFileSync17 } from "node:fs";
172989
173706
  function registerMemoryCommand(program2) {
172990
173707
  const memory = program2.command("memory").description("Manage agent persistent memories");
172991
173708
  memory.command("list").description("List memories for an agent").option("-a, --agent <id>", "Agent ID to filter by").option("-t, --type <type>", "Memory type filter (observation, fact, instruction, reflection)").option("-l, --limit <n>", "Maximum results", "20").action(async (options) => {
@@ -173189,13 +173906,13 @@ Memory Statistics for ${agentId}`));
173189
173906
  }
173190
173907
  }
173191
173908
  const json = JSON.stringify(allMemories, null, 2);
173192
- writeFileSync16(outputFile, json, "utf-8");
173909
+ writeFileSync17(outputFile, json, "utf-8");
173193
173910
  console.log(chalk16.green(`Exported ${allMemories.length} memories to ${outputFile}`));
173194
173911
  });
173195
173912
  memory.command("import <file>").description("Import memories from JSON").action(async (file) => {
173196
173913
  const store = await getStore();
173197
173914
  try {
173198
- const raw = readFileSync24(file, "utf-8");
173915
+ const raw = readFileSync25(file, "utf-8");
173199
173916
  const entries = JSON.parse(raw);
173200
173917
  if (!Array.isArray(entries)) {
173201
173918
  console.error(chalk16.red("Invalid format: expected a JSON array of memory entries."));
@@ -173715,8 +174432,8 @@ ${results.length} results for "${query}":
173715
174432
  }
173716
174433
 
173717
174434
  // src/commands/test.ts
173718
- import { resolve as resolve17, relative as relative5 } from "node:path";
173719
- import { readdirSync as readdirSync6, statSync as statSync6, existsSync as existsSync24 } from "node:fs";
174435
+ import { resolve as resolve17, relative as relative6 } from "node:path";
174436
+ import { readdirSync as readdirSync7, statSync as statSync7, existsSync as existsSync25 } from "node:fs";
173720
174437
  import chalk20 from "chalk";
173721
174438
  var TEST_FILE_PATTERNS = [
173722
174439
  ".nestor-test.yaml",
@@ -173729,7 +174446,7 @@ function registerTestCommand(program2) {
173729
174446
  program2.command("test [path]").description("Run skill and agent test suites").option("-l, --list", "List discovered test files", false).option("-f, --file <file>", "Run a specific test file").option("-r, --record <file>", "Record LLM responses to a fixture file").option("-p, --prompt <prompt>", "Prompt for recording mode").option("-v, --verbose", "Show detailed test output", false).option("-j, --json", "Output results as JSON (for CI)", false).action(async (path30, opts) => {
173730
174447
  if (opts.file) {
173731
174448
  const filePath = resolve17(opts.file);
173732
- if (!existsSync24(filePath)) {
174449
+ if (!existsSync25(filePath)) {
173733
174450
  console.error(chalk20.red(`File not found: ${opts.file}`));
173734
174451
  process.exit(1);
173735
174452
  }
@@ -173760,7 +174477,7 @@ function registerTestCommand(program2) {
173760
174477
  ];
173761
174478
  const allFiles = [];
173762
174479
  for (const testDir of defaultTestDirs) {
173763
- if (existsSync24(testDir)) {
174480
+ if (existsSync25(testDir)) {
173764
174481
  allFiles.push(...discoverTestFiles(testDir));
173765
174482
  }
173766
174483
  }
@@ -173779,7 +174496,7 @@ function discoverTestFiles(dir) {
173779
174496
  function walk(current) {
173780
174497
  let entries;
173781
174498
  try {
173782
- entries = readdirSync6(current);
174499
+ entries = readdirSync7(current);
173783
174500
  } catch {
173784
174501
  return;
173785
174502
  }
@@ -173787,7 +174504,7 @@ function discoverTestFiles(dir) {
173787
174504
  if (entry === "node_modules" || entry === ".git" || entry === "dist") continue;
173788
174505
  const fullPath = resolve17(current, entry);
173789
174506
  try {
173790
- const stat = statSync6(fullPath);
174507
+ const stat = statSync7(fullPath);
173791
174508
  if (stat.isDirectory()) {
173792
174509
  walk(fullPath);
173793
174510
  } else if (stat.isFile()) {
@@ -173803,7 +174520,7 @@ function discoverTestFiles(dir) {
173803
174520
  }
173804
174521
  }
173805
174522
  }
173806
- if (existsSync24(dir) && !statSync6(dir).isDirectory()) {
174523
+ if (existsSync25(dir) && !statSync7(dir).isDirectory()) {
173807
174524
  return [dir];
173808
174525
  }
173809
174526
  walk(dir);
@@ -173812,7 +174529,7 @@ function discoverTestFiles(dir) {
173812
174529
  async function listTestFiles(dir) {
173813
174530
  const files = discoverTestFiles(dir);
173814
174531
  const nestorTestDir = resolve17(dir, ".nestor", "tests");
173815
- if (existsSync24(nestorTestDir)) {
174532
+ if (existsSync25(nestorTestDir)) {
173816
174533
  files.push(...discoverTestFiles(nestorTestDir));
173817
174534
  }
173818
174535
  const unique = [...new Set(files)];
@@ -173824,7 +174541,7 @@ async function listTestFiles(dir) {
173824
174541
  Discovered ${unique.length} test file(s):
173825
174542
  `));
173826
174543
  for (const file of unique) {
173827
- console.log(chalk20.dim(" ") + chalk20.cyan(relative5(dir, file)));
174544
+ console.log(chalk20.dim(" ") + chalk20.cyan(relative6(dir, file)));
173828
174545
  }
173829
174546
  console.log("");
173830
174547
  }
@@ -173868,7 +174585,7 @@ async function runSkillTestsByName(skillName, verbose, json) {
173868
174585
  ];
173869
174586
  const matchingFiles = [];
173870
174587
  for (const dir of searchDirs) {
173871
- if (!existsSync24(dir)) continue;
174588
+ if (!existsSync25(dir)) continue;
173872
174589
  const files = discoverTestFiles(dir);
173873
174590
  for (const file of files) {
173874
174591
  if (file.includes(skillName)) {
@@ -173894,7 +174611,7 @@ Running ${files.length} test suite(s) (legacy runner)...
173894
174611
  let totalFailed = 0;
173895
174612
  const startTime4 = Date.now();
173896
174613
  for (const file of files) {
173897
- const relPath = relative5(process.cwd(), file);
174614
+ const relPath = relative6(process.cwd(), file);
173898
174615
  let suite;
173899
174616
  try {
173900
174617
  suite = agentModule.AgentTestRunner.loadSuite(file);
@@ -174069,7 +174786,7 @@ init_db();
174069
174786
  init_config2();
174070
174787
  import chalk22 from "chalk";
174071
174788
  import { randomUUID as randomUUID51 } from "node:crypto";
174072
- import { readFileSync as readFileSync25, existsSync as existsSync25 } from "node:fs";
174789
+ import { readFileSync as readFileSync26, existsSync as existsSync26 } from "node:fs";
174073
174790
  import { execSync as execSync3 } from "node:child_process";
174074
174791
  function runShellCommand(cmd, cwd) {
174075
174792
  try {
@@ -174140,11 +174857,11 @@ function registerLoopCommand(program2) {
174140
174857
  program2.command("loop").description("Run an agent in a fresh-context loop until a specification is met (Ralph pattern)").option("--agent <name>", "Agent name to use", "default").option("--spec <text>", "Specification to achieve").option("--spec-file <path>", "File containing the specification").option("--verify <command>", "Shell command to verify spec (exit 0 = done)").option("--max-iterations <n>", "Max loop iterations", "10").option("--budget <usd>", "Max total budget in USD", "5").option("--cwd <path>", "Working directory", process.cwd()).action(async (opts) => {
174141
174858
  let spec = opts.spec;
174142
174859
  if (!spec && opts.specFile) {
174143
- if (!existsSync25(opts.specFile)) {
174860
+ if (!existsSync26(opts.specFile)) {
174144
174861
  console.error(chalk22.red(`Spec file not found: ${opts.specFile}`));
174145
174862
  process.exit(1);
174146
174863
  }
174147
- spec = readFileSync25(opts.specFile, "utf-8").trim();
174864
+ spec = readFileSync26(opts.specFile, "utf-8").trim();
174148
174865
  }
174149
174866
  if (!spec) {
174150
174867
  console.error(chalk22.red("Must provide --spec or --spec-file"));
@@ -174344,9 +175061,9 @@ function registerLoopCommand(program2) {
174344
175061
 
174345
175062
  // src/index.ts
174346
175063
  function checkBetaAccess() {
174347
- const licenseFile = join29(homedir12(), ".nestor", "license.key");
174348
- if (!existsSync26(licenseFile)) return false;
174349
- const key = readFileSync26(licenseFile, "utf-8").trim();
175064
+ const licenseFile = join30(homedir12(), ".nestor", "license.key");
175065
+ if (!existsSync27(licenseFile)) return false;
175066
+ const key = readFileSync27(licenseFile, "utf-8").trim();
174350
175067
  return /^NESTOR-BETA-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/.test(key);
174351
175068
  }
174352
175069
  var command2 = process.argv[2];
@@ -174366,7 +175083,7 @@ if (command2 && !["--help", "-h", "--version", "-V", "install"].includes(command
174366
175083
  }
174367
175084
  }
174368
175085
  var program = new Command();
174369
- program.name("nestor-sh").description("Nestor AI Agent Platform \u2014 orchestrate, secure and monitor AI agents").version("2.9.0");
175086
+ program.name("nestor-sh").description("Nestor AI Agent Platform \u2014 orchestrate, secure and monitor AI agents").version("3.0.0");
174370
175087
  registerStartCommand(program);
174371
175088
  registerInstallCommand(program);
174372
175089
  registerAgentCommand(program);