nexrall-code 0.5.93 → 0.5.95
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 +319 -104
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -11149,19 +11149,19 @@ var require_memory = __commonJS({
|
|
|
11149
11149
|
};
|
|
11150
11150
|
}();
|
|
11151
11151
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11152
|
-
exports2.AGENT_MEMORY_MAX_BYTES = exports2.AGENT_MEMORY_INJECT_MAX = exports2.MEMORY_HARD_CAP_BYTES = exports2.MEMORY_COMPACT_TRIGGER_BYTES = exports2.MEMORY_MAX_BYTES = exports2.MEMORY_ENTRY_MAX_CHARS = void 0;
|
|
11152
|
+
exports2.AGENT_MEMORY_MAX_BYTES = exports2.AGENT_MEMORY_INJECT_MAX = exports2.MEMORY_ARCHIVE_MAX_BYTES = exports2.MEMORY_HARD_CAP_BYTES = exports2.MEMORY_COMPACT_TRIGGER_BYTES = exports2.MEMORY_MAX_BYTES = exports2.MEMORY_ENTRY_MAX_CHARS = void 0;
|
|
11153
11153
|
exports2.memoryFilePath = memoryFilePath;
|
|
11154
11154
|
exports2.writeMemory = writeMemory;
|
|
11155
11155
|
exports2.readMemory = readMemory2;
|
|
11156
11156
|
exports2.readAllMemory = readAllMemory2;
|
|
11157
11157
|
exports2.clearMemory = clearMemory2;
|
|
11158
11158
|
exports2.memoryStats = memoryStats2;
|
|
11159
|
+
exports2.compactMemoryIfNeeded = compactMemoryIfNeeded2;
|
|
11159
11160
|
exports2.isSafeAgentName = isSafeAgentName;
|
|
11160
11161
|
exports2.agentMemoryPath = agentMemoryPath;
|
|
11161
11162
|
exports2.readAgentMemory = readAgentMemory;
|
|
11162
11163
|
exports2.writeAgentMemory = writeAgentMemory;
|
|
11163
11164
|
exports2.agentMemoryPreamble = agentMemoryPreamble;
|
|
11164
|
-
exports2.compactMemoryIfNeeded = compactMemoryIfNeeded2;
|
|
11165
11165
|
var fs9 = __importStar(__require("fs"));
|
|
11166
11166
|
var os6 = __importStar(__require("os"));
|
|
11167
11167
|
var path7 = __importStar(__require("path"));
|
|
@@ -11178,7 +11178,10 @@ var require_memory = __commonJS({
|
|
|
11178
11178
|
exports2.MEMORY_MAX_BYTES = 12e3;
|
|
11179
11179
|
exports2.MEMORY_COMPACT_TRIGGER_BYTES = 16e3;
|
|
11180
11180
|
exports2.MEMORY_HARD_CAP_BYTES = 4 * exports2.MEMORY_COMPACT_TRIGGER_BYTES;
|
|
11181
|
+
exports2.MEMORY_ARCHIVE_MAX_BYTES = Math.floor(exports2.MEMORY_MAX_BYTES / 2);
|
|
11181
11182
|
var FINGERPRINT_LEN = 60;
|
|
11183
|
+
var SOURCE_TAG_MAX_CHARS = 60;
|
|
11184
|
+
var SUPERSEDED_HEADER = "## Superseded";
|
|
11182
11185
|
var _locks = /* @__PURE__ */ new Map();
|
|
11183
11186
|
async function withLock(key, fn) {
|
|
11184
11187
|
const prev = _locks.get(key) ?? Promise.resolve();
|
|
@@ -11207,49 +11210,107 @@ var require_memory = __commonJS({
|
|
|
11207
11210
|
fs9.mkdirSync(path7.dirname(file), { recursive: true });
|
|
11208
11211
|
fs9.writeFileSync(file, content, "utf-8");
|
|
11209
11212
|
}
|
|
11210
|
-
function
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
return
|
|
11213
|
+
function parseSections(content) {
|
|
11214
|
+
const lines = content.split("\n");
|
|
11215
|
+
const headerIdx = lines.findIndex((l2) => l2.trim() === SUPERSEDED_HEADER);
|
|
11216
|
+
if (headerIdx === -1) {
|
|
11217
|
+
return { active: lines.filter((l2) => l2.trim().length > 0), archived: [] };
|
|
11218
|
+
}
|
|
11219
|
+
return {
|
|
11220
|
+
active: lines.slice(0, headerIdx).filter((l2) => l2.trim().length > 0),
|
|
11221
|
+
archived: lines.slice(headerIdx + 1).filter((l2) => l2.trim().length > 0)
|
|
11222
|
+
};
|
|
11223
|
+
}
|
|
11224
|
+
function serializeSections(active, archived) {
|
|
11225
|
+
let out = "\n" + active.join("\n");
|
|
11226
|
+
if (archived.length > 0)
|
|
11227
|
+
out += `
|
|
11228
|
+
|
|
11229
|
+
${SUPERSEDED_HEADER}
|
|
11230
|
+
` + archived.join("\n");
|
|
11231
|
+
return out;
|
|
11232
|
+
}
|
|
11233
|
+
function evictToFit(active, archived, maxBytes) {
|
|
11234
|
+
const a = [...active];
|
|
11235
|
+
const arch = [...archived];
|
|
11236
|
+
let content = serializeSections(a, arch);
|
|
11237
|
+
while (Buffer.byteLength(content, "utf-8") > maxBytes && (arch.length > 0 || a.length > 1)) {
|
|
11238
|
+
if (arch.length > 0)
|
|
11239
|
+
arch.shift();
|
|
11240
|
+
else
|
|
11241
|
+
a.shift();
|
|
11242
|
+
content = serializeSections(a, arch);
|
|
11243
|
+
}
|
|
11244
|
+
return content;
|
|
11217
11245
|
}
|
|
11218
|
-
|
|
11246
|
+
function sanitizeSourceTag(source2) {
|
|
11247
|
+
if (!source2)
|
|
11248
|
+
return "";
|
|
11249
|
+
return source2.trim().replace(/[[\]\n\r]/g, "").slice(0, SOURCE_TAG_MAX_CHARS);
|
|
11250
|
+
}
|
|
11251
|
+
async function writeMemory(content, scope, workDir, opts = {}) {
|
|
11219
11252
|
let trimmed = content.trim();
|
|
11220
11253
|
if (!trimmed)
|
|
11221
11254
|
return { ok: false, already: false, scope, file: "" };
|
|
11222
|
-
|
|
11223
|
-
|
|
11255
|
+
const sourceTag = sanitizeSourceTag(opts.source);
|
|
11256
|
+
const prefix = sourceTag ? `[src: ${sourceTag}] ` : "";
|
|
11257
|
+
const budget = exports2.MEMORY_ENTRY_MAX_CHARS - prefix.length;
|
|
11258
|
+
if (budget <= 0) {
|
|
11259
|
+
if (trimmed.length > exports2.MEMORY_ENTRY_MAX_CHARS)
|
|
11260
|
+
trimmed = trimmed.slice(0, exports2.MEMORY_ENTRY_MAX_CHARS - 1).trimEnd() + "\u2026";
|
|
11261
|
+
} else if (trimmed.length > budget) {
|
|
11262
|
+
trimmed = trimmed.slice(0, budget - 1).trimEnd() + "\u2026";
|
|
11263
|
+
}
|
|
11264
|
+
const body = prefix && budget > 0 ? prefix + trimmed : trimmed;
|
|
11224
11265
|
const file = memoryFilePath(scope, workDir);
|
|
11225
11266
|
return withLock(file, async () => {
|
|
11226
11267
|
const existing = readMemoryFile(file);
|
|
11227
|
-
|
|
11228
|
-
if (existing.toLowerCase().includes(fingerprint)) {
|
|
11229
|
-
return { ok: true, already: true, scope, file };
|
|
11230
|
-
}
|
|
11268
|
+
let { active, archived } = parseSections(existing);
|
|
11231
11269
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
11232
|
-
let
|
|
11233
|
-
|
|
11270
|
+
let superseded = false;
|
|
11271
|
+
if (opts.supersedes && opts.supersedes.trim()) {
|
|
11272
|
+
const supFingerprint = opts.supersedes.trim().toLowerCase().slice(0, FINGERPRINT_LEN);
|
|
11273
|
+
const stillActive = [];
|
|
11274
|
+
for (const line of active) {
|
|
11275
|
+
if (!superseded && line.toLowerCase().includes(supFingerprint)) {
|
|
11276
|
+
archived = [...archived, `${line} \u2014 superseded ${today}`];
|
|
11277
|
+
superseded = true;
|
|
11278
|
+
} else {
|
|
11279
|
+
stillActive.push(line);
|
|
11280
|
+
}
|
|
11281
|
+
}
|
|
11282
|
+
active = stillActive;
|
|
11283
|
+
}
|
|
11284
|
+
const fingerprint = body.toLowerCase().slice(0, FINGERPRINT_LEN);
|
|
11285
|
+
if (active.some((l2) => l2.toLowerCase().includes(fingerprint))) {
|
|
11286
|
+
if (superseded)
|
|
11287
|
+
writeMemoryFile(file, serializeSections(active, archived));
|
|
11288
|
+
return { ok: true, already: true, scope, file, superseded };
|
|
11289
|
+
}
|
|
11290
|
+
active = [...active, `- [${today}] ${body}`];
|
|
11291
|
+
let next = serializeSections(active, archived);
|
|
11234
11292
|
if (Buffer.byteLength(next, "utf-8") > exports2.MEMORY_HARD_CAP_BYTES) {
|
|
11235
|
-
next =
|
|
11293
|
+
next = evictToFit(active, archived, exports2.MEMORY_MAX_BYTES);
|
|
11236
11294
|
}
|
|
11237
11295
|
writeMemoryFile(file, next);
|
|
11238
|
-
return { ok: true, already: false, scope, file };
|
|
11296
|
+
return { ok: true, already: false, scope, file, superseded };
|
|
11239
11297
|
});
|
|
11240
11298
|
}
|
|
11241
|
-
function readMemory2(scope, workDir) {
|
|
11299
|
+
function readMemory2(scope, workDir, opts = {}) {
|
|
11242
11300
|
const file = memoryFilePath(scope, workDir);
|
|
11243
|
-
|
|
11301
|
+
const { active, archived } = parseSections(readMemoryFile(file));
|
|
11302
|
+
if (!opts.includeArchived)
|
|
11303
|
+
return active.length ? serializeSections(active, []).trim() : "";
|
|
11304
|
+
return serializeSections(active, archived).trim();
|
|
11244
11305
|
}
|
|
11245
|
-
function readAllMemory2(workDir) {
|
|
11306
|
+
function readAllMemory2(workDir, opts = {}) {
|
|
11246
11307
|
const parts = [];
|
|
11247
|
-
const globalMem = readMemory2("global");
|
|
11308
|
+
const globalMem = readMemory2("global", void 0, opts);
|
|
11248
11309
|
if (globalMem)
|
|
11249
11310
|
parts.push(`[Global memories \u2014 apply to every project]
|
|
11250
11311
|
${globalMem}`);
|
|
11251
11312
|
if (workDir) {
|
|
11252
|
-
const projMem = readMemory2("project", workDir);
|
|
11313
|
+
const projMem = readMemory2("project", workDir, opts);
|
|
11253
11314
|
if (projMem)
|
|
11254
11315
|
parts.push(`[Project memories \u2014 ${path7.basename(path7.resolve(workDir))}]
|
|
11255
11316
|
${projMem}`);
|
|
@@ -11266,8 +11327,52 @@ ${projMem}`);
|
|
|
11266
11327
|
function memoryStats2(scope, workDir) {
|
|
11267
11328
|
const file = memoryFilePath(scope, workDir);
|
|
11268
11329
|
const content = readMemoryFile(file);
|
|
11269
|
-
const
|
|
11270
|
-
return {
|
|
11330
|
+
const { active, archived } = parseSections(content);
|
|
11331
|
+
return {
|
|
11332
|
+
file,
|
|
11333
|
+
bytes: Buffer.byteLength(content, "utf-8"),
|
|
11334
|
+
entries: active.filter((l2) => /^-\s\[\d{4}-\d{2}-\d{2}\]/.test(l2)).length,
|
|
11335
|
+
archived: archived.filter((l2) => /^-\s\[\d{4}-\d{2}-\d{2}\]/.test(l2)).length
|
|
11336
|
+
};
|
|
11337
|
+
}
|
|
11338
|
+
async function compactMemoryIfNeeded2(scope, workDir, summarize) {
|
|
11339
|
+
const file = memoryFilePath(scope, workDir);
|
|
11340
|
+
return withLock(file, async () => {
|
|
11341
|
+
const content = readMemoryFile(file);
|
|
11342
|
+
if (Buffer.byteLength(content, "utf-8") <= exports2.MEMORY_COMPACT_TRIGGER_BYTES)
|
|
11343
|
+
return false;
|
|
11344
|
+
let { active, archived } = parseSections(content);
|
|
11345
|
+
let changed = false;
|
|
11346
|
+
if (Buffer.byteLength(archived.join("\n"), "utf-8") > exports2.MEMORY_ARCHIVE_MAX_BYTES) {
|
|
11347
|
+
while (archived.length > 1 && Buffer.byteLength(archived.join("\n"), "utf-8") > exports2.MEMORY_ARCHIVE_MAX_BYTES) {
|
|
11348
|
+
archived = archived.slice(1);
|
|
11349
|
+
}
|
|
11350
|
+
changed = true;
|
|
11351
|
+
}
|
|
11352
|
+
if (Buffer.byteLength(serializeSections(active, archived), "utf-8") > exports2.MEMORY_COMPACT_TRIGGER_BYTES && active.length >= 8) {
|
|
11353
|
+
const cut = Math.floor(active.length / 2);
|
|
11354
|
+
const older = active.slice(0, cut);
|
|
11355
|
+
const recent = active.slice(cut);
|
|
11356
|
+
const prompt2 = `Consolidate these persistent-memory bullet entries into a shorter set of bullets, merging duplicates/near-duplicates that describe the same fact in different words. Do NOT invent a resolution for facts that seem to conflict \u2014 contradictions are handled structurally elsewhere; if two entries genuinely disagree, keep both rather than guessing which is current. Keep each resulting bullet under ${exports2.MEMORY_ENTRY_MAX_CHARS} characters, one fact per line, prefixed "- [YYYY-MM-DD] " using the LATEST date among the entries it draws from, and preserve any leading "[src: ...]" provenance tag verbatim when present. Output ONLY the bullet lines, nothing else.
|
|
11357
|
+
|
|
11358
|
+
${older.join("\n")}`;
|
|
11359
|
+
try {
|
|
11360
|
+
const summarized = (await summarize(prompt2)).trim();
|
|
11361
|
+
if (summarized) {
|
|
11362
|
+
active = [...summarized.split("\n").filter((l2) => l2.trim().length > 0), ...recent];
|
|
11363
|
+
changed = true;
|
|
11364
|
+
}
|
|
11365
|
+
} catch {
|
|
11366
|
+
}
|
|
11367
|
+
}
|
|
11368
|
+
if (!changed)
|
|
11369
|
+
return false;
|
|
11370
|
+
let next = serializeSections(active, archived);
|
|
11371
|
+
if (Buffer.byteLength(next, "utf-8") > exports2.MEMORY_MAX_BYTES)
|
|
11372
|
+
next = evictToFit(active, archived, exports2.MEMORY_MAX_BYTES);
|
|
11373
|
+
writeMemoryFile(file, next);
|
|
11374
|
+
return true;
|
|
11375
|
+
});
|
|
11271
11376
|
}
|
|
11272
11377
|
exports2.AGENT_MEMORY_INJECT_MAX = 8e3;
|
|
11273
11378
|
exports2.AGENT_MEMORY_MAX_BYTES = 24e3;
|
|
@@ -11318,7 +11423,10 @@ ${projMem}`);
|
|
|
11318
11423
|
let next = existing + `
|
|
11319
11424
|
- [${today}] ${trimmed}`;
|
|
11320
11425
|
if (Buffer.byteLength(next, "utf-8") > exports2.AGENT_MEMORY_MAX_BYTES) {
|
|
11321
|
-
|
|
11426
|
+
const lines = next.split("\n").filter((l2) => l2.trim().length > 0);
|
|
11427
|
+
while (lines.length > 1 && Buffer.byteLength(lines.join("\n"), "utf-8") > exports2.AGENT_MEMORY_MAX_BYTES)
|
|
11428
|
+
lines.shift();
|
|
11429
|
+
next = "\n" + lines.join("\n");
|
|
11322
11430
|
}
|
|
11323
11431
|
writeMemoryFile(file, next);
|
|
11324
11432
|
return { ok: true, already: false, file };
|
|
@@ -11334,34 +11442,6 @@ These are notes YOU saved on previous runs. Treat them as your accumulated exper
|
|
|
11334
11442
|
|
|
11335
11443
|
${kept}`;
|
|
11336
11444
|
}
|
|
11337
|
-
async function compactMemoryIfNeeded2(scope, workDir, summarize) {
|
|
11338
|
-
const file = memoryFilePath(scope, workDir);
|
|
11339
|
-
return withLock(file, async () => {
|
|
11340
|
-
const content = readMemoryFile(file);
|
|
11341
|
-
if (Buffer.byteLength(content, "utf-8") <= exports2.MEMORY_COMPACT_TRIGGER_BYTES)
|
|
11342
|
-
return false;
|
|
11343
|
-
const lines = content.split("\n").filter((l2) => l2.trim().length > 0);
|
|
11344
|
-
if (lines.length < 8)
|
|
11345
|
-
return false;
|
|
11346
|
-
const cut = Math.floor(lines.length / 2);
|
|
11347
|
-
const older = lines.slice(0, cut);
|
|
11348
|
-
const recent = lines.slice(cut);
|
|
11349
|
-
const prompt2 = `Consolidate these persistent-memory bullet entries into a shorter set of bullets, merging duplicates/near-duplicates and dropping anything clearly stale or superseded by a later entry. Keep each resulting bullet under ${exports2.MEMORY_ENTRY_MAX_CHARS} characters, one fact per line, prefixed "- [YYYY-MM-DD] " using the LATEST date among the entries it draws from. Output ONLY the bullet lines, nothing else.
|
|
11350
|
-
|
|
11351
|
-
${older.join("\n")}`;
|
|
11352
|
-
let summarized;
|
|
11353
|
-
try {
|
|
11354
|
-
summarized = (await summarize(prompt2)).trim();
|
|
11355
|
-
} catch {
|
|
11356
|
-
return false;
|
|
11357
|
-
}
|
|
11358
|
-
if (!summarized)
|
|
11359
|
-
return false;
|
|
11360
|
-
const next = summarized + "\n" + recent.join("\n");
|
|
11361
|
-
writeMemoryFile(file, Buffer.byteLength(next, "utf-8") > exports2.MEMORY_MAX_BYTES ? evictOldest(next, exports2.MEMORY_MAX_BYTES) : next);
|
|
11362
|
-
return true;
|
|
11363
|
-
});
|
|
11364
|
-
}
|
|
11365
11445
|
}
|
|
11366
11446
|
});
|
|
11367
11447
|
|
|
@@ -11574,17 +11654,86 @@ var require_frontmatter = __commonJS({
|
|
|
11574
11654
|
"use strict";
|
|
11575
11655
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11576
11656
|
exports2.parseFrontmatter = parseFrontmatter;
|
|
11657
|
+
var TOP_LEVEL_KEY = /^([A-Za-z0-9_-]+)\s*:\s*(.*)$/;
|
|
11658
|
+
var BLOCK_SCALAR = /^[|>][+-]?$/;
|
|
11659
|
+
function leadingIndent(line) {
|
|
11660
|
+
const m2 = /^[ \t]*/.exec(line);
|
|
11661
|
+
return m2 ? m2[0].length : 0;
|
|
11662
|
+
}
|
|
11663
|
+
function unquote(v) {
|
|
11664
|
+
return v.trim().replace(/^["']|["']$/g, "");
|
|
11665
|
+
}
|
|
11577
11666
|
function parseFrontmatter(raw) {
|
|
11578
11667
|
const m2 = /^\s*---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(raw);
|
|
11579
11668
|
if (!m2)
|
|
11580
|
-
return { meta: {}, body: raw.trim() };
|
|
11669
|
+
return { meta: {}, body: raw.trim(), ok: false };
|
|
11670
|
+
const lines = m2[1].split(/\r?\n/);
|
|
11581
11671
|
const meta = {};
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11672
|
+
let nested;
|
|
11673
|
+
let i2 = 0;
|
|
11674
|
+
while (i2 < lines.length) {
|
|
11675
|
+
const line = lines[i2];
|
|
11676
|
+
if (!line.trim() || leadingIndent(line) > 0) {
|
|
11677
|
+
i2++;
|
|
11678
|
+
continue;
|
|
11679
|
+
}
|
|
11680
|
+
const kv = TOP_LEVEL_KEY.exec(line.trim());
|
|
11681
|
+
if (!kv) {
|
|
11682
|
+
i2++;
|
|
11683
|
+
continue;
|
|
11684
|
+
}
|
|
11685
|
+
const key = kv[1].toLowerCase();
|
|
11686
|
+
const value = kv[2].trim();
|
|
11687
|
+
const continuation = [];
|
|
11688
|
+
let j = i2 + 1;
|
|
11689
|
+
while (j < lines.length && (leadingIndent(lines[j]) > 0 || !lines[j].trim())) {
|
|
11690
|
+
continuation.push(lines[j]);
|
|
11691
|
+
j++;
|
|
11692
|
+
}
|
|
11693
|
+
while (continuation.length && !continuation[continuation.length - 1].trim())
|
|
11694
|
+
continuation.pop();
|
|
11695
|
+
if (BLOCK_SCALAR.test(value)) {
|
|
11696
|
+
const folded = value.startsWith(">");
|
|
11697
|
+
const base = continuation.length ? leadingIndent(continuation.find((l2) => l2.trim()) ?? continuation[0]) : 0;
|
|
11698
|
+
const dedented = continuation.map((l2) => l2.trim() ? l2.slice(Math.min(base, leadingIndent(l2))) : "");
|
|
11699
|
+
meta[key] = folded ? dedented.join(" ").replace(/\s+/g, " ").trim() : dedented.join("\n").trim();
|
|
11700
|
+
} else if (value === "") {
|
|
11701
|
+
const looksNested = continuation.length > 0 && continuation.every((l2) => !l2.trim() || TOP_LEVEL_KEY.test(l2.trim()));
|
|
11702
|
+
if (looksNested && continuation.some((l2) => l2.trim())) {
|
|
11703
|
+
const map = {};
|
|
11704
|
+
for (const l2 of continuation) {
|
|
11705
|
+
const sub = TOP_LEVEL_KEY.exec(l2.trim());
|
|
11706
|
+
if (sub)
|
|
11707
|
+
map[sub[1].toLowerCase()] = unquote(sub[2]);
|
|
11708
|
+
}
|
|
11709
|
+
nested = nested ?? {};
|
|
11710
|
+
nested[key] = map;
|
|
11711
|
+
} else if (continuation.length) {
|
|
11712
|
+
meta[key] = [value, ...continuation.map((l2) => l2.trim())].filter(Boolean).join(" ").trim();
|
|
11713
|
+
} else {
|
|
11714
|
+
meta[key] = "";
|
|
11715
|
+
}
|
|
11716
|
+
} else {
|
|
11717
|
+
const looksNested = continuation.length > 0 && continuation.every((l2) => !l2.trim() || TOP_LEVEL_KEY.test(l2.trim()));
|
|
11718
|
+
if (continuation.length && !looksNested) {
|
|
11719
|
+
meta[key] = unquote([value, ...continuation.map((l2) => l2.trim())].join(" "));
|
|
11720
|
+
} else if (continuation.length && looksNested) {
|
|
11721
|
+
meta[key] = unquote(value);
|
|
11722
|
+
const map = {};
|
|
11723
|
+
for (const l2 of continuation) {
|
|
11724
|
+
const sub = TOP_LEVEL_KEY.exec(l2.trim());
|
|
11725
|
+
if (sub)
|
|
11726
|
+
map[sub[1].toLowerCase()] = unquote(sub[2]);
|
|
11727
|
+
}
|
|
11728
|
+
nested = nested ?? {};
|
|
11729
|
+
nested[key] = map;
|
|
11730
|
+
} else {
|
|
11731
|
+
meta[key] = unquote(value);
|
|
11732
|
+
}
|
|
11733
|
+
}
|
|
11734
|
+
i2 = j;
|
|
11586
11735
|
}
|
|
11587
|
-
return { meta, body: (m2[2] ?? "").trim() };
|
|
11736
|
+
return { meta, body: (m2[2] ?? "").trim(), nested, ok: true };
|
|
11588
11737
|
}
|
|
11589
11738
|
}
|
|
11590
11739
|
});
|
|
@@ -11818,6 +11967,7 @@ var require_skills = __commonJS({
|
|
|
11818
11967
|
};
|
|
11819
11968
|
}();
|
|
11820
11969
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11970
|
+
exports2.loadSkillsWithWarnings = loadSkillsWithWarnings;
|
|
11821
11971
|
exports2.loadSkills = loadSkills2;
|
|
11822
11972
|
exports2.findSkill = findSkill2;
|
|
11823
11973
|
exports2.autoInvokableSkills = autoInvokableSkills;
|
|
@@ -11830,6 +11980,19 @@ var require_skills = __commonJS({
|
|
|
11830
11980
|
var index_1 = require_plugins();
|
|
11831
11981
|
var loader_1 = require_loader();
|
|
11832
11982
|
var frontmatter_1 = require_frontmatter();
|
|
11983
|
+
var KNOWN_META_KEYS = /* @__PURE__ */ new Set([
|
|
11984
|
+
"name",
|
|
11985
|
+
"description",
|
|
11986
|
+
"model",
|
|
11987
|
+
"mode",
|
|
11988
|
+
"disable-model-invocation",
|
|
11989
|
+
"user-invocable",
|
|
11990
|
+
"license",
|
|
11991
|
+
"compatibility",
|
|
11992
|
+
"metadata",
|
|
11993
|
+
"allowed-tools"
|
|
11994
|
+
]);
|
|
11995
|
+
var SPEC_NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
11833
11996
|
function parseBool(v, fallback) {
|
|
11834
11997
|
if (v === void 0)
|
|
11835
11998
|
return fallback;
|
|
@@ -11840,7 +12003,13 @@ var require_skills = __commonJS({
|
|
|
11840
12003
|
return false;
|
|
11841
12004
|
return fallback;
|
|
11842
12005
|
}
|
|
11843
|
-
function
|
|
12006
|
+
function parseSpaceList(v) {
|
|
12007
|
+
if (!v)
|
|
12008
|
+
return void 0;
|
|
12009
|
+
const items = v.split(/[,\s]+/).map((t2) => t2.trim()).filter(Boolean);
|
|
12010
|
+
return items.length ? items : void 0;
|
|
12011
|
+
}
|
|
12012
|
+
function toSkill(meta, body, name, source2, dir, nested) {
|
|
11844
12013
|
const model = ["turbo", "pro", "ultra"].find((x2) => x2 === (meta.model ?? "").toLowerCase());
|
|
11845
12014
|
return {
|
|
11846
12015
|
name,
|
|
@@ -11851,10 +12020,38 @@ var require_skills = __commonJS({
|
|
|
11851
12020
|
source: source2,
|
|
11852
12021
|
dir,
|
|
11853
12022
|
disableModelInvocation: parseBool(meta["disable-model-invocation"], false),
|
|
11854
|
-
userInvocable: parseBool(meta["user-invocable"], true)
|
|
12023
|
+
userInvocable: parseBool(meta["user-invocable"], true),
|
|
12024
|
+
license: meta.license || void 0,
|
|
12025
|
+
compatibility: meta.compatibility || void 0,
|
|
12026
|
+
metadata: nested?.metadata,
|
|
12027
|
+
allowedTools: parseSpaceList(meta["allowed-tools"])
|
|
11855
12028
|
};
|
|
11856
12029
|
}
|
|
11857
|
-
function
|
|
12030
|
+
function validateSkillMeta(meta, rawName, effectiveName, dirName, file, warnings) {
|
|
12031
|
+
if (!warnings)
|
|
12032
|
+
return;
|
|
12033
|
+
if (!SPEC_NAME_RE.test(rawName)) {
|
|
12034
|
+
warnings.push({
|
|
12035
|
+
file,
|
|
12036
|
+
name: effectiveName,
|
|
12037
|
+
message: `name "${rawName}" does not match the agentskills.io convention (lowercase letters, numbers, and single hyphens only) \u2014 loaded anyway, but other clients reading this skill may warn or reject it.`
|
|
12038
|
+
});
|
|
12039
|
+
} else if (rawName.length > 64) {
|
|
12040
|
+
warnings.push({ file, name: effectiveName, message: `name is ${rawName.length} characters \u2014 the spec caps this at 64. Loaded anyway.` });
|
|
12041
|
+
}
|
|
12042
|
+
if (dirName !== void 0 && meta.name && meta.name.trim().toLowerCase() !== dirName.toLowerCase()) {
|
|
12043
|
+
warnings.push({
|
|
12044
|
+
file,
|
|
12045
|
+
name: effectiveName,
|
|
12046
|
+
message: `frontmatter name "${meta.name}" does not match its directory name "${dirName}" \u2014 the spec requires them to match for cross-client compatibility. Loaded anyway, using the frontmatter name.`
|
|
12047
|
+
});
|
|
12048
|
+
}
|
|
12049
|
+
const strayKeys = Object.keys(meta).filter((k) => !KNOWN_META_KEYS.has(k));
|
|
12050
|
+
if (strayKeys.length) {
|
|
12051
|
+
warnings.push({ file, name: effectiveName, message: `has unrecognised frontmatter key(s): ${strayKeys.join(", ")} \u2014 these are ignored.` });
|
|
12052
|
+
}
|
|
12053
|
+
}
|
|
12054
|
+
function loadFlatCommandDir(dir, source2, into, warnings) {
|
|
11858
12055
|
let files;
|
|
11859
12056
|
try {
|
|
11860
12057
|
files = fs9.readdirSync(dir).filter((f3) => f3.endsWith(".md"));
|
|
@@ -11862,20 +12059,24 @@ var require_skills = __commonJS({
|
|
|
11862
12059
|
return;
|
|
11863
12060
|
}
|
|
11864
12061
|
for (const file of files) {
|
|
12062
|
+
const full = path7.join(dir, file);
|
|
11865
12063
|
try {
|
|
11866
|
-
const raw = fs9.readFileSync(
|
|
12064
|
+
const raw = fs9.readFileSync(full, "utf-8");
|
|
11867
12065
|
const { meta, body } = (0, frontmatter_1.parseFrontmatter)(raw);
|
|
11868
|
-
const
|
|
12066
|
+
const rawName = (meta.name || path7.basename(file, ".md")).trim();
|
|
12067
|
+
const name = rawName.toLowerCase();
|
|
11869
12068
|
if (!name)
|
|
11870
12069
|
continue;
|
|
11871
12070
|
if (source2 !== "project" && into.has(name))
|
|
11872
12071
|
continue;
|
|
12072
|
+
validateSkillMeta(meta, rawName, name, void 0, full, warnings);
|
|
11873
12073
|
into.set(name, toSkill(meta, body, name, source2));
|
|
11874
|
-
} catch {
|
|
12074
|
+
} catch (err) {
|
|
12075
|
+
warnings?.push({ file: full, name: path7.basename(file, ".md"), message: `could not be read or parsed (${err.message}) \u2014 skipped.` });
|
|
11875
12076
|
}
|
|
11876
12077
|
}
|
|
11877
12078
|
}
|
|
11878
|
-
function loadSkillDir(root, source2, into) {
|
|
12079
|
+
function loadSkillDir(root, source2, into, warnings) {
|
|
11879
12080
|
let entries;
|
|
11880
12081
|
try {
|
|
11881
12082
|
entries = fs9.readdirSync(root, { withFileTypes: true });
|
|
@@ -11895,14 +12096,17 @@ var require_skills = __commonJS({
|
|
|
11895
12096
|
}
|
|
11896
12097
|
try {
|
|
11897
12098
|
const raw = fs9.readFileSync(skillFile, "utf-8");
|
|
11898
|
-
const { meta, body } = (0, frontmatter_1.parseFrontmatter)(raw);
|
|
11899
|
-
const
|
|
12099
|
+
const { meta, body, nested } = (0, frontmatter_1.parseFrontmatter)(raw);
|
|
12100
|
+
const rawName = (meta.name || entry.name).trim();
|
|
12101
|
+
const name = rawName.toLowerCase();
|
|
11900
12102
|
if (!name)
|
|
11901
12103
|
continue;
|
|
11902
12104
|
if (source2 !== "project" && into.has(name))
|
|
11903
12105
|
continue;
|
|
11904
|
-
|
|
11905
|
-
|
|
12106
|
+
validateSkillMeta(meta, rawName, name, entry.name, skillFile, warnings);
|
|
12107
|
+
into.set(name, toSkill(meta, body, name, source2, skillDir, nested));
|
|
12108
|
+
} catch (err) {
|
|
12109
|
+
warnings?.push({ file: skillFile, name: entry.name, message: `could not be read or parsed (${err.message}) \u2014 skipped.` });
|
|
11906
12110
|
}
|
|
11907
12111
|
}
|
|
11908
12112
|
}
|
|
@@ -11942,21 +12146,27 @@ var require_skills = __commonJS({
|
|
|
11942
12146
|
].join("\n")
|
|
11943
12147
|
}
|
|
11944
12148
|
];
|
|
11945
|
-
function
|
|
12149
|
+
function loadSkillsWithWarnings(workDir) {
|
|
11946
12150
|
const out = /* @__PURE__ */ new Map();
|
|
11947
|
-
|
|
11948
|
-
loadSkillDir(path7.join(workDir, ".
|
|
11949
|
-
loadFlatCommandDir(path7.join(
|
|
11950
|
-
loadSkillDir(path7.join(
|
|
12151
|
+
const warnings = [];
|
|
12152
|
+
loadSkillDir(path7.join(workDir, ".agents", "skills"), "project", out, warnings);
|
|
12153
|
+
loadFlatCommandDir(path7.join(workDir, ".nexrall", "commands"), "project", out, warnings);
|
|
12154
|
+
loadSkillDir(path7.join(workDir, ".nexrall", "skills"), "project", out, warnings);
|
|
12155
|
+
loadFlatCommandDir(path7.join(os6.homedir(), ".nexrall", "commands"), "global", out, warnings);
|
|
12156
|
+
loadSkillDir(path7.join(os6.homedir(), ".nexrall", "skills"), "global", out, warnings);
|
|
12157
|
+
loadSkillDir(path7.join(os6.homedir(), ".agents", "skills"), "global", out, warnings);
|
|
11951
12158
|
for (const dir of (0, index_1.pluginAssetDirs)(workDir, "commands"))
|
|
11952
|
-
loadFlatCommandDir(dir, "plugin", out);
|
|
12159
|
+
loadFlatCommandDir(dir, "plugin", out, warnings);
|
|
11953
12160
|
for (const dir of (0, index_1.pluginAssetDirs)(workDir, "skills"))
|
|
11954
|
-
loadSkillDir(dir, "plugin", out);
|
|
12161
|
+
loadSkillDir(dir, "plugin", out, warnings);
|
|
11955
12162
|
for (const skill of BUILTIN_SKILLS) {
|
|
11956
12163
|
if (!out.has(skill.name))
|
|
11957
12164
|
out.set(skill.name, skill);
|
|
11958
12165
|
}
|
|
11959
|
-
return [...out.values()];
|
|
12166
|
+
return { skills: [...out.values()], warnings };
|
|
12167
|
+
}
|
|
12168
|
+
function loadSkills2(workDir) {
|
|
12169
|
+
return loadSkillsWithWarnings(workDir).skills;
|
|
11960
12170
|
}
|
|
11961
12171
|
function findSkill2(skills, name) {
|
|
11962
12172
|
const want = name.replace(/^\//, "").trim().toLowerCase();
|
|
@@ -101327,18 +101537,24 @@ ${lines.join("\n")}` };
|
|
|
101327
101537
|
if (!content)
|
|
101328
101538
|
return { error: "content is required" };
|
|
101329
101539
|
const scope = memoryScopeOf(input);
|
|
101330
|
-
const
|
|
101540
|
+
const supersedes = typeof input.supersedes === "string" ? input.supersedes.trim() : void 0;
|
|
101541
|
+
const source2 = typeof input.source === "string" ? input.source.trim() : void 0;
|
|
101542
|
+
const r2 = await (0, memory_1.writeMemory)(content, scope, workDir, { supersedes, source: source2 });
|
|
101331
101543
|
if (!r2.ok)
|
|
101332
101544
|
return { error: "failed to save memory" };
|
|
101333
|
-
|
|
101545
|
+
if (r2.already)
|
|
101546
|
+
return { output: `Memory already recorded (skipped duplicate): ${content}` };
|
|
101547
|
+
const supersedeNote = r2.superseded ? " (older fact moved to Superseded)" : "";
|
|
101548
|
+
return { output: `Memory saved (${scope}): ${content}${supersedeNote}` };
|
|
101334
101549
|
}
|
|
101335
101550
|
async function memoryRead(input, workDir) {
|
|
101336
101551
|
try {
|
|
101552
|
+
const includeArchived = input?.include_archived === true;
|
|
101337
101553
|
if (input && (input.scope === "project" || input.scope === "global")) {
|
|
101338
|
-
const mem2 = (0, memory_1.readMemory)(input.scope, workDir);
|
|
101554
|
+
const mem2 = (0, memory_1.readMemory)(input.scope, workDir, { includeArchived });
|
|
101339
101555
|
return { output: mem2 || "No memories saved yet." };
|
|
101340
101556
|
}
|
|
101341
|
-
const mem = (0, memory_1.readAllMemory)(workDir);
|
|
101557
|
+
const mem = (0, memory_1.readAllMemory)(workDir, { includeArchived });
|
|
101342
101558
|
return { output: mem || "No memories saved yet." };
|
|
101343
101559
|
} catch (err) {
|
|
101344
101560
|
return { error: err.message };
|
|
@@ -101553,6 +101769,7 @@ var require_agentTypes = __commonJS({
|
|
|
101553
101769
|
var path7 = __importStar(__require("path"));
|
|
101554
101770
|
var os6 = __importStar(__require("os"));
|
|
101555
101771
|
var index_1 = require_plugins();
|
|
101772
|
+
var frontmatter_1 = require_frontmatter();
|
|
101556
101773
|
var VALID_MEMORY_SCOPES = ["project", "user", "local"];
|
|
101557
101774
|
function parseMemoryScope(v) {
|
|
101558
101775
|
const s2 = (v ?? "").trim().toLowerCase();
|
|
@@ -101906,18 +102123,6 @@ var require_agentTypes = __commonJS({
|
|
|
101906
102123
|
"ultra",
|
|
101907
102124
|
"fast"
|
|
101908
102125
|
];
|
|
101909
|
-
function parseFrontmatter(raw) {
|
|
101910
|
-
const m2 = /^\s*---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(raw);
|
|
101911
|
-
if (!m2)
|
|
101912
|
-
return { meta: {}, body: raw.trim(), ok: false };
|
|
101913
|
-
const meta = {};
|
|
101914
|
-
for (const line of m2[1].split(/\r?\n/)) {
|
|
101915
|
-
const kv = /^([A-Za-z0-9_-]+)\s*:\s*(.*)$/.exec(line.trim());
|
|
101916
|
-
if (kv)
|
|
101917
|
-
meta[kv[1].toLowerCase()] = kv[2].trim().replace(/^["']|["']$/g, "");
|
|
101918
|
-
}
|
|
101919
|
-
return { meta, body: (m2[2] ?? "").trim(), ok: true };
|
|
101920
|
-
}
|
|
101921
102126
|
function parseModel(v) {
|
|
101922
102127
|
const raw = (v ?? "").trim();
|
|
101923
102128
|
if (!raw)
|
|
@@ -101958,7 +102163,7 @@ var require_agentTypes = __commonJS({
|
|
|
101958
102163
|
warnings.push({ file: full, agent: path7.basename(entry.name, ".md"), message: `could not be read (${err.message}) \u2014 this agent was skipped` });
|
|
101959
102164
|
continue;
|
|
101960
102165
|
}
|
|
101961
|
-
const { meta, body, ok } = parseFrontmatter(raw);
|
|
102166
|
+
const { meta, body, ok } = (0, frontmatter_1.parseFrontmatter)(raw);
|
|
101962
102167
|
const name = (meta.name || path7.basename(entry.name, ".md")).trim();
|
|
101963
102168
|
if (!name)
|
|
101964
102169
|
continue;
|
|
@@ -106870,6 +107075,9 @@ var require_trust = __commonJS({
|
|
|
106870
107075
|
if (exists(".nexrall", "agents")) {
|
|
106871
107076
|
signals.push(".nexrall/agents/ \u2014 custom sub-agent definitions");
|
|
106872
107077
|
}
|
|
107078
|
+
if (exists(".agents", "skills")) {
|
|
107079
|
+
signals.push(".agents/skills/ \u2014 cross-client agent playbooks (agentskills.io convention)");
|
|
107080
|
+
}
|
|
106873
107081
|
return signals;
|
|
106874
107082
|
}
|
|
106875
107083
|
}
|
|
@@ -143254,6 +143462,9 @@ function detectTrustSignals(dir) {
|
|
|
143254
143462
|
if (exists(".nexrall", "agents")) {
|
|
143255
143463
|
signals.push(".nexrall/agents/ \u2014 custom sub-agent definitions");
|
|
143256
143464
|
}
|
|
143465
|
+
if (exists(".agents", "skills")) {
|
|
143466
|
+
signals.push(".agents/skills/ \u2014 cross-client agent playbooks (agentskills.io convention)");
|
|
143467
|
+
}
|
|
143257
143468
|
return signals;
|
|
143258
143469
|
}
|
|
143259
143470
|
|
|
@@ -153271,7 +153482,7 @@ function printHelp() {
|
|
|
153271
153482
|
["/rewind [id]", "List file checkpoints, or roll back to one"],
|
|
153272
153483
|
["/compact", "Summarize conversation to save tokens"],
|
|
153273
153484
|
["/init", "Generate nexrall.md for this project"],
|
|
153274
|
-
["/memory [global] [clear]", "View persistent memory (project or global);
|
|
153485
|
+
["/memory [global] [archived] [clear]", "View persistent memory (project or global); archived also shows superseded facts; clear wipes it"],
|
|
153275
153486
|
["/help", "Show this help"],
|
|
153276
153487
|
["/model [name]", "Switch model (e.g. claude-opus-5, gpt-5.4)"],
|
|
153277
153488
|
["/mode [ask|edit|plan|auto]", "Set agent mode"],
|
|
@@ -153818,6 +154029,7 @@ ${dirList}`;
|
|
|
153818
154029
|
const memArgs = arg.toLowerCase().split(/\s+/).filter(Boolean);
|
|
153819
154030
|
const wantsGlobalOnly = memArgs.includes("global");
|
|
153820
154031
|
const wantsClear = memArgs.includes("clear");
|
|
154032
|
+
const wantsArchived = memArgs.includes("archived");
|
|
153821
154033
|
const memScope = wantsGlobalOnly ? "global" : "project";
|
|
153822
154034
|
if (wantsClear) {
|
|
153823
154035
|
const label = memScope === "global" ? "GLOBAL" : "this PROJECT's";
|
|
@@ -153835,20 +154047,23 @@ ${dirList}`;
|
|
|
153835
154047
|
console.log();
|
|
153836
154048
|
if (wantsGlobalOnly) {
|
|
153837
154049
|
const stats = (0, import_code_core3.memoryStats)("global");
|
|
153838
|
-
const content = (0, import_code_core3.readMemory)("global");
|
|
153839
|
-
|
|
154050
|
+
const content = (0, import_code_core3.readMemory)("global", void 0, { includeArchived: wantsArchived });
|
|
154051
|
+
const archivedNote = stats.archived > 0 ? `, ${stats.archived} archived` : "";
|
|
154052
|
+
console.log(source_default.bold(" Global memory ") + source_default.dim(`(${stats.entries} entries${archivedNote}, ${(stats.bytes / 1024).toFixed(1)}KB) \u2014 ${stats.file}`));
|
|
153840
154053
|
console.log();
|
|
153841
154054
|
console.log(content || source_default.dim(" No global memories saved yet."));
|
|
153842
154055
|
} else {
|
|
153843
154056
|
const projStats = (0, import_code_core3.memoryStats)("project", workDir);
|
|
153844
154057
|
const globalStats = (0, import_code_core3.memoryStats)("global");
|
|
153845
|
-
|
|
154058
|
+
const projArchived = projStats.archived > 0 ? `+${projStats.archived} archived ` : "";
|
|
154059
|
+
const globalArchived = globalStats.archived > 0 ? `+${globalStats.archived} archived ` : "";
|
|
154060
|
+
console.log(source_default.bold(" Memory") + source_default.dim(` \u2014 project: ${projStats.entries} ${projArchived}entries (${(projStats.bytes / 1024).toFixed(1)}KB) \xB7 global: ${globalStats.entries} ${globalArchived}entries (${(globalStats.bytes / 1024).toFixed(1)}KB)`));
|
|
153846
154061
|
console.log();
|
|
153847
|
-
const merged = (0, import_code_core3.readAllMemory)(workDir);
|
|
154062
|
+
const merged = (0, import_code_core3.readAllMemory)(workDir, { includeArchived: wantsArchived });
|
|
153848
154063
|
console.log(merged || source_default.dim(" No memories saved yet."));
|
|
153849
154064
|
}
|
|
153850
154065
|
console.log();
|
|
153851
|
-
console.log(source_default.dim(" Tip: /memory global \xB7 /memory clear \xB7 /memory global clear"));
|
|
154066
|
+
console.log(source_default.dim(" Tip: /memory global \xB7 /memory archived \xB7 /memory clear \xB7 /memory global clear"));
|
|
153852
154067
|
rl.prompt();
|
|
153853
154068
|
return;
|
|
153854
154069
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexrall-code",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.95",
|
|
4
4
|
"description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"release": "node build.js && node scripts/upload-release.cjs"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@nexrall/code-core": "^1.4.
|
|
44
|
+
"@nexrall/code-core": "^1.4.48",
|
|
45
45
|
"chalk": "^5.3.0",
|
|
46
46
|
"commander": "^12.0.0",
|
|
47
47
|
"diff": "^5.2.0",
|