nestor-sh 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nestor.mjs +903 -221
- package/package.json +1 -1
package/dist/nestor.mjs
CHANGED
|
@@ -558,7 +558,7 @@ var SCHEMA_VERSION, CREATE_TABLES_SQL, CREATE_FTS5_SQL;
|
|
|
558
558
|
var init_schema = __esm({
|
|
559
559
|
"../db/src/schema.ts"() {
|
|
560
560
|
"use strict";
|
|
561
|
-
SCHEMA_VERSION =
|
|
561
|
+
SCHEMA_VERSION = 7;
|
|
562
562
|
CREATE_TABLES_SQL = `
|
|
563
563
|
-- \u2500\u2500\u2500 Tenants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
564
564
|
|
|
@@ -1532,6 +1532,22 @@ CREATE TABLE IF NOT EXISTS conversations (
|
|
|
1532
1532
|
CREATE INDEX IF NOT EXISTS idx_conversations_agent ON conversations(agent_id);
|
|
1533
1533
|
CREATE INDEX IF NOT EXISTS idx_conversations_tenant ON conversations(tenant_id);
|
|
1534
1534
|
|
|
1535
|
+
-- \u2500\u2500\u2500 LLM Provider Keys (encrypted LLM provider credentials) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1536
|
+
|
|
1537
|
+
CREATE TABLE IF NOT EXISTS llm_provider_keys (
|
|
1538
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
1539
|
+
tenant_id TEXT NOT NULL DEFAULT 'default',
|
|
1540
|
+
provider TEXT NOT NULL CHECK(provider IN ('claude','openai','gemini','grok','mistral','ollama')),
|
|
1541
|
+
key_encrypted TEXT NOT NULL,
|
|
1542
|
+
label TEXT DEFAULT '',
|
|
1543
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1544
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1545
|
+
UNIQUE(tenant_id, provider)
|
|
1546
|
+
);
|
|
1547
|
+
|
|
1548
|
+
CREATE INDEX IF NOT EXISTS idx_llm_keys_tenant ON llm_provider_keys(tenant_id);
|
|
1549
|
+
CREATE INDEX IF NOT EXISTS idx_llm_keys_provider ON llm_provider_keys(provider);
|
|
1550
|
+
|
|
1535
1551
|
-- NOTE: sql.js (emscripten WASM build of SQLite) does not include the FTS5
|
|
1536
1552
|
-- extension by default. The FTS5 virtual table and sync triggers below will
|
|
1537
1553
|
-- only take effect when running against a SQLite build that ships FTS5
|
|
@@ -6133,6 +6149,80 @@ var init_store = __esm({
|
|
|
6133
6149
|
if (affected > 0) this.save();
|
|
6134
6150
|
return affected > 0;
|
|
6135
6151
|
}
|
|
6152
|
+
// ─── API Keys ──────────────────────────────────────────────────────────
|
|
6153
|
+
/**
|
|
6154
|
+
* Upsert an encrypted API key for a provider.
|
|
6155
|
+
*/
|
|
6156
|
+
setApiKey(provider, encryptedKey, tenantId = "default", label = "") {
|
|
6157
|
+
const id = crypto2.randomUUID();
|
|
6158
|
+
runSql(
|
|
6159
|
+
this.db,
|
|
6160
|
+
`INSERT INTO llm_provider_keys (id, tenant_id, provider, key_encrypted, label, created_at, updated_at)
|
|
6161
|
+
VALUES (?, ?, ?, ?, ?, datetime('now'), datetime('now'))
|
|
6162
|
+
ON CONFLICT(tenant_id, provider) DO UPDATE SET
|
|
6163
|
+
key_encrypted = excluded.key_encrypted,
|
|
6164
|
+
label = excluded.label,
|
|
6165
|
+
updated_at = datetime('now')`,
|
|
6166
|
+
[id, tenantId, provider, encryptedKey, label]
|
|
6167
|
+
);
|
|
6168
|
+
this.save();
|
|
6169
|
+
}
|
|
6170
|
+
/**
|
|
6171
|
+
* Get the encrypted key for a provider, or null if not set.
|
|
6172
|
+
*/
|
|
6173
|
+
getApiKey(provider, tenantId = "default") {
|
|
6174
|
+
const row = queryOne(
|
|
6175
|
+
this.db,
|
|
6176
|
+
"SELECT key_encrypted FROM llm_provider_keys WHERE provider = ? AND tenant_id = ?",
|
|
6177
|
+
[provider, tenantId]
|
|
6178
|
+
);
|
|
6179
|
+
return row ? row.key_encrypted : null;
|
|
6180
|
+
}
|
|
6181
|
+
/**
|
|
6182
|
+
* List all configured API key providers with masked keys (for API response).
|
|
6183
|
+
* Does NOT return the actual encrypted key — only metadata.
|
|
6184
|
+
*/
|
|
6185
|
+
listProviderKeys(tenantId = "default") {
|
|
6186
|
+
const rows = queryAll(
|
|
6187
|
+
this.db,
|
|
6188
|
+
"SELECT provider, label, created_at, updated_at FROM llm_provider_keys WHERE tenant_id = ? ORDER BY provider",
|
|
6189
|
+
[tenantId]
|
|
6190
|
+
);
|
|
6191
|
+
return rows.map((row) => ({
|
|
6192
|
+
provider: row.provider,
|
|
6193
|
+
label: row.label || "",
|
|
6194
|
+
createdAt: row.created_at,
|
|
6195
|
+
updatedAt: row.updated_at,
|
|
6196
|
+
hasKey: true
|
|
6197
|
+
}));
|
|
6198
|
+
}
|
|
6199
|
+
/**
|
|
6200
|
+
* List all API keys with encrypted values (server-side only, for decryption).
|
|
6201
|
+
*/
|
|
6202
|
+
listApiKeysRaw(tenantId = "default") {
|
|
6203
|
+
const rows = queryAll(
|
|
6204
|
+
this.db,
|
|
6205
|
+
"SELECT provider, key_encrypted, label FROM llm_provider_keys WHERE tenant_id = ?",
|
|
6206
|
+
[tenantId]
|
|
6207
|
+
);
|
|
6208
|
+
return rows.map((row) => ({
|
|
6209
|
+
provider: row.provider,
|
|
6210
|
+
keyEncrypted: row.key_encrypted,
|
|
6211
|
+
label: row.label || ""
|
|
6212
|
+
}));
|
|
6213
|
+
}
|
|
6214
|
+
/**
|
|
6215
|
+
* Delete an API key for a provider.
|
|
6216
|
+
*/
|
|
6217
|
+
deleteProviderKey(provider, tenantId = "default") {
|
|
6218
|
+
const affected = runSql(
|
|
6219
|
+
this.db,
|
|
6220
|
+
"DELETE FROM llm_provider_keys WHERE provider = ? AND tenant_id = ?",
|
|
6221
|
+
[provider, tenantId]
|
|
6222
|
+
);
|
|
6223
|
+
if (affected > 0) this.save();
|
|
6224
|
+
return affected > 0;
|
|
6225
|
+
}
|
|
6136
6226
|
};
|
|
6137
6227
|
}
|
|
6138
6228
|
});
|
|
@@ -10593,7 +10683,7 @@ var SERVER_VERSION, startTime;
|
|
|
10593
10683
|
var init_health = __esm({
|
|
10594
10684
|
"../server/src/routes/health.ts"() {
|
|
10595
10685
|
"use strict";
|
|
10596
|
-
SERVER_VERSION = "2.1.
|
|
10686
|
+
SERVER_VERSION = "2.1.1";
|
|
10597
10687
|
startTime = Date.now();
|
|
10598
10688
|
}
|
|
10599
10689
|
});
|
|
@@ -19383,7 +19473,7 @@ function isNativeAvailable() {
|
|
|
19383
19473
|
return nativeModule !== null;
|
|
19384
19474
|
}
|
|
19385
19475
|
function getNativeVersion() {
|
|
19386
|
-
return nativeModule ? "2.1.
|
|
19476
|
+
return nativeModule ? "2.1.1" : null;
|
|
19387
19477
|
}
|
|
19388
19478
|
function validateSsrf(url, allowPrivate = false) {
|
|
19389
19479
|
if (nativeModule) {
|
|
@@ -70149,7 +70239,7 @@ var require_util2 = __commonJS({
|
|
|
70149
70239
|
return path30;
|
|
70150
70240
|
}
|
|
70151
70241
|
exports2.normalize = normalize4;
|
|
70152
|
-
function
|
|
70242
|
+
function join26(aRoot, aPath) {
|
|
70153
70243
|
if (aRoot === "") {
|
|
70154
70244
|
aRoot = ".";
|
|
70155
70245
|
}
|
|
@@ -70181,7 +70271,7 @@ var require_util2 = __commonJS({
|
|
|
70181
70271
|
}
|
|
70182
70272
|
return joined;
|
|
70183
70273
|
}
|
|
70184
|
-
exports2.join =
|
|
70274
|
+
exports2.join = join26;
|
|
70185
70275
|
exports2.isAbsolute = function(aPath) {
|
|
70186
70276
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
70187
70277
|
};
|
|
@@ -70354,7 +70444,7 @@ var require_util2 = __commonJS({
|
|
|
70354
70444
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
70355
70445
|
}
|
|
70356
70446
|
}
|
|
70357
|
-
sourceURL =
|
|
70447
|
+
sourceURL = join26(urlGenerate(parsed), sourceURL);
|
|
70358
70448
|
}
|
|
70359
70449
|
return normalize4(sourceURL);
|
|
70360
70450
|
}
|
|
@@ -72156,7 +72246,7 @@ var require_escodegen = __commonJS({
|
|
|
72156
72246
|
function noEmptySpace() {
|
|
72157
72247
|
return space ? space : " ";
|
|
72158
72248
|
}
|
|
72159
|
-
function
|
|
72249
|
+
function join26(left2, right2) {
|
|
72160
72250
|
var leftSource, rightSource, leftCharCode, rightCharCode;
|
|
72161
72251
|
leftSource = toSourceNodeWhenNeeded(left2).toString();
|
|
72162
72252
|
if (leftSource.length === 0) {
|
|
@@ -72487,8 +72577,8 @@ var require_escodegen = __commonJS({
|
|
|
72487
72577
|
} else {
|
|
72488
72578
|
result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
|
|
72489
72579
|
}
|
|
72490
|
-
result =
|
|
72491
|
-
result = [
|
|
72580
|
+
result = join26(result, operator);
|
|
72581
|
+
result = [join26(
|
|
72492
72582
|
result,
|
|
72493
72583
|
that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)
|
|
72494
72584
|
), ")"];
|
|
@@ -72631,11 +72721,11 @@ var require_escodegen = __commonJS({
|
|
|
72631
72721
|
var result, fragment;
|
|
72632
72722
|
result = ["class"];
|
|
72633
72723
|
if (stmt.id) {
|
|
72634
|
-
result =
|
|
72724
|
+
result = join26(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
|
|
72635
72725
|
}
|
|
72636
72726
|
if (stmt.superClass) {
|
|
72637
|
-
fragment =
|
|
72638
|
-
result =
|
|
72727
|
+
fragment = join26("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
|
|
72728
|
+
result = join26(result, fragment);
|
|
72639
72729
|
}
|
|
72640
72730
|
result.push(space);
|
|
72641
72731
|
result.push(this.generateStatement(stmt.body, S_TFFT));
|
|
@@ -72648,9 +72738,9 @@ var require_escodegen = __commonJS({
|
|
|
72648
72738
|
return escapeDirective(stmt.directive) + this.semicolon(flags);
|
|
72649
72739
|
},
|
|
72650
72740
|
DoWhileStatement: function(stmt, flags) {
|
|
72651
|
-
var result =
|
|
72741
|
+
var result = join26("do", this.maybeBlock(stmt.body, S_TFFF));
|
|
72652
72742
|
result = this.maybeBlockSuffix(stmt.body, result);
|
|
72653
|
-
return
|
|
72743
|
+
return join26(result, [
|
|
72654
72744
|
"while" + space + "(",
|
|
72655
72745
|
this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
|
|
72656
72746
|
")" + this.semicolon(flags)
|
|
@@ -72686,11 +72776,11 @@ var require_escodegen = __commonJS({
|
|
|
72686
72776
|
ExportDefaultDeclaration: function(stmt, flags) {
|
|
72687
72777
|
var result = ["export"], bodyFlags;
|
|
72688
72778
|
bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
|
|
72689
|
-
result =
|
|
72779
|
+
result = join26(result, "default");
|
|
72690
72780
|
if (isStatement(stmt.declaration)) {
|
|
72691
|
-
result =
|
|
72781
|
+
result = join26(result, this.generateStatement(stmt.declaration, bodyFlags));
|
|
72692
72782
|
} else {
|
|
72693
|
-
result =
|
|
72783
|
+
result = join26(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
|
|
72694
72784
|
}
|
|
72695
72785
|
return result;
|
|
72696
72786
|
},
|
|
@@ -72698,15 +72788,15 @@ var require_escodegen = __commonJS({
|
|
|
72698
72788
|
var result = ["export"], bodyFlags, that = this;
|
|
72699
72789
|
bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
|
|
72700
72790
|
if (stmt.declaration) {
|
|
72701
|
-
return
|
|
72791
|
+
return join26(result, this.generateStatement(stmt.declaration, bodyFlags));
|
|
72702
72792
|
}
|
|
72703
72793
|
if (stmt.specifiers) {
|
|
72704
72794
|
if (stmt.specifiers.length === 0) {
|
|
72705
|
-
result =
|
|
72795
|
+
result = join26(result, "{" + space + "}");
|
|
72706
72796
|
} else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
|
|
72707
|
-
result =
|
|
72797
|
+
result = join26(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
|
|
72708
72798
|
} else {
|
|
72709
|
-
result =
|
|
72799
|
+
result = join26(result, "{");
|
|
72710
72800
|
withIndent(function(indent2) {
|
|
72711
72801
|
var i, iz;
|
|
72712
72802
|
result.push(newline);
|
|
@@ -72724,7 +72814,7 @@ var require_escodegen = __commonJS({
|
|
|
72724
72814
|
result.push(base + "}");
|
|
72725
72815
|
}
|
|
72726
72816
|
if (stmt.source) {
|
|
72727
|
-
result =
|
|
72817
|
+
result = join26(result, [
|
|
72728
72818
|
"from" + space,
|
|
72729
72819
|
// ModuleSpecifier
|
|
72730
72820
|
this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
|
|
@@ -72812,7 +72902,7 @@ var require_escodegen = __commonJS({
|
|
|
72812
72902
|
];
|
|
72813
72903
|
cursor = 0;
|
|
72814
72904
|
if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
|
|
72815
|
-
result =
|
|
72905
|
+
result = join26(result, [
|
|
72816
72906
|
this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
|
|
72817
72907
|
]);
|
|
72818
72908
|
++cursor;
|
|
@@ -72822,7 +72912,7 @@ var require_escodegen = __commonJS({
|
|
|
72822
72912
|
result.push(",");
|
|
72823
72913
|
}
|
|
72824
72914
|
if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
|
|
72825
|
-
result =
|
|
72915
|
+
result = join26(result, [
|
|
72826
72916
|
space,
|
|
72827
72917
|
this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
|
|
72828
72918
|
]);
|
|
@@ -72851,7 +72941,7 @@ var require_escodegen = __commonJS({
|
|
|
72851
72941
|
}
|
|
72852
72942
|
}
|
|
72853
72943
|
}
|
|
72854
|
-
result =
|
|
72944
|
+
result = join26(result, [
|
|
72855
72945
|
"from" + space,
|
|
72856
72946
|
// ModuleSpecifier
|
|
72857
72947
|
this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
|
|
@@ -72905,7 +72995,7 @@ var require_escodegen = __commonJS({
|
|
|
72905
72995
|
return result;
|
|
72906
72996
|
},
|
|
72907
72997
|
ThrowStatement: function(stmt, flags) {
|
|
72908
|
-
return [
|
|
72998
|
+
return [join26(
|
|
72909
72999
|
"throw",
|
|
72910
73000
|
this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
|
|
72911
73001
|
), this.semicolon(flags)];
|
|
@@ -72916,7 +73006,7 @@ var require_escodegen = __commonJS({
|
|
|
72916
73006
|
result = this.maybeBlockSuffix(stmt.block, result);
|
|
72917
73007
|
if (stmt.handlers) {
|
|
72918
73008
|
for (i = 0, iz = stmt.handlers.length; i < iz; ++i) {
|
|
72919
|
-
result =
|
|
73009
|
+
result = join26(result, this.generateStatement(stmt.handlers[i], S_TFFF));
|
|
72920
73010
|
if (stmt.finalizer || i + 1 !== iz) {
|
|
72921
73011
|
result = this.maybeBlockSuffix(stmt.handlers[i].body, result);
|
|
72922
73012
|
}
|
|
@@ -72924,7 +73014,7 @@ var require_escodegen = __commonJS({
|
|
|
72924
73014
|
} else {
|
|
72925
73015
|
guardedHandlers = stmt.guardedHandlers || [];
|
|
72926
73016
|
for (i = 0, iz = guardedHandlers.length; i < iz; ++i) {
|
|
72927
|
-
result =
|
|
73017
|
+
result = join26(result, this.generateStatement(guardedHandlers[i], S_TFFF));
|
|
72928
73018
|
if (stmt.finalizer || i + 1 !== iz) {
|
|
72929
73019
|
result = this.maybeBlockSuffix(guardedHandlers[i].body, result);
|
|
72930
73020
|
}
|
|
@@ -72932,13 +73022,13 @@ var require_escodegen = __commonJS({
|
|
|
72932
73022
|
if (stmt.handler) {
|
|
72933
73023
|
if (Array.isArray(stmt.handler)) {
|
|
72934
73024
|
for (i = 0, iz = stmt.handler.length; i < iz; ++i) {
|
|
72935
|
-
result =
|
|
73025
|
+
result = join26(result, this.generateStatement(stmt.handler[i], S_TFFF));
|
|
72936
73026
|
if (stmt.finalizer || i + 1 !== iz) {
|
|
72937
73027
|
result = this.maybeBlockSuffix(stmt.handler[i].body, result);
|
|
72938
73028
|
}
|
|
72939
73029
|
}
|
|
72940
73030
|
} else {
|
|
72941
|
-
result =
|
|
73031
|
+
result = join26(result, this.generateStatement(stmt.handler, S_TFFF));
|
|
72942
73032
|
if (stmt.finalizer) {
|
|
72943
73033
|
result = this.maybeBlockSuffix(stmt.handler.body, result);
|
|
72944
73034
|
}
|
|
@@ -72946,7 +73036,7 @@ var require_escodegen = __commonJS({
|
|
|
72946
73036
|
}
|
|
72947
73037
|
}
|
|
72948
73038
|
if (stmt.finalizer) {
|
|
72949
|
-
result =
|
|
73039
|
+
result = join26(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
|
|
72950
73040
|
}
|
|
72951
73041
|
return result;
|
|
72952
73042
|
},
|
|
@@ -72980,7 +73070,7 @@ var require_escodegen = __commonJS({
|
|
|
72980
73070
|
withIndent(function() {
|
|
72981
73071
|
if (stmt.test) {
|
|
72982
73072
|
result = [
|
|
72983
|
-
|
|
73073
|
+
join26("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
|
|
72984
73074
|
":"
|
|
72985
73075
|
];
|
|
72986
73076
|
} else {
|
|
@@ -73028,9 +73118,9 @@ var require_escodegen = __commonJS({
|
|
|
73028
73118
|
result.push(this.maybeBlock(stmt.consequent, S_TFFF));
|
|
73029
73119
|
result = this.maybeBlockSuffix(stmt.consequent, result);
|
|
73030
73120
|
if (stmt.alternate.type === Syntax.IfStatement) {
|
|
73031
|
-
result =
|
|
73121
|
+
result = join26(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
|
|
73032
73122
|
} else {
|
|
73033
|
-
result =
|
|
73123
|
+
result = join26(result, join26("else", this.maybeBlock(stmt.alternate, bodyFlags)));
|
|
73034
73124
|
}
|
|
73035
73125
|
} else {
|
|
73036
73126
|
result.push(this.maybeBlock(stmt.consequent, bodyFlags));
|
|
@@ -73131,7 +73221,7 @@ var require_escodegen = __commonJS({
|
|
|
73131
73221
|
},
|
|
73132
73222
|
ReturnStatement: function(stmt, flags) {
|
|
73133
73223
|
if (stmt.argument) {
|
|
73134
|
-
return [
|
|
73224
|
+
return [join26(
|
|
73135
73225
|
"return",
|
|
73136
73226
|
this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
|
|
73137
73227
|
), this.semicolon(flags)];
|
|
@@ -73220,14 +73310,14 @@ var require_escodegen = __commonJS({
|
|
|
73220
73310
|
if (leftSource.charCodeAt(leftSource.length - 1) === 47 && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
|
|
73221
73311
|
result = [fragment, noEmptySpace(), expr.operator];
|
|
73222
73312
|
} else {
|
|
73223
|
-
result =
|
|
73313
|
+
result = join26(fragment, expr.operator);
|
|
73224
73314
|
}
|
|
73225
73315
|
fragment = this.generateExpression(expr.right, rightPrecedence, flags);
|
|
73226
73316
|
if (expr.operator === "/" && fragment.toString().charAt(0) === "/" || expr.operator.slice(-1) === "<" && fragment.toString().slice(0, 3) === "!--") {
|
|
73227
73317
|
result.push(noEmptySpace());
|
|
73228
73318
|
result.push(fragment);
|
|
73229
73319
|
} else {
|
|
73230
|
-
result =
|
|
73320
|
+
result = join26(result, fragment);
|
|
73231
73321
|
}
|
|
73232
73322
|
if (expr.operator === "in" && !(flags & F_ALLOW_IN)) {
|
|
73233
73323
|
return ["(", result, ")"];
|
|
@@ -73267,7 +73357,7 @@ var require_escodegen = __commonJS({
|
|
|
73267
73357
|
var result, length, i, iz, itemFlags;
|
|
73268
73358
|
length = expr["arguments"].length;
|
|
73269
73359
|
itemFlags = flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0 ? E_TFT : E_TFF;
|
|
73270
|
-
result =
|
|
73360
|
+
result = join26(
|
|
73271
73361
|
"new",
|
|
73272
73362
|
this.generateExpression(expr.callee, Precedence.New, itemFlags)
|
|
73273
73363
|
);
|
|
@@ -73317,11 +73407,11 @@ var require_escodegen = __commonJS({
|
|
|
73317
73407
|
var result, fragment, rightCharCode, leftSource, leftCharCode;
|
|
73318
73408
|
fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
|
|
73319
73409
|
if (space === "") {
|
|
73320
|
-
result =
|
|
73410
|
+
result = join26(expr.operator, fragment);
|
|
73321
73411
|
} else {
|
|
73322
73412
|
result = [expr.operator];
|
|
73323
73413
|
if (expr.operator.length > 2) {
|
|
73324
|
-
result =
|
|
73414
|
+
result = join26(result, fragment);
|
|
73325
73415
|
} else {
|
|
73326
73416
|
leftSource = toSourceNodeWhenNeeded(result).toString();
|
|
73327
73417
|
leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
|
|
@@ -73344,7 +73434,7 @@ var require_escodegen = __commonJS({
|
|
|
73344
73434
|
result = "yield";
|
|
73345
73435
|
}
|
|
73346
73436
|
if (expr.argument) {
|
|
73347
|
-
result =
|
|
73437
|
+
result = join26(
|
|
73348
73438
|
result,
|
|
73349
73439
|
this.generateExpression(expr.argument, Precedence.Yield, E_TTT)
|
|
73350
73440
|
);
|
|
@@ -73352,7 +73442,7 @@ var require_escodegen = __commonJS({
|
|
|
73352
73442
|
return parenthesize(result, Precedence.Yield, precedence);
|
|
73353
73443
|
},
|
|
73354
73444
|
AwaitExpression: function(expr, precedence, flags) {
|
|
73355
|
-
var result =
|
|
73445
|
+
var result = join26(
|
|
73356
73446
|
expr.all ? "await*" : "await",
|
|
73357
73447
|
this.generateExpression(expr.argument, Precedence.Await, E_TTT)
|
|
73358
73448
|
);
|
|
@@ -73435,11 +73525,11 @@ var require_escodegen = __commonJS({
|
|
|
73435
73525
|
var result, fragment;
|
|
73436
73526
|
result = ["class"];
|
|
73437
73527
|
if (expr.id) {
|
|
73438
|
-
result =
|
|
73528
|
+
result = join26(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
|
|
73439
73529
|
}
|
|
73440
73530
|
if (expr.superClass) {
|
|
73441
|
-
fragment =
|
|
73442
|
-
result =
|
|
73531
|
+
fragment = join26("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
|
|
73532
|
+
result = join26(result, fragment);
|
|
73443
73533
|
}
|
|
73444
73534
|
result.push(space);
|
|
73445
73535
|
result.push(this.generateStatement(expr.body, S_TFFT));
|
|
@@ -73454,7 +73544,7 @@ var require_escodegen = __commonJS({
|
|
|
73454
73544
|
}
|
|
73455
73545
|
if (expr.kind === "get" || expr.kind === "set") {
|
|
73456
73546
|
fragment = [
|
|
73457
|
-
|
|
73547
|
+
join26(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
|
|
73458
73548
|
this.generateFunctionBody(expr.value)
|
|
73459
73549
|
];
|
|
73460
73550
|
} else {
|
|
@@ -73464,7 +73554,7 @@ var require_escodegen = __commonJS({
|
|
|
73464
73554
|
this.generateFunctionBody(expr.value)
|
|
73465
73555
|
];
|
|
73466
73556
|
}
|
|
73467
|
-
return
|
|
73557
|
+
return join26(result, fragment);
|
|
73468
73558
|
},
|
|
73469
73559
|
Property: function(expr, precedence, flags) {
|
|
73470
73560
|
if (expr.kind === "get" || expr.kind === "set") {
|
|
@@ -73659,7 +73749,7 @@ var require_escodegen = __commonJS({
|
|
|
73659
73749
|
for (i = 0, iz = expr.blocks.length; i < iz; ++i) {
|
|
73660
73750
|
fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT);
|
|
73661
73751
|
if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
|
|
73662
|
-
result =
|
|
73752
|
+
result = join26(result, fragment);
|
|
73663
73753
|
} else {
|
|
73664
73754
|
result.push(fragment);
|
|
73665
73755
|
}
|
|
@@ -73667,13 +73757,13 @@ var require_escodegen = __commonJS({
|
|
|
73667
73757
|
});
|
|
73668
73758
|
}
|
|
73669
73759
|
if (expr.filter) {
|
|
73670
|
-
result =
|
|
73760
|
+
result = join26(result, "if" + space);
|
|
73671
73761
|
fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
|
|
73672
|
-
result =
|
|
73762
|
+
result = join26(result, ["(", fragment, ")"]);
|
|
73673
73763
|
}
|
|
73674
73764
|
if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
|
|
73675
73765
|
fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
|
|
73676
|
-
result =
|
|
73766
|
+
result = join26(result, fragment);
|
|
73677
73767
|
}
|
|
73678
73768
|
result.push(expr.type === Syntax.GeneratorExpression ? ")" : "]");
|
|
73679
73769
|
return result;
|
|
@@ -73689,8 +73779,8 @@ var require_escodegen = __commonJS({
|
|
|
73689
73779
|
} else {
|
|
73690
73780
|
fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
|
|
73691
73781
|
}
|
|
73692
|
-
fragment =
|
|
73693
|
-
fragment =
|
|
73782
|
+
fragment = join26(fragment, expr.of ? "of" : "in");
|
|
73783
|
+
fragment = join26(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
|
|
73694
73784
|
return ["for" + space + "(", fragment, ")"];
|
|
73695
73785
|
},
|
|
73696
73786
|
SpreadElement: function(expr, precedence, flags) {
|
|
@@ -101249,8 +101339,8 @@ function findChromePath() {
|
|
|
101249
101339
|
for (const p8 of paths) {
|
|
101250
101340
|
if (p8) {
|
|
101251
101341
|
try {
|
|
101252
|
-
const { existsSync:
|
|
101253
|
-
if (
|
|
101342
|
+
const { existsSync: existsSync22 } = __require("node:fs");
|
|
101343
|
+
if (existsSync22(p8)) return p8;
|
|
101254
101344
|
} catch {
|
|
101255
101345
|
}
|
|
101256
101346
|
}
|
|
@@ -101265,8 +101355,8 @@ function findChromePath() {
|
|
|
101265
101355
|
];
|
|
101266
101356
|
for (const p8 of paths) {
|
|
101267
101357
|
try {
|
|
101268
|
-
const { existsSync:
|
|
101269
|
-
if (
|
|
101358
|
+
const { existsSync: existsSync22 } = __require("node:fs");
|
|
101359
|
+
if (existsSync22(p8)) return p8;
|
|
101270
101360
|
} catch {
|
|
101271
101361
|
}
|
|
101272
101362
|
}
|
|
@@ -101281,8 +101371,8 @@ function findChromePath() {
|
|
|
101281
101371
|
];
|
|
101282
101372
|
for (const p8 of linuxPaths) {
|
|
101283
101373
|
try {
|
|
101284
|
-
const { existsSync:
|
|
101285
|
-
if (
|
|
101374
|
+
const { existsSync: existsSync22 } = __require("node:fs");
|
|
101375
|
+
if (existsSync22(p8)) return p8;
|
|
101286
101376
|
} catch {
|
|
101287
101377
|
}
|
|
101288
101378
|
}
|
|
@@ -102464,8 +102554,19 @@ async function fileListHandler(input, context3) {
|
|
|
102464
102554
|
return { output: `Failed to list directory: ${message}`, isError: true };
|
|
102465
102555
|
}
|
|
102466
102556
|
}
|
|
102557
|
+
function htmlToText(html) {
|
|
102558
|
+
return html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<noscript[^>]*>[\s\S]*?<\/noscript>/gi, "").replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n\n").replace(/<\/div>/gi, "\n").replace(/<\/h[1-6]>/gi, "\n\n").replace(/<h[1-6][^>]*>/gi, "\n\n## ").replace(/<li>/gi, "- ").replace(/<\/li>/gi, "\n").replace(/<\/tr>/gi, "\n").replace(/<\/td>/gi, " | ").replace(/<\/th>/gi, " | ").replace(/<hr[^>]*>/gi, "\n---\n").replace(/<[^>]*>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'").replace(/'/g, "'").replace(/ /g, " ").replace(/—/g, "\u2014").replace(/–/g, "\u2013").replace(/…/g, "...").replace(/«/g, "\xAB").replace(/»/g, "\xBB").replace(/&#(\d+);/g, (_m, code) => String.fromCharCode(parseInt(code, 10))).replace(/&#x([0-9a-fA-F]+);/g, (_m, code) => String.fromCharCode(parseInt(code, 16))).replace(/\n{3,}/g, "\n\n").replace(/[ \t]+/g, " ").replace(/^ +/gm, "").trim();
|
|
102559
|
+
}
|
|
102560
|
+
function extractTitle(html) {
|
|
102561
|
+
const match = html.match(/<title[^>]*>(.*?)<\/title>/i);
|
|
102562
|
+
return match ? match[1].replace(/<[^>]*>/g, "").trim() : "";
|
|
102563
|
+
}
|
|
102564
|
+
function extractMetaDescription(html) {
|
|
102565
|
+
const match = html.match(/<meta[^>]*name=["']description["'][^>]*content=["'](.*?)["'][^>]*>/i) || html.match(/<meta[^>]*content=["'](.*?)["'][^>]*name=["']description["'][^>]*>/i);
|
|
102566
|
+
return match ? match[1].trim() : "";
|
|
102567
|
+
}
|
|
102467
102568
|
async function webFetchHandler(input, context3) {
|
|
102468
|
-
const { url, method, headers, body, timeout: timeout2 } = input;
|
|
102569
|
+
const { url, method, headers, body, timeout: timeout2, raw } = input;
|
|
102469
102570
|
const timeoutMs = timeout2 ?? 15e3;
|
|
102470
102571
|
try {
|
|
102471
102572
|
const controller = new AbortController();
|
|
@@ -102473,11 +102574,17 @@ async function webFetchHandler(input, context3) {
|
|
|
102473
102574
|
if (context3.signal) {
|
|
102474
102575
|
context3.signal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
102475
102576
|
}
|
|
102577
|
+
const defaultHeaders = {
|
|
102578
|
+
"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",
|
|
102579
|
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,application/json;q=0.8,*/*;q=0.7",
|
|
102580
|
+
"Accept-Language": "en-US,en;q=0.9,fr;q=0.8"
|
|
102581
|
+
};
|
|
102476
102582
|
const resp = await fetch(url, {
|
|
102477
102583
|
method: method ?? "GET",
|
|
102478
|
-
headers: headers ?? {},
|
|
102584
|
+
headers: { ...defaultHeaders, ...headers ?? {} },
|
|
102479
102585
|
body: body ?? void 0,
|
|
102480
|
-
signal: controller.signal
|
|
102586
|
+
signal: controller.signal,
|
|
102587
|
+
redirect: "follow"
|
|
102481
102588
|
});
|
|
102482
102589
|
clearTimeout(timer2);
|
|
102483
102590
|
const contentType = resp.headers.get("content-type") ?? "";
|
|
@@ -102486,9 +102593,22 @@ async function webFetchHandler(input, context3) {
|
|
|
102486
102593
|
const json = await resp.json();
|
|
102487
102594
|
responseBody = JSON.stringify(json, null, 2);
|
|
102488
102595
|
} else {
|
|
102489
|
-
|
|
102596
|
+
const rawText = await resp.text();
|
|
102597
|
+
if (!raw && contentType.includes("text/html")) {
|
|
102598
|
+
const title = extractTitle(rawText);
|
|
102599
|
+
const description = extractMetaDescription(rawText);
|
|
102600
|
+
const textContent = htmlToText(rawText);
|
|
102601
|
+
const parts = [];
|
|
102602
|
+
if (title) parts.push(`# ${title}`);
|
|
102603
|
+
if (description) parts.push(`> ${description}`);
|
|
102604
|
+
if (parts.length > 0) parts.push("");
|
|
102605
|
+
parts.push(textContent);
|
|
102606
|
+
responseBody = parts.join("\n");
|
|
102607
|
+
} else {
|
|
102608
|
+
responseBody = rawText;
|
|
102609
|
+
}
|
|
102490
102610
|
}
|
|
102491
|
-
const maxLen = 1e5;
|
|
102611
|
+
const maxLen = !raw && contentType.includes("text/html") ? 1e4 : 1e5;
|
|
102492
102612
|
if (responseBody.length > maxLen) {
|
|
102493
102613
|
responseBody = responseBody.slice(0, maxLen) + `
|
|
102494
102614
|
|
|
@@ -102497,6 +102617,7 @@ async function webFetchHandler(input, context3) {
|
|
|
102497
102617
|
const output = [
|
|
102498
102618
|
`HTTP ${resp.status} ${resp.statusText}`,
|
|
102499
102619
|
`Content-Type: ${contentType}`,
|
|
102620
|
+
`URL: ${resp.url}`,
|
|
102500
102621
|
"",
|
|
102501
102622
|
responseBody
|
|
102502
102623
|
].join("\n");
|
|
@@ -102509,6 +102630,130 @@ async function webFetchHandler(input, context3) {
|
|
|
102509
102630
|
return { output: `Fetch failed: ${message}`, isError: true };
|
|
102510
102631
|
}
|
|
102511
102632
|
}
|
|
102633
|
+
async function webSearchHandler(input, context3) {
|
|
102634
|
+
const { query, engine, maxResults } = input;
|
|
102635
|
+
const max = maxResults || 5;
|
|
102636
|
+
const searchEngine = engine || "duckduckgo";
|
|
102637
|
+
let searchUrl;
|
|
102638
|
+
switch (searchEngine) {
|
|
102639
|
+
case "google":
|
|
102640
|
+
searchUrl = `https://www.google.com/search?q=${encodeURIComponent(query)}&num=${max}`;
|
|
102641
|
+
break;
|
|
102642
|
+
case "bing":
|
|
102643
|
+
searchUrl = `https://www.bing.com/search?q=${encodeURIComponent(query)}&count=${max}`;
|
|
102644
|
+
break;
|
|
102645
|
+
case "duckduckgo":
|
|
102646
|
+
default:
|
|
102647
|
+
searchUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
|
|
102648
|
+
break;
|
|
102649
|
+
}
|
|
102650
|
+
try {
|
|
102651
|
+
const controller = new AbortController();
|
|
102652
|
+
const timer2 = setTimeout(() => controller.abort(), 15e3);
|
|
102653
|
+
if (context3.signal) {
|
|
102654
|
+
context3.signal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
102655
|
+
}
|
|
102656
|
+
const resp = await fetch(searchUrl, {
|
|
102657
|
+
headers: {
|
|
102658
|
+
"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",
|
|
102659
|
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
102660
|
+
"Accept-Language": "en-US,en;q=0.9,fr;q=0.8"
|
|
102661
|
+
},
|
|
102662
|
+
signal: controller.signal,
|
|
102663
|
+
redirect: "follow"
|
|
102664
|
+
});
|
|
102665
|
+
clearTimeout(timer2);
|
|
102666
|
+
if (!resp.ok) {
|
|
102667
|
+
return { output: `Search failed: HTTP ${resp.status}. Try a different search engine with engine:"google" or engine:"bing".`, isError: true };
|
|
102668
|
+
}
|
|
102669
|
+
const html = await resp.text();
|
|
102670
|
+
const results = [];
|
|
102671
|
+
if (searchEngine === "duckduckgo") {
|
|
102672
|
+
const linkRegex = /<a[^>]*class="result__a"[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi;
|
|
102673
|
+
const snippetRegex = /<a[^>]*class="result__snippet"[^>]*>(.*?)<\/a>/gi;
|
|
102674
|
+
let linkMatch;
|
|
102675
|
+
const links = [];
|
|
102676
|
+
while ((linkMatch = linkRegex.exec(html)) !== null && links.length < max) {
|
|
102677
|
+
let url = linkMatch[1];
|
|
102678
|
+
const uddg = url.match(/uddg=([^&]*)/);
|
|
102679
|
+
if (uddg) url = decodeURIComponent(uddg[1]);
|
|
102680
|
+
const title = linkMatch[2].replace(/<[^>]*>/g, "").trim();
|
|
102681
|
+
if (url.startsWith("http")) {
|
|
102682
|
+
links.push({ url, title });
|
|
102683
|
+
}
|
|
102684
|
+
}
|
|
102685
|
+
let snippetMatch;
|
|
102686
|
+
const snippets = [];
|
|
102687
|
+
while ((snippetMatch = snippetRegex.exec(html)) !== null) {
|
|
102688
|
+
snippets.push(snippetMatch[1].replace(/<[^>]*>/g, "").trim());
|
|
102689
|
+
}
|
|
102690
|
+
for (let i = 0; i < links.length; i++) {
|
|
102691
|
+
results.push({
|
|
102692
|
+
title: links[i].title,
|
|
102693
|
+
url: links[i].url,
|
|
102694
|
+
snippet: snippets[i] || ""
|
|
102695
|
+
});
|
|
102696
|
+
}
|
|
102697
|
+
} else if (searchEngine === "google") {
|
|
102698
|
+
const resultBlockRegex = /<div class="[^"]*g[^"]*"[^>]*>[\s\S]*?<a[^>]*href="(https?:\/\/[^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?(?:<span[^>]*>([\s\S]*?)<\/span>)?/gi;
|
|
102699
|
+
let blockMatch;
|
|
102700
|
+
while ((blockMatch = resultBlockRegex.exec(html)) !== null && results.length < max) {
|
|
102701
|
+
const url = blockMatch[1];
|
|
102702
|
+
const title = blockMatch[2].replace(/<[^>]*>/g, "").trim();
|
|
102703
|
+
const snippet = (blockMatch[3] || "").replace(/<[^>]*>/g, "").trim();
|
|
102704
|
+
if (title.length > 3 && !url.includes("google.com")) {
|
|
102705
|
+
results.push({ title, url, snippet });
|
|
102706
|
+
}
|
|
102707
|
+
}
|
|
102708
|
+
} else if (searchEngine === "bing") {
|
|
102709
|
+
const bingRegex = /<li class="b_algo"[^>]*>[\s\S]*?<a[^>]*href="(https?:\/\/[^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<p[^>]*>([\s\S]*?)<\/p>/gi;
|
|
102710
|
+
let bingMatch;
|
|
102711
|
+
while ((bingMatch = bingRegex.exec(html)) !== null && results.length < max) {
|
|
102712
|
+
const url = bingMatch[1];
|
|
102713
|
+
const title = bingMatch[2].replace(/<[^>]*>/g, "").trim();
|
|
102714
|
+
const snippet = bingMatch[3].replace(/<[^>]*>/g, "").trim();
|
|
102715
|
+
if (title.length > 3) {
|
|
102716
|
+
results.push({ title, url, snippet });
|
|
102717
|
+
}
|
|
102718
|
+
}
|
|
102719
|
+
}
|
|
102720
|
+
if (results.length === 0) {
|
|
102721
|
+
const anyLinkRegex = /<a[^>]*href="(https?:\/\/[^"]*)"[^>]*>(.*?)<\/a>/gi;
|
|
102722
|
+
let anyMatch;
|
|
102723
|
+
while ((anyMatch = anyLinkRegex.exec(html)) !== null && results.length < max) {
|
|
102724
|
+
const url = anyMatch[1];
|
|
102725
|
+
const title = anyMatch[2].replace(/<[^>]*>/g, "").trim();
|
|
102726
|
+
if (title.length > 5 && !url.includes("duckduckgo.com") && !url.includes("google.com") && !url.includes("bing.com")) {
|
|
102727
|
+
results.push({ title, url, snippet: "" });
|
|
102728
|
+
}
|
|
102729
|
+
}
|
|
102730
|
+
}
|
|
102731
|
+
if (results.length === 0) {
|
|
102732
|
+
return {
|
|
102733
|
+
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.`,
|
|
102734
|
+
isError: false
|
|
102735
|
+
};
|
|
102736
|
+
}
|
|
102737
|
+
const formatted = results.map(
|
|
102738
|
+
(r, i) => `${i + 1}. ${r.title}
|
|
102739
|
+
${r.url}
|
|
102740
|
+
${r.snippet}`
|
|
102741
|
+
).join("\n\n");
|
|
102742
|
+
return {
|
|
102743
|
+
output: `Search results for "${query}":
|
|
102744
|
+
|
|
102745
|
+
${formatted}
|
|
102746
|
+
|
|
102747
|
+
Use web_fetch on any URL above to get the full page content.`,
|
|
102748
|
+
isError: false
|
|
102749
|
+
};
|
|
102750
|
+
} catch (err) {
|
|
102751
|
+
if (err.name === "AbortError") {
|
|
102752
|
+
return { output: `Search timed out for "${query}". Try a simpler query or different engine.`, isError: true };
|
|
102753
|
+
}
|
|
102754
|
+
return { output: `Search error: ${err.message}. Try a different search engine with engine:"google" or engine:"bing".`, isError: true };
|
|
102755
|
+
}
|
|
102756
|
+
}
|
|
102512
102757
|
async function messageSendHandler(input, context3) {
|
|
102513
102758
|
const { to, subject, body } = input;
|
|
102514
102759
|
try {
|
|
@@ -102610,6 +102855,7 @@ function registerBuiltinTools(registry) {
|
|
|
102610
102855
|
registry.register(fileWriteTool);
|
|
102611
102856
|
registry.register(fileListTool);
|
|
102612
102857
|
registry.register(webFetchTool);
|
|
102858
|
+
registry.register(webSearchTool);
|
|
102613
102859
|
registry.register(messageSendTool);
|
|
102614
102860
|
registry.register(messageReadTool);
|
|
102615
102861
|
registry.register(handoffTool);
|
|
@@ -102626,7 +102872,7 @@ function registerBrowserTools(registry, config2) {
|
|
|
102626
102872
|
}
|
|
102627
102873
|
return manager;
|
|
102628
102874
|
}
|
|
102629
|
-
var shellExecSchema, sandboxCache, DANGEROUS_METACHARACTERS, shellExecTool, fileReadSchema, fileReadTool, fileWriteSchema, fileWriteTool, fileListSchema, fileListTool, webFetchSchema, webFetchTool, messageSendSchema, messageSendTool, messageReadSchema, messageReadTool, handoffSchema, handoffTool, undoSchema;
|
|
102875
|
+
var shellExecSchema, sandboxCache, DANGEROUS_METACHARACTERS, shellExecTool, fileReadSchema, fileReadTool, fileWriteSchema, fileWriteTool, fileListSchema, fileListTool, webFetchSchema, webFetchTool, webSearchSchema, webSearchTool, messageSendSchema, messageSendTool, messageReadSchema, messageReadTool, handoffSchema, handoffTool, undoSchema;
|
|
102630
102876
|
var init_builtin = __esm({
|
|
102631
102877
|
"../agent/src/tools/builtin.ts"() {
|
|
102632
102878
|
"use strict";
|
|
@@ -102692,14 +102938,26 @@ var init_builtin = __esm({
|
|
|
102692
102938
|
method: z26.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).optional().describe("HTTP method (default: GET)"),
|
|
102693
102939
|
headers: z26.record(z26.string()).optional().describe("HTTP headers"),
|
|
102694
102940
|
body: z26.string().optional().describe("Request body (for POST/PUT/PATCH)"),
|
|
102695
|
-
timeout: z26.number().optional().describe("Timeout in milliseconds (default: 15000)")
|
|
102941
|
+
timeout: z26.number().optional().describe("Timeout in milliseconds (default: 15000)"),
|
|
102942
|
+
raw: z26.boolean().optional().describe("If true, return raw response without HTML-to-text conversion (default: false)")
|
|
102696
102943
|
});
|
|
102697
102944
|
webFetchTool = {
|
|
102698
102945
|
name: "web_fetch",
|
|
102699
|
-
description: "
|
|
102946
|
+
description: "Fetch a URL and return its content. For HTML pages, automatically converts to readable text. Use raw:true to get the original HTML. Useful for reading articles, documentation, API responses, etc.",
|
|
102700
102947
|
inputSchema: webFetchSchema,
|
|
102701
102948
|
handler: webFetchHandler
|
|
102702
102949
|
};
|
|
102950
|
+
webSearchSchema = z26.object({
|
|
102951
|
+
query: z26.string().describe("The search query"),
|
|
102952
|
+
engine: z26.string().optional().describe("Search engine: google, duckduckgo, bing. Default: duckduckgo"),
|
|
102953
|
+
maxResults: z26.number().optional().describe("Max results to return. Default: 5")
|
|
102954
|
+
});
|
|
102955
|
+
webSearchTool = {
|
|
102956
|
+
name: "web_search",
|
|
102957
|
+
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.",
|
|
102958
|
+
inputSchema: webSearchSchema,
|
|
102959
|
+
handler: webSearchHandler
|
|
102960
|
+
};
|
|
102703
102961
|
messageSendSchema = z26.object({
|
|
102704
102962
|
to: z26.string().describe('Target agent ID or name. Use "*" to broadcast to all agents.'),
|
|
102705
102963
|
subject: z26.string().describe("Message subject \u2014 a short label describing the purpose."),
|
|
@@ -111354,6 +111612,7 @@ __export(src_exports3, {
|
|
|
111354
111612
|
shellExecTool: () => shellExecTool,
|
|
111355
111613
|
unloadPlugin: () => unloadPlugin,
|
|
111356
111614
|
webFetchTool: () => webFetchTool,
|
|
111615
|
+
webSearchTool: () => webSearchTool,
|
|
111357
111616
|
withinBudget: () => withinBudget,
|
|
111358
111617
|
withinDuration: () => withinDuration,
|
|
111359
111618
|
wrapExternalData: () => wrapExternalData,
|
|
@@ -144297,22 +144556,64 @@ function chatRoutes(store) {
|
|
|
144297
144556
|
initialMessages.push({ role: msg.role, content: msg.content });
|
|
144298
144557
|
}
|
|
144299
144558
|
}
|
|
144300
|
-
const
|
|
144301
|
-
|
|
144302
|
-
|
|
144303
|
-
|
|
144304
|
-
|
|
144305
|
-
|
|
144306
|
-
|
|
144307
|
-
|
|
144308
|
-
|
|
144309
|
-
|
|
144310
|
-
|
|
144311
|
-
|
|
144312
|
-
|
|
144313
|
-
|
|
144314
|
-
|
|
144315
|
-
|
|
144559
|
+
const toolCount = registry.size;
|
|
144560
|
+
const systemPromptPrefix = `You are a Nestor AI agent \u2014 a proactive, resourceful assistant that NEVER gives up.
|
|
144561
|
+
|
|
144562
|
+
## Core Behavior Rules
|
|
144563
|
+
1. NEVER say "I can't do that" or "I don't have the ability to" \u2014 ALWAYS find a way using your tools
|
|
144564
|
+
2. NEVER ask for permission to use tools \u2014 just use them
|
|
144565
|
+
3. If one approach fails, try another approach immediately
|
|
144566
|
+
4. Break complex tasks into steps and execute them one by one
|
|
144567
|
+
5. When searching for information, use web_search first, then web_fetch to read specific pages
|
|
144568
|
+
6. When asked to do something on the system, use shell_exec and file_* tools
|
|
144569
|
+
7. When asked to manage the Nestor platform, use nestor_* tools
|
|
144570
|
+
8. Always show your work \u2014 explain what you're doing as you do it
|
|
144571
|
+
9. If you encounter an error, analyze it and try a different approach
|
|
144572
|
+
10. Complete tasks from 0% to 100% \u2014 don't stop halfway
|
|
144573
|
+
|
|
144574
|
+
## Problem-Solving Strategy
|
|
144575
|
+
- Need information? \u2192 web_search \u2192 web_fetch the best results
|
|
144576
|
+
- Need to install something? \u2192 shell_exec with npm/pip/apt/choco
|
|
144577
|
+
- Need to transform data? \u2192 shell_exec with built-in tools (jq, sed, awk, etc.) or write a script
|
|
144578
|
+
- Need to check something? \u2192 Use the right tool, don't guess
|
|
144579
|
+
- Something failed? \u2192 Read the error, fix it, try again. Never give up after one failure.
|
|
144580
|
+
- Don't know how? \u2192 web_search for the answer, then do it
|
|
144581
|
+
|
|
144582
|
+
## Available Tools (${toolCount} tools)
|
|
144583
|
+
|
|
144584
|
+
### Internet & Web
|
|
144585
|
+
- **web_search**: Search the internet (DuckDuckGo/Google/Bing). Use this FIRST for any information lookup.
|
|
144586
|
+
- **web_fetch**: Fetch and read a specific URL. Automatically converts HTML to readable text.
|
|
144587
|
+
|
|
144588
|
+
### System & Files
|
|
144589
|
+
- **shell_exec**: Execute shell commands. Use for builds, tests, git, installs, data processing, anything.
|
|
144590
|
+
- **file_read**: Read file contents.
|
|
144591
|
+
- **file_write**: Write/create files. Can append.
|
|
144592
|
+
- **file_list**: List directory contents.
|
|
144593
|
+
|
|
144594
|
+
### Nestor Platform
|
|
144595
|
+
- **nestor_create_agent**: Create new AI agents
|
|
144596
|
+
- **nestor_list_agents**: List all agents
|
|
144597
|
+
- **nestor_run_agent**: Run an agent with a prompt
|
|
144598
|
+
- **nestor_delete_agent**: Delete an agent
|
|
144599
|
+
- **nestor_create_workflow**: Create automation workflows
|
|
144600
|
+
- **nestor_list_workflows**: List all workflows
|
|
144601
|
+
- **nestor_search_memory**: Search stored knowledge
|
|
144602
|
+
- **nestor_store_memory**: Remember information for later
|
|
144603
|
+
- **nestor_list_skills**: List installed skills
|
|
144604
|
+
- **nestor_list_plans**: List execution plans
|
|
144605
|
+
- **nestor_list_guardrails / nestor_create_guardrail**: Manage safety rules
|
|
144606
|
+
- **nestor_system_info**: Check platform status
|
|
144607
|
+
- **nestor_read_config**: Read configuration
|
|
144608
|
+
|
|
144609
|
+
### Communication
|
|
144610
|
+
- **message_send**: Send messages to other agents
|
|
144611
|
+
- **message_read**: Read incoming messages
|
|
144612
|
+
- **handoff**: Hand off to human when truly stuck (last resort)
|
|
144613
|
+
|
|
144614
|
+
## Language
|
|
144615
|
+
Respond in the same language the user writes in. If they write in French, respond in French.
|
|
144616
|
+
If they write in English, respond in English.
|
|
144316
144617
|
`;
|
|
144317
144618
|
const agentDescription = agent.description || "You are a helpful AI assistant.";
|
|
144318
144619
|
const runtime = new AgentRuntime({
|
|
@@ -144516,10 +144817,384 @@ var init_providers = __esm({
|
|
|
144516
144817
|
}
|
|
144517
144818
|
});
|
|
144518
144819
|
|
|
144820
|
+
// ../server/src/services/key-vault.ts
|
|
144821
|
+
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes7, scryptSync as scryptSync2 } from "node:crypto";
|
|
144822
|
+
import { readFileSync as readFileSync16, writeFileSync as writeFileSync8, existsSync as existsSync11, mkdirSync as mkdirSync6 } from "node:fs";
|
|
144823
|
+
import { join as join17, dirname as dirname8 } from "node:path";
|
|
144824
|
+
import { homedir as homedir5 } from "node:os";
|
|
144825
|
+
function getVaultKey() {
|
|
144826
|
+
if (!existsSync11(KEY_FILE)) {
|
|
144827
|
+
const dir = dirname8(KEY_FILE);
|
|
144828
|
+
if (!existsSync11(dir)) {
|
|
144829
|
+
mkdirSync6(dir, { recursive: true });
|
|
144830
|
+
}
|
|
144831
|
+
const masterSecret = randomBytes7(32).toString("hex");
|
|
144832
|
+
writeFileSync8(KEY_FILE, masterSecret, { mode: 384 });
|
|
144833
|
+
}
|
|
144834
|
+
const secret = readFileSync16(KEY_FILE, "utf-8").trim();
|
|
144835
|
+
return scryptSync2(secret, "nestor-vault-salt", 32);
|
|
144836
|
+
}
|
|
144837
|
+
function encryptApiKey(plainKey) {
|
|
144838
|
+
const key = getVaultKey();
|
|
144839
|
+
const iv = randomBytes7(16);
|
|
144840
|
+
const cipher = createCipheriv2(ALGORITHM2, key, iv);
|
|
144841
|
+
let encrypted = cipher.update(plainKey, "utf8", "hex");
|
|
144842
|
+
encrypted += cipher.final("hex");
|
|
144843
|
+
const authTag = cipher.getAuthTag().toString("hex");
|
|
144844
|
+
return `${iv.toString("hex")}:${authTag}:${encrypted}`;
|
|
144845
|
+
}
|
|
144846
|
+
function decryptApiKey(encryptedStr) {
|
|
144847
|
+
const key = getVaultKey();
|
|
144848
|
+
const parts = encryptedStr.split(":");
|
|
144849
|
+
if (parts.length !== 3) {
|
|
144850
|
+
throw new Error("Invalid encrypted key format");
|
|
144851
|
+
}
|
|
144852
|
+
const [ivHex, authTagHex, encrypted] = parts;
|
|
144853
|
+
const iv = Buffer.from(ivHex, "hex");
|
|
144854
|
+
const authTag = Buffer.from(authTagHex, "hex");
|
|
144855
|
+
const decipher = createDecipheriv2(ALGORITHM2, key, iv);
|
|
144856
|
+
decipher.setAuthTag(authTag);
|
|
144857
|
+
let decrypted = decipher.update(encrypted, "hex", "utf8");
|
|
144858
|
+
decrypted += decipher.final("utf8");
|
|
144859
|
+
return decrypted;
|
|
144860
|
+
}
|
|
144861
|
+
function maskKey(key) {
|
|
144862
|
+
if (key.length <= 8) return "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
144863
|
+
return key.slice(0, 4) + "\u2022".repeat(Math.min(key.length - 8, 20)) + key.slice(-4);
|
|
144864
|
+
}
|
|
144865
|
+
function loadApiKeysIntoEnv(store, tenantId = "default") {
|
|
144866
|
+
try {
|
|
144867
|
+
if (!store.listApiKeysRaw) return;
|
|
144868
|
+
const keys = store.listApiKeysRaw(tenantId);
|
|
144869
|
+
for (const { provider, keyEncrypted } of keys) {
|
|
144870
|
+
const envVar = PROVIDER_ENV_MAP[provider];
|
|
144871
|
+
if (envVar && !process.env[envVar]) {
|
|
144872
|
+
try {
|
|
144873
|
+
process.env[envVar] = decryptApiKey(keyEncrypted);
|
|
144874
|
+
} catch {
|
|
144875
|
+
}
|
|
144876
|
+
}
|
|
144877
|
+
}
|
|
144878
|
+
} catch {
|
|
144879
|
+
}
|
|
144880
|
+
}
|
|
144881
|
+
var ALGORITHM2, KEY_FILE, PROVIDER_ENV_MAP;
|
|
144882
|
+
var init_key_vault = __esm({
|
|
144883
|
+
"../server/src/services/key-vault.ts"() {
|
|
144884
|
+
"use strict";
|
|
144885
|
+
ALGORITHM2 = "aes-256-gcm";
|
|
144886
|
+
KEY_FILE = join17(homedir5(), ".nestor", ".vault-key");
|
|
144887
|
+
PROVIDER_ENV_MAP = {
|
|
144888
|
+
claude: "ANTHROPIC_API_KEY",
|
|
144889
|
+
openai: "OPENAI_API_KEY",
|
|
144890
|
+
gemini: "GEMINI_API_KEY",
|
|
144891
|
+
grok: "XAI_API_KEY",
|
|
144892
|
+
mistral: "MISTRAL_API_KEY",
|
|
144893
|
+
ollama: ""
|
|
144894
|
+
// Ollama doesn't need an API key
|
|
144895
|
+
};
|
|
144896
|
+
}
|
|
144897
|
+
});
|
|
144898
|
+
|
|
144899
|
+
// ../server/src/routes/api-keys.ts
|
|
144900
|
+
import { Router as Router39 } from "express";
|
|
144901
|
+
function isValidProvider(p8) {
|
|
144902
|
+
return VALID_PROVIDERS.includes(p8);
|
|
144903
|
+
}
|
|
144904
|
+
async function testClaude(apiKey) {
|
|
144905
|
+
try {
|
|
144906
|
+
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
|
144907
|
+
method: "POST",
|
|
144908
|
+
headers: {
|
|
144909
|
+
"Content-Type": "application/json",
|
|
144910
|
+
"x-api-key": apiKey,
|
|
144911
|
+
"anthropic-version": "2023-06-01"
|
|
144912
|
+
},
|
|
144913
|
+
body: JSON.stringify({
|
|
144914
|
+
model: "claude-sonnet-4-20250514",
|
|
144915
|
+
max_tokens: 1,
|
|
144916
|
+
messages: [{ role: "user", content: "Hi" }]
|
|
144917
|
+
})
|
|
144918
|
+
});
|
|
144919
|
+
if (res.ok) {
|
|
144920
|
+
return { valid: true, message: "API key is valid. Claude is accessible." };
|
|
144921
|
+
}
|
|
144922
|
+
const body = await res.json().catch(() => ({}));
|
|
144923
|
+
const errMsg = body?.error?.message || res.statusText;
|
|
144924
|
+
if (res.status === 401) return { valid: false, message: `Invalid API key: ${errMsg}` };
|
|
144925
|
+
if (res.status === 429 || res.status === 400) {
|
|
144926
|
+
return { valid: true, message: `Key accepted (status ${res.status}: ${errMsg})` };
|
|
144927
|
+
}
|
|
144928
|
+
return { valid: false, message: `API error ${res.status}: ${errMsg}` };
|
|
144929
|
+
} catch (err) {
|
|
144930
|
+
return { valid: false, message: `Connection failed: ${err.message}` };
|
|
144931
|
+
}
|
|
144932
|
+
}
|
|
144933
|
+
async function testOpenAI(apiKey) {
|
|
144934
|
+
try {
|
|
144935
|
+
const res = await fetch("https://api.openai.com/v1/models", {
|
|
144936
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
144937
|
+
});
|
|
144938
|
+
if (res.ok) {
|
|
144939
|
+
const body = await res.json();
|
|
144940
|
+
const models = (body.data || []).slice(0, 10).map((m) => m.id);
|
|
144941
|
+
return { valid: true, message: "API key is valid.", models };
|
|
144942
|
+
}
|
|
144943
|
+
if (res.status === 401) return { valid: false, message: "Invalid API key." };
|
|
144944
|
+
return { valid: false, message: `API error ${res.status}: ${res.statusText}` };
|
|
144945
|
+
} catch (err) {
|
|
144946
|
+
return { valid: false, message: `Connection failed: ${err.message}` };
|
|
144947
|
+
}
|
|
144948
|
+
}
|
|
144949
|
+
async function testGemini(apiKey) {
|
|
144950
|
+
try {
|
|
144951
|
+
const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`);
|
|
144952
|
+
if (res.ok) {
|
|
144953
|
+
const body = await res.json();
|
|
144954
|
+
const models = (body.models || []).slice(0, 10).map((m) => m.name.replace("models/", ""));
|
|
144955
|
+
return { valid: true, message: "API key is valid.", models };
|
|
144956
|
+
}
|
|
144957
|
+
if (res.status === 400 || res.status === 403) {
|
|
144958
|
+
return { valid: false, message: "Invalid API key." };
|
|
144959
|
+
}
|
|
144960
|
+
return { valid: false, message: `API error ${res.status}: ${res.statusText}` };
|
|
144961
|
+
} catch (err) {
|
|
144962
|
+
return { valid: false, message: `Connection failed: ${err.message}` };
|
|
144963
|
+
}
|
|
144964
|
+
}
|
|
144965
|
+
async function testGrok(apiKey) {
|
|
144966
|
+
try {
|
|
144967
|
+
const res = await fetch("https://api.x.ai/v1/models", {
|
|
144968
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
144969
|
+
});
|
|
144970
|
+
if (res.ok) {
|
|
144971
|
+
const body = await res.json();
|
|
144972
|
+
const models = (body.data || []).slice(0, 10).map((m) => m.id);
|
|
144973
|
+
return { valid: true, message: "API key is valid.", models };
|
|
144974
|
+
}
|
|
144975
|
+
if (res.status === 401) return { valid: false, message: "Invalid API key." };
|
|
144976
|
+
return { valid: false, message: `API error ${res.status}: ${res.statusText}` };
|
|
144977
|
+
} catch (err) {
|
|
144978
|
+
return { valid: false, message: `Connection failed: ${err.message}` };
|
|
144979
|
+
}
|
|
144980
|
+
}
|
|
144981
|
+
async function testMistral(apiKey) {
|
|
144982
|
+
try {
|
|
144983
|
+
const res = await fetch("https://api.mistral.ai/v1/models", {
|
|
144984
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
144985
|
+
});
|
|
144986
|
+
if (res.ok) {
|
|
144987
|
+
const body = await res.json();
|
|
144988
|
+
const models = (body.data || []).slice(0, 10).map((m) => m.id);
|
|
144989
|
+
return { valid: true, message: "API key is valid.", models };
|
|
144990
|
+
}
|
|
144991
|
+
if (res.status === 401) return { valid: false, message: "Invalid API key." };
|
|
144992
|
+
return { valid: false, message: `API error ${res.status}: ${res.statusText}` };
|
|
144993
|
+
} catch (err) {
|
|
144994
|
+
return { valid: false, message: `Connection failed: ${err.message}` };
|
|
144995
|
+
}
|
|
144996
|
+
}
|
|
144997
|
+
async function testOllama() {
|
|
144998
|
+
const baseUrl = process.env.OLLAMA_BASE_URL || "http://localhost:11434";
|
|
144999
|
+
try {
|
|
145000
|
+
const res = await fetch(`${baseUrl}/api/tags`);
|
|
145001
|
+
if (res.ok) {
|
|
145002
|
+
const body = await res.json();
|
|
145003
|
+
const models = (body.models || []).map((m) => m.name);
|
|
145004
|
+
return { valid: true, message: `Ollama is running at ${baseUrl}.`, models };
|
|
145005
|
+
}
|
|
145006
|
+
return { valid: false, message: `Ollama returned ${res.status}: ${res.statusText}` };
|
|
145007
|
+
} catch (err) {
|
|
145008
|
+
return { valid: false, message: `Ollama not reachable at ${baseUrl}: ${err.message}` };
|
|
145009
|
+
}
|
|
145010
|
+
}
|
|
145011
|
+
function apiKeyRoutes(db) {
|
|
145012
|
+
const router = Router39();
|
|
145013
|
+
router.get("/", (req, res) => {
|
|
145014
|
+
const tenantId = req.tenantId || "default";
|
|
145015
|
+
const dbKeys = db.listProviderKeys(tenantId);
|
|
145016
|
+
const dbProviders = new Set(dbKeys.map((k) => k.provider));
|
|
145017
|
+
const result = [];
|
|
145018
|
+
for (const provider of VALID_PROVIDERS) {
|
|
145019
|
+
const envVar = PROVIDER_ENV_MAP[provider];
|
|
145020
|
+
const dbEntry = dbKeys.find((k) => k.provider === provider);
|
|
145021
|
+
if (dbEntry) {
|
|
145022
|
+
try {
|
|
145023
|
+
const encrypted = db.getApiKey(provider, tenantId);
|
|
145024
|
+
const decrypted = encrypted ? decryptApiKey(encrypted) : "";
|
|
145025
|
+
result.push({
|
|
145026
|
+
provider,
|
|
145027
|
+
configured: true,
|
|
145028
|
+
source: "db",
|
|
145029
|
+
maskedKey: decrypted ? maskKey(decrypted) : null,
|
|
145030
|
+
label: dbEntry.label,
|
|
145031
|
+
createdAt: dbEntry.createdAt,
|
|
145032
|
+
updatedAt: dbEntry.updatedAt
|
|
145033
|
+
});
|
|
145034
|
+
} catch {
|
|
145035
|
+
result.push({
|
|
145036
|
+
provider,
|
|
145037
|
+
configured: true,
|
|
145038
|
+
source: "db",
|
|
145039
|
+
maskedKey: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
145040
|
+
label: dbEntry.label,
|
|
145041
|
+
createdAt: dbEntry.createdAt,
|
|
145042
|
+
updatedAt: dbEntry.updatedAt
|
|
145043
|
+
});
|
|
145044
|
+
}
|
|
145045
|
+
} else if (envVar && process.env[envVar]) {
|
|
145046
|
+
result.push({
|
|
145047
|
+
provider,
|
|
145048
|
+
configured: true,
|
|
145049
|
+
source: "env",
|
|
145050
|
+
maskedKey: maskKey(process.env[envVar]),
|
|
145051
|
+
label: "From environment variable",
|
|
145052
|
+
createdAt: null,
|
|
145053
|
+
updatedAt: null
|
|
145054
|
+
});
|
|
145055
|
+
} else if (provider === "ollama") {
|
|
145056
|
+
result.push({
|
|
145057
|
+
provider,
|
|
145058
|
+
configured: true,
|
|
145059
|
+
source: "none",
|
|
145060
|
+
maskedKey: null,
|
|
145061
|
+
label: "Local \u2014 no key required",
|
|
145062
|
+
createdAt: null,
|
|
145063
|
+
updatedAt: null
|
|
145064
|
+
});
|
|
145065
|
+
} else {
|
|
145066
|
+
result.push({
|
|
145067
|
+
provider,
|
|
145068
|
+
configured: false,
|
|
145069
|
+
source: "none",
|
|
145070
|
+
maskedKey: null,
|
|
145071
|
+
label: "",
|
|
145072
|
+
createdAt: null,
|
|
145073
|
+
updatedAt: null
|
|
145074
|
+
});
|
|
145075
|
+
}
|
|
145076
|
+
}
|
|
145077
|
+
res.json({ data: result });
|
|
145078
|
+
});
|
|
145079
|
+
router.post("/", (req, res) => {
|
|
145080
|
+
const tenantId = req.tenantId || "default";
|
|
145081
|
+
const { provider, key, label } = req.body;
|
|
145082
|
+
if (!provider || !isValidProvider(provider)) {
|
|
145083
|
+
res.status(400).json({
|
|
145084
|
+
error: { code: "INVALID_PROVIDER", message: `Provider must be one of: ${VALID_PROVIDERS.join(", ")}` }
|
|
145085
|
+
});
|
|
145086
|
+
return;
|
|
145087
|
+
}
|
|
145088
|
+
if (!key || typeof key !== "string" || key.trim().length === 0) {
|
|
145089
|
+
res.status(400).json({
|
|
145090
|
+
error: { code: "INVALID_KEY", message: "API key is required and must be a non-empty string." }
|
|
145091
|
+
});
|
|
145092
|
+
return;
|
|
145093
|
+
}
|
|
145094
|
+
const encrypted = encryptApiKey(key.trim());
|
|
145095
|
+
db.setApiKey(provider, encrypted, tenantId, label || "");
|
|
145096
|
+
const envVar = PROVIDER_ENV_MAP[provider];
|
|
145097
|
+
if (envVar) {
|
|
145098
|
+
process.env[envVar] = key.trim();
|
|
145099
|
+
}
|
|
145100
|
+
res.json({
|
|
145101
|
+
data: {
|
|
145102
|
+
provider,
|
|
145103
|
+
configured: true,
|
|
145104
|
+
source: "db",
|
|
145105
|
+
maskedKey: maskKey(key.trim()),
|
|
145106
|
+
label: label || ""
|
|
145107
|
+
},
|
|
145108
|
+
message: `API key for ${provider} saved successfully.`
|
|
145109
|
+
});
|
|
145110
|
+
});
|
|
145111
|
+
router.delete("/:provider", (req, res) => {
|
|
145112
|
+
const tenantId = req.tenantId || "default";
|
|
145113
|
+
const { provider } = req.params;
|
|
145114
|
+
if (!isValidProvider(provider)) {
|
|
145115
|
+
res.status(400).json({
|
|
145116
|
+
error: { code: "INVALID_PROVIDER", message: `Provider must be one of: ${VALID_PROVIDERS.join(", ")}` }
|
|
145117
|
+
});
|
|
145118
|
+
return;
|
|
145119
|
+
}
|
|
145120
|
+
const deleted = db.deleteProviderKey(provider, tenantId);
|
|
145121
|
+
const envVar = PROVIDER_ENV_MAP[provider];
|
|
145122
|
+
if (envVar) {
|
|
145123
|
+
delete process.env[envVar];
|
|
145124
|
+
}
|
|
145125
|
+
if (deleted) {
|
|
145126
|
+
res.json({ message: `API key for ${provider} removed.` });
|
|
145127
|
+
} else {
|
|
145128
|
+
res.status(404).json({
|
|
145129
|
+
error: { code: "NOT_FOUND", message: `No API key found for provider: ${provider}` }
|
|
145130
|
+
});
|
|
145131
|
+
}
|
|
145132
|
+
});
|
|
145133
|
+
router.get("/test/:provider", async (req, res) => {
|
|
145134
|
+
const tenantId = req.tenantId || "default";
|
|
145135
|
+
const { provider } = req.params;
|
|
145136
|
+
if (!isValidProvider(provider)) {
|
|
145137
|
+
res.status(400).json({
|
|
145138
|
+
error: { code: "INVALID_PROVIDER", message: `Provider must be one of: ${VALID_PROVIDERS.join(", ")}` }
|
|
145139
|
+
});
|
|
145140
|
+
return;
|
|
145141
|
+
}
|
|
145142
|
+
let apiKey = null;
|
|
145143
|
+
const encrypted = db.getApiKey(provider, tenantId);
|
|
145144
|
+
if (encrypted) {
|
|
145145
|
+
try {
|
|
145146
|
+
apiKey = decryptApiKey(encrypted);
|
|
145147
|
+
} catch {
|
|
145148
|
+
}
|
|
145149
|
+
}
|
|
145150
|
+
if (!apiKey) {
|
|
145151
|
+
const envVar = PROVIDER_ENV_MAP[provider];
|
|
145152
|
+
if (envVar && process.env[envVar]) {
|
|
145153
|
+
apiKey = process.env[envVar];
|
|
145154
|
+
}
|
|
145155
|
+
}
|
|
145156
|
+
if (provider === "ollama") {
|
|
145157
|
+
apiKey = "";
|
|
145158
|
+
}
|
|
145159
|
+
if (apiKey === null) {
|
|
145160
|
+
res.json({
|
|
145161
|
+
data: { valid: false, message: "No API key configured for this provider." }
|
|
145162
|
+
});
|
|
145163
|
+
return;
|
|
145164
|
+
}
|
|
145165
|
+
try {
|
|
145166
|
+
const testFn = TEST_FUNCTIONS[provider];
|
|
145167
|
+
const result = await testFn(apiKey);
|
|
145168
|
+
res.json({ data: result });
|
|
145169
|
+
} catch (err) {
|
|
145170
|
+
res.json({
|
|
145171
|
+
data: { valid: false, message: `Test failed: ${err.message}` }
|
|
145172
|
+
});
|
|
145173
|
+
}
|
|
145174
|
+
});
|
|
145175
|
+
return router;
|
|
145176
|
+
}
|
|
145177
|
+
var VALID_PROVIDERS, TEST_FUNCTIONS;
|
|
145178
|
+
var init_api_keys = __esm({
|
|
145179
|
+
"../server/src/routes/api-keys.ts"() {
|
|
145180
|
+
"use strict";
|
|
145181
|
+
init_key_vault();
|
|
145182
|
+
VALID_PROVIDERS = ["claude", "openai", "gemini", "grok", "mistral", "ollama"];
|
|
145183
|
+
TEST_FUNCTIONS = {
|
|
145184
|
+
claude: testClaude,
|
|
145185
|
+
openai: testOpenAI,
|
|
145186
|
+
gemini: testGemini,
|
|
145187
|
+
grok: testGrok,
|
|
145188
|
+
mistral: testMistral,
|
|
145189
|
+
ollama: () => testOllama()
|
|
145190
|
+
};
|
|
145191
|
+
}
|
|
145192
|
+
});
|
|
145193
|
+
|
|
144519
145194
|
// ../server/src/app.ts
|
|
144520
145195
|
import express from "express";
|
|
144521
|
-
import { resolve as resolve13, join as
|
|
144522
|
-
import { existsSync as
|
|
145196
|
+
import { resolve as resolve13, join as join18 } from "node:path";
|
|
145197
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
144523
145198
|
import compression from "compression";
|
|
144524
145199
|
import cors from "cors";
|
|
144525
145200
|
function getStudioState() {
|
|
@@ -144539,6 +145214,10 @@ function createApp(config2) {
|
|
|
144539
145214
|
const anomalyDetector = new AnomalyDetector();
|
|
144540
145215
|
const incidentResponder = new IncidentResponder(config2.db, anomalyDetector, auditLogger);
|
|
144541
145216
|
const securityCtx = { anomalyDetector, auditLogger, incidentResponder };
|
|
145217
|
+
try {
|
|
145218
|
+
loadApiKeysIntoEnv(config2.db);
|
|
145219
|
+
} catch {
|
|
145220
|
+
}
|
|
144542
145221
|
const corsOrigins = config2.corsConfig?.allowedOrigins ?? [];
|
|
144543
145222
|
const corsOptions = {
|
|
144544
145223
|
origin: (origin, callback) => {
|
|
@@ -144673,6 +145352,7 @@ function createApp(config2) {
|
|
|
144673
145352
|
app.use("/api/execution", executionRoutes(authService));
|
|
144674
145353
|
app.use("/api/chat", chatRoutes(config2.db));
|
|
144675
145354
|
app.use("/api/providers", providerRoutes());
|
|
145355
|
+
app.use("/api/keys", apiKeyRoutes(config2.db));
|
|
144676
145356
|
app.use("/api/audit", auditRoutes(config2.db));
|
|
144677
145357
|
app.use("/api/admin", adminMiddleware(config2.apiKey), adminRoutes(config2.db));
|
|
144678
145358
|
app.get("/api/docs/openapi.json", (_req, res) => {
|
|
@@ -144738,7 +145418,7 @@ function createApp(config2) {
|
|
|
144738
145418
|
}
|
|
144739
145419
|
for (const dir of candidateDirs) {
|
|
144740
145420
|
try {
|
|
144741
|
-
if (
|
|
145421
|
+
if (existsSync12(join18(dir, "index.html"))) {
|
|
144742
145422
|
studioDistDir = dir;
|
|
144743
145423
|
break;
|
|
144744
145424
|
}
|
|
@@ -144762,7 +145442,7 @@ function createApp(config2) {
|
|
|
144762
145442
|
if (!studioState.enabled) {
|
|
144763
145443
|
return res.status(403).json({ error: { code: "STUDIO_DISABLED", message: "Studio is disabled." } });
|
|
144764
145444
|
}
|
|
144765
|
-
res.sendFile(
|
|
145445
|
+
res.sendFile(join18(studioDistDir, "index.html"));
|
|
144766
145446
|
});
|
|
144767
145447
|
app.use("/studio", express.static(studioDistDir, { index: false }));
|
|
144768
145448
|
app.use(express.static(studioDistDir, { index: false }));
|
|
@@ -144770,7 +145450,7 @@ function createApp(config2) {
|
|
|
144770
145450
|
if (!studioState.enabled) {
|
|
144771
145451
|
return res.status(403).json({ error: { code: "STUDIO_DISABLED", message: "Studio is disabled." } });
|
|
144772
145452
|
}
|
|
144773
|
-
res.sendFile(
|
|
145453
|
+
res.sendFile(join18(studioDistDir, "index.html"));
|
|
144774
145454
|
});
|
|
144775
145455
|
} else {
|
|
144776
145456
|
app.get("/studio", (_req, res) => {
|
|
@@ -144798,7 +145478,7 @@ function createApp(config2) {
|
|
|
144798
145478
|
if (!studioState.enabled) {
|
|
144799
145479
|
return res.status(403).json({ error: { code: "STUDIO_DISABLED", message: "Studio is disabled." } });
|
|
144800
145480
|
}
|
|
144801
|
-
res.sendFile(
|
|
145481
|
+
res.sendFile(join18(studioDistDir, "index.html"));
|
|
144802
145482
|
});
|
|
144803
145483
|
}
|
|
144804
145484
|
app.use(errorHandler());
|
|
@@ -144865,12 +145545,14 @@ var init_app = __esm({
|
|
|
144865
145545
|
init_knowledge2();
|
|
144866
145546
|
init_chat();
|
|
144867
145547
|
init_providers();
|
|
145548
|
+
init_api_keys();
|
|
145549
|
+
init_key_vault();
|
|
144868
145550
|
studioState = { enabled: true };
|
|
144869
145551
|
}
|
|
144870
145552
|
});
|
|
144871
145553
|
|
|
144872
145554
|
// ../server/src/services/config-watcher.ts
|
|
144873
|
-
import { watch, existsSync as
|
|
145555
|
+
import { watch, existsSync as existsSync13 } from "node:fs";
|
|
144874
145556
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
144875
145557
|
var ConfigWatcher;
|
|
144876
145558
|
var init_config_watcher = __esm({
|
|
@@ -144894,7 +145576,7 @@ var init_config_watcher = __esm({
|
|
|
144894
145576
|
*/
|
|
144895
145577
|
async start() {
|
|
144896
145578
|
await this.reload();
|
|
144897
|
-
if (
|
|
145579
|
+
if (existsSync13(this.configPath)) {
|
|
144898
145580
|
this.watcher = watch(this.configPath, { persistent: false }, (eventType) => {
|
|
144899
145581
|
if (eventType === "change") {
|
|
144900
145582
|
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
@@ -144930,7 +145612,7 @@ var init_config_watcher = __esm({
|
|
|
144930
145612
|
// ─── Internal ───────────────────────────────────────────────────────
|
|
144931
145613
|
async reload() {
|
|
144932
145614
|
try {
|
|
144933
|
-
if (!
|
|
145615
|
+
if (!existsSync13(this.configPath)) {
|
|
144934
145616
|
console.warn("[config-watcher] Config file not found, keeping current config.");
|
|
144935
145617
|
return;
|
|
144936
145618
|
}
|
|
@@ -144974,9 +145656,9 @@ __export(telemetry_exports, {
|
|
|
144974
145656
|
resetTelemetry: () => resetTelemetry
|
|
144975
145657
|
});
|
|
144976
145658
|
import { randomUUID as randomUUID35 } from "node:crypto";
|
|
144977
|
-
import { existsSync as
|
|
144978
|
-
import { join as
|
|
144979
|
-
import { homedir as
|
|
145659
|
+
import { existsSync as existsSync14, readFileSync as readFileSync17, writeFileSync as writeFileSync9, appendFileSync as appendFileSync2, mkdirSync as mkdirSync7 } from "node:fs";
|
|
145660
|
+
import { join as join19 } from "node:path";
|
|
145661
|
+
import { homedir as homedir6 } from "node:os";
|
|
144980
145662
|
function getTelemetry(config2) {
|
|
144981
145663
|
if (!_instance2) {
|
|
144982
145664
|
_instance2 = new TelemetryService(config2 ?? { enabled: false, flushIntervalMs: 6e4 });
|
|
@@ -144991,9 +145673,9 @@ var init_telemetry2 = __esm({
|
|
|
144991
145673
|
"../server/src/services/telemetry.ts"() {
|
|
144992
145674
|
"use strict";
|
|
144993
145675
|
VERSION2 = "0.1.0";
|
|
144994
|
-
DATA_DIR3 =
|
|
144995
|
-
TELEMETRY_ID_FILE =
|
|
144996
|
-
TELEMETRY_LOG_FILE =
|
|
145676
|
+
DATA_DIR3 = join19(homedir6(), ".nestor");
|
|
145677
|
+
TELEMETRY_ID_FILE = join19(DATA_DIR3, "telemetry-id");
|
|
145678
|
+
TELEMETRY_LOG_FILE = join19(DATA_DIR3, "telemetry.jsonl");
|
|
144997
145679
|
DEFAULT_FLUSH_THRESHOLD = 10;
|
|
144998
145680
|
TelemetryService = class {
|
|
144999
145681
|
enabled;
|
|
@@ -145086,8 +145768,8 @@ var init_telemetry2 = __esm({
|
|
|
145086
145768
|
// ─── Private ─────────────────────────────────────────────────────────
|
|
145087
145769
|
getOrCreateInstallId() {
|
|
145088
145770
|
try {
|
|
145089
|
-
if (
|
|
145090
|
-
const id =
|
|
145771
|
+
if (existsSync14(TELEMETRY_ID_FILE)) {
|
|
145772
|
+
const id = readFileSync17(TELEMETRY_ID_FILE, "utf-8").trim();
|
|
145091
145773
|
if (id.length > 0) return id;
|
|
145092
145774
|
}
|
|
145093
145775
|
} catch {
|
|
@@ -145095,14 +145777,14 @@ var init_telemetry2 = __esm({
|
|
|
145095
145777
|
const newId = randomUUID35();
|
|
145096
145778
|
try {
|
|
145097
145779
|
this.ensureDataDir();
|
|
145098
|
-
|
|
145780
|
+
writeFileSync9(TELEMETRY_ID_FILE, newId + "\n", "utf-8");
|
|
145099
145781
|
} catch {
|
|
145100
145782
|
}
|
|
145101
145783
|
return newId;
|
|
145102
145784
|
}
|
|
145103
145785
|
ensureDataDir() {
|
|
145104
|
-
if (!
|
|
145105
|
-
|
|
145786
|
+
if (!existsSync14(DATA_DIR3)) {
|
|
145787
|
+
mkdirSync7(DATA_DIR3, { recursive: true });
|
|
145106
145788
|
}
|
|
145107
145789
|
}
|
|
145108
145790
|
startFlushTimer() {
|
|
@@ -156688,7 +157370,7 @@ var require_dist12 = __commonJS({
|
|
|
156688
157370
|
});
|
|
156689
157371
|
|
|
156690
157372
|
// ../skill-tester/src/yaml-loader.ts
|
|
156691
|
-
import { readFileSync as
|
|
157373
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
156692
157374
|
function parseYamlContent(content) {
|
|
156693
157375
|
try {
|
|
156694
157376
|
return JSON.parse(content);
|
|
@@ -156804,7 +157486,7 @@ var init_yaml_loader = __esm({
|
|
|
156804
157486
|
* Load a YAML test suite from a file path.
|
|
156805
157487
|
*/
|
|
156806
157488
|
static loadFile(filePath) {
|
|
156807
|
-
const content =
|
|
157489
|
+
const content = readFileSync18(filePath, "utf-8");
|
|
156808
157490
|
return _YamlTestLoader.parse(content);
|
|
156809
157491
|
}
|
|
156810
157492
|
/**
|
|
@@ -156883,8 +157565,8 @@ var init_yaml_loader = __esm({
|
|
|
156883
157565
|
});
|
|
156884
157566
|
|
|
156885
157567
|
// ../skill-tester/src/runner.ts
|
|
156886
|
-
import { readFileSync as
|
|
156887
|
-
import { join as
|
|
157568
|
+
import { readFileSync as readFileSync19, readdirSync as readdirSync4, statSync as statSync5, existsSync as existsSync16, mkdirSync as mkdirSync9, rmSync as rmSync2 } from "node:fs";
|
|
157569
|
+
import { join as join21, resolve as resolve14 } from "node:path";
|
|
156888
157570
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
156889
157571
|
import { randomUUID as randomUUID37 } from "node:crypto";
|
|
156890
157572
|
var SequentialMockAdapter, SkillTestRunner;
|
|
@@ -156959,25 +157641,25 @@ var init_runner2 = __esm({
|
|
|
156959
157641
|
try {
|
|
156960
157642
|
const mockResponses = test.mockResponses.length > 0 ? test.mockResponses : [{ content: "Test completed." }];
|
|
156961
157643
|
const adapter = new SequentialMockAdapter(mockResponses);
|
|
156962
|
-
const tempDir =
|
|
156963
|
-
|
|
157644
|
+
const tempDir = join21(tmpdir4(), `nestor-skill-test-${randomUUID37()}`);
|
|
157645
|
+
mkdirSync9(tempDir, { recursive: true });
|
|
156964
157646
|
try {
|
|
156965
157647
|
const agentModule = await Promise.resolve().then(() => (init_src5(), src_exports3));
|
|
156966
157648
|
const events = new agentModule.RuntimeEventBus();
|
|
156967
157649
|
const tools = new agentModule.ToolRegistry();
|
|
156968
157650
|
const toolExecutor = new agentModule.ToolExecutor();
|
|
156969
157651
|
let instructions = "You are a helpful AI assistant.";
|
|
156970
|
-
if (test.skill &&
|
|
156971
|
-
instructions =
|
|
157652
|
+
if (test.skill && existsSync16(test.skill)) {
|
|
157653
|
+
instructions = readFileSync19(test.skill, "utf-8");
|
|
156972
157654
|
} else if (test.skill) {
|
|
156973
157655
|
const skillPaths = [
|
|
156974
|
-
|
|
156975
|
-
|
|
156976
|
-
|
|
157656
|
+
join21(process.cwd(), ".nestor", "skills", test.skill, "SKILL.md"),
|
|
157657
|
+
join21(process.cwd(), "skills", test.skill, "SKILL.md"),
|
|
157658
|
+
join21(process.cwd(), "skills-registry", test.skill, "SKILL.md")
|
|
156977
157659
|
];
|
|
156978
157660
|
for (const p8 of skillPaths) {
|
|
156979
|
-
if (
|
|
156980
|
-
instructions =
|
|
157661
|
+
if (existsSync16(p8)) {
|
|
157662
|
+
instructions = readFileSync19(p8, "utf-8");
|
|
156981
157663
|
break;
|
|
156982
157664
|
}
|
|
156983
157665
|
}
|
|
@@ -157187,7 +157869,7 @@ var init_runner2 = __esm({
|
|
|
157187
157869
|
discoverTestFiles(dir) {
|
|
157188
157870
|
const files = [];
|
|
157189
157871
|
const resolvedDir = resolve14(dir);
|
|
157190
|
-
if (!
|
|
157872
|
+
if (!existsSync16(resolvedDir)) return files;
|
|
157191
157873
|
const stat = statSync5(resolvedDir);
|
|
157192
157874
|
if (!stat.isDirectory()) {
|
|
157193
157875
|
return [resolvedDir];
|
|
@@ -157201,7 +157883,7 @@ var init_runner2 = __esm({
|
|
|
157201
157883
|
}
|
|
157202
157884
|
for (const entry of entries) {
|
|
157203
157885
|
if (entry === "node_modules" || entry === ".git" || entry === "dist") continue;
|
|
157204
|
-
const fullPath =
|
|
157886
|
+
const fullPath = join21(current, entry);
|
|
157205
157887
|
try {
|
|
157206
157888
|
const s = statSync5(fullPath);
|
|
157207
157889
|
if (s.isDirectory()) {
|
|
@@ -159071,7 +159753,7 @@ var init_server = __esm({
|
|
|
159071
159753
|
MCP_PROTOCOL_VERSION = "2024-11-05";
|
|
159072
159754
|
SERVER_INFO = {
|
|
159073
159755
|
name: "nestor",
|
|
159074
|
-
version: "2.1.
|
|
159756
|
+
version: "2.1.1"
|
|
159075
159757
|
};
|
|
159076
159758
|
SERVER_CAPABILITIES = {
|
|
159077
159759
|
tools: { listChanged: false },
|
|
@@ -159257,9 +159939,9 @@ __export(shell_exports, {
|
|
|
159257
159939
|
registerShellCommand: () => registerShellCommand
|
|
159258
159940
|
});
|
|
159259
159941
|
import * as readline3 from "node:readline";
|
|
159260
|
-
import { existsSync as
|
|
159261
|
-
import { join as
|
|
159262
|
-
import { homedir as
|
|
159942
|
+
import { existsSync as existsSync17, readFileSync as readFileSync20, writeFileSync as writeFileSync11, mkdirSync as mkdirSync10, appendFileSync as appendFileSync3 } from "node:fs";
|
|
159943
|
+
import { join as join22, resolve as resolve15, dirname as dirname10, basename as basename4 } from "node:path";
|
|
159944
|
+
import { homedir as homedir7 } from "node:os";
|
|
159263
159945
|
import { readdirSync as readdirSync5 } from "node:fs";
|
|
159264
159946
|
import { randomUUID as randomUUID43 } from "node:crypto";
|
|
159265
159947
|
import chalk11 from "chalk";
|
|
@@ -159291,8 +159973,8 @@ async function startShell() {
|
|
|
159291
159973
|
currentRouter: null,
|
|
159292
159974
|
verbose: false
|
|
159293
159975
|
};
|
|
159294
|
-
if (!
|
|
159295
|
-
|
|
159976
|
+
if (!existsSync17(NESTOR_DIR)) {
|
|
159977
|
+
mkdirSync10(NESTOR_DIR, { recursive: true });
|
|
159296
159978
|
}
|
|
159297
159979
|
refreshAgentNameCache(session);
|
|
159298
159980
|
const history = loadHistory();
|
|
@@ -160012,8 +160694,8 @@ function cmdExport(args2, session) {
|
|
|
160012
160694
|
timestamp: new Date(e.timestamp).toISOString()
|
|
160013
160695
|
}))
|
|
160014
160696
|
};
|
|
160015
|
-
const filename =
|
|
160016
|
-
|
|
160697
|
+
const filename = join22(NESTOR_DIR, `conversation-${timestamp}.json`);
|
|
160698
|
+
writeFileSync11(filename, JSON.stringify(data, null, 2), "utf-8");
|
|
160017
160699
|
console.log(chalk11.green(`Exported to: ${filename}`));
|
|
160018
160700
|
return;
|
|
160019
160701
|
}
|
|
@@ -160037,8 +160719,8 @@ function cmdExport(args2, session) {
|
|
|
160037
160719
|
lines.push(entry.content);
|
|
160038
160720
|
lines.push("");
|
|
160039
160721
|
}
|
|
160040
|
-
const filename =
|
|
160041
|
-
|
|
160722
|
+
const filename = join22(NESTOR_DIR, `conversation-${timestamp}.md`);
|
|
160723
|
+
writeFileSync11(filename, lines.join("\n"), "utf-8");
|
|
160042
160724
|
console.log(chalk11.green(`Exported to: ${filename}`));
|
|
160043
160725
|
return;
|
|
160044
160726
|
}
|
|
@@ -160074,8 +160756,8 @@ ${rows}
|
|
|
160074
160756
|
<div class="stats">Tokens: ${fmtNum(session.totalTokensIn)} in / ${fmtNum(session.totalTokensOut)} out | Cost: $${session.totalCostUsd.toFixed(4)} | Tool calls: ${session.totalToolCalls}</div>
|
|
160075
160757
|
</body>
|
|
160076
160758
|
</html>`;
|
|
160077
|
-
const filename =
|
|
160078
|
-
|
|
160759
|
+
const filename = join22(NESTOR_DIR, `conversation-${timestamp}.html`);
|
|
160760
|
+
writeFileSync11(filename, html, "utf-8");
|
|
160079
160761
|
console.log(chalk11.green(`Exported to: ${filename}`));
|
|
160080
160762
|
}
|
|
160081
160763
|
}
|
|
@@ -160580,7 +161262,7 @@ function createUnifiedDiff(oldText, newText, fileName) {
|
|
|
160580
161262
|
function showDiffForStep(filePath, newContent) {
|
|
160581
161263
|
try {
|
|
160582
161264
|
const absolutePath = resolve15(process.cwd(), filePath);
|
|
160583
|
-
const oldContent =
|
|
161265
|
+
const oldContent = readFileSync20(absolutePath, "utf-8");
|
|
160584
161266
|
const diff = createUnifiedDiff(oldContent, newContent, filePath);
|
|
160585
161267
|
for (const line of diff.split("\n")) {
|
|
160586
161268
|
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
@@ -160986,11 +161668,11 @@ function completeFilePath(partial) {
|
|
|
160986
161668
|
dir = resolved;
|
|
160987
161669
|
prefix = partial.endsWith("/") || partial.endsWith("\\") ? partial : partial + "/";
|
|
160988
161670
|
} else {
|
|
160989
|
-
dir =
|
|
161671
|
+
dir = dirname10(resolved);
|
|
160990
161672
|
prefix = partial.substring(0, partial.lastIndexOf("/") + 1) || partial.substring(0, partial.lastIndexOf("\\") + 1);
|
|
160991
161673
|
}
|
|
160992
161674
|
} catch {
|
|
160993
|
-
dir =
|
|
161675
|
+
dir = dirname10(resolved);
|
|
160994
161676
|
prefix = partial.substring(0, Math.max(partial.lastIndexOf("/"), partial.lastIndexOf("\\")) + 1);
|
|
160995
161677
|
}
|
|
160996
161678
|
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
@@ -161024,8 +161706,8 @@ function refreshAgentNameCache(session) {
|
|
|
161024
161706
|
}
|
|
161025
161707
|
function loadHistory() {
|
|
161026
161708
|
try {
|
|
161027
|
-
if (
|
|
161028
|
-
const raw =
|
|
161709
|
+
if (existsSync17(HISTORY_FILE)) {
|
|
161710
|
+
const raw = readFileSync20(HISTORY_FILE, "utf-8");
|
|
161029
161711
|
return raw.split("\n").filter((l) => l.trim().length > 0).slice(-MAX_HISTORY);
|
|
161030
161712
|
}
|
|
161031
161713
|
} catch {
|
|
@@ -161036,8 +161718,8 @@ function saveHistory(rl) {
|
|
|
161036
161718
|
}
|
|
161037
161719
|
function appendToHistoryFile(line) {
|
|
161038
161720
|
try {
|
|
161039
|
-
if (!
|
|
161040
|
-
|
|
161721
|
+
if (!existsSync17(NESTOR_DIR)) {
|
|
161722
|
+
mkdirSync10(NESTOR_DIR, { recursive: true });
|
|
161041
161723
|
}
|
|
161042
161724
|
appendFileSync3(HISTORY_FILE, line + "\n", "utf-8");
|
|
161043
161725
|
} catch {
|
|
@@ -161379,8 +162061,8 @@ var init_shell = __esm({
|
|
|
161379
162061
|
init_config2();
|
|
161380
162062
|
init_spinner();
|
|
161381
162063
|
init_table();
|
|
161382
|
-
NESTOR_DIR =
|
|
161383
|
-
HISTORY_FILE =
|
|
162064
|
+
NESTOR_DIR = join22(homedir7(), ".nestor");
|
|
162065
|
+
HISTORY_FILE = join22(NESTOR_DIR, "shell_history");
|
|
161384
162066
|
MAX_HISTORY = 1e3;
|
|
161385
162067
|
SLASH_COMMANDS = {
|
|
161386
162068
|
"/help": { description: "Show all commands", usage: "/help" },
|
|
@@ -161432,9 +162114,9 @@ var init_shell = __esm({
|
|
|
161432
162114
|
|
|
161433
162115
|
// src/index.ts
|
|
161434
162116
|
import { Command } from "commander";
|
|
161435
|
-
import { existsSync as
|
|
161436
|
-
import { join as
|
|
161437
|
-
import { homedir as
|
|
162117
|
+
import { existsSync as existsSync21, readFileSync as readFileSync24 } from "node:fs";
|
|
162118
|
+
import { join as join25 } from "node:path";
|
|
162119
|
+
import { homedir as homedir10 } from "node:os";
|
|
161438
162120
|
|
|
161439
162121
|
// src/commands/start.ts
|
|
161440
162122
|
init_config2();
|
|
@@ -161578,16 +162260,16 @@ init_config();
|
|
|
161578
162260
|
init_config2();
|
|
161579
162261
|
import * as p from "@clack/prompts";
|
|
161580
162262
|
import chalk2 from "chalk";
|
|
161581
|
-
import { mkdirSync as
|
|
161582
|
-
import { join as
|
|
161583
|
-
import { randomBytes as
|
|
162263
|
+
import { mkdirSync as mkdirSync8, existsSync as existsSync15 } from "node:fs";
|
|
162264
|
+
import { join as join20 } from "node:path";
|
|
162265
|
+
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
161584
162266
|
function generateApiKey() {
|
|
161585
|
-
return `nst_${
|
|
162267
|
+
return `nst_${randomBytes8(32).toString("hex")}`;
|
|
161586
162268
|
}
|
|
161587
162269
|
function randomSegment() {
|
|
161588
162270
|
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
161589
162271
|
let result = "";
|
|
161590
|
-
const bytes =
|
|
162272
|
+
const bytes = randomBytes8(4);
|
|
161591
162273
|
for (let i = 0; i < 4; i++) {
|
|
161592
162274
|
result += chars[bytes[i] % chars.length];
|
|
161593
162275
|
}
|
|
@@ -161598,7 +162280,7 @@ function generateBetaKey() {
|
|
|
161598
162280
|
}
|
|
161599
162281
|
async function initializeDatabase(dataDir) {
|
|
161600
162282
|
const { NestorStore: NestorStore2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
|
|
161601
|
-
const dbPath =
|
|
162283
|
+
const dbPath = join20(dataDir, "nestor.db");
|
|
161602
162284
|
const store = await NestorStore2.open(dbPath);
|
|
161603
162285
|
store.close();
|
|
161604
162286
|
}
|
|
@@ -161646,31 +162328,31 @@ async function runNonInteractiveInstall() {
|
|
|
161646
162328
|
console.log();
|
|
161647
162329
|
const config2 = buildConfigFromDefaults();
|
|
161648
162330
|
const dataDir = expandPath(config2.server.dataDir);
|
|
161649
|
-
if (!
|
|
161650
|
-
|
|
162331
|
+
if (!existsSync15(dataDir)) {
|
|
162332
|
+
mkdirSync8(dataDir, { recursive: true });
|
|
161651
162333
|
console.log(chalk2.green(" Created data directory:"), dataDir);
|
|
161652
162334
|
}
|
|
161653
162335
|
for (const sub of ["adapters", "skills", "plugins", "logs"]) {
|
|
161654
|
-
const subDir =
|
|
161655
|
-
if (!
|
|
161656
|
-
|
|
162336
|
+
const subDir = join20(dataDir, sub);
|
|
162337
|
+
if (!existsSync15(subDir)) {
|
|
162338
|
+
mkdirSync8(subDir, { recursive: true });
|
|
161657
162339
|
}
|
|
161658
162340
|
}
|
|
161659
162341
|
writeConfigFile(config2);
|
|
161660
162342
|
console.log(chalk2.green(" Configuration saved:"), getConfigPath());
|
|
161661
162343
|
try {
|
|
161662
162344
|
await initializeDatabase(dataDir);
|
|
161663
|
-
console.log(chalk2.green(" Database initialized:"),
|
|
162345
|
+
console.log(chalk2.green(" Database initialized:"), join20(dataDir, "nestor.db"));
|
|
161664
162346
|
} catch (err) {
|
|
161665
162347
|
console.log(chalk2.yellow(" Database initialization skipped (install @nestor/db first)"));
|
|
161666
162348
|
}
|
|
161667
162349
|
const apiKey = generateApiKey();
|
|
161668
|
-
const apiKeyPath =
|
|
161669
|
-
const { writeFileSync:
|
|
161670
|
-
|
|
162350
|
+
const apiKeyPath = join20(dataDir, ".api-keys");
|
|
162351
|
+
const { writeFileSync: writeFileSync14 } = await import("node:fs");
|
|
162352
|
+
writeFileSync14(apiKeyPath, JSON.stringify({ admin: apiKey }, null, 2) + "\n", "utf-8");
|
|
161671
162353
|
console.log(chalk2.green(" Admin API key created"));
|
|
161672
162354
|
const betaKey = generateBetaKey();
|
|
161673
|
-
|
|
162355
|
+
writeFileSync14(join20(dataDir, "license.key"), betaKey, "utf-8");
|
|
161674
162356
|
console.log(chalk2.green(" Beta key created"));
|
|
161675
162357
|
console.log();
|
|
161676
162358
|
console.log(chalk2.bold("Admin API Key:"), chalk2.yellow(apiKey));
|
|
@@ -161766,9 +162448,9 @@ async function runInteractiveInstall() {
|
|
|
161766
162448
|
const dataDir = expandPath(config2.server.dataDir);
|
|
161767
162449
|
const spinner3 = p.spinner();
|
|
161768
162450
|
spinner3.start("Creating directories...");
|
|
161769
|
-
for (const dir of [dataDir,
|
|
161770
|
-
if (!
|
|
161771
|
-
|
|
162451
|
+
for (const dir of [dataDir, join20(dataDir, "adapters"), join20(dataDir, "skills"), join20(dataDir, "plugins"), join20(dataDir, "logs")]) {
|
|
162452
|
+
if (!existsSync15(dir)) {
|
|
162453
|
+
mkdirSync8(dir, { recursive: true });
|
|
161772
162454
|
}
|
|
161773
162455
|
}
|
|
161774
162456
|
spinner3.stop("Directories created");
|
|
@@ -161793,14 +162475,14 @@ async function runInteractiveInstall() {
|
|
|
161793
162475
|
const spinner4 = p.spinner();
|
|
161794
162476
|
spinner4.start("Generating admin API key...");
|
|
161795
162477
|
const apiKey = generateApiKey();
|
|
161796
|
-
const apiKeyPath =
|
|
161797
|
-
const { writeFileSync:
|
|
161798
|
-
|
|
162478
|
+
const apiKeyPath = join20(dataDir, ".api-keys");
|
|
162479
|
+
const { writeFileSync: writeFileSync14 } = await import("node:fs");
|
|
162480
|
+
writeFileSync14(apiKeyPath, JSON.stringify({ admin: apiKey }, null, 2) + "\n", "utf-8");
|
|
161799
162481
|
spinner4.stop("Admin API key created!");
|
|
161800
162482
|
const spinner5 = p.spinner();
|
|
161801
162483
|
spinner5.start("Generating beta key...");
|
|
161802
162484
|
const betaKey = generateBetaKey();
|
|
161803
|
-
|
|
162485
|
+
writeFileSync14(join20(dataDir, "license.key"), betaKey, "utf-8");
|
|
161804
162486
|
spinner5.stop("Beta key created!");
|
|
161805
162487
|
p.note(
|
|
161806
162488
|
`Config file: ${getConfigPath()}
|
|
@@ -163093,23 +163775,23 @@ init_db();
|
|
|
163093
163775
|
init_spinner();
|
|
163094
163776
|
init_table();
|
|
163095
163777
|
import {
|
|
163096
|
-
existsSync as
|
|
163097
|
-
readFileSync as
|
|
163098
|
-
writeFileSync as
|
|
163099
|
-
mkdirSync as
|
|
163778
|
+
existsSync as existsSync18,
|
|
163779
|
+
readFileSync as readFileSync21,
|
|
163780
|
+
writeFileSync as writeFileSync12,
|
|
163781
|
+
mkdirSync as mkdirSync11,
|
|
163100
163782
|
unlinkSync,
|
|
163101
163783
|
appendFileSync as appendFileSync4
|
|
163102
163784
|
} from "node:fs";
|
|
163103
|
-
import { join as
|
|
163104
|
-
import { homedir as
|
|
163785
|
+
import { join as join23 } from "node:path";
|
|
163786
|
+
import { homedir as homedir8 } from "node:os";
|
|
163105
163787
|
import { fork as fork2 } from "node:child_process";
|
|
163106
163788
|
import "node:readline";
|
|
163107
163789
|
import chalk12 from "chalk";
|
|
163108
|
-
var NESTOR_DIR2 =
|
|
163109
|
-
var PID_FILE =
|
|
163110
|
-
var LOG_DIR =
|
|
163111
|
-
var LOG_FILE =
|
|
163112
|
-
var HEARTBEAT_FILE =
|
|
163790
|
+
var NESTOR_DIR2 = join23(homedir8(), ".nestor");
|
|
163791
|
+
var PID_FILE = join23(NESTOR_DIR2, "daemon.pid");
|
|
163792
|
+
var LOG_DIR = join23(NESTOR_DIR2, "logs");
|
|
163793
|
+
var LOG_FILE = join23(LOG_DIR, "daemon.log");
|
|
163794
|
+
var HEARTBEAT_FILE = join23(NESTOR_DIR2, "daemon.heartbeat");
|
|
163113
163795
|
var HEARTBEAT_INTERVAL_MS2 = 3e4;
|
|
163114
163796
|
function registerDaemonCommand(program2) {
|
|
163115
163797
|
const daemon = program2.command("daemon").description("Manage the Nestor background daemon");
|
|
@@ -163277,13 +163959,13 @@ async function showStatus() {
|
|
|
163277
163959
|
console.log("");
|
|
163278
163960
|
}
|
|
163279
163961
|
async function showLogs(follow, lineCount) {
|
|
163280
|
-
if (!
|
|
163962
|
+
if (!existsSync18(LOG_FILE)) {
|
|
163281
163963
|
console.log(chalk12.yellow("No daemon log file found."));
|
|
163282
163964
|
console.log(chalk12.dim(`Expected at: ${LOG_FILE}`));
|
|
163283
163965
|
return;
|
|
163284
163966
|
}
|
|
163285
163967
|
if (!follow) {
|
|
163286
|
-
const content =
|
|
163968
|
+
const content = readFileSync21(LOG_FILE, "utf-8");
|
|
163287
163969
|
const lines = content.split("\n").filter((l) => l.length > 0);
|
|
163288
163970
|
const lastLines = lines.slice(-lineCount);
|
|
163289
163971
|
if (lastLines.length === 0) {
|
|
@@ -163297,19 +163979,19 @@ async function showLogs(follow, lineCount) {
|
|
|
163297
163979
|
}
|
|
163298
163980
|
console.log(chalk12.dim(`Following ${LOG_FILE}... (Ctrl+C to stop)`));
|
|
163299
163981
|
console.log("");
|
|
163300
|
-
if (
|
|
163301
|
-
const content =
|
|
163982
|
+
if (existsSync18(LOG_FILE)) {
|
|
163983
|
+
const content = readFileSync21(LOG_FILE, "utf-8");
|
|
163302
163984
|
const lines = content.split("\n").filter((l) => l.length > 0);
|
|
163303
163985
|
const lastLines = lines.slice(-10);
|
|
163304
163986
|
for (const line of lastLines) {
|
|
163305
163987
|
console.log(colorizeLogLine(line));
|
|
163306
163988
|
}
|
|
163307
163989
|
}
|
|
163308
|
-
let lastSize =
|
|
163990
|
+
let lastSize = existsSync18(LOG_FILE) ? readFileSync21(LOG_FILE).length : 0;
|
|
163309
163991
|
const watcher = setInterval(() => {
|
|
163310
163992
|
try {
|
|
163311
|
-
if (!
|
|
163312
|
-
const content =
|
|
163993
|
+
if (!existsSync18(LOG_FILE)) return;
|
|
163994
|
+
const content = readFileSync21(LOG_FILE, "utf-8");
|
|
163313
163995
|
if (content.length > lastSize) {
|
|
163314
163996
|
const newContent = content.substring(lastSize);
|
|
163315
163997
|
const newLines = newContent.split("\n").filter((l) => l.length > 0);
|
|
@@ -163619,7 +164301,7 @@ var DaemonRunner = class {
|
|
|
163619
164301
|
activeAgents: this.runningAgents.size,
|
|
163620
164302
|
nextScheduledRun: void 0
|
|
163621
164303
|
};
|
|
163622
|
-
|
|
164304
|
+
writeFileSync12(HEARTBEAT_FILE, JSON.stringify(data), "utf-8");
|
|
163623
164305
|
} catch {
|
|
163624
164306
|
}
|
|
163625
164307
|
}
|
|
@@ -163637,8 +164319,8 @@ async function importDaemonAgentModule() {
|
|
|
163637
164319
|
}
|
|
163638
164320
|
function readHeartbeat() {
|
|
163639
164321
|
try {
|
|
163640
|
-
if (
|
|
163641
|
-
const raw =
|
|
164322
|
+
if (existsSync18(HEARTBEAT_FILE)) {
|
|
164323
|
+
const raw = readFileSync21(HEARTBEAT_FILE, "utf-8");
|
|
163642
164324
|
return JSON.parse(raw);
|
|
163643
164325
|
}
|
|
163644
164326
|
} catch {
|
|
@@ -163647,8 +164329,8 @@ function readHeartbeat() {
|
|
|
163647
164329
|
}
|
|
163648
164330
|
function readPid() {
|
|
163649
164331
|
try {
|
|
163650
|
-
if (
|
|
163651
|
-
const raw =
|
|
164332
|
+
if (existsSync18(PID_FILE)) {
|
|
164333
|
+
const raw = readFileSync21(PID_FILE, "utf-8").trim();
|
|
163652
164334
|
const pid = parseInt(raw, 10);
|
|
163653
164335
|
return isNaN(pid) ? null : pid;
|
|
163654
164336
|
}
|
|
@@ -163658,11 +164340,11 @@ function readPid() {
|
|
|
163658
164340
|
}
|
|
163659
164341
|
function writePid(pid) {
|
|
163660
164342
|
ensureDirs();
|
|
163661
|
-
|
|
164343
|
+
writeFileSync12(PID_FILE, String(pid), "utf-8");
|
|
163662
164344
|
}
|
|
163663
164345
|
function cleanupPid() {
|
|
163664
164346
|
try {
|
|
163665
|
-
if (
|
|
164347
|
+
if (existsSync18(PID_FILE)) {
|
|
163666
164348
|
unlinkSync(PID_FILE);
|
|
163667
164349
|
}
|
|
163668
164350
|
} catch {
|
|
@@ -163702,11 +164384,11 @@ function colorizeLogLine(line) {
|
|
|
163702
164384
|
return line;
|
|
163703
164385
|
}
|
|
163704
164386
|
function ensureDirs() {
|
|
163705
|
-
if (!
|
|
163706
|
-
|
|
164387
|
+
if (!existsSync18(NESTOR_DIR2)) {
|
|
164388
|
+
mkdirSync11(NESTOR_DIR2, { recursive: true });
|
|
163707
164389
|
}
|
|
163708
|
-
if (!
|
|
163709
|
-
|
|
164390
|
+
if (!existsSync18(LOG_DIR)) {
|
|
164391
|
+
mkdirSync11(LOG_DIR, { recursive: true });
|
|
163710
164392
|
}
|
|
163711
164393
|
}
|
|
163712
164394
|
function delay(ms) {
|
|
@@ -163747,13 +164429,13 @@ if (process.argv[2] === "__daemon_child__" || process.env.NESTOR_DAEMON_MODE ===
|
|
|
163747
164429
|
|
|
163748
164430
|
// src/commands/watch.ts
|
|
163749
164431
|
init_db();
|
|
163750
|
-
import { existsSync as
|
|
163751
|
-
import { join as
|
|
163752
|
-
import { homedir as
|
|
164432
|
+
import { existsSync as existsSync19, readFileSync as readFileSync22 } from "node:fs";
|
|
164433
|
+
import { join as join24 } from "node:path";
|
|
164434
|
+
import { homedir as homedir9 } from "node:os";
|
|
163753
164435
|
import chalk13 from "chalk";
|
|
163754
|
-
var NESTOR_DIR3 =
|
|
163755
|
-
var HEARTBEAT_FILE2 =
|
|
163756
|
-
var LOG_FILE2 =
|
|
164436
|
+
var NESTOR_DIR3 = join24(homedir9(), ".nestor");
|
|
164437
|
+
var HEARTBEAT_FILE2 = join24(NESTOR_DIR3, "daemon.heartbeat");
|
|
164438
|
+
var LOG_FILE2 = join24(NESTOR_DIR3, "logs", "daemon.log");
|
|
163757
164439
|
var REFRESH_INTERVAL_MS = 1e3;
|
|
163758
164440
|
var MAX_EVENTS = 12;
|
|
163759
164441
|
function registerWatchCommand(program2) {
|
|
@@ -163821,8 +164503,8 @@ async function refreshData(state) {
|
|
|
163821
164503
|
} catch {
|
|
163822
164504
|
}
|
|
163823
164505
|
try {
|
|
163824
|
-
if (
|
|
163825
|
-
const raw =
|
|
164506
|
+
if (existsSync19(HEARTBEAT_FILE2)) {
|
|
164507
|
+
const raw = readFileSync22(HEARTBEAT_FILE2, "utf-8");
|
|
163826
164508
|
const heartbeat = JSON.parse(raw);
|
|
163827
164509
|
state.daemonRunning = isDaemonAlive(heartbeat.pid);
|
|
163828
164510
|
state.daemonPid = heartbeat.pid;
|
|
@@ -163839,8 +164521,8 @@ async function refreshData(state) {
|
|
|
163839
164521
|
}
|
|
163840
164522
|
function loadRecentEvents(state) {
|
|
163841
164523
|
try {
|
|
163842
|
-
if (!
|
|
163843
|
-
const content =
|
|
164524
|
+
if (!existsSync19(LOG_FILE2)) return;
|
|
164525
|
+
const content = readFileSync22(LOG_FILE2, "utf-8");
|
|
163844
164526
|
const lines = content.split("\n").filter((l) => l.length > 0);
|
|
163845
164527
|
const recent = lines.slice(-MAX_EVENTS);
|
|
163846
164528
|
state.recentEvents = recent.map((line) => {
|
|
@@ -164166,10 +164848,10 @@ function registerTelemetryCommand(program2) {
|
|
|
164166
164848
|
}
|
|
164167
164849
|
console.log(` ${chalk15.dim("Flush:")} every ${(config2.telemetry?.flushIntervalMs ?? 6e4) / 1e3}s`);
|
|
164168
164850
|
}
|
|
164169
|
-
const { join:
|
|
164170
|
-
const { homedir:
|
|
164171
|
-
const telemetryFile =
|
|
164172
|
-
const idFile =
|
|
164851
|
+
const { join: join26 } = __require("node:path");
|
|
164852
|
+
const { homedir: homedir11 } = __require("node:os");
|
|
164853
|
+
const telemetryFile = join26(homedir11(), ".nestor", "telemetry.jsonl");
|
|
164854
|
+
const idFile = join26(homedir11(), ".nestor", "telemetry-id");
|
|
164173
164855
|
if (fs28.existsSync(idFile)) {
|
|
164174
164856
|
const installId = fs28.readFileSync(idFile, "utf-8").trim();
|
|
164175
164857
|
console.log(` ${chalk15.dim("Install ID:")} ${installId.slice(0, 8)}...`);
|
|
@@ -164210,7 +164892,7 @@ function setTelemetryEnabled(enabled) {
|
|
|
164210
164892
|
init_db();
|
|
164211
164893
|
init_table();
|
|
164212
164894
|
import chalk16 from "chalk";
|
|
164213
|
-
import { readFileSync as
|
|
164895
|
+
import { readFileSync as readFileSync23, writeFileSync as writeFileSync13 } from "node:fs";
|
|
164214
164896
|
function registerMemoryCommand(program2) {
|
|
164215
164897
|
const memory = program2.command("memory").description("Manage agent persistent memories");
|
|
164216
164898
|
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) => {
|
|
@@ -164414,13 +165096,13 @@ Memory Statistics for ${agentId}`));
|
|
|
164414
165096
|
}
|
|
164415
165097
|
}
|
|
164416
165098
|
const json = JSON.stringify(allMemories, null, 2);
|
|
164417
|
-
|
|
165099
|
+
writeFileSync13(outputFile, json, "utf-8");
|
|
164418
165100
|
console.log(chalk16.green(`Exported ${allMemories.length} memories to ${outputFile}`));
|
|
164419
165101
|
});
|
|
164420
165102
|
memory.command("import <file>").description("Import memories from JSON").action(async (file) => {
|
|
164421
165103
|
const store = await getStore();
|
|
164422
165104
|
try {
|
|
164423
|
-
const raw =
|
|
165105
|
+
const raw = readFileSync23(file, "utf-8");
|
|
164424
165106
|
const entries = JSON.parse(raw);
|
|
164425
165107
|
if (!Array.isArray(entries)) {
|
|
164426
165108
|
console.error(chalk16.red("Invalid format: expected a JSON array of memory entries."));
|
|
@@ -164941,7 +165623,7 @@ ${results.length} results for "${query}":
|
|
|
164941
165623
|
|
|
164942
165624
|
// src/commands/test.ts
|
|
164943
165625
|
import { resolve as resolve17, relative as relative5 } from "node:path";
|
|
164944
|
-
import { readdirSync as readdirSync6, statSync as statSync6, existsSync as
|
|
165626
|
+
import { readdirSync as readdirSync6, statSync as statSync6, existsSync as existsSync20 } from "node:fs";
|
|
164945
165627
|
import chalk20 from "chalk";
|
|
164946
165628
|
var TEST_FILE_PATTERNS = [
|
|
164947
165629
|
".nestor-test.yaml",
|
|
@@ -164954,7 +165636,7 @@ function registerTestCommand(program2) {
|
|
|
164954
165636
|
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) => {
|
|
164955
165637
|
if (opts.file) {
|
|
164956
165638
|
const filePath = resolve17(opts.file);
|
|
164957
|
-
if (!
|
|
165639
|
+
if (!existsSync20(filePath)) {
|
|
164958
165640
|
console.error(chalk20.red(`File not found: ${opts.file}`));
|
|
164959
165641
|
process.exit(1);
|
|
164960
165642
|
}
|
|
@@ -164985,7 +165667,7 @@ function registerTestCommand(program2) {
|
|
|
164985
165667
|
];
|
|
164986
165668
|
const allFiles = [];
|
|
164987
165669
|
for (const testDir of defaultTestDirs) {
|
|
164988
|
-
if (
|
|
165670
|
+
if (existsSync20(testDir)) {
|
|
164989
165671
|
allFiles.push(...discoverTestFiles(testDir));
|
|
164990
165672
|
}
|
|
164991
165673
|
}
|
|
@@ -165028,7 +165710,7 @@ function discoverTestFiles(dir) {
|
|
|
165028
165710
|
}
|
|
165029
165711
|
}
|
|
165030
165712
|
}
|
|
165031
|
-
if (
|
|
165713
|
+
if (existsSync20(dir) && !statSync6(dir).isDirectory()) {
|
|
165032
165714
|
return [dir];
|
|
165033
165715
|
}
|
|
165034
165716
|
walk(dir);
|
|
@@ -165037,7 +165719,7 @@ function discoverTestFiles(dir) {
|
|
|
165037
165719
|
async function listTestFiles(dir) {
|
|
165038
165720
|
const files = discoverTestFiles(dir);
|
|
165039
165721
|
const nestorTestDir = resolve17(dir, ".nestor", "tests");
|
|
165040
|
-
if (
|
|
165722
|
+
if (existsSync20(nestorTestDir)) {
|
|
165041
165723
|
files.push(...discoverTestFiles(nestorTestDir));
|
|
165042
165724
|
}
|
|
165043
165725
|
const unique = [...new Set(files)];
|
|
@@ -165093,7 +165775,7 @@ async function runSkillTestsByName(skillName, verbose, json) {
|
|
|
165093
165775
|
];
|
|
165094
165776
|
const matchingFiles = [];
|
|
165095
165777
|
for (const dir of searchDirs) {
|
|
165096
|
-
if (!
|
|
165778
|
+
if (!existsSync20(dir)) continue;
|
|
165097
165779
|
const files = discoverTestFiles(dir);
|
|
165098
165780
|
for (const file of files) {
|
|
165099
165781
|
if (file.includes(skillName)) {
|
|
@@ -165291,9 +165973,9 @@ function registerGuardrailCommand(program2) {
|
|
|
165291
165973
|
|
|
165292
165974
|
// src/index.ts
|
|
165293
165975
|
function checkBetaAccess() {
|
|
165294
|
-
const licenseFile =
|
|
165295
|
-
if (!
|
|
165296
|
-
const key =
|
|
165976
|
+
const licenseFile = join25(homedir10(), ".nestor", "license.key");
|
|
165977
|
+
if (!existsSync21(licenseFile)) return false;
|
|
165978
|
+
const key = readFileSync24(licenseFile, "utf-8").trim();
|
|
165297
165979
|
return /^NESTOR-BETA-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/.test(key);
|
|
165298
165980
|
}
|
|
165299
165981
|
var command2 = process.argv[2];
|
|
@@ -165313,7 +165995,7 @@ if (command2 && !["--help", "-h", "--version", "-V", "install"].includes(command
|
|
|
165313
165995
|
}
|
|
165314
165996
|
}
|
|
165315
165997
|
var program = new Command();
|
|
165316
|
-
program.name("nestor-sh").description("Nestor AI Agent Platform \u2014 orchestrate, secure and monitor AI agents").version("2.1.
|
|
165998
|
+
program.name("nestor-sh").description("Nestor AI Agent Platform \u2014 orchestrate, secure and monitor AI agents").version("2.1.1");
|
|
165317
165999
|
registerStartCommand(program);
|
|
165318
166000
|
registerInstallCommand(program);
|
|
165319
166001
|
registerAgentCommand(program);
|