nexrall-code 0.5.49 → 0.5.51
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/index.js +1106 -202
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1773,13 +1773,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1773
1773
|
* @param {string} source - expected values are default/config/env/cli/implied
|
|
1774
1774
|
* @return {Command} `this` command for chaining
|
|
1775
1775
|
*/
|
|
1776
|
-
setOptionValueWithSource(key, value,
|
|
1776
|
+
setOptionValueWithSource(key, value, source2) {
|
|
1777
1777
|
if (this._storeOptionsAsProperties) {
|
|
1778
1778
|
this[key] = value;
|
|
1779
1779
|
} else {
|
|
1780
1780
|
this._optionValues[key] = value;
|
|
1781
1781
|
}
|
|
1782
|
-
this._optionValueSources[key] =
|
|
1782
|
+
this._optionValueSources[key] = source2;
|
|
1783
1783
|
return this;
|
|
1784
1784
|
}
|
|
1785
1785
|
/**
|
|
@@ -1800,13 +1800,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1800
1800
|
* @return {string}
|
|
1801
1801
|
*/
|
|
1802
1802
|
getOptionValueSourceWithGlobals(key) {
|
|
1803
|
-
let
|
|
1803
|
+
let source2;
|
|
1804
1804
|
this._getCommandAndAncestors().forEach((cmd) => {
|
|
1805
1805
|
if (cmd.getOptionValueSource(key) !== void 0) {
|
|
1806
|
-
|
|
1806
|
+
source2 = cmd.getOptionValueSource(key);
|
|
1807
1807
|
}
|
|
1808
1808
|
});
|
|
1809
|
-
return
|
|
1809
|
+
return source2;
|
|
1810
1810
|
}
|
|
1811
1811
|
/**
|
|
1812
1812
|
* Get user arguments from implied or explicit arguments.
|
|
@@ -2615,8 +2615,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2615
2615
|
const getErrorMessage = (option2) => {
|
|
2616
2616
|
const bestOption = findBestOptionFromValue(option2);
|
|
2617
2617
|
const optionKey = bestOption.attributeName();
|
|
2618
|
-
const
|
|
2619
|
-
if (
|
|
2618
|
+
const source2 = this.getOptionValueSource(optionKey);
|
|
2619
|
+
if (source2 === "env") {
|
|
2620
2620
|
return `environment variable '${bestOption.envVar}'`;
|
|
2621
2621
|
}
|
|
2622
2622
|
return `option '${bestOption.flags}'`;
|
|
@@ -5998,10 +5998,10 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
5998
5998
|
return ctor;
|
|
5999
5999
|
}
|
|
6000
6000
|
const DOMException2 = getFromGlobal() || createPolyfill();
|
|
6001
|
-
function ReadableStreamPipeTo(
|
|
6002
|
-
const reader = AcquireReadableStreamDefaultReader(
|
|
6001
|
+
function ReadableStreamPipeTo(source2, dest, preventClose, preventAbort, preventCancel, signal) {
|
|
6002
|
+
const reader = AcquireReadableStreamDefaultReader(source2);
|
|
6003
6003
|
const writer = AcquireWritableStreamDefaultWriter(dest);
|
|
6004
|
-
|
|
6004
|
+
source2._disturbed = true;
|
|
6005
6005
|
let shuttingDown = false;
|
|
6006
6006
|
let currentWrite = promiseResolvedWith(void 0);
|
|
6007
6007
|
return newPromise((resolve3, reject) => {
|
|
@@ -6020,8 +6020,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
6020
6020
|
}
|
|
6021
6021
|
if (!preventCancel) {
|
|
6022
6022
|
actions.push(() => {
|
|
6023
|
-
if (
|
|
6024
|
-
return ReadableStreamCancel(
|
|
6023
|
+
if (source2._state === "readable") {
|
|
6024
|
+
return ReadableStreamCancel(source2, error);
|
|
6025
6025
|
}
|
|
6026
6026
|
return promiseResolvedWith(void 0);
|
|
6027
6027
|
});
|
|
@@ -6063,7 +6063,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
6063
6063
|
});
|
|
6064
6064
|
});
|
|
6065
6065
|
}
|
|
6066
|
-
isOrBecomesErrored(
|
|
6066
|
+
isOrBecomesErrored(source2, reader._closedPromise, (storedError) => {
|
|
6067
6067
|
if (!preventAbort) {
|
|
6068
6068
|
shutdownWithAction(() => WritableStreamAbort(dest, storedError), true, storedError);
|
|
6069
6069
|
} else {
|
|
@@ -6073,13 +6073,13 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
6073
6073
|
});
|
|
6074
6074
|
isOrBecomesErrored(dest, writer._closedPromise, (storedError) => {
|
|
6075
6075
|
if (!preventCancel) {
|
|
6076
|
-
shutdownWithAction(() => ReadableStreamCancel(
|
|
6076
|
+
shutdownWithAction(() => ReadableStreamCancel(source2, storedError), true, storedError);
|
|
6077
6077
|
} else {
|
|
6078
6078
|
shutdown(true, storedError);
|
|
6079
6079
|
}
|
|
6080
6080
|
return null;
|
|
6081
6081
|
});
|
|
6082
|
-
isOrBecomesClosed(
|
|
6082
|
+
isOrBecomesClosed(source2, reader._closedPromise, () => {
|
|
6083
6083
|
if (!preventClose) {
|
|
6084
6084
|
shutdownWithAction(() => WritableStreamDefaultWriterCloseWithErrorPropagation(writer));
|
|
6085
6085
|
} else {
|
|
@@ -6090,7 +6090,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
6090
6090
|
if (WritableStreamCloseQueuedOrInFlight(dest) || dest._state === "closed") {
|
|
6091
6091
|
const destClosed = new TypeError("the destination writable stream closed before all data could be piped to it");
|
|
6092
6092
|
if (!preventCancel) {
|
|
6093
|
-
shutdownWithAction(() => ReadableStreamCancel(
|
|
6093
|
+
shutdownWithAction(() => ReadableStreamCancel(source2, destClosed), true, destClosed);
|
|
6094
6094
|
} else {
|
|
6095
6095
|
shutdown(true, destClosed);
|
|
6096
6096
|
}
|
|
@@ -6726,11 +6726,11 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
6726
6726
|
function isReadableStreamLike(stream) {
|
|
6727
6727
|
return typeIsObject(stream) && typeof stream.getReader !== "undefined";
|
|
6728
6728
|
}
|
|
6729
|
-
function ReadableStreamFrom(
|
|
6730
|
-
if (isReadableStreamLike(
|
|
6731
|
-
return ReadableStreamFromDefaultReader(
|
|
6729
|
+
function ReadableStreamFrom(source2) {
|
|
6730
|
+
if (isReadableStreamLike(source2)) {
|
|
6731
|
+
return ReadableStreamFromDefaultReader(source2.getReader());
|
|
6732
6732
|
}
|
|
6733
|
-
return ReadableStreamFromIterable(
|
|
6733
|
+
return ReadableStreamFromIterable(source2);
|
|
6734
6734
|
}
|
|
6735
6735
|
function ReadableStreamFromIterable(asyncIterable) {
|
|
6736
6736
|
let stream;
|
|
@@ -6817,9 +6817,9 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
6817
6817
|
stream = CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, 0);
|
|
6818
6818
|
return stream;
|
|
6819
6819
|
}
|
|
6820
|
-
function convertUnderlyingDefaultOrByteSource(
|
|
6821
|
-
assertDictionary(
|
|
6822
|
-
const original =
|
|
6820
|
+
function convertUnderlyingDefaultOrByteSource(source2, context) {
|
|
6821
|
+
assertDictionary(source2, context);
|
|
6822
|
+
const original = source2;
|
|
6823
6823
|
const autoAllocateChunkSize = original === null || original === void 0 ? void 0 : original.autoAllocateChunkSize;
|
|
6824
6824
|
const cancel = original === null || original === void 0 ? void 0 : original.cancel;
|
|
6825
6825
|
const pull = original === null || original === void 0 ? void 0 : original.pull;
|
|
@@ -11201,6 +11201,8 @@ var require_plugins = __commonJS({
|
|
|
11201
11201
|
};
|
|
11202
11202
|
}();
|
|
11203
11203
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11204
|
+
exports.FILE_CANDIDATES = void 0;
|
|
11205
|
+
exports.resolvePluginFile = resolvePluginFile;
|
|
11204
11206
|
exports.loadPlugins = loadPlugins3;
|
|
11205
11207
|
exports.pluginAssetDirs = pluginAssetDirs;
|
|
11206
11208
|
exports.pluginHooks = pluginHooks;
|
|
@@ -11208,9 +11210,28 @@ var require_plugins = __commonJS({
|
|
|
11208
11210
|
var fs9 = __importStar(__require("fs"));
|
|
11209
11211
|
var path6 = __importStar(__require("path"));
|
|
11210
11212
|
var os6 = __importStar(__require("os"));
|
|
11213
|
+
exports.FILE_CANDIDATES = {
|
|
11214
|
+
manifest: ["plugin.json", path6.join(".claude-plugin", "plugin.json")],
|
|
11215
|
+
hooks: ["hooks.json", path6.join("hooks", "hooks.json")],
|
|
11216
|
+
mcp: ["mcp.json", ".mcp.json"]
|
|
11217
|
+
};
|
|
11218
|
+
function resolvePluginFile(dir, kind) {
|
|
11219
|
+
for (const rel of exports.FILE_CANDIDATES[kind]) {
|
|
11220
|
+
const full = path6.join(dir, rel);
|
|
11221
|
+
try {
|
|
11222
|
+
if (fs9.statSync(full).isFile())
|
|
11223
|
+
return full;
|
|
11224
|
+
} catch {
|
|
11225
|
+
}
|
|
11226
|
+
}
|
|
11227
|
+
return null;
|
|
11228
|
+
}
|
|
11211
11229
|
function readMeta(dir) {
|
|
11230
|
+
const file = resolvePluginFile(dir, "manifest");
|
|
11231
|
+
if (!file)
|
|
11232
|
+
return {};
|
|
11212
11233
|
try {
|
|
11213
|
-
const raw = fs9.readFileSync(
|
|
11234
|
+
const raw = fs9.readFileSync(file, "utf-8");
|
|
11214
11235
|
const j = JSON.parse(raw);
|
|
11215
11236
|
return {
|
|
11216
11237
|
name: typeof j.name === "string" ? j.name : void 0,
|
|
@@ -11263,8 +11284,11 @@ var require_plugins = __commonJS({
|
|
|
11263
11284
|
function pluginHooks(workDir) {
|
|
11264
11285
|
const merged = {};
|
|
11265
11286
|
for (const p of loadPlugins3(workDir)) {
|
|
11287
|
+
const file = resolvePluginFile(p.dir, "hooks");
|
|
11288
|
+
if (!file)
|
|
11289
|
+
continue;
|
|
11266
11290
|
try {
|
|
11267
|
-
const raw = fs9.readFileSync(
|
|
11291
|
+
const raw = fs9.readFileSync(file, "utf-8");
|
|
11268
11292
|
const j = JSON.parse(raw);
|
|
11269
11293
|
const hooks = j.hooks ?? j;
|
|
11270
11294
|
for (const [phase, entries] of Object.entries(hooks)) {
|
|
@@ -11280,8 +11304,11 @@ var require_plugins = __commonJS({
|
|
|
11280
11304
|
function pluginMcpServers(workDir) {
|
|
11281
11305
|
const merged = {};
|
|
11282
11306
|
for (const p of loadPlugins3(workDir)) {
|
|
11307
|
+
const file = resolvePluginFile(p.dir, "mcp");
|
|
11308
|
+
if (!file)
|
|
11309
|
+
continue;
|
|
11283
11310
|
try {
|
|
11284
|
-
const raw = fs9.readFileSync(
|
|
11311
|
+
const raw = fs9.readFileSync(file, "utf-8");
|
|
11285
11312
|
const j = JSON.parse(raw);
|
|
11286
11313
|
const servers = j.mcpServers ?? j;
|
|
11287
11314
|
for (const [name, cfg] of Object.entries(servers)) {
|
|
@@ -11400,7 +11427,7 @@ var require_loader = __commonJS({
|
|
|
11400
11427
|
}
|
|
11401
11428
|
return { meta, body: (m2[2] ?? "").trim() };
|
|
11402
11429
|
}
|
|
11403
|
-
function loadDir(dir,
|
|
11430
|
+
function loadDir(dir, source2, into) {
|
|
11404
11431
|
let files;
|
|
11405
11432
|
try {
|
|
11406
11433
|
files = fs9.readdirSync(dir).filter((f3) => f3.endsWith(".md"));
|
|
@@ -11414,7 +11441,7 @@ var require_loader = __commonJS({
|
|
|
11414
11441
|
const name = (meta.name || path6.basename(file, ".md")).trim().toLowerCase();
|
|
11415
11442
|
if (!name)
|
|
11416
11443
|
continue;
|
|
11417
|
-
if (
|
|
11444
|
+
if (source2 !== "project" && into.has(name))
|
|
11418
11445
|
continue;
|
|
11419
11446
|
const model = ["turbo", "pro", "ultra"].find((x2) => x2 === (meta.model ?? "").toLowerCase());
|
|
11420
11447
|
into.set(name, {
|
|
@@ -11423,7 +11450,7 @@ var require_loader = __commonJS({
|
|
|
11423
11450
|
model,
|
|
11424
11451
|
mode: meta.mode || void 0,
|
|
11425
11452
|
body,
|
|
11426
|
-
source
|
|
11453
|
+
source: source2
|
|
11427
11454
|
});
|
|
11428
11455
|
} catch {
|
|
11429
11456
|
}
|
|
@@ -11569,7 +11596,7 @@ var require_skills = __commonJS({
|
|
|
11569
11596
|
return false;
|
|
11570
11597
|
return fallback;
|
|
11571
11598
|
}
|
|
11572
|
-
function toSkill(meta, body, name,
|
|
11599
|
+
function toSkill(meta, body, name, source2, dir) {
|
|
11573
11600
|
const model = ["turbo", "pro", "ultra"].find((x2) => x2 === (meta.model ?? "").toLowerCase());
|
|
11574
11601
|
return {
|
|
11575
11602
|
name,
|
|
@@ -11577,13 +11604,13 @@ var require_skills = __commonJS({
|
|
|
11577
11604
|
model,
|
|
11578
11605
|
mode: meta.mode || void 0,
|
|
11579
11606
|
body,
|
|
11580
|
-
source,
|
|
11607
|
+
source: source2,
|
|
11581
11608
|
dir,
|
|
11582
11609
|
disableModelInvocation: parseBool(meta["disable-model-invocation"], false),
|
|
11583
11610
|
userInvocable: parseBool(meta["user-invocable"], true)
|
|
11584
11611
|
};
|
|
11585
11612
|
}
|
|
11586
|
-
function loadFlatCommandDir(dir,
|
|
11613
|
+
function loadFlatCommandDir(dir, source2, into) {
|
|
11587
11614
|
let files;
|
|
11588
11615
|
try {
|
|
11589
11616
|
files = fs9.readdirSync(dir).filter((f3) => f3.endsWith(".md"));
|
|
@@ -11597,14 +11624,14 @@ var require_skills = __commonJS({
|
|
|
11597
11624
|
const name = (meta.name || path6.basename(file, ".md")).trim().toLowerCase();
|
|
11598
11625
|
if (!name)
|
|
11599
11626
|
continue;
|
|
11600
|
-
if (
|
|
11627
|
+
if (source2 !== "project" && into.has(name))
|
|
11601
11628
|
continue;
|
|
11602
|
-
into.set(name, toSkill(meta, body, name,
|
|
11629
|
+
into.set(name, toSkill(meta, body, name, source2));
|
|
11603
11630
|
} catch {
|
|
11604
11631
|
}
|
|
11605
11632
|
}
|
|
11606
11633
|
}
|
|
11607
|
-
function loadSkillDir(root,
|
|
11634
|
+
function loadSkillDir(root, source2, into) {
|
|
11608
11635
|
let entries;
|
|
11609
11636
|
try {
|
|
11610
11637
|
entries = fs9.readdirSync(root, { withFileTypes: true });
|
|
@@ -11628,9 +11655,9 @@ var require_skills = __commonJS({
|
|
|
11628
11655
|
const name = (meta.name || entry.name).trim().toLowerCase();
|
|
11629
11656
|
if (!name)
|
|
11630
11657
|
continue;
|
|
11631
|
-
if (
|
|
11658
|
+
if (source2 !== "project" && into.has(name))
|
|
11632
11659
|
continue;
|
|
11633
|
-
into.set(name, toSkill(meta, body, name,
|
|
11660
|
+
into.set(name, toSkill(meta, body, name, source2, skillDir));
|
|
11634
11661
|
} catch {
|
|
11635
11662
|
}
|
|
11636
11663
|
}
|
|
@@ -12164,12 +12191,12 @@ var require_symbols = __commonJS({
|
|
|
12164
12191
|
return new Set(EXT_TO_LANG.keys());
|
|
12165
12192
|
}
|
|
12166
12193
|
var MAX_FILE_BYTES = 1024 * 1024;
|
|
12167
|
-
function extractSymbols(filePath,
|
|
12194
|
+
function extractSymbols(filePath, source2) {
|
|
12168
12195
|
const lang = EXT_TO_LANG.get(path6.extname(filePath).toLowerCase());
|
|
12169
12196
|
if (!lang)
|
|
12170
12197
|
return [];
|
|
12171
12198
|
const hits = [];
|
|
12172
|
-
const lines =
|
|
12199
|
+
const lines = source2.split("\n");
|
|
12173
12200
|
let inBlockComment = false;
|
|
12174
12201
|
for (let i2 = 0; i2 < lines.length; i2++) {
|
|
12175
12202
|
const trimmed = lines[i2].trim();
|
|
@@ -12206,21 +12233,21 @@ var require_symbols = __commonJS({
|
|
|
12206
12233
|
if (!rel)
|
|
12207
12234
|
return { error: "path is required" };
|
|
12208
12235
|
const abs = resolveIn(workDir, rel);
|
|
12209
|
-
let
|
|
12236
|
+
let source2;
|
|
12210
12237
|
try {
|
|
12211
12238
|
const st = fs9.statSync(abs);
|
|
12212
12239
|
if (!st.isFile())
|
|
12213
12240
|
return { error: `Not a file: ${rel}` };
|
|
12214
12241
|
if (st.size > MAX_FILE_BYTES)
|
|
12215
12242
|
return { error: `File too large for symbol scan (${Math.round(st.size / 1024)} KB > 1024 KB)` };
|
|
12216
|
-
|
|
12243
|
+
source2 = fs9.readFileSync(abs, "utf-8");
|
|
12217
12244
|
} catch (err) {
|
|
12218
12245
|
return { error: `Cannot read ${rel}: ${err.message}` };
|
|
12219
12246
|
}
|
|
12220
12247
|
if (!EXT_TO_LANG.has(path6.extname(abs).toLowerCase())) {
|
|
12221
12248
|
return { output: `No symbol support for ${path6.extname(abs) || "this file type"} (regex-based scanner). Use search_files instead.` };
|
|
12222
12249
|
}
|
|
12223
|
-
const hits = extractSymbols(abs,
|
|
12250
|
+
const hits = extractSymbols(abs, source2);
|
|
12224
12251
|
if (!hits.length)
|
|
12225
12252
|
return { output: `No symbols found in ${rel}.` };
|
|
12226
12253
|
const lines = hits.map((h2) => `${h2.kind.padEnd(10)} ${h2.name} (line ${h2.line})`);
|
|
@@ -12262,10 +12289,10 @@ ${lines.join("\n")}` };
|
|
|
12262
12289
|
const st = fs9.statSync(full);
|
|
12263
12290
|
if (st.size > MAX_FILE_BYTES)
|
|
12264
12291
|
continue;
|
|
12265
|
-
const
|
|
12266
|
-
if (!
|
|
12292
|
+
const source2 = fs9.readFileSync(full, "utf-8");
|
|
12293
|
+
if (!source2.toLowerCase().includes(q))
|
|
12267
12294
|
continue;
|
|
12268
|
-
for (const h2 of extractSymbols(full,
|
|
12295
|
+
for (const h2 of extractSymbols(full, source2)) {
|
|
12269
12296
|
if (h2.name.toLowerCase().includes(q)) {
|
|
12270
12297
|
results.push({ ...h2, file: path6.relative(root, full) });
|
|
12271
12298
|
if (results.length >= MAX_RESULTS)
|
|
@@ -12452,18 +12479,18 @@ var require_tsLangService = __commonJS({
|
|
|
12452
12479
|
return false;
|
|
12453
12480
|
}
|
|
12454
12481
|
}
|
|
12455
|
-
function posToOffset(
|
|
12456
|
-
const lines =
|
|
12482
|
+
function posToOffset(source2, line, character) {
|
|
12483
|
+
const lines = source2.split("\n");
|
|
12457
12484
|
let offset = 0;
|
|
12458
12485
|
for (let i2 = 0; i2 < line - 1 && i2 < lines.length; i2++)
|
|
12459
12486
|
offset += lines[i2].length + 1;
|
|
12460
12487
|
return offset + Math.max(0, character - 1);
|
|
12461
12488
|
}
|
|
12462
|
-
function offsetToPos(
|
|
12489
|
+
function offsetToPos(source2, offset) {
|
|
12463
12490
|
let line = 1;
|
|
12464
12491
|
let last = 0;
|
|
12465
|
-
for (let i2 = 0; i2 < offset && i2 <
|
|
12466
|
-
if (
|
|
12492
|
+
for (let i2 = 0; i2 < offset && i2 < source2.length; i2++) {
|
|
12493
|
+
if (source2[i2] === "\n") {
|
|
12467
12494
|
line++;
|
|
12468
12495
|
last = i2 + 1;
|
|
12469
12496
|
}
|
|
@@ -12480,8 +12507,8 @@ var require_tsLangService = __commonJS({
|
|
|
12480
12507
|
return null;
|
|
12481
12508
|
if (!ensureFile(svc, deps.filePath))
|
|
12482
12509
|
return { error: `Cannot read ${deps.filePath}` };
|
|
12483
|
-
const
|
|
12484
|
-
const offset = posToOffset(
|
|
12510
|
+
const source2 = svc.snapshots.get(deps.filePath) ?? "";
|
|
12511
|
+
const offset = posToOffset(source2, deps.line, deps.character);
|
|
12485
12512
|
let defs;
|
|
12486
12513
|
try {
|
|
12487
12514
|
defs = svc.service.getDefinitionAtPosition(deps.filePath, offset);
|
|
@@ -12504,8 +12531,8 @@ ${out.join("\n")}` };
|
|
|
12504
12531
|
return null;
|
|
12505
12532
|
if (!ensureFile(svc, deps.filePath))
|
|
12506
12533
|
return { error: `Cannot read ${deps.filePath}` };
|
|
12507
|
-
const
|
|
12508
|
-
const offset = posToOffset(
|
|
12534
|
+
const source2 = svc.snapshots.get(deps.filePath) ?? "";
|
|
12535
|
+
const offset = posToOffset(source2, deps.line, deps.character);
|
|
12509
12536
|
let refs;
|
|
12510
12537
|
try {
|
|
12511
12538
|
refs = svc.service.getReferencesAtPosition(deps.filePath, offset);
|
|
@@ -12532,8 +12559,8 @@ ${lines.join("\n")}` };
|
|
|
12532
12559
|
return null;
|
|
12533
12560
|
if (!ensureFile(svc, deps.filePath))
|
|
12534
12561
|
return { error: `Cannot read ${deps.filePath}` };
|
|
12535
|
-
const
|
|
12536
|
-
const offset = posToOffset(
|
|
12562
|
+
const source2 = svc.snapshots.get(deps.filePath) ?? "";
|
|
12563
|
+
const offset = posToOffset(source2, deps.line, deps.character);
|
|
12537
12564
|
let info;
|
|
12538
12565
|
try {
|
|
12539
12566
|
info = svc.service.getQuickInfoAtPosition(deps.filePath, offset);
|
|
@@ -13528,14 +13555,14 @@ ${globalCapMatches(output)}` : "";
|
|
|
13528
13555
|
}
|
|
13529
13556
|
}
|
|
13530
13557
|
async function moveFile(input, workDir) {
|
|
13531
|
-
const
|
|
13558
|
+
const source2 = typeof input.source === "string" ? input.source : "";
|
|
13532
13559
|
const dest = typeof input.dest === "string" ? input.dest : "";
|
|
13533
|
-
if (!
|
|
13560
|
+
if (!source2)
|
|
13534
13561
|
return { error: "Missing required parameter: source" };
|
|
13535
13562
|
if (!dest)
|
|
13536
13563
|
return { error: "Missing required parameter: dest" };
|
|
13537
13564
|
try {
|
|
13538
|
-
const resolvedSource = resolvePath(
|
|
13565
|
+
const resolvedSource = resolvePath(source2, workDir);
|
|
13539
13566
|
const resolvedDest = resolvePath(dest, workDir);
|
|
13540
13567
|
fs9.mkdirSync(path6.dirname(resolvedDest), { recursive: true });
|
|
13541
13568
|
try {
|
|
@@ -13680,14 +13707,14 @@ ${diff3}${xfile}${sec}` };
|
|
|
13680
13707
|
}
|
|
13681
13708
|
}
|
|
13682
13709
|
async function copyFile(input, workDir) {
|
|
13683
|
-
const
|
|
13710
|
+
const source2 = typeof input.source === "string" ? input.source : "";
|
|
13684
13711
|
const destination = typeof input.destination === "string" ? input.destination : "";
|
|
13685
|
-
if (!
|
|
13712
|
+
if (!source2)
|
|
13686
13713
|
return { error: "Missing required parameter: source" };
|
|
13687
13714
|
if (!destination)
|
|
13688
13715
|
return { error: "Missing required parameter: destination" };
|
|
13689
13716
|
try {
|
|
13690
|
-
const resolvedSrc = resolvePath(
|
|
13717
|
+
const resolvedSrc = resolvePath(source2, workDir);
|
|
13691
13718
|
const resolvedDest = resolvePath(destination, workDir);
|
|
13692
13719
|
if (fs9.existsSync(resolvedDest) && fs9.statSync(resolvedDest).isDirectory()) {
|
|
13693
13720
|
return { error: `Destination is a directory: ${resolvedDest}. Provide a full file path including the filename.` };
|
|
@@ -14133,7 +14160,7 @@ ${lines.join("\n")}`;
|
|
|
14133
14160
|
const editType = typeof input.edit_type === "string" ? input.edit_type : "";
|
|
14134
14161
|
const rawIdx = input.cell_index;
|
|
14135
14162
|
const cellIndex = typeof rawIdx === "number" ? Math.floor(rawIdx) : typeof rawIdx === "string" && rawIdx.trim() !== "" ? parseInt(rawIdx, 10) : -1;
|
|
14136
|
-
const
|
|
14163
|
+
const source2 = typeof input.source === "string" ? input.source : null;
|
|
14137
14164
|
const cellType = typeof input.cell_type === "string" ? input.cell_type : "code";
|
|
14138
14165
|
if (!filePath)
|
|
14139
14166
|
return { error: "Missing required parameter: path" };
|
|
@@ -14152,10 +14179,10 @@ ${lines.join("\n")}`;
|
|
|
14152
14179
|
if (editType === "replace") {
|
|
14153
14180
|
if (cellIndex < 0 || cellIndex >= n)
|
|
14154
14181
|
return { error: `cell_index ${cellIndex} out of range (0\u2013${n - 1})` };
|
|
14155
|
-
if (
|
|
14182
|
+
if (source2 === null)
|
|
14156
14183
|
return { error: "Missing required parameter: source (required for replace)" };
|
|
14157
14184
|
const cell = nb.cells[cellIndex];
|
|
14158
|
-
cell.source =
|
|
14185
|
+
cell.source = source2;
|
|
14159
14186
|
if (cell.cell_type === "code") {
|
|
14160
14187
|
cell.outputs = [];
|
|
14161
14188
|
cell.execution_count = null;
|
|
@@ -14170,12 +14197,12 @@ ${lines.join("\n")}`;
|
|
|
14170
14197
|
save();
|
|
14171
14198
|
return { output: `Deleted cell ${cellIndex} [${removed.cell_type}] from ${resolved}. Notebook now has ${nb.cells.length} cells.` };
|
|
14172
14199
|
}
|
|
14173
|
-
if (
|
|
14200
|
+
if (source2 === null)
|
|
14174
14201
|
return { error: "Missing required parameter: source (required for insert)" };
|
|
14175
14202
|
const insertAt = cellIndex >= 0 ? Math.min(cellIndex + 1, n) : n;
|
|
14176
14203
|
const newCell = {
|
|
14177
14204
|
cell_type: cellType,
|
|
14178
|
-
source,
|
|
14205
|
+
source: source2,
|
|
14179
14206
|
metadata: {},
|
|
14180
14207
|
...cellType === "code" ? { execution_count: null, outputs: [] } : {}
|
|
14181
14208
|
};
|
|
@@ -14542,7 +14569,10 @@ var require_agentTypes = __commonJS({
|
|
|
14542
14569
|
};
|
|
14543
14570
|
}();
|
|
14544
14571
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14545
|
-
exports.loadAgentTypes =
|
|
14572
|
+
exports.loadAgentTypes = loadAgentTypes;
|
|
14573
|
+
exports.loadAgentTypesWithWarnings = loadAgentTypesWithWarnings2;
|
|
14574
|
+
exports.knownToolNames = knownToolNames;
|
|
14575
|
+
exports.builtinAgents = builtinAgents;
|
|
14546
14576
|
exports.summariseAgents = summariseAgents;
|
|
14547
14577
|
exports.findAgentType = findAgentType;
|
|
14548
14578
|
var fs9 = __importStar(__require("fs"));
|
|
@@ -14557,9 +14587,17 @@ var require_agentTypes = __commonJS({
|
|
|
14557
14587
|
"list_directory",
|
|
14558
14588
|
"bash",
|
|
14559
14589
|
"bash_output",
|
|
14590
|
+
// kill_shell belongs next to bash_output: an agent that can start a background
|
|
14591
|
+
// process and poll it but never stop it leaks that process past its own
|
|
14592
|
+
// lifetime. Stopping a shell you started is not a write to the repo.
|
|
14593
|
+
"kill_shell",
|
|
14560
14594
|
"notebook_read",
|
|
14561
14595
|
"todo_write",
|
|
14562
14596
|
"todo_read",
|
|
14597
|
+
// Skills are reusable prompt playbooks, and loop.ts advertises the skills
|
|
14598
|
+
// catalogue to sub-agents at EVERY depth — so withholding the tool that loads
|
|
14599
|
+
// one meant showing every sub-agent a menu it could not order from.
|
|
14600
|
+
"use_skill",
|
|
14563
14601
|
// VS Code language server (ignored on the CLI)
|
|
14564
14602
|
"get_symbols",
|
|
14565
14603
|
"get_workspace_symbols",
|
|
@@ -14568,7 +14606,7 @@ var require_agentTypes = __commonJS({
|
|
|
14568
14606
|
"get_hover",
|
|
14569
14607
|
"get_diagnostics"
|
|
14570
14608
|
];
|
|
14571
|
-
var RESEARCH_TOOLS = [...READ_ONLY_TOOLS, "
|
|
14609
|
+
var RESEARCH_TOOLS = [...READ_ONLY_TOOLS, "fetch_url"];
|
|
14572
14610
|
var WRITE_TOOLS = [
|
|
14573
14611
|
...READ_ONLY_TOOLS,
|
|
14574
14612
|
"write_file",
|
|
@@ -14576,7 +14614,11 @@ var require_agentTypes = __commonJS({
|
|
|
14576
14614
|
"multi_edit",
|
|
14577
14615
|
"create_directory",
|
|
14578
14616
|
"move_file",
|
|
14579
|
-
"copy_file"
|
|
14617
|
+
"copy_file",
|
|
14618
|
+
// notebook_edit is a write tool like any other, and allowsTestOnlyWrite already
|
|
14619
|
+
// knows its shape (`source` is cell CONTENT, not a path). Omitting it just meant
|
|
14620
|
+
// test-writer silently could not touch notebooks.
|
|
14621
|
+
"notebook_edit"
|
|
14580
14622
|
];
|
|
14581
14623
|
var BUILTIN_AGENTS = [
|
|
14582
14624
|
{
|
|
@@ -14756,17 +14798,61 @@ var require_agentTypes = __commonJS({
|
|
|
14756
14798
|
].join("\n")
|
|
14757
14799
|
}
|
|
14758
14800
|
];
|
|
14801
|
+
var KNOWN_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
14802
|
+
"read_file",
|
|
14803
|
+
"write_file",
|
|
14804
|
+
"edit_file",
|
|
14805
|
+
"multi_edit",
|
|
14806
|
+
"list_directory",
|
|
14807
|
+
"create_directory",
|
|
14808
|
+
"move_file",
|
|
14809
|
+
"copy_file",
|
|
14810
|
+
"delete_file",
|
|
14811
|
+
"search_files",
|
|
14812
|
+
"glob",
|
|
14813
|
+
"bash",
|
|
14814
|
+
"bash_output",
|
|
14815
|
+
"kill_shell",
|
|
14816
|
+
"notebook_read",
|
|
14817
|
+
"notebook_edit",
|
|
14818
|
+
"todo_write",
|
|
14819
|
+
"todo_read",
|
|
14820
|
+
"memory_write",
|
|
14821
|
+
"memory_read",
|
|
14822
|
+
"use_skill",
|
|
14823
|
+
"fetch_url",
|
|
14824
|
+
"web_search",
|
|
14825
|
+
"generate_image",
|
|
14826
|
+
"stock_photo",
|
|
14827
|
+
"open_in_browser",
|
|
14828
|
+
"task",
|
|
14829
|
+
"get_symbols",
|
|
14830
|
+
"get_workspace_symbols",
|
|
14831
|
+
"find_references",
|
|
14832
|
+
"go_to_definition",
|
|
14833
|
+
"get_hover",
|
|
14834
|
+
"get_diagnostics"
|
|
14835
|
+
]);
|
|
14836
|
+
var KNOWN_META_KEYS = /* @__PURE__ */ new Set([
|
|
14837
|
+
"name",
|
|
14838
|
+
"description",
|
|
14839
|
+
"tools",
|
|
14840
|
+
"model",
|
|
14841
|
+
"test_files_only",
|
|
14842
|
+
"testfilesonly"
|
|
14843
|
+
]);
|
|
14844
|
+
var VALID_MODELS = ["turbo", "pro", "ultra"];
|
|
14759
14845
|
function parseFrontmatter(raw) {
|
|
14760
14846
|
const m2 = /^\s*---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(raw);
|
|
14761
14847
|
if (!m2)
|
|
14762
|
-
return { meta: {}, body: raw.trim() };
|
|
14848
|
+
return { meta: {}, body: raw.trim(), ok: false };
|
|
14763
14849
|
const meta = {};
|
|
14764
14850
|
for (const line of m2[1].split(/\r?\n/)) {
|
|
14765
14851
|
const kv = /^([A-Za-z0-9_-]+)\s*:\s*(.*)$/.exec(line.trim());
|
|
14766
14852
|
if (kv)
|
|
14767
14853
|
meta[kv[1].toLowerCase()] = kv[2].trim().replace(/^["']|["']$/g, "");
|
|
14768
14854
|
}
|
|
14769
|
-
return { meta, body: (m2[2] ?? "").trim() };
|
|
14855
|
+
return { meta, body: (m2[2] ?? "").trim(), ok: true };
|
|
14770
14856
|
}
|
|
14771
14857
|
function parseModel(v) {
|
|
14772
14858
|
const s2 = (v ?? "").toLowerCase();
|
|
@@ -14781,51 +14867,113 @@ var require_agentTypes = __commonJS({
|
|
|
14781
14867
|
const tools = v.replace(/^\[|\]$/g, "").split(/[,\s]+/).map((t2) => t2.trim()).filter(Boolean);
|
|
14782
14868
|
return tools.length ? tools : void 0;
|
|
14783
14869
|
}
|
|
14784
|
-
function loadDir(dir,
|
|
14870
|
+
function loadDir(dir, source2, into, warnings) {
|
|
14785
14871
|
let entries;
|
|
14786
14872
|
try {
|
|
14787
|
-
entries = fs9.readdirSync(dir
|
|
14873
|
+
entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
14788
14874
|
} catch {
|
|
14789
14875
|
return;
|
|
14790
14876
|
}
|
|
14791
|
-
for (const
|
|
14877
|
+
for (const entry of entries) {
|
|
14878
|
+
const full = path6.join(dir, entry.name);
|
|
14879
|
+
if (entry.isDirectory()) {
|
|
14880
|
+
loadDir(full, source2, into, warnings);
|
|
14881
|
+
continue;
|
|
14882
|
+
}
|
|
14883
|
+
if (!entry.name.endsWith(".md"))
|
|
14884
|
+
continue;
|
|
14885
|
+
let raw;
|
|
14792
14886
|
try {
|
|
14793
|
-
|
|
14794
|
-
|
|
14795
|
-
|
|
14796
|
-
|
|
14797
|
-
|
|
14798
|
-
|
|
14799
|
-
|
|
14800
|
-
|
|
14801
|
-
|
|
14802
|
-
|
|
14803
|
-
|
|
14804
|
-
|
|
14805
|
-
|
|
14806
|
-
|
|
14807
|
-
|
|
14808
|
-
|
|
14809
|
-
|
|
14810
|
-
|
|
14811
|
-
|
|
14887
|
+
raw = fs9.readFileSync(full, "utf-8");
|
|
14888
|
+
} catch (err) {
|
|
14889
|
+
warnings.push({ file: full, agent: path6.basename(entry.name, ".md"), message: `could not be read (${err.message}) \u2014 this agent was skipped` });
|
|
14890
|
+
continue;
|
|
14891
|
+
}
|
|
14892
|
+
const { meta, body, ok } = parseFrontmatter(raw);
|
|
14893
|
+
const name = (meta.name || path6.basename(entry.name, ".md")).trim();
|
|
14894
|
+
if (!name)
|
|
14895
|
+
continue;
|
|
14896
|
+
if (source2 !== "project" && into.has(name))
|
|
14897
|
+
continue;
|
|
14898
|
+
const tools = parseToolList(meta.tools);
|
|
14899
|
+
let effectiveTools = tools;
|
|
14900
|
+
if (!ok) {
|
|
14901
|
+
effectiveTools = READ_ONLY_TOOLS;
|
|
14902
|
+
warnings.push({
|
|
14903
|
+
file: full,
|
|
14904
|
+
agent: name,
|
|
14905
|
+
message: "has no valid YAML frontmatter (a `---` block must be the first thing in the file), so no tool allowlist could be read. Treating it as READ-ONLY. Add frontmatter with a `tools:` line to grant more."
|
|
14812
14906
|
});
|
|
14813
|
-
}
|
|
14907
|
+
} else {
|
|
14908
|
+
if (!meta.description) {
|
|
14909
|
+
warnings.push({
|
|
14910
|
+
file: full,
|
|
14911
|
+
agent: name,
|
|
14912
|
+
message: "has no `description:` \u2014 that text is the ONLY thing the model uses to decide when to delegate to this agent, so it will rarely be picked."
|
|
14913
|
+
});
|
|
14914
|
+
}
|
|
14915
|
+
if (meta.model !== void 0 && parseModel(meta.model) === void 0) {
|
|
14916
|
+
warnings.push({
|
|
14917
|
+
file: full,
|
|
14918
|
+
agent: name,
|
|
14919
|
+
message: `has model: "${meta.model}", which is not valid \u2014 use one of ${VALID_MODELS.join(", ")}, or omit the line to inherit the current session's model.`
|
|
14920
|
+
});
|
|
14921
|
+
}
|
|
14922
|
+
const unknown = (tools ?? []).filter((t2) => !KNOWN_TOOL_NAMES.has(t2) && !t2.includes("__"));
|
|
14923
|
+
if (unknown.length) {
|
|
14924
|
+
warnings.push({
|
|
14925
|
+
file: full,
|
|
14926
|
+
agent: name,
|
|
14927
|
+
message: `lists unknown tool name(s): ${unknown.join(", ")}. An allowlist only grants, so these silently do nothing and the agent cannot use them. Tool names are lower_snake_case (read_file, search_files, glob, bash).`
|
|
14928
|
+
});
|
|
14929
|
+
}
|
|
14930
|
+
const strayKeys = Object.keys(meta).filter((k) => !KNOWN_META_KEYS.has(k));
|
|
14931
|
+
if (strayKeys.length) {
|
|
14932
|
+
warnings.push({
|
|
14933
|
+
file: full,
|
|
14934
|
+
agent: name,
|
|
14935
|
+
message: `has unrecognised frontmatter key(s): ${strayKeys.join(", ")} \u2014 these are ignored.`
|
|
14936
|
+
});
|
|
14937
|
+
}
|
|
14938
|
+
if (!body) {
|
|
14939
|
+
warnings.push({
|
|
14940
|
+
file: full,
|
|
14941
|
+
agent: name,
|
|
14942
|
+
message: "has an empty body \u2014 the text below the frontmatter IS the agent's system prompt, so it currently has no instructions."
|
|
14943
|
+
});
|
|
14944
|
+
}
|
|
14814
14945
|
}
|
|
14946
|
+
into.set(name, {
|
|
14947
|
+
name,
|
|
14948
|
+
description: meta.description || `Custom ${name} agent`,
|
|
14949
|
+
tools: effectiveTools,
|
|
14950
|
+
model: parseModel(meta.model),
|
|
14951
|
+
prompt: body,
|
|
14952
|
+
source: source2,
|
|
14953
|
+
// Exposed to user/plugin definitions too — `test_files_only: true` (or
|
|
14954
|
+
// `testFilesOnly`) lets anyone build a test-writing agent that genuinely
|
|
14955
|
+
// cannot touch production source, rather than only the builtin getting
|
|
14956
|
+
// that guarantee.
|
|
14957
|
+
...parseBool(meta.test_files_only ?? meta.testfilesonly) ? { testFilesOnly: true } : {}
|
|
14958
|
+
});
|
|
14815
14959
|
}
|
|
14816
14960
|
}
|
|
14817
|
-
function
|
|
14961
|
+
function loadAgentTypes(workDir) {
|
|
14962
|
+
return loadAgentTypesWithWarnings2(workDir).types;
|
|
14963
|
+
}
|
|
14964
|
+
function loadAgentTypesWithWarnings2(workDir) {
|
|
14818
14965
|
const out = /* @__PURE__ */ new Map();
|
|
14819
|
-
|
|
14820
|
-
loadDir(path6.join(
|
|
14966
|
+
const warnings = [];
|
|
14967
|
+
loadDir(path6.join(workDir, ".nexrall", "agents"), "project", out, warnings);
|
|
14968
|
+
loadDir(path6.join(os6.homedir(), ".nexrall", "agents"), "global", out, warnings);
|
|
14821
14969
|
for (const dir of (0, index_1.pluginAssetDirs)(workDir, "agents"))
|
|
14822
|
-
loadDir(dir, "plugin", out);
|
|
14970
|
+
loadDir(dir, "plugin", out, warnings);
|
|
14823
14971
|
for (const agent of BUILTIN_AGENTS) {
|
|
14824
14972
|
if (!out.has(agent.name))
|
|
14825
14973
|
out.set(agent.name, agent);
|
|
14826
14974
|
}
|
|
14827
14975
|
const builtinOrder = new Map(BUILTIN_AGENTS.map((a, i2) => [a.name, i2]));
|
|
14828
|
-
|
|
14976
|
+
const types3 = [...out.values()].sort((a, b) => {
|
|
14829
14977
|
const ai = builtinOrder.get(a.name);
|
|
14830
14978
|
const bi = builtinOrder.get(b.name);
|
|
14831
14979
|
if (ai !== void 0 && bi !== void 0)
|
|
@@ -14836,6 +14984,13 @@ var require_agentTypes = __commonJS({
|
|
|
14836
14984
|
return 1;
|
|
14837
14985
|
return a.name.localeCompare(b.name);
|
|
14838
14986
|
});
|
|
14987
|
+
return { types: types3, warnings };
|
|
14988
|
+
}
|
|
14989
|
+
function knownToolNames() {
|
|
14990
|
+
return [...KNOWN_TOOL_NAMES].sort();
|
|
14991
|
+
}
|
|
14992
|
+
function builtinAgents() {
|
|
14993
|
+
return BUILTIN_AGENTS;
|
|
14839
14994
|
}
|
|
14840
14995
|
function summariseAgents(types3) {
|
|
14841
14996
|
if (!types3.length)
|
|
@@ -15037,6 +15192,9 @@ var require_rules = __commonJS({
|
|
|
15037
15192
|
case "stock_photo":
|
|
15038
15193
|
vals.push(str(input.path));
|
|
15039
15194
|
break;
|
|
15195
|
+
case "task":
|
|
15196
|
+
vals.push(str(input.subagent_type));
|
|
15197
|
+
break;
|
|
15040
15198
|
default:
|
|
15041
15199
|
pushPath(str(input.path));
|
|
15042
15200
|
break;
|
|
@@ -15077,6 +15235,350 @@ var require_rules = __commonJS({
|
|
|
15077
15235
|
}
|
|
15078
15236
|
});
|
|
15079
15237
|
|
|
15238
|
+
// ../core/dist/agent/planMode.js
|
|
15239
|
+
var require_planMode = __commonJS({
|
|
15240
|
+
"../core/dist/agent/planMode.js"(exports) {
|
|
15241
|
+
"use strict";
|
|
15242
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15243
|
+
exports.PLAN_MODE_INSTRUCTIONS = void 0;
|
|
15244
|
+
exports.isReadOnlyCommand = isReadOnlyCommand;
|
|
15245
|
+
exports.checkPlanMode = checkPlanMode;
|
|
15246
|
+
var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
15247
|
+
"read_file",
|
|
15248
|
+
"search_files",
|
|
15249
|
+
"glob",
|
|
15250
|
+
"list_directory",
|
|
15251
|
+
"notebook_read",
|
|
15252
|
+
// Planning bookkeeping. todo_write persists only to the session's own todo
|
|
15253
|
+
// list, not the repo, so it stays available — a plan mode that cannot draft
|
|
15254
|
+
// a checklist is missing the point of plan mode.
|
|
15255
|
+
"todo_write",
|
|
15256
|
+
"todo_read",
|
|
15257
|
+
// Reading memory is fine; memory_write is NOT here on purpose. Memory is
|
|
15258
|
+
// durable state that survives the session, so writing it is a real mutation
|
|
15259
|
+
// even though no file in the repo changes.
|
|
15260
|
+
"memory_read",
|
|
15261
|
+
"use_skill",
|
|
15262
|
+
"fetch_url",
|
|
15263
|
+
"web_search",
|
|
15264
|
+
// Delegating research is ALLOWED, and this is safe rather than a hole:
|
|
15265
|
+
// runSubTask passes planMode down, so the sub-agent is under the same lock and
|
|
15266
|
+
// its own write tools are refused by this very function one level deeper.
|
|
15267
|
+
//
|
|
15268
|
+
// Worth allowing rather than blanket-refusing, because plan mode exists to
|
|
15269
|
+
// support deep research and the explorer agent is the cheapest way to do bulk
|
|
15270
|
+
// searching without flooding the main context. Blocking `task` would have made
|
|
15271
|
+
// the mode's headline use case worse, for no security gain.
|
|
15272
|
+
"task",
|
|
15273
|
+
// VS Code language server — all pure queries.
|
|
15274
|
+
"get_symbols",
|
|
15275
|
+
"get_workspace_symbols",
|
|
15276
|
+
"find_references",
|
|
15277
|
+
"go_to_definition",
|
|
15278
|
+
"get_hover",
|
|
15279
|
+
"get_diagnostics",
|
|
15280
|
+
// Reading output from an ALREADY-running background shell. Starting one is
|
|
15281
|
+
// gated with the rest of bash below; draining a buffer is not a new effect.
|
|
15282
|
+
"bash_output"
|
|
15283
|
+
]);
|
|
15284
|
+
var READ_ONLY_BASH = /* @__PURE__ */ new Set([
|
|
15285
|
+
"ls",
|
|
15286
|
+
"cat",
|
|
15287
|
+
"head",
|
|
15288
|
+
"tail",
|
|
15289
|
+
"wc",
|
|
15290
|
+
"file",
|
|
15291
|
+
"stat",
|
|
15292
|
+
"du",
|
|
15293
|
+
"df",
|
|
15294
|
+
"pwd",
|
|
15295
|
+
"which",
|
|
15296
|
+
"type",
|
|
15297
|
+
"echo",
|
|
15298
|
+
"printf",
|
|
15299
|
+
"basename",
|
|
15300
|
+
"dirname",
|
|
15301
|
+
"realpath",
|
|
15302
|
+
"readlink",
|
|
15303
|
+
"grep",
|
|
15304
|
+
"egrep",
|
|
15305
|
+
"fgrep",
|
|
15306
|
+
"rg",
|
|
15307
|
+
"ag",
|
|
15308
|
+
"ack",
|
|
15309
|
+
"find",
|
|
15310
|
+
"fd",
|
|
15311
|
+
"locate",
|
|
15312
|
+
"diff",
|
|
15313
|
+
"comm",
|
|
15314
|
+
"cmp",
|
|
15315
|
+
"sort",
|
|
15316
|
+
"uniq",
|
|
15317
|
+
"cut",
|
|
15318
|
+
"tr",
|
|
15319
|
+
"column",
|
|
15320
|
+
"jq",
|
|
15321
|
+
"yq",
|
|
15322
|
+
"date",
|
|
15323
|
+
"whoami",
|
|
15324
|
+
"hostname",
|
|
15325
|
+
"uname",
|
|
15326
|
+
"env",
|
|
15327
|
+
"printenv",
|
|
15328
|
+
"id",
|
|
15329
|
+
"groups",
|
|
15330
|
+
"ps",
|
|
15331
|
+
"top",
|
|
15332
|
+
"uptime",
|
|
15333
|
+
"free",
|
|
15334
|
+
"node",
|
|
15335
|
+
"python",
|
|
15336
|
+
"python3",
|
|
15337
|
+
"tree",
|
|
15338
|
+
"less",
|
|
15339
|
+
"more",
|
|
15340
|
+
"nl",
|
|
15341
|
+
"tac",
|
|
15342
|
+
"strings",
|
|
15343
|
+
"md5sum",
|
|
15344
|
+
"sha256sum",
|
|
15345
|
+
"true",
|
|
15346
|
+
"false",
|
|
15347
|
+
"test",
|
|
15348
|
+
"sleep",
|
|
15349
|
+
"seq",
|
|
15350
|
+
"expr"
|
|
15351
|
+
]);
|
|
15352
|
+
var READ_ONLY_SUBCOMMANDS = {
|
|
15353
|
+
git: /* @__PURE__ */ new Set([
|
|
15354
|
+
"log",
|
|
15355
|
+
"show",
|
|
15356
|
+
"diff",
|
|
15357
|
+
"status",
|
|
15358
|
+
"blame",
|
|
15359
|
+
"branch",
|
|
15360
|
+
"tag",
|
|
15361
|
+
"remote",
|
|
15362
|
+
"describe",
|
|
15363
|
+
"rev-parse",
|
|
15364
|
+
"rev-list",
|
|
15365
|
+
"ls-files",
|
|
15366
|
+
"ls-tree",
|
|
15367
|
+
"ls-remote",
|
|
15368
|
+
"cat-file",
|
|
15369
|
+
"shortlog",
|
|
15370
|
+
"reflog",
|
|
15371
|
+
"whatchanged",
|
|
15372
|
+
"grep",
|
|
15373
|
+
"config",
|
|
15374
|
+
"check-ignore",
|
|
15375
|
+
"merge-base",
|
|
15376
|
+
"name-rev",
|
|
15377
|
+
"count-objects",
|
|
15378
|
+
"verify-commit"
|
|
15379
|
+
]),
|
|
15380
|
+
// Package managers: only their query verbs.
|
|
15381
|
+
npm: /* @__PURE__ */ new Set(["ls", "list", "view", "info", "outdated", "why", "config", "ping", "search"]),
|
|
15382
|
+
pnpm: /* @__PURE__ */ new Set(["ls", "list", "view", "info", "outdated", "why", "config"]),
|
|
15383
|
+
yarn: /* @__PURE__ */ new Set(["list", "info", "why", "config"]),
|
|
15384
|
+
cargo: /* @__PURE__ */ new Set(["tree", "metadata", "search"]),
|
|
15385
|
+
go: /* @__PURE__ */ new Set(["list", "version", "env", "vet", "doc"]),
|
|
15386
|
+
docker: /* @__PURE__ */ new Set(["ps", "images", "logs", "inspect", "version", "info", "top", "port", "diff", "stats"]),
|
|
15387
|
+
kubectl: /* @__PURE__ */ new Set(["get", "describe", "logs", "explain", "top", "version", "api-resources", "api-versions"]),
|
|
15388
|
+
// gh: read verbs only. `gh run rerun`, `gh pr merge` etc. are excluded, and
|
|
15389
|
+
// the nested-verb check in isReadOnlyCommand handles `gh pr view` vs `gh pr merge`.
|
|
15390
|
+
gh: /* @__PURE__ */ new Set(["browse"])
|
|
15391
|
+
};
|
|
15392
|
+
var READ_ONLY_NESTED = {
|
|
15393
|
+
gh: /* @__PURE__ */ new Set(["view", "list", "status", "diff", "checks"])
|
|
15394
|
+
};
|
|
15395
|
+
var SHELL_CONTROL = /[\n\r;&|`]|\$\(|>>|>|<\(/;
|
|
15396
|
+
function firstWords(command) {
|
|
15397
|
+
return command.trim().split(/\s+/).filter(Boolean);
|
|
15398
|
+
}
|
|
15399
|
+
function isReadOnlyCommand(command) {
|
|
15400
|
+
const cmd = command.trim();
|
|
15401
|
+
if (!cmd)
|
|
15402
|
+
return false;
|
|
15403
|
+
if (SHELL_CONTROL.test(cmd))
|
|
15404
|
+
return false;
|
|
15405
|
+
const words = firstWords(cmd);
|
|
15406
|
+
if (!words.length)
|
|
15407
|
+
return false;
|
|
15408
|
+
let i2 = 0;
|
|
15409
|
+
while (i2 < words.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(words[i2]))
|
|
15410
|
+
i2++;
|
|
15411
|
+
if (i2 >= words.length)
|
|
15412
|
+
return false;
|
|
15413
|
+
let verb = words[i2];
|
|
15414
|
+
const slash = verb.lastIndexOf("/");
|
|
15415
|
+
if (slash >= 0)
|
|
15416
|
+
verb = verb.slice(slash + 1);
|
|
15417
|
+
if (verb === "sudo" || verb === "doas" || verb === "su")
|
|
15418
|
+
return false;
|
|
15419
|
+
const rest = words.slice(i2 + 1).filter((w) => !w.startsWith("-"));
|
|
15420
|
+
const subs = READ_ONLY_SUBCOMMANDS[verb];
|
|
15421
|
+
if (subs) {
|
|
15422
|
+
const sub = rest[0];
|
|
15423
|
+
if (!sub) {
|
|
15424
|
+
return true;
|
|
15425
|
+
}
|
|
15426
|
+
if (subs.has(sub)) {
|
|
15427
|
+
if (verb === "git" && sub === "config") {
|
|
15428
|
+
const args = words.slice(i2 + 2).filter((w) => !w.startsWith("-"));
|
|
15429
|
+
return args.length <= 1;
|
|
15430
|
+
}
|
|
15431
|
+
return true;
|
|
15432
|
+
}
|
|
15433
|
+
const nested = READ_ONLY_NESTED[verb];
|
|
15434
|
+
if (nested && rest[1] && nested.has(rest[1]))
|
|
15435
|
+
return true;
|
|
15436
|
+
return false;
|
|
15437
|
+
}
|
|
15438
|
+
if (!READ_ONLY_TOOLS.has(verb) && !READ_ONLY_BASH.has(verb))
|
|
15439
|
+
return false;
|
|
15440
|
+
if (verb === "node" || verb === "python" || verb === "python3") {
|
|
15441
|
+
return words.slice(i2 + 1).every((w) => w === "--version" || w === "-V" || w === "-v");
|
|
15442
|
+
}
|
|
15443
|
+
if (verb === "find" && words.some((w) => w === "-exec" || w === "-execdir" || w === "-delete")) {
|
|
15444
|
+
return false;
|
|
15445
|
+
}
|
|
15446
|
+
return true;
|
|
15447
|
+
}
|
|
15448
|
+
function checkPlanMode(tool, input) {
|
|
15449
|
+
if (tool === "bash") {
|
|
15450
|
+
const command = typeof input.command === "string" ? input.command : "";
|
|
15451
|
+
if (input.run_in_background === true) {
|
|
15452
|
+
return {
|
|
15453
|
+
reason: "bash-not-read-only",
|
|
15454
|
+
message: "Plan mode is ON: background processes cannot be started. Finish researching and propose your plan; the user will leave plan mode if they want it carried out."
|
|
15455
|
+
};
|
|
15456
|
+
}
|
|
15457
|
+
if (isReadOnlyCommand(command))
|
|
15458
|
+
return null;
|
|
15459
|
+
return {
|
|
15460
|
+
reason: "bash-not-read-only",
|
|
15461
|
+
message: `Plan mode is ON, so \`bash\` is limited to provably read-only commands and this one was not recognised as such (chained commands, redirection and command substitution are always refused). Do NOT ask the user to approve it and do NOT try a variation to get around this \u2014 it is a session-wide lock, not a per-call prompt. Use read-only inspection instead, and put the command in your plan as a step to run once plan mode is off.`
|
|
15462
|
+
};
|
|
15463
|
+
}
|
|
15464
|
+
if (READ_ONLY_TOOLS.has(tool))
|
|
15465
|
+
return null;
|
|
15466
|
+
return {
|
|
15467
|
+
reason: "mutating-tool",
|
|
15468
|
+
message: `Plan mode is ON, so \`${tool}\` is unavailable \u2014 this session may not modify anything yet. Do NOT ask for approval: no answer the user gives at this prompt can unlock it, because it is a session-wide lock they control directly. Research with read-only tools and finish by proposing a concrete plan (files to change, in order, and how to verify). The user will exit plan mode to let you carry it out.`
|
|
15469
|
+
};
|
|
15470
|
+
}
|
|
15471
|
+
exports.PLAN_MODE_INSTRUCTIONS = [
|
|
15472
|
+
"# PLAN MODE IS ACTIVE",
|
|
15473
|
+
"",
|
|
15474
|
+
"This session is READ-ONLY. You cannot edit files, write files, run mutating commands, or start",
|
|
15475
|
+
"background processes. This is enforced outside your control \u2014 it is not a permission prompt, and",
|
|
15476
|
+
"the user cannot approve an exception from inside this turn.",
|
|
15477
|
+
"",
|
|
15478
|
+
"Therefore:",
|
|
15479
|
+
'- NEVER ask "shall I go ahead and make this change?" \u2014 you cannot, whatever the answer.',
|
|
15480
|
+
'- NEVER attempt a mutating tool "just to see" \u2014 it will be refused and wastes the turn.',
|
|
15481
|
+
"- NEVER try to reach a blocked command another way (a different flag, a script, an interpreter).",
|
|
15482
|
+
"",
|
|
15483
|
+
"Your job is to research thoroughly, then deliver a plan:",
|
|
15484
|
+
"1. What you found \u2014 the specific files, functions and line numbers that matter.",
|
|
15485
|
+
"2. What you propose to change \u2014 file by file, in dependency order.",
|
|
15486
|
+
"3. Risks and unknowns \u2014 what could break, what you could not verify, what you assumed.",
|
|
15487
|
+
"4. How it will be verified \u2014 the exact build/test/lint command that proves it works.",
|
|
15488
|
+
"",
|
|
15489
|
+
'Be concrete. "Update the auth logic" is not a plan; "add a `refreshToken` field to AuthConfig in',
|
|
15490
|
+
'auth/index.ts:42, then thread it through client.ts:118" is. The user will review the plan and',
|
|
15491
|
+
"leave plan mode to have it carried out."
|
|
15492
|
+
].join("\n");
|
|
15493
|
+
}
|
|
15494
|
+
});
|
|
15495
|
+
|
|
15496
|
+
// ../core/dist/agent/agentRegistry.js
|
|
15497
|
+
var require_agentRegistry = __commonJS({
|
|
15498
|
+
"../core/dist/agent/agentRegistry.js"(exports) {
|
|
15499
|
+
"use strict";
|
|
15500
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15501
|
+
exports._limits = void 0;
|
|
15502
|
+
exports.rememberAgent = rememberAgent;
|
|
15503
|
+
exports.updateAgent = updateAgent;
|
|
15504
|
+
exports.getAgent = getAgent;
|
|
15505
|
+
exports.listAgents = listAgents;
|
|
15506
|
+
exports._resetAgentRegistry = _resetAgentRegistry;
|
|
15507
|
+
var MAX_AGENTS = 20;
|
|
15508
|
+
var MAX_TOTAL_BYTES = 8 * 1024 * 1024;
|
|
15509
|
+
var _agents = /* @__PURE__ */ new Map();
|
|
15510
|
+
var _counter = 0;
|
|
15511
|
+
var _seq = 0;
|
|
15512
|
+
function totalBytes() {
|
|
15513
|
+
let n = 0;
|
|
15514
|
+
for (const a of _agents.values())
|
|
15515
|
+
n += a.bytes;
|
|
15516
|
+
return n;
|
|
15517
|
+
}
|
|
15518
|
+
function evictUntilWithinLimits() {
|
|
15519
|
+
while (_agents.size > MAX_AGENTS) {
|
|
15520
|
+
const oldest = _agents.keys().next().value;
|
|
15521
|
+
if (oldest === void 0)
|
|
15522
|
+
break;
|
|
15523
|
+
_agents.delete(oldest);
|
|
15524
|
+
}
|
|
15525
|
+
while (totalBytes() > MAX_TOTAL_BYTES && _agents.size > 1) {
|
|
15526
|
+
const oldest = _agents.keys().next().value;
|
|
15527
|
+
if (oldest === void 0)
|
|
15528
|
+
break;
|
|
15529
|
+
_agents.delete(oldest);
|
|
15530
|
+
}
|
|
15531
|
+
}
|
|
15532
|
+
function sizeOf(messages) {
|
|
15533
|
+
try {
|
|
15534
|
+
return JSON.stringify(messages).length;
|
|
15535
|
+
} catch {
|
|
15536
|
+
return MAX_TOTAL_BYTES;
|
|
15537
|
+
}
|
|
15538
|
+
}
|
|
15539
|
+
function rememberAgent(agentName, description, messages) {
|
|
15540
|
+
const id = `agent_${++_counter}`;
|
|
15541
|
+
const now = Date.now();
|
|
15542
|
+
_agents.set(id, {
|
|
15543
|
+
id,
|
|
15544
|
+
agentName,
|
|
15545
|
+
description,
|
|
15546
|
+
messages,
|
|
15547
|
+
createdAt: now,
|
|
15548
|
+
updatedAt: now,
|
|
15549
|
+
seq: ++_seq,
|
|
15550
|
+
bytes: sizeOf(messages)
|
|
15551
|
+
});
|
|
15552
|
+
evictUntilWithinLimits();
|
|
15553
|
+
return id;
|
|
15554
|
+
}
|
|
15555
|
+
function updateAgent(id, messages) {
|
|
15556
|
+
const existing = _agents.get(id);
|
|
15557
|
+
if (!existing)
|
|
15558
|
+
return;
|
|
15559
|
+
existing.messages = messages;
|
|
15560
|
+
existing.updatedAt = Date.now();
|
|
15561
|
+
existing.seq = ++_seq;
|
|
15562
|
+
existing.bytes = sizeOf(messages);
|
|
15563
|
+
_agents.delete(id);
|
|
15564
|
+
_agents.set(id, existing);
|
|
15565
|
+
evictUntilWithinLimits();
|
|
15566
|
+
}
|
|
15567
|
+
function getAgent(id) {
|
|
15568
|
+
return _agents.get(id);
|
|
15569
|
+
}
|
|
15570
|
+
function listAgents() {
|
|
15571
|
+
return [..._agents.values()].sort((a, b) => b.seq - a.seq);
|
|
15572
|
+
}
|
|
15573
|
+
function _resetAgentRegistry() {
|
|
15574
|
+
_agents.clear();
|
|
15575
|
+
_counter = 0;
|
|
15576
|
+
_seq = 0;
|
|
15577
|
+
}
|
|
15578
|
+
exports._limits = { MAX_AGENTS, MAX_TOTAL_BYTES };
|
|
15579
|
+
}
|
|
15580
|
+
});
|
|
15581
|
+
|
|
15080
15582
|
// ../core/dist/agent/flaky.js
|
|
15081
15583
|
var require_flaky = __commonJS({
|
|
15082
15584
|
"../core/dist/agent/flaky.js"(exports) {
|
|
@@ -15255,7 +15757,7 @@ var require_loop = __commonJS({
|
|
|
15255
15757
|
};
|
|
15256
15758
|
}();
|
|
15257
15759
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15258
|
-
exports.VERIFY_CMD_RE = exports.WRITE_TOOL_NAMES = void 0;
|
|
15760
|
+
exports.VERIFY_CMD_RE = exports.WRITE_TOOL_NAMES = exports.ToolNotAllowedError = void 0;
|
|
15259
15761
|
exports.resolveMaxIterations = resolveMaxIterations;
|
|
15260
15762
|
exports.createLimiter = createLimiter;
|
|
15261
15763
|
exports.extractSubTaskText = extractSubTaskText;
|
|
@@ -15281,6 +15783,8 @@ var require_loop = __commonJS({
|
|
|
15281
15783
|
var agentTypes_1 = require_agentTypes();
|
|
15282
15784
|
var skills_1 = require_skills();
|
|
15283
15785
|
var rules_1 = require_rules();
|
|
15786
|
+
var planMode_1 = require_planMode();
|
|
15787
|
+
var agentRegistry_1 = require_agentRegistry();
|
|
15284
15788
|
var sandbox_1 = require_sandbox();
|
|
15285
15789
|
var index_1 = require_plugins();
|
|
15286
15790
|
var testIntegrity_1 = require_testIntegrity();
|
|
@@ -15532,6 +16036,13 @@ var require_loop = __commonJS({
|
|
|
15532
16036
|
var _subTaskCounter = 0;
|
|
15533
16037
|
var SUBTASK_TIMEOUT_MS = Number(process.env.NEXRALL_SUBTASK_TIMEOUT_MS) > 0 ? Number(process.env.NEXRALL_SUBTASK_TIMEOUT_MS) : 10 * 60 * 1e3;
|
|
15534
16038
|
var SUBTASK_MAX = 48e3;
|
|
16039
|
+
var ToolNotAllowedError = class extends Error {
|
|
16040
|
+
constructor(message) {
|
|
16041
|
+
super(message);
|
|
16042
|
+
this.name = "ToolNotAllowedError";
|
|
16043
|
+
}
|
|
16044
|
+
};
|
|
16045
|
+
exports.ToolNotAllowedError = ToolNotAllowedError;
|
|
15535
16046
|
function sliceSafeEnd(s2, max) {
|
|
15536
16047
|
if (s2.length <= max)
|
|
15537
16048
|
return s2;
|
|
@@ -15594,11 +16105,34 @@ ${tail}`;
|
|
|
15594
16105
|
if (depth >= MAX_TASK_DEPTH) {
|
|
15595
16106
|
return { error: "Sub-agents cannot spawn further sub-agents. Do this work directly, or report back so the main agent can delegate it." };
|
|
15596
16107
|
}
|
|
15597
|
-
const
|
|
15598
|
-
const
|
|
16108
|
+
const resumeId = typeof input.resume_agent_id === "string" ? input.resume_agent_id.trim() : "";
|
|
16109
|
+
const resumed = resumeId ? (0, agentRegistry_1.getAgent)(resumeId) : void 0;
|
|
16110
|
+
if (resumeId && !resumed) {
|
|
16111
|
+
return {
|
|
16112
|
+
error: `No resumable sub-agent with id "${resumeId}". Ids live only for the current session and the oldest are dropped when too many accumulate, so this one has expired or never existed. Start a fresh sub-task with a self-contained prompt instead.`
|
|
16113
|
+
};
|
|
16114
|
+
}
|
|
16115
|
+
const requestedType = resumed ? resumed.agentName ?? "" : typeof input.subagent_type === "string" ? input.subagent_type : "";
|
|
16116
|
+
if (requestedType) {
|
|
16117
|
+
const decision = (0, rules_1.evaluatePermission)((0, rules_1.loadSettings)(options.workDir).permissions, "task", { subagent_type: requestedType }, options.workDir);
|
|
16118
|
+
if (decision === "deny") {
|
|
16119
|
+
return {
|
|
16120
|
+
error: `The sub-agent "${requestedType}" is disabled by a permission rule in this project (permissions.deny in settings.json). This is a deliberate policy choice, not a missing file \u2014 do not create it and do not retry. Do the work yourself, or use a different sub-agent.`
|
|
16121
|
+
};
|
|
16122
|
+
}
|
|
16123
|
+
}
|
|
16124
|
+
let agent = (0, agentTypes_1.findAgentType)(agentTypes, requestedType);
|
|
16125
|
+
let knownTypes = agentTypes;
|
|
15599
16126
|
if (requestedType && !agent) {
|
|
15600
|
-
|
|
15601
|
-
|
|
16127
|
+
knownTypes = (0, agentTypes_1.loadAgentTypes)(options.workDir);
|
|
16128
|
+
agent = (0, agentTypes_1.findAgentType)(knownTypes, requestedType);
|
|
16129
|
+
}
|
|
16130
|
+
if (requestedType && !agent) {
|
|
16131
|
+
const known = knownTypes.map((a) => a.name).join(", ") || "(none defined)";
|
|
16132
|
+
return {
|
|
16133
|
+
error: `Unknown subagent_type "${requestedType}". Available types: ${known}.
|
|
16134
|
+
If you just created .nexrall/agents/` + requestedType + ".md, make sure the write finished in an EARLIER tool call than this one \u2014 a file written in the same batch may not be on disk yet."
|
|
16135
|
+
};
|
|
15602
16136
|
}
|
|
15603
16137
|
const subNexrallMd = agent ? `# Sub-agent role: ${agent.name}
|
|
15604
16138
|
${agent.prompt}` + (options.nexrallMd ? `
|
|
@@ -15608,15 +16142,15 @@ ${agent.prompt}` + (options.nexrallMd ? `
|
|
|
15608
16142
|
${options.nexrallMd}` : "") : options.nexrallMd;
|
|
15609
16143
|
const allowed = agent?.tools ? new Set(agent.tools) : null;
|
|
15610
16144
|
const gatedPermission = async (req) => {
|
|
15611
|
-
if (allowed && !allowed.has(req.tool))
|
|
15612
|
-
|
|
15613
|
-
|
|
15614
|
-
|
|
16145
|
+
if (allowed && !allowed.has(req.tool)) {
|
|
16146
|
+
throw new ToolNotAllowedError(`The "${agent.name}" sub-agent is not allowed to use \`${req.tool}\` \u2014 it is not in that agent's tool allowlist. This is a restriction of the agent definition, NOT a user decision: do not ask for approval, use one of the tools you do have, or report back that the task needs a different agent.`);
|
|
16147
|
+
}
|
|
16148
|
+
if (agent?.testFilesOnly && !allowsTestOnlyWrite(req.tool, req.input)) {
|
|
16149
|
+
throw new ToolNotAllowedError(`The "${agent.name}" sub-agent may only write to TEST files, so \`${req.tool}\` was refused for this path. Do not try to work around it: if production code must change, say so in your report instead.`);
|
|
16150
|
+
}
|
|
15615
16151
|
return options.requestPermission(req);
|
|
15616
16152
|
};
|
|
15617
|
-
const subMessages = [
|
|
15618
|
-
{ role: "user", content: [{ type: "text", text: prompt2 }] }
|
|
15619
|
-
];
|
|
16153
|
+
const subMessages = resumed ? [...resumed.messages, { role: "user", content: [{ type: "text", text: prompt2 }] }] : [{ role: "user", content: [{ type: "text", text: prompt2 }] }];
|
|
15620
16154
|
const subAbort = { aborted: false };
|
|
15621
16155
|
const timer = setTimeout(() => {
|
|
15622
16156
|
subAbort.aborted = true;
|
|
@@ -15634,6 +16168,9 @@ ${options.nexrallMd}` : "") : options.nexrallMd;
|
|
|
15634
16168
|
editorContext: null,
|
|
15635
16169
|
// fresh isolated context for sub-agent
|
|
15636
16170
|
model: agent?.model ?? options.model,
|
|
16171
|
+
// Plan mode is inherited, never relaxed. If the main agent could spawn a
|
|
16172
|
+
// sub-agent that writes, the lock would be one `task` call from useless.
|
|
16173
|
+
planMode: options.planMode,
|
|
15637
16174
|
nexrallMd: subNexrallMd,
|
|
15638
16175
|
abortSignal: subAbort,
|
|
15639
16176
|
requestPermission: gatedPermission,
|
|
@@ -15682,7 +16219,13 @@ ${partial}` : "",
|
|
|
15682
16219
|
return { error: sections.join("\n\n") };
|
|
15683
16220
|
}
|
|
15684
16221
|
const text = capSubTaskText(extractSubTaskText(result, true));
|
|
15685
|
-
|
|
16222
|
+
const agentId = resumed ? ((0, agentRegistry_1.updateAgent)(resumed.id, result), resumed.id) : (0, agentRegistry_1.rememberAgent)(agent?.name ?? null, typeof input.description === "string" && input.description.trim() || prompt2.slice(0, 80), result);
|
|
16223
|
+
const body = text || "(sub-task completed with no text output)";
|
|
16224
|
+
return {
|
|
16225
|
+
output: `${body}
|
|
16226
|
+
|
|
16227
|
+
[resumable: this sub-agent is "${agentId}". To ask IT a follow-up \u2014 keeping everything it already read and concluded \u2014 call task again with resume_agent_id="` + agentId + '" instead of writing a new prompt from scratch.]'
|
|
16228
|
+
};
|
|
15686
16229
|
} catch (err) {
|
|
15687
16230
|
const salvaged = (0, types_1.salvageHistory)(err);
|
|
15688
16231
|
if (salvaged) {
|
|
@@ -16064,10 +16607,15 @@ Continue the work from here.` }] });
|
|
|
16064
16607
|
const hooks = loadHooks(options.workDir);
|
|
16065
16608
|
const depth = options._depth ?? 0;
|
|
16066
16609
|
const agentScope = options._agentScope ?? "root";
|
|
16067
|
-
const
|
|
16610
|
+
const settings = (0, rules_1.loadSettings)(options.workDir);
|
|
16611
|
+
const agentTypes = (0, agentTypes_1.loadAgentTypes)(options.workDir).filter((t2) => (0, rules_1.evaluatePermission)(settings.permissions, "task", { subagent_type: t2.name }, options.workDir) !== "deny");
|
|
16068
16612
|
const agentsCatalogue = depth === 0 ? (0, agentTypes_1.summariseAgents)(agentTypes) : "";
|
|
16069
16613
|
const skillsCatalogue = (0, skills_1.summariseSkills)((0, skills_1.loadSkills)(options.workDir));
|
|
16070
|
-
const
|
|
16614
|
+
const planAwareNexrallMd = options.planMode ? planMode_1.PLAN_MODE_INSTRUCTIONS + (options.nexrallMd ? `
|
|
16615
|
+
|
|
16616
|
+
---
|
|
16617
|
+
|
|
16618
|
+
${options.nexrallMd}` : "") : options.nexrallMd;
|
|
16071
16619
|
const sandboxCfg = (0, sandbox_1.parseSandboxConfig)(settings.raw.sandbox) ?? void 0;
|
|
16072
16620
|
const maxIterations = resolveMaxIterations(options.maxIterations, settings.raw);
|
|
16073
16621
|
const autoContinue = resolveAutoContinue(options.autoContinue, settings.raw);
|
|
@@ -16175,7 +16723,7 @@ Continue the work from here.` }] });
|
|
|
16175
16723
|
effort: options.effort,
|
|
16176
16724
|
env: options.env,
|
|
16177
16725
|
editorContext: options.editorContext,
|
|
16178
|
-
nexrallMd:
|
|
16726
|
+
nexrallMd: planAwareNexrallMd,
|
|
16179
16727
|
clientType: options.clientType,
|
|
16180
16728
|
abortSignal: options.abortSignal,
|
|
16181
16729
|
extraTools: options.mcpManager?.getAnthropicTools(),
|
|
@@ -16295,15 +16843,26 @@ Continue the work from here.` }] });
|
|
|
16295
16843
|
options.onToolResult(name, result);
|
|
16296
16844
|
return { block: { ...block, id }, result };
|
|
16297
16845
|
}
|
|
16846
|
+
if (options.planMode) {
|
|
16847
|
+
const refusal = (0, planMode_1.checkPlanMode)(name, input);
|
|
16848
|
+
if (refusal) {
|
|
16849
|
+
result = { error: refusal.message };
|
|
16850
|
+
options.onToolResult(name, result);
|
|
16851
|
+
return { block: { ...block, id }, result };
|
|
16852
|
+
}
|
|
16853
|
+
}
|
|
16298
16854
|
const description = humanDescription(name, input);
|
|
16299
16855
|
let permitted;
|
|
16856
|
+
let deniedReason = null;
|
|
16300
16857
|
try {
|
|
16301
16858
|
permitted = await options.requestPermission({ tool: name, input, description });
|
|
16302
|
-
} catch {
|
|
16859
|
+
} catch (err) {
|
|
16303
16860
|
permitted = false;
|
|
16861
|
+
if (err instanceof ToolNotAllowedError)
|
|
16862
|
+
deniedReason = err.message;
|
|
16304
16863
|
}
|
|
16305
16864
|
if (!permitted) {
|
|
16306
|
-
result = { error: "Permission denied by user" };
|
|
16865
|
+
result = { error: deniedReason ?? "Permission denied by user" };
|
|
16307
16866
|
} else if (name === "task") {
|
|
16308
16867
|
result = depth === 0 ? await _subTaskLimit(() => runSubTask(input, options, agentTypes)) : await runSubTask(input, options, agentTypes);
|
|
16309
16868
|
} else {
|
|
@@ -17744,6 +18303,175 @@ var require_destructive = __commonJS({
|
|
|
17744
18303
|
}
|
|
17745
18304
|
});
|
|
17746
18305
|
|
|
18306
|
+
// ../core/dist/plugins/sources.js
|
|
18307
|
+
var require_sources = __commonJS({
|
|
18308
|
+
"../core/dist/plugins/sources.js"(exports) {
|
|
18309
|
+
"use strict";
|
|
18310
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m2, k, k2) {
|
|
18311
|
+
if (k2 === void 0)
|
|
18312
|
+
k2 = k;
|
|
18313
|
+
var desc = Object.getOwnPropertyDescriptor(m2, k);
|
|
18314
|
+
if (!desc || ("get" in desc ? !m2.__esModule : desc.writable || desc.configurable)) {
|
|
18315
|
+
desc = { enumerable: true, get: function() {
|
|
18316
|
+
return m2[k];
|
|
18317
|
+
} };
|
|
18318
|
+
}
|
|
18319
|
+
Object.defineProperty(o, k2, desc);
|
|
18320
|
+
} : function(o, m2, k, k2) {
|
|
18321
|
+
if (k2 === void 0)
|
|
18322
|
+
k2 = k;
|
|
18323
|
+
o[k2] = m2[k];
|
|
18324
|
+
});
|
|
18325
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
|
|
18326
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18327
|
+
} : function(o, v) {
|
|
18328
|
+
o["default"] = v;
|
|
18329
|
+
});
|
|
18330
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
|
|
18331
|
+
var ownKeys = function(o) {
|
|
18332
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
18333
|
+
var ar = [];
|
|
18334
|
+
for (var k in o2)
|
|
18335
|
+
if (Object.prototype.hasOwnProperty.call(o2, k))
|
|
18336
|
+
ar[ar.length] = k;
|
|
18337
|
+
return ar;
|
|
18338
|
+
};
|
|
18339
|
+
return ownKeys(o);
|
|
18340
|
+
};
|
|
18341
|
+
return function(mod) {
|
|
18342
|
+
if (mod && mod.__esModule)
|
|
18343
|
+
return mod;
|
|
18344
|
+
var result = {};
|
|
18345
|
+
if (mod != null) {
|
|
18346
|
+
for (var k = ownKeys(mod), i2 = 0; i2 < k.length; i2++)
|
|
18347
|
+
if (k[i2] !== "default")
|
|
18348
|
+
__createBinding(result, mod, k[i2]);
|
|
18349
|
+
}
|
|
18350
|
+
__setModuleDefault(result, mod);
|
|
18351
|
+
return result;
|
|
18352
|
+
};
|
|
18353
|
+
}();
|
|
18354
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18355
|
+
exports.loadDeclaredSources = loadDeclaredSources2;
|
|
18356
|
+
exports.allowedSourcePatterns = allowedSourcePatterns2;
|
|
18357
|
+
exports.isSourceAllowed = isSourceAllowed2;
|
|
18358
|
+
exports.resolveSourceAlias = resolveSourceAlias2;
|
|
18359
|
+
exports.writeDeclaredSource = writeDeclaredSource2;
|
|
18360
|
+
exports.removeDeclaredSource = removeDeclaredSource2;
|
|
18361
|
+
exports.sourcesFileFor = sourcesFileFor2;
|
|
18362
|
+
var fs9 = __importStar(__require("fs"));
|
|
18363
|
+
var path6 = __importStar(__require("path"));
|
|
18364
|
+
var os6 = __importStar(__require("os"));
|
|
18365
|
+
function managedSettingsPath() {
|
|
18366
|
+
if (process.platform === "darwin")
|
|
18367
|
+
return "/Library/Application Support/Nexrall/managed-settings.json";
|
|
18368
|
+
if (process.platform === "win32")
|
|
18369
|
+
return path6.join(process.env.PROGRAMDATA ?? "C:\\ProgramData", "Nexrall", "managed-settings.json");
|
|
18370
|
+
return "/etc/nexrall/managed-settings.json";
|
|
18371
|
+
}
|
|
18372
|
+
function readJson(file) {
|
|
18373
|
+
try {
|
|
18374
|
+
return JSON.parse(fs9.readFileSync(file, "utf-8"));
|
|
18375
|
+
} catch {
|
|
18376
|
+
return null;
|
|
18377
|
+
}
|
|
18378
|
+
}
|
|
18379
|
+
var ALIAS_RE = /^[a-z0-9][\w.-]{0,63}$/i;
|
|
18380
|
+
function readSpec(value) {
|
|
18381
|
+
if (typeof value === "string")
|
|
18382
|
+
return value.trim() || null;
|
|
18383
|
+
if (value && typeof value === "object") {
|
|
18384
|
+
const v = value;
|
|
18385
|
+
const inner = v.source ?? v.repo ?? v.url;
|
|
18386
|
+
if (typeof inner === "string")
|
|
18387
|
+
return inner.trim() || null;
|
|
18388
|
+
if (inner && typeof inner === "object") {
|
|
18389
|
+
const deep = inner.repo ?? inner.url;
|
|
18390
|
+
if (typeof deep === "string")
|
|
18391
|
+
return deep.trim() || null;
|
|
18392
|
+
}
|
|
18393
|
+
}
|
|
18394
|
+
return null;
|
|
18395
|
+
}
|
|
18396
|
+
function collect(file, tier, into) {
|
|
18397
|
+
const obj = readJson(file);
|
|
18398
|
+
const raw = obj?.pluginSources;
|
|
18399
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
18400
|
+
return;
|
|
18401
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
18402
|
+
if (!ALIAS_RE.test(name))
|
|
18403
|
+
continue;
|
|
18404
|
+
const spec = readSpec(value);
|
|
18405
|
+
if (!spec)
|
|
18406
|
+
continue;
|
|
18407
|
+
if (into.has(name))
|
|
18408
|
+
continue;
|
|
18409
|
+
into.set(name, { name, spec, tier, file });
|
|
18410
|
+
}
|
|
18411
|
+
}
|
|
18412
|
+
function loadDeclaredSources2(workDir, opts = {}) {
|
|
18413
|
+
const out = /* @__PURE__ */ new Map();
|
|
18414
|
+
collect(managedSettingsPath(), "managed", out);
|
|
18415
|
+
collect(path6.join(os6.homedir(), ".nexrall", "settings.json"), "user", out);
|
|
18416
|
+
if (opts.includeProject) {
|
|
18417
|
+
collect(path6.join(workDir, ".nexrall", "settings.json"), "project", out);
|
|
18418
|
+
collect(path6.join(workDir, ".nexrall", "settings.local.json"), "project", out);
|
|
18419
|
+
}
|
|
18420
|
+
return [...out.values()];
|
|
18421
|
+
}
|
|
18422
|
+
function allowedSourcePatterns2() {
|
|
18423
|
+
const obj = readJson(managedSettingsPath());
|
|
18424
|
+
const v = obj?.allowedPluginSources;
|
|
18425
|
+
if (!Array.isArray(v))
|
|
18426
|
+
return null;
|
|
18427
|
+
const pats = v.filter((x2) => typeof x2 === "string" && x2.trim().length > 0);
|
|
18428
|
+
return pats.length ? pats : null;
|
|
18429
|
+
}
|
|
18430
|
+
function isSourceAllowed2(spec, patterns = allowedSourcePatterns2()) {
|
|
18431
|
+
if (!patterns)
|
|
18432
|
+
return true;
|
|
18433
|
+
const cleaned = spec.trim().replace(/^https?:\/\/(?:www\.)?github\.com\//i, "").replace(/\.git$/, "");
|
|
18434
|
+
const base = cleaned.split("#")[0].split("/").slice(0, 2).join("/").toLowerCase();
|
|
18435
|
+
return patterns.some((p) => {
|
|
18436
|
+
const pat = p.trim().toLowerCase().replace(/^https?:\/\/(?:www\.)?github\.com\//i, "");
|
|
18437
|
+
if (pat === "*")
|
|
18438
|
+
return true;
|
|
18439
|
+
if (pat.endsWith("/*"))
|
|
18440
|
+
return base.startsWith(pat.slice(0, -1));
|
|
18441
|
+
return base === pat.split("#")[0].split("/").slice(0, 2).join("/");
|
|
18442
|
+
});
|
|
18443
|
+
}
|
|
18444
|
+
function resolveSourceAlias2(alias, workDir, opts = {}) {
|
|
18445
|
+
const want = alias.trim().toLowerCase();
|
|
18446
|
+
return loadDeclaredSources2(workDir, opts).find((s2) => s2.name.toLowerCase() === want) ?? null;
|
|
18447
|
+
}
|
|
18448
|
+
function writeDeclaredSource2(file, name, spec) {
|
|
18449
|
+
if (!ALIAS_RE.test(name)) {
|
|
18450
|
+
throw new Error(`Invalid source name "${name}". Use letters, numbers, dot, dash or underscore.`);
|
|
18451
|
+
}
|
|
18452
|
+
const obj = readJson(file) ?? {};
|
|
18453
|
+
const existing = obj.pluginSources && typeof obj.pluginSources === "object" && !Array.isArray(obj.pluginSources) ? obj.pluginSources : {};
|
|
18454
|
+
obj.pluginSources = { ...existing, [name]: spec };
|
|
18455
|
+
fs9.mkdirSync(path6.dirname(file), { recursive: true });
|
|
18456
|
+
fs9.writeFileSync(file, JSON.stringify(obj, null, 2) + "\n", "utf-8");
|
|
18457
|
+
}
|
|
18458
|
+
function removeDeclaredSource2(file, name) {
|
|
18459
|
+
const obj = readJson(file);
|
|
18460
|
+
if (!obj?.pluginSources || typeof obj.pluginSources !== "object")
|
|
18461
|
+
return false;
|
|
18462
|
+
const sources = obj.pluginSources;
|
|
18463
|
+
if (!(name in sources))
|
|
18464
|
+
return false;
|
|
18465
|
+
delete sources[name];
|
|
18466
|
+
fs9.writeFileSync(file, JSON.stringify(obj, null, 2) + "\n", "utf-8");
|
|
18467
|
+
return true;
|
|
18468
|
+
}
|
|
18469
|
+
function sourcesFileFor2(scope, workDir) {
|
|
18470
|
+
return scope === "user" ? path6.join(os6.homedir(), ".nexrall", "settings.json") : path6.join(workDir, ".nexrall", "settings.json");
|
|
18471
|
+
}
|
|
18472
|
+
}
|
|
18473
|
+
});
|
|
18474
|
+
|
|
17747
18475
|
// ../core/dist/plugins/installer.js
|
|
17748
18476
|
var require_installer = __commonJS({
|
|
17749
18477
|
"../core/dist/plugins/installer.js"(exports) {
|
|
@@ -17796,8 +18524,8 @@ var require_installer = __commonJS({
|
|
|
17796
18524
|
exports.searchRegistry = searchRegistry2;
|
|
17797
18525
|
exports.getRegistryPlugin = getRegistryPlugin2;
|
|
17798
18526
|
exports.reportInstall = reportInstall2;
|
|
17799
|
-
exports.parsePluginSource =
|
|
17800
|
-
exports.inspectPluginDir =
|
|
18527
|
+
exports.parsePluginSource = parsePluginSource2;
|
|
18528
|
+
exports.inspectPluginDir = inspectPluginDir2;
|
|
17801
18529
|
exports.installPlugin = installPlugin2;
|
|
17802
18530
|
exports.readReceipt = readReceipt2;
|
|
17803
18531
|
exports.removePlugin = removePlugin2;
|
|
@@ -17807,6 +18535,8 @@ var require_installer = __commonJS({
|
|
|
17807
18535
|
var os6 = __importStar(__require("os"));
|
|
17808
18536
|
var child_process_1 = __require("child_process");
|
|
17809
18537
|
var client_1 = require_client();
|
|
18538
|
+
var index_1 = require_plugins();
|
|
18539
|
+
var sources_1 = require_sources();
|
|
17810
18540
|
var RECEIPT_FILE = "_install.json";
|
|
17811
18541
|
async function searchRegistry2(query, limit = 50) {
|
|
17812
18542
|
const u = new URL(`${client_1.API_BASE}/api/code/plugins`);
|
|
@@ -17836,7 +18566,7 @@ var require_installer = __commonJS({
|
|
|
17836
18566
|
fetch(`${client_1.API_BASE}/api/code/plugins/${encodeURIComponent(name)}/installed`, { method: "POST" }).catch(() => {
|
|
17837
18567
|
});
|
|
17838
18568
|
}
|
|
17839
|
-
function
|
|
18569
|
+
function parsePluginSource2(spec) {
|
|
17840
18570
|
const raw = spec.trim();
|
|
17841
18571
|
if (!raw)
|
|
17842
18572
|
throw new Error("Empty plugin source.");
|
|
@@ -17883,29 +18613,45 @@ var require_installer = __commonJS({
|
|
|
17883
18613
|
return [];
|
|
17884
18614
|
}
|
|
17885
18615
|
}
|
|
17886
|
-
function
|
|
18616
|
+
function inspectPluginDir2(dir) {
|
|
17887
18617
|
let meta = {};
|
|
17888
|
-
|
|
17889
|
-
|
|
17890
|
-
|
|
17891
|
-
|
|
17892
|
-
|
|
17893
|
-
|
|
17894
|
-
|
|
17895
|
-
|
|
18618
|
+
const manifest = (0, index_1.resolvePluginFile)(dir, "manifest");
|
|
18619
|
+
if (manifest) {
|
|
18620
|
+
try {
|
|
18621
|
+
const j = JSON.parse(fs9.readFileSync(manifest, "utf-8"));
|
|
18622
|
+
meta = {
|
|
18623
|
+
name: typeof j.name === "string" ? j.name : void 0,
|
|
18624
|
+
version: typeof j.version === "string" ? j.version : void 0,
|
|
18625
|
+
description: typeof j.description === "string" ? j.description : void 0
|
|
18626
|
+
};
|
|
18627
|
+
} catch {
|
|
18628
|
+
}
|
|
17896
18629
|
}
|
|
17897
18630
|
return {
|
|
17898
18631
|
commands: listMd(path6.join(dir, "commands")),
|
|
17899
18632
|
agents: listMd(path6.join(dir, "agents")),
|
|
17900
|
-
hasHooks:
|
|
17901
|
-
hasMcp:
|
|
18633
|
+
hasHooks: (0, index_1.resolvePluginFile)(dir, "hooks") !== null,
|
|
18634
|
+
hasMcp: (0, index_1.resolvePluginFile)(dir, "mcp") !== null,
|
|
17902
18635
|
meta
|
|
17903
18636
|
};
|
|
17904
18637
|
}
|
|
17905
18638
|
function looksLikePlugin(dir) {
|
|
17906
|
-
const i2 =
|
|
18639
|
+
const i2 = inspectPluginDir2(dir);
|
|
17907
18640
|
return i2.commands.length > 0 || i2.agents.length > 0 || i2.hasHooks || i2.hasMcp || i2.meta.name !== void 0;
|
|
17908
18641
|
}
|
|
18642
|
+
async function resolveCommitSha(repo, ref) {
|
|
18643
|
+
try {
|
|
18644
|
+
const res = await fetch(`https://api.github.com/repos/${repo}/commits/${encodeURIComponent(ref || "HEAD")}`, {
|
|
18645
|
+
headers: { Accept: "application/vnd.github.sha", "User-Agent": "nexrall-code" }
|
|
18646
|
+
});
|
|
18647
|
+
if (!res.ok)
|
|
18648
|
+
return null;
|
|
18649
|
+
const sha = (await res.text()).trim();
|
|
18650
|
+
return /^[0-9a-f]{40}$/i.test(sha) ? sha : null;
|
|
18651
|
+
} catch {
|
|
18652
|
+
return null;
|
|
18653
|
+
}
|
|
18654
|
+
}
|
|
17909
18655
|
async function downloadTarball(repo, ref, destFile) {
|
|
17910
18656
|
const r2 = ref || "HEAD";
|
|
17911
18657
|
const url = `https://codeload.github.com/${repo}/tar.gz/${encodeURIComponent(r2)}`;
|
|
@@ -17956,28 +18702,33 @@ var require_installer = __commonJS({
|
|
|
17956
18702
|
return scope === "project" ? path6.join(workDir || process.cwd(), ".nexrall", "plugins") : path6.join(os6.homedir(), ".nexrall", "plugins");
|
|
17957
18703
|
}
|
|
17958
18704
|
async function installPlugin2(spec, opts = {}) {
|
|
17959
|
-
const
|
|
18705
|
+
const source2 = parsePluginSource2(spec);
|
|
17960
18706
|
const scope = opts.scope ?? "global";
|
|
18707
|
+
const patterns = (0, sources_1.allowedSourcePatterns)();
|
|
18708
|
+
if (patterns && source2.kind === "github" && !(0, sources_1.isSourceAllowed)(source2.raw, patterns)) {
|
|
18709
|
+
throw new Error(`Blocked by your organisation's policy: plugins may only be installed from ${patterns.join(", ")}.`);
|
|
18710
|
+
}
|
|
17961
18711
|
const tmpBase = fs9.mkdtempSync(path6.join(os6.tmpdir(), "nexrall-plugin-"));
|
|
17962
18712
|
try {
|
|
17963
18713
|
let repoRoot;
|
|
17964
|
-
if (
|
|
17965
|
-
if (!fs9.existsSync(
|
|
17966
|
-
throw new Error(`Local plugin path not found: ${
|
|
18714
|
+
if (source2.kind === "local") {
|
|
18715
|
+
if (!fs9.existsSync(source2.repo) || !fs9.statSync(source2.repo).isDirectory()) {
|
|
18716
|
+
throw new Error(`Local plugin path not found: ${source2.repo}`);
|
|
17967
18717
|
}
|
|
17968
|
-
repoRoot =
|
|
18718
|
+
repoRoot = source2.repo;
|
|
17969
18719
|
} else {
|
|
17970
18720
|
const tarFile = path6.join(tmpBase, "plugin.tar.gz");
|
|
17971
|
-
await downloadTarball(
|
|
18721
|
+
await downloadTarball(source2.repo, source2.ref, tarFile);
|
|
17972
18722
|
repoRoot = extractTarball(tarFile, path6.join(tmpBase, "x"));
|
|
17973
18723
|
}
|
|
17974
|
-
|
|
18724
|
+
const sha = source2.kind === "github" ? await resolveCommitSha(source2.repo, source2.ref) : null;
|
|
18725
|
+
let pluginRoot = source2.subdir ? path6.join(repoRoot, source2.subdir) : repoRoot;
|
|
17975
18726
|
pluginRoot = path6.resolve(pluginRoot);
|
|
17976
18727
|
if (!path6.resolve(pluginRoot).startsWith(path6.resolve(repoRoot))) {
|
|
17977
18728
|
throw new Error("Plugin subdirectory escapes the repository \u2014 refusing.");
|
|
17978
18729
|
}
|
|
17979
18730
|
if (!fs9.existsSync(pluginRoot) || !fs9.statSync(pluginRoot).isDirectory()) {
|
|
17980
|
-
throw new Error(`Subdirectory not found in repo: ${
|
|
18731
|
+
throw new Error(`Subdirectory not found in repo: ${source2.subdir}`);
|
|
17981
18732
|
}
|
|
17982
18733
|
if (!looksLikePlugin(pluginRoot)) {
|
|
17983
18734
|
const candidates = ["plugin", ".nexrall-plugin"].map((c) => path6.join(pluginRoot, c));
|
|
@@ -17988,12 +18739,16 @@ var require_installer = __commonJS({
|
|
|
17988
18739
|
throw new Error("No plugin found: expected plugin.json, commands/, agents/, hooks.json or mcp.json at the source root.");
|
|
17989
18740
|
}
|
|
17990
18741
|
}
|
|
17991
|
-
const inspection =
|
|
17992
|
-
const name = opts.name || inspection.meta.name || (
|
|
18742
|
+
const inspection = inspectPluginDir2(pluginRoot);
|
|
18743
|
+
const name = opts.name || inspection.meta.name || (source2.subdir ? path6.basename(source2.subdir) : void 0) || (source2.kind === "github" ? source2.repo.split("/")[1] : path6.basename(source2.repo));
|
|
17993
18744
|
if (!/^[\w.-]+$/.test(name))
|
|
17994
18745
|
throw new Error(`Invalid plugin name "${name}".`);
|
|
17995
18746
|
if (opts.confirm) {
|
|
17996
|
-
const ok = await opts.confirm(inspection, name
|
|
18747
|
+
const ok = await opts.confirm(inspection, name, {
|
|
18748
|
+
sha: sha ?? void 0,
|
|
18749
|
+
previousSha: opts._previousSha,
|
|
18750
|
+
isUpdate: Boolean(opts._previousSha) || Boolean(opts.force)
|
|
18751
|
+
});
|
|
17997
18752
|
if (!ok)
|
|
17998
18753
|
throw new Error("Installation cancelled.");
|
|
17999
18754
|
}
|
|
@@ -18006,14 +18761,15 @@ var require_installer = __commonJS({
|
|
|
18006
18761
|
}
|
|
18007
18762
|
copyPluginDir(pluginRoot, dest);
|
|
18008
18763
|
const receipt = {
|
|
18009
|
-
source:
|
|
18010
|
-
kind:
|
|
18011
|
-
ref:
|
|
18012
|
-
subdir:
|
|
18013
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
18764
|
+
source: source2.raw,
|
|
18765
|
+
kind: source2.kind,
|
|
18766
|
+
ref: source2.ref,
|
|
18767
|
+
subdir: source2.subdir,
|
|
18768
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18769
|
+
...sha ? { sha } : {}
|
|
18014
18770
|
};
|
|
18015
18771
|
fs9.writeFileSync(path6.join(dest, RECEIPT_FILE), JSON.stringify(receipt, null, 2));
|
|
18016
|
-
return { name, dir: dest, scope, inspection };
|
|
18772
|
+
return { name, dir: dest, scope, inspection, sha: sha ?? void 0, previousSha: opts._previousSha };
|
|
18017
18773
|
} finally {
|
|
18018
18774
|
fs9.rmSync(tmpBase, { recursive: true, force: true });
|
|
18019
18775
|
}
|
|
@@ -18052,7 +18808,14 @@ var require_installer = __commonJS({
|
|
|
18052
18808
|
if (receipt.kind === "local") {
|
|
18053
18809
|
throw new Error(`Plugin "${name}" was installed from a local path \u2014 re-run 'nex plugin install ${receipt.source} --force'.`);
|
|
18054
18810
|
}
|
|
18055
|
-
return installPlugin2(receipt.source, {
|
|
18811
|
+
return installPlugin2(receipt.source, {
|
|
18812
|
+
scope: s2,
|
|
18813
|
+
workDir: opts.workDir,
|
|
18814
|
+
name,
|
|
18815
|
+
force: true,
|
|
18816
|
+
confirm: opts.confirm,
|
|
18817
|
+
_previousSha: receipt.sha
|
|
18818
|
+
});
|
|
18056
18819
|
}
|
|
18057
18820
|
throw new Error(`Plugin "${name}" is not installed.`);
|
|
18058
18821
|
}
|
|
@@ -18103,10 +18866,13 @@ var require_dist2 = __commonJS({
|
|
|
18103
18866
|
__exportStar(require_manager2(), exports);
|
|
18104
18867
|
__exportStar(require_loader(), exports);
|
|
18105
18868
|
__exportStar(require_agentTypes(), exports);
|
|
18869
|
+
__exportStar(require_planMode(), exports);
|
|
18870
|
+
__exportStar(require_agentRegistry(), exports);
|
|
18106
18871
|
__exportStar(require_rules(), exports);
|
|
18107
18872
|
__exportStar(require_destructive(), exports);
|
|
18108
18873
|
__exportStar(require_plugins(), exports);
|
|
18109
18874
|
__exportStar(require_installer(), exports);
|
|
18875
|
+
__exportStar(require_sources(), exports);
|
|
18110
18876
|
}
|
|
18111
18877
|
});
|
|
18112
18878
|
|
|
@@ -20922,23 +21688,23 @@ var require_react_reconciler_production = __commonJS({
|
|
|
20922
21688
|
return "\nError generating stack: " + x2.message + "\n" + x2.stack;
|
|
20923
21689
|
}
|
|
20924
21690
|
}
|
|
20925
|
-
function createCapturedValueAtFiber(value,
|
|
21691
|
+
function createCapturedValueAtFiber(value, source2) {
|
|
20926
21692
|
if ("object" === typeof value && null !== value) {
|
|
20927
21693
|
var existing = CapturedStacks.get(value);
|
|
20928
21694
|
if (void 0 !== existing)
|
|
20929
21695
|
return existing;
|
|
20930
|
-
|
|
21696
|
+
source2 = {
|
|
20931
21697
|
value,
|
|
20932
|
-
source,
|
|
20933
|
-
stack: getStackByFiberInDevAndProd(
|
|
21698
|
+
source: source2,
|
|
21699
|
+
stack: getStackByFiberInDevAndProd(source2)
|
|
20934
21700
|
};
|
|
20935
|
-
CapturedStacks.set(value,
|
|
20936
|
-
return
|
|
21701
|
+
CapturedStacks.set(value, source2);
|
|
21702
|
+
return source2;
|
|
20937
21703
|
}
|
|
20938
21704
|
return {
|
|
20939
21705
|
value,
|
|
20940
|
-
source,
|
|
20941
|
-
stack: getStackByFiberInDevAndProd(
|
|
21706
|
+
source: source2,
|
|
21707
|
+
stack: getStackByFiberInDevAndProd(source2)
|
|
20942
21708
|
};
|
|
20943
21709
|
}
|
|
20944
21710
|
function pushTreeFork(workInProgress2, totalChildren) {
|
|
@@ -30110,23 +30876,23 @@ var require_react_reconciler_development = __commonJS({
|
|
|
30110
30876
|
function describeFunctionComponentFrameWithoutLineNumber(fn) {
|
|
30111
30877
|
return (fn = fn ? fn.displayName || fn.name : "") ? describeBuiltInComponentFrame(fn) : "";
|
|
30112
30878
|
}
|
|
30113
|
-
function createCapturedValueAtFiber(value,
|
|
30879
|
+
function createCapturedValueAtFiber(value, source2) {
|
|
30114
30880
|
if ("object" === typeof value && null !== value) {
|
|
30115
30881
|
var existing = CapturedStacks.get(value);
|
|
30116
30882
|
if (void 0 !== existing)
|
|
30117
30883
|
return existing;
|
|
30118
|
-
|
|
30884
|
+
source2 = {
|
|
30119
30885
|
value,
|
|
30120
|
-
source,
|
|
30121
|
-
stack: getStackByFiberInDevAndProd(
|
|
30886
|
+
source: source2,
|
|
30887
|
+
stack: getStackByFiberInDevAndProd(source2)
|
|
30122
30888
|
};
|
|
30123
|
-
CapturedStacks.set(value,
|
|
30124
|
-
return
|
|
30889
|
+
CapturedStacks.set(value, source2);
|
|
30890
|
+
return source2;
|
|
30125
30891
|
}
|
|
30126
30892
|
return {
|
|
30127
30893
|
value,
|
|
30128
|
-
source,
|
|
30129
|
-
stack: getStackByFiberInDevAndProd(
|
|
30894
|
+
source: source2,
|
|
30895
|
+
stack: getStackByFiberInDevAndProd(source2)
|
|
30130
30896
|
};
|
|
30131
30897
|
}
|
|
30132
30898
|
function pushTreeFork(workInProgress2, totalChildren) {
|
|
@@ -42684,9 +43450,9 @@ var require_buffer_util = __commonJS({
|
|
|
42684
43450
|
}
|
|
42685
43451
|
return target;
|
|
42686
43452
|
}
|
|
42687
|
-
function _mask(
|
|
43453
|
+
function _mask(source2, mask, output, offset, length) {
|
|
42688
43454
|
for (let i2 = 0; i2 < length; i2++) {
|
|
42689
|
-
output[offset + i2] =
|
|
43455
|
+
output[offset + i2] = source2[i2] ^ mask[i2 & 3];
|
|
42690
43456
|
}
|
|
42691
43457
|
}
|
|
42692
43458
|
function _unmask(buffer, mask) {
|
|
@@ -42725,11 +43491,11 @@ var require_buffer_util = __commonJS({
|
|
|
42725
43491
|
if (!process.env.WS_NO_BUFFER_UTIL) {
|
|
42726
43492
|
try {
|
|
42727
43493
|
const bufferUtil = __require("bufferutil");
|
|
42728
|
-
module.exports.mask = function(
|
|
43494
|
+
module.exports.mask = function(source2, mask, output, offset, length) {
|
|
42729
43495
|
if (length < 48)
|
|
42730
|
-
_mask(
|
|
43496
|
+
_mask(source2, mask, output, offset, length);
|
|
42731
43497
|
else
|
|
42732
|
-
bufferUtil.mask(
|
|
43498
|
+
bufferUtil.mask(source2, mask, output, offset, length);
|
|
42733
43499
|
};
|
|
42734
43500
|
module.exports.unmask = function(buffer, mask) {
|
|
42735
43501
|
if (buffer.length < 32)
|
|
@@ -49446,16 +50212,16 @@ var require_dist3 = __commonJS({
|
|
|
49446
50212
|
}
|
|
49447
50213
|
function _objectSpread(target) {
|
|
49448
50214
|
for (var i2 = 1; i2 < arguments.length; i2++) {
|
|
49449
|
-
var
|
|
50215
|
+
var source2 = arguments[i2] != null ? arguments[i2] : {};
|
|
49450
50216
|
if (i2 % 2) {
|
|
49451
|
-
ownKeys(Object(
|
|
49452
|
-
_defineProperty(target, key,
|
|
50217
|
+
ownKeys(Object(source2), true).forEach(function(key) {
|
|
50218
|
+
_defineProperty(target, key, source2[key]);
|
|
49453
50219
|
});
|
|
49454
50220
|
} else if (Object.getOwnPropertyDescriptors) {
|
|
49455
|
-
Object.defineProperties(target, Object.getOwnPropertyDescriptors(
|
|
50221
|
+
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source2));
|
|
49456
50222
|
} else {
|
|
49457
|
-
ownKeys(Object(
|
|
49458
|
-
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(
|
|
50223
|
+
ownKeys(Object(source2)).forEach(function(key) {
|
|
50224
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source2, key));
|
|
49459
50225
|
});
|
|
49460
50226
|
}
|
|
49461
50227
|
}
|
|
@@ -54175,6 +54941,16 @@ function trustGrantedByEnv() {
|
|
|
54175
54941
|
const v = process.env[TRUST_ENV_VAR];
|
|
54176
54942
|
return v === "1" || v === "true";
|
|
54177
54943
|
}
|
|
54944
|
+
function declaresPluginSources(dir) {
|
|
54945
|
+
try {
|
|
54946
|
+
const raw = fs5.readFileSync(path3.join(dir, ".nexrall", "settings.json"), "utf-8");
|
|
54947
|
+
const obj = JSON.parse(raw);
|
|
54948
|
+
const s2 = obj.pluginSources;
|
|
54949
|
+
return Boolean(s2 && typeof s2 === "object" && !Array.isArray(s2) && Object.keys(s2).length > 0);
|
|
54950
|
+
} catch {
|
|
54951
|
+
return false;
|
|
54952
|
+
}
|
|
54953
|
+
}
|
|
54178
54954
|
function detectTrustSignals(dir) {
|
|
54179
54955
|
const signals = [];
|
|
54180
54956
|
const exists = (...p) => {
|
|
@@ -54194,7 +54970,9 @@ function detectTrustSignals(dir) {
|
|
|
54194
54970
|
signals.push(".nexrall/permissions.json \u2014 pre-approved tool permissions");
|
|
54195
54971
|
}
|
|
54196
54972
|
if (exists(".nexrall", "settings.json")) {
|
|
54197
|
-
signals.push(
|
|
54973
|
+
signals.push(
|
|
54974
|
+
declaresPluginSources(dir) ? ".nexrall/settings.json \u2014 project settings, and declares plugin sources (aliases for remote plugin repos)" : ".nexrall/settings.json \u2014 project settings and permission rules"
|
|
54975
|
+
);
|
|
54198
54976
|
}
|
|
54199
54977
|
if (exists("nexrall.md")) {
|
|
54200
54978
|
signals.push("nexrall.md \u2014 project instructions added to the agent\u2019s prompt");
|
|
@@ -60703,15 +61481,15 @@ var generateLineNumbers = (line, around) => {
|
|
|
60703
61481
|
}
|
|
60704
61482
|
return lineNumbers;
|
|
60705
61483
|
};
|
|
60706
|
-
var codeExcerpt = (
|
|
61484
|
+
var codeExcerpt = (source2, line, options = {}) => {
|
|
60707
61485
|
var _a;
|
|
60708
|
-
if (typeof
|
|
61486
|
+
if (typeof source2 !== "string") {
|
|
60709
61487
|
throw new TypeError("Source code is missing.");
|
|
60710
61488
|
}
|
|
60711
61489
|
if (!line || line < 1) {
|
|
60712
61490
|
throw new TypeError("Line number must start from `1`.");
|
|
60713
61491
|
}
|
|
60714
|
-
const lines = dist_default3(
|
|
61492
|
+
const lines = dist_default3(source2).split(/\r?\n/);
|
|
60715
61493
|
if (line > lines.length) {
|
|
60716
61494
|
return;
|
|
60717
61495
|
}
|
|
@@ -63166,7 +63944,7 @@ var InkReadlineAdapter = class extends EventEmitter3 {
|
|
|
63166
63944
|
};
|
|
63167
63945
|
|
|
63168
63946
|
// src/commands/chat.ts
|
|
63169
|
-
var CLI_VERSION = "0.5.
|
|
63947
|
+
var CLI_VERSION = "0.5.51";
|
|
63170
63948
|
var MODEL_LABELS = {
|
|
63171
63949
|
turbo: "Nexrall Turbo",
|
|
63172
63950
|
pro: "Nexrall Pro",
|
|
@@ -63384,15 +64162,23 @@ function formatContextUsage(messages, modelAlias) {
|
|
|
63384
64162
|
return lines.join("\n");
|
|
63385
64163
|
}
|
|
63386
64164
|
function formatAgentsList(workDir) {
|
|
63387
|
-
const types3 = (0, import_code_core3.
|
|
64165
|
+
const { types: types3, warnings } = (0, import_code_core3.loadAgentTypesWithWarnings)(workDir);
|
|
63388
64166
|
if (!types3.length)
|
|
63389
64167
|
return source_default.dim(" No agent types found (this should not happen \u2014 builtins always register).");
|
|
63390
64168
|
const lines = types3.map((t2) => {
|
|
63391
|
-
const tools = t2.tools ? source_default.dim(` \u2014 tools: ${t2.tools.join(", ")}`) : source_default.dim(" \u2014
|
|
64169
|
+
const tools = t2.tools ? source_default.dim(` \u2014 tools: ${t2.tools.join(", ")}`) : source_default.dim(" \u2014 ALL tools (no allowlist)");
|
|
63392
64170
|
const model = t2.model ? source_default.dim(` \u2014 model: ${t2.model}`) : "";
|
|
63393
64171
|
const scope = source_default.dim(` (${t2.source})`);
|
|
63394
64172
|
return " " + source_default.cyan(t2.name.padEnd(16)) + source_default.white(t2.description) + scope + tools + model;
|
|
63395
64173
|
});
|
|
64174
|
+
if (warnings.length) {
|
|
64175
|
+
lines.push("");
|
|
64176
|
+
lines.push(" " + source_default.yellow.bold(`\u26A0 ${warnings.length} problem${warnings.length > 1 ? "s" : ""} in your agent definitions:`));
|
|
64177
|
+
for (const w of warnings) {
|
|
64178
|
+
lines.push(" " + source_default.yellow(`\u2022 ${w.agent}`) + source_default.dim(` \u2014 ${w.message}`));
|
|
64179
|
+
lines.push(" " + source_default.dim(w.file));
|
|
64180
|
+
}
|
|
64181
|
+
}
|
|
63396
64182
|
return lines.join("\n");
|
|
63397
64183
|
}
|
|
63398
64184
|
async function runTurn(messages, modelAlias, workDir, abortSignal, env3, nexrallMd, mode, effort, checkpointManager, onProgress) {
|
|
@@ -63429,6 +64215,12 @@ async function runTurn(messages, modelAlias, workDir, abortSignal, env3, nexrall
|
|
|
63429
64215
|
env: env3,
|
|
63430
64216
|
nexrallMd,
|
|
63431
64217
|
mode,
|
|
64218
|
+
// `/mode plan` previously only hinted to the backend — the footer said "plan
|
|
64219
|
+
// mode on" while every write tool stayed live, so the one mode whose entire
|
|
64220
|
+
// promise is "I will not touch anything" was the one not enforced. This
|
|
64221
|
+
// makes it real: the loop refuses mutating tools before the permission
|
|
64222
|
+
// prompt, and sub-agents inherit the lock.
|
|
64223
|
+
planMode: mode === "plan",
|
|
63432
64224
|
effort,
|
|
63433
64225
|
// The backend streams a cumulative output-token count (routes/code.js's
|
|
63434
64226
|
// sendProgress, throttled to ≤5/s) covering thinking, visible text AND
|
|
@@ -63582,6 +64374,7 @@ async function runTurnHeadless(messages, modelAlias, workDir, _abortSignal, env3
|
|
|
63582
64374
|
env: env3,
|
|
63583
64375
|
nexrallMd,
|
|
63584
64376
|
mode,
|
|
64377
|
+
planMode: mode === "plan",
|
|
63585
64378
|
effort,
|
|
63586
64379
|
abortSignal: _abortSignal,
|
|
63587
64380
|
onText: (text) => {
|
|
@@ -64509,11 +65302,23 @@ ${caption}` : `[Attached: ${rel}]`;
|
|
|
64509
65302
|
// src/commands/plugin.ts
|
|
64510
65303
|
var import_prompts = __toESM(require_prompts3(), 1);
|
|
64511
65304
|
var import_code_core4 = __toESM(require_dist2(), 1);
|
|
64512
|
-
function describeInspection(i2, name) {
|
|
65305
|
+
function describeInspection(i2, name, ctx) {
|
|
64513
65306
|
console.log();
|
|
64514
65307
|
console.log(source_default.bold(` Plugin: ${name}`) + (i2.meta.version ? source_default.dim(` v${i2.meta.version}`) : ""));
|
|
64515
65308
|
if (i2.meta.description)
|
|
64516
65309
|
console.log(source_default.dim(` ${i2.meta.description}`));
|
|
65310
|
+
if (ctx?.sha) {
|
|
65311
|
+
const short = (s2) => s2.slice(0, 7);
|
|
65312
|
+
if (ctx.previousSha && ctx.previousSha !== ctx.sha) {
|
|
65313
|
+
console.log(source_default.dim(" commit: ") + source_default.yellow(`${short(ctx.previousSha)} \u2192 ${short(ctx.sha)}`));
|
|
65314
|
+
} else if (ctx.previousSha === ctx.sha) {
|
|
65315
|
+
console.log(source_default.dim(` commit: ${short(ctx.sha)} (already up to date)`));
|
|
65316
|
+
} else {
|
|
65317
|
+
console.log(source_default.dim(` commit: ${short(ctx.sha)}`));
|
|
65318
|
+
}
|
|
65319
|
+
} else if (ctx?.isUpdate) {
|
|
65320
|
+
console.log(source_default.dim(" commit: unknown (could not reach the GitHub API)"));
|
|
65321
|
+
}
|
|
64517
65322
|
if (i2.commands.length)
|
|
64518
65323
|
console.log(` ${source_default.cyan("commands:")} ${i2.commands.map((c) => "/" + c).join(", ")}`);
|
|
64519
65324
|
if (i2.agents.length)
|
|
@@ -64523,10 +65328,16 @@ function describeInspection(i2, name) {
|
|
|
64523
65328
|
if (i2.hasMcp)
|
|
64524
65329
|
console.log(` ${source_default.yellow("mcp:")} yes`);
|
|
64525
65330
|
}
|
|
64526
|
-
async function confirmInstall(i2, name, autoYes) {
|
|
64527
|
-
describeInspection(i2, name);
|
|
65331
|
+
async function confirmInstall(i2, name, autoYes, ctx) {
|
|
65332
|
+
describeInspection(i2, name, ctx);
|
|
64528
65333
|
const dangerous = i2.hasHooks || i2.hasMcp;
|
|
64529
65334
|
if (dangerous) {
|
|
65335
|
+
if (ctx?.isUpdate) {
|
|
65336
|
+
console.log();
|
|
65337
|
+
console.log(source_default.red.bold(" \u26A0 THIS UPDATE SHIPS CODE EXECUTION"));
|
|
65338
|
+
console.log(source_default.red(" A version of this plugin you already trust is being replaced by one"));
|
|
65339
|
+
console.log(source_default.red(" that runs commands. Review the diff before continuing."));
|
|
65340
|
+
}
|
|
64530
65341
|
console.log();
|
|
64531
65342
|
console.log(source_default.red.bold(" \u26A0 SECURITY WARNING"));
|
|
64532
65343
|
if (i2.hasHooks) {
|
|
@@ -64562,35 +65373,43 @@ async function confirmInstall(i2, name, autoYes) {
|
|
|
64562
65373
|
async function pluginInstallCommand(spec, opts) {
|
|
64563
65374
|
const scope = opts.project ? "project" : "global";
|
|
64564
65375
|
try {
|
|
64565
|
-
let
|
|
65376
|
+
let source2 = spec;
|
|
64566
65377
|
let registryName;
|
|
64567
65378
|
const isShortName = /^[\w.-]+$/.test(spec.trim()) && !spec.includes("/");
|
|
64568
65379
|
if (isShortName) {
|
|
65380
|
+
const alias = (0, import_code_core4.resolveSourceAlias)(spec.trim(), process.cwd(), { includeProject: true });
|
|
65381
|
+
if (alias) {
|
|
65382
|
+
source2 = alias.spec;
|
|
65383
|
+
console.log(source_default.dim(` Source: ${alias.name} (${alias.tier}) \u2190 ${alias.spec}`));
|
|
65384
|
+
}
|
|
65385
|
+
}
|
|
65386
|
+
if (isShortName && source2 === spec) {
|
|
64569
65387
|
const entry = await (0, import_code_core4.getRegistryPlugin)(spec.trim()).catch(() => null);
|
|
64570
65388
|
if (entry) {
|
|
64571
|
-
|
|
65389
|
+
source2 = entry.source;
|
|
64572
65390
|
registryName = entry.name;
|
|
64573
65391
|
const badge = entry.official ? source_default.magenta(" [official]") : entry.verified ? source_default.green(" [verified]") : "";
|
|
64574
65392
|
console.log(source_default.dim(` Registry: ${entry.display_name}${badge} \u2190 ${entry.source}`));
|
|
64575
65393
|
} else {
|
|
64576
|
-
console.error(source_default.red(` \u2717 "${spec}" not
|
|
64577
|
-
console.error(source_default.dim(" Search:
|
|
64578
|
-
console.error(source_default.dim("
|
|
65394
|
+
console.error(source_default.red(` \u2717 "${spec}" is not a declared source or a registry plugin.`));
|
|
65395
|
+
console.error(source_default.dim(" Search: nex plugin search <keyword>"));
|
|
65396
|
+
console.error(source_default.dim(" From GitHub: nex plugin install owner/repo"));
|
|
65397
|
+
console.error(source_default.dim(" Declare it: nex plugin source add " + spec.trim() + " owner/repo"));
|
|
64579
65398
|
process.exitCode = 1;
|
|
64580
65399
|
return;
|
|
64581
65400
|
}
|
|
64582
65401
|
}
|
|
64583
|
-
const res = await (0, import_code_core4.installPlugin)(
|
|
65402
|
+
const res = await (0, import_code_core4.installPlugin)(source2, {
|
|
64584
65403
|
scope,
|
|
64585
65404
|
workDir: process.cwd(),
|
|
64586
65405
|
name: opts.name ?? registryName,
|
|
64587
65406
|
force: opts.force,
|
|
64588
|
-
confirm: (i2, name) => confirmInstall(i2, name, opts.yes === true)
|
|
65407
|
+
confirm: (i2, name, ctx) => confirmInstall(i2, name, opts.yes === true, ctx)
|
|
64589
65408
|
});
|
|
64590
65409
|
if (registryName)
|
|
64591
65410
|
(0, import_code_core4.reportInstall)(registryName);
|
|
64592
65411
|
console.log();
|
|
64593
|
-
console.log(source_default.green(` \u2713 Installed "${res.name}" (${res.scope}) \u2192 ${res.dir}`));
|
|
65412
|
+
console.log(source_default.green(` \u2713 Installed "${res.name}" (${res.scope}) \u2192 ${res.dir}`) + (res.sha ? source_default.dim(` @ ${res.sha.slice(0, 7)}`) : ""));
|
|
64594
65413
|
if (res.inspection.commands.length) {
|
|
64595
65414
|
console.log(source_default.dim(` Try: ${res.inspection.commands.map((c) => "/" + c).join(", ")}`));
|
|
64596
65415
|
}
|
|
@@ -64624,9 +65443,10 @@ async function pluginUpdateCommand(name, opts) {
|
|
|
64624
65443
|
try {
|
|
64625
65444
|
const res = await (0, import_code_core4.updatePlugin)(t2, {
|
|
64626
65445
|
workDir,
|
|
64627
|
-
confirm: (i2, n) => confirmInstall(i2, n, opts.yes === true)
|
|
65446
|
+
confirm: (i2, n, ctx) => confirmInstall(i2, n, opts.yes === true, ctx)
|
|
64628
65447
|
});
|
|
64629
|
-
|
|
65448
|
+
const moved = res.sha && res.previousSha && res.sha !== res.previousSha ? source_default.dim(` ${res.previousSha.slice(0, 7)} \u2192 ${res.sha.slice(0, 7)}`) : res.sha && res.previousSha === res.sha ? source_default.dim(" (unchanged)") : "";
|
|
65449
|
+
console.log(source_default.green(` \u2713 Updated "${res.name}"`) + moved);
|
|
64630
65450
|
} catch (err) {
|
|
64631
65451
|
console.error(source_default.red(` \u2717 ${t2}: ${err.message}`));
|
|
64632
65452
|
process.exitCode = 1;
|
|
@@ -64708,24 +65528,98 @@ function pluginListCommand() {
|
|
|
64708
65528
|
for (const p of plugins) {
|
|
64709
65529
|
const receipt = (0, import_code_core4.readReceipt)(p.dir);
|
|
64710
65530
|
const src = receipt ? source_default.dim(` \u2190 ${receipt.source}`) : source_default.dim(" (manual)");
|
|
65531
|
+
const at = receipt?.sha ? source_default.dim(` @ ${receipt.sha.slice(0, 7)}`) : "";
|
|
65532
|
+
const insp = (0, import_code_core4.inspectPluginDir)(p.dir);
|
|
65533
|
+
const runs = insp.hasHooks || insp.hasMcp ? source_default.yellow(` \u26A0 ${[insp.hasHooks && "hooks", insp.hasMcp && "mcp"].filter(Boolean).join("+")}`) : "";
|
|
64711
65534
|
console.log(
|
|
64712
|
-
" " + source_default.cyan(p.name.padEnd(24)) + source_default.dim(`${(p.version ?? "").padEnd(10)}${p.scope.padEnd(9)}`) + src
|
|
65535
|
+
" " + source_default.cyan(p.name.padEnd(24)) + source_default.dim(`${(p.version ?? "").padEnd(10)}${p.scope.padEnd(9)}`) + src + at + runs
|
|
64713
65536
|
);
|
|
64714
65537
|
}
|
|
64715
65538
|
console.log();
|
|
64716
65539
|
}
|
|
65540
|
+
function pluginSourceListCommand() {
|
|
65541
|
+
const workDir = process.cwd();
|
|
65542
|
+
const sources = (0, import_code_core4.loadDeclaredSources)(workDir, { includeProject: true });
|
|
65543
|
+
const patterns = (0, import_code_core4.allowedSourcePatterns)();
|
|
65544
|
+
if (patterns) {
|
|
65545
|
+
console.log();
|
|
65546
|
+
console.log(source_default.bold(" Organisation policy: ") + source_default.dim(`installs restricted to ${patterns.join(", ")}`));
|
|
65547
|
+
}
|
|
65548
|
+
if (!sources.length) {
|
|
65549
|
+
console.log(source_default.dim("\n No plugin sources declared."));
|
|
65550
|
+
console.log(source_default.dim(" Add one: nex plugin source add <alias> owner/repo"));
|
|
65551
|
+
console.log();
|
|
65552
|
+
return;
|
|
65553
|
+
}
|
|
65554
|
+
console.log();
|
|
65555
|
+
console.log(source_default.bold(" Declared plugin sources:"));
|
|
65556
|
+
for (const s2 of sources) {
|
|
65557
|
+
const tier = s2.tier === "project" ? source_default.yellow(s2.tier.padEnd(9)) : source_default.dim(s2.tier.padEnd(9));
|
|
65558
|
+
const blocked = !(0, import_code_core4.isSourceAllowed)(s2.spec, patterns) ? source_default.red(" \u2717 blocked by policy") : "";
|
|
65559
|
+
console.log(" " + source_default.cyan(s2.name.padEnd(20)) + tier + source_default.white(s2.spec) + blocked);
|
|
65560
|
+
}
|
|
65561
|
+
console.log();
|
|
65562
|
+
console.log(source_default.dim(" Install from one: nex plugin install <alias>"));
|
|
65563
|
+
console.log(source_default.dim(" Declaring a source does not install anything."));
|
|
65564
|
+
console.log();
|
|
65565
|
+
}
|
|
65566
|
+
function pluginSourceAddCommand(name, spec, opts) {
|
|
65567
|
+
try {
|
|
65568
|
+
(0, import_code_core4.parsePluginSource)(spec);
|
|
65569
|
+
const patterns = (0, import_code_core4.allowedSourcePatterns)();
|
|
65570
|
+
if (patterns && !(0, import_code_core4.isSourceAllowed)(spec, patterns)) {
|
|
65571
|
+
console.error(source_default.red(` \u2717 "${spec}" is not permitted by your organisation's policy.`));
|
|
65572
|
+
console.error(source_default.dim(` Allowed: ${patterns.join(", ")}`));
|
|
65573
|
+
process.exitCode = 1;
|
|
65574
|
+
return;
|
|
65575
|
+
}
|
|
65576
|
+
const scope = opts.project ? "project" : "user";
|
|
65577
|
+
const file = (0, import_code_core4.sourcesFileFor)(scope, process.cwd());
|
|
65578
|
+
(0, import_code_core4.writeDeclaredSource)(file, name, spec);
|
|
65579
|
+
console.log();
|
|
65580
|
+
console.log(source_default.green(` \u2713 Declared "${name}" \u2192 ${spec}`) + source_default.dim(` (${scope})`));
|
|
65581
|
+
console.log(source_default.dim(` ${file}`));
|
|
65582
|
+
console.log(source_default.dim(` Nothing installed yet \u2014 run: nex plugin install ${name}`));
|
|
65583
|
+
console.log();
|
|
65584
|
+
} catch (err) {
|
|
65585
|
+
console.error(source_default.red(` \u2717 ${err.message}`));
|
|
65586
|
+
process.exitCode = 1;
|
|
65587
|
+
}
|
|
65588
|
+
}
|
|
65589
|
+
function pluginSourceRemoveCommand(name, opts) {
|
|
65590
|
+
const workDir = process.cwd();
|
|
65591
|
+
const scope = opts.project ? "project" : "user";
|
|
65592
|
+
const file = (0, import_code_core4.sourcesFileFor)(scope, workDir);
|
|
65593
|
+
if ((0, import_code_core4.removeDeclaredSource)(file, name)) {
|
|
65594
|
+
console.log(source_default.green(` \u2713 Removed source "${name}" (${scope})`));
|
|
65595
|
+
console.log(source_default.dim(" Plugins already installed from it are untouched \u2014 remove them with nex plugin remove <name>"));
|
|
65596
|
+
return;
|
|
65597
|
+
}
|
|
65598
|
+
const found = (0, import_code_core4.resolveSourceAlias)(name, workDir, { includeProject: true });
|
|
65599
|
+
if (found) {
|
|
65600
|
+
console.error(source_default.red(` \u2717 "${name}" is declared in the ${found.tier} tier, not ${scope}.`));
|
|
65601
|
+
console.error(source_default.dim(` ${found.file}`));
|
|
65602
|
+
if (found.tier === "project")
|
|
65603
|
+
console.error(source_default.dim(" Retry with --project"));
|
|
65604
|
+
if (found.tier === "managed")
|
|
65605
|
+
console.error(source_default.dim(" Managed sources are set by your organisation and cannot be removed here."));
|
|
65606
|
+
} else {
|
|
65607
|
+
console.error(source_default.red(` \u2717 No source named "${name}".`));
|
|
65608
|
+
}
|
|
65609
|
+
process.exitCode = 1;
|
|
65610
|
+
}
|
|
64717
65611
|
|
|
64718
65612
|
// src/index.ts
|
|
64719
65613
|
var program2 = new Command();
|
|
64720
|
-
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.
|
|
65614
|
+
program2.name("nex").description("Nexrall Code \u2014 AI coding assistant (powered by Nexrall)").version("0.5.51").enablePositionalOptions();
|
|
64721
65615
|
program2.command("auth").description("Login to your Nexrall account").action(authCommand);
|
|
64722
65616
|
program2.command("logout").description("Log out of your Nexrall account").action(logoutCommand);
|
|
64723
65617
|
program2.command("update").description("Update nex to the latest version").option("-c, --check", "Check for updates without installing").option("-y, --yes", "Skip confirmation prompt").action(async (opts) => {
|
|
64724
65618
|
await updateCommand({ check: opts.check, yes: opts.yes });
|
|
64725
65619
|
});
|
|
64726
65620
|
var plugin = program2.command("plugin").description("Manage plugins (install from GitHub, list, update, remove)");
|
|
64727
|
-
plugin.command("install <source>").description("Install a plugin: registry name, owner/repo(#ref)(/subdir), GitHub URL, or local path").option("--project", "Install into ./.nexrall/plugins (default: ~/.nexrall/plugins)").option("--name <name>", "Override the installed plugin name").option("-f, --force", "Overwrite if already installed").option("-y, --yes", "Skip confirmation (still prompts for plugins with hooks/MCP)").action(async (
|
|
64728
|
-
await pluginInstallCommand(
|
|
65621
|
+
plugin.command("install <source>").description("Install a plugin: registry name, owner/repo(#ref)(/subdir), GitHub URL, or local path").option("--project", "Install into ./.nexrall/plugins (default: ~/.nexrall/plugins)").option("--name <name>", "Override the installed plugin name").option("-f, --force", "Overwrite if already installed").option("-y, --yes", "Skip confirmation (still prompts for plugins with hooks/MCP)").action(async (source2, opts) => {
|
|
65622
|
+
await pluginInstallCommand(source2, opts);
|
|
64729
65623
|
});
|
|
64730
65624
|
plugin.command("remove <name>").alias("uninstall").description("Remove an installed plugin").option("--project", "Only look in ./.nexrall/plugins").action((name, opts) => {
|
|
64731
65625
|
pluginRemoveCommand(name, opts);
|
|
@@ -64742,6 +65636,16 @@ plugin.command("search [query]").description("Search the Nexrall plugin registry
|
|
|
64742
65636
|
plugin.command("info <name>").description("Show registry details for a plugin").action(async (name) => {
|
|
64743
65637
|
await pluginInfoCommand(name);
|
|
64744
65638
|
});
|
|
65639
|
+
var source = plugin.command("source").description("Declare where plugins may be installed from (aliases for plugin repos)");
|
|
65640
|
+
source.command("list").alias("ls").description("List declared plugin sources").action(() => {
|
|
65641
|
+
pluginSourceListCommand();
|
|
65642
|
+
});
|
|
65643
|
+
source.command("add <name> <spec>").description("Declare a source: nex plugin source add acme acme/plugins").option("--project", "Write to ./.nexrall/settings.json so the team shares it (default: ~/.nexrall/settings.json)").action((name, spec, opts) => {
|
|
65644
|
+
pluginSourceAddCommand(name, spec, opts);
|
|
65645
|
+
});
|
|
65646
|
+
source.command("remove <name>").alias("rm").description("Remove a declared source (installed plugins are untouched)").option("--project", "Remove from ./.nexrall/settings.json").action((name, opts) => {
|
|
65647
|
+
pluginSourceRemoveCommand(name, opts);
|
|
65648
|
+
});
|
|
64745
65649
|
program2.command("sessions").description("List or delete saved chat sessions").option("-d, --delete <id>", "Delete a session by id").option("--clear-all", "Delete ALL saved sessions").action((opts) => {
|
|
64746
65650
|
if (opts.clearAll) {
|
|
64747
65651
|
const sessions2 = listSessions();
|