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.
Files changed (2) hide show
  1. package/dist/index.js +319 -104
  2. 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 evictOldest(content, maxBytes) {
11211
- if (Buffer.byteLength(content, "utf-8") <= maxBytes)
11212
- return content;
11213
- const lines = content.split("\n").filter((l2) => l2.trim().length > 0);
11214
- while (lines.length > 1 && Buffer.byteLength(lines.join("\n"), "utf-8") > maxBytes)
11215
- lines.shift();
11216
- return "\n" + lines.join("\n");
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
- async function writeMemory(content, scope, workDir) {
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
- if (trimmed.length > exports2.MEMORY_ENTRY_MAX_CHARS)
11223
- trimmed = trimmed.slice(0, exports2.MEMORY_ENTRY_MAX_CHARS - 1).trimEnd() + "\u2026";
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
- const fingerprint = trimmed.toLowerCase().slice(0, FINGERPRINT_LEN);
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 next = existing + `
11233
- - [${today}] ${trimmed}`;
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 = evictOldest(next, exports2.MEMORY_MAX_BYTES);
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
- return readMemoryFile(file).trim();
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 entries = content.split("\n").filter((l2) => /^-\s\[\d{4}-\d{2}-\d{2}\]/.test(l2)).length;
11270
- return { file, bytes: Buffer.byteLength(content, "utf-8"), entries };
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
- next = evictOldest(next, exports2.AGENT_MEMORY_MAX_BYTES);
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
- for (const line of m2[1].split(/\r?\n/)) {
11583
- const kv = /^([A-Za-z0-9_-]+)\s*:\s*(.*)$/.exec(line.trim());
11584
- if (kv)
11585
- meta[kv[1].toLowerCase()] = kv[2].trim().replace(/^["']|["']$/g, "");
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 toSkill(meta, body, name, source2, dir) {
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 loadFlatCommandDir(dir, source2, into) {
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(path7.join(dir, file), "utf-8");
12064
+ const raw = fs9.readFileSync(full, "utf-8");
11867
12065
  const { meta, body } = (0, frontmatter_1.parseFrontmatter)(raw);
11868
- const name = (meta.name || path7.basename(file, ".md")).trim().toLowerCase();
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 name = (meta.name || entry.name).trim().toLowerCase();
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
- into.set(name, toSkill(meta, body, name, source2, skillDir));
11905
- } catch {
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 loadSkills2(workDir) {
12149
+ function loadSkillsWithWarnings(workDir) {
11946
12150
  const out = /* @__PURE__ */ new Map();
11947
- loadFlatCommandDir(path7.join(workDir, ".nexrall", "commands"), "project", out);
11948
- loadSkillDir(path7.join(workDir, ".nexrall", "skills"), "project", out);
11949
- loadFlatCommandDir(path7.join(os6.homedir(), ".nexrall", "commands"), "global", out);
11950
- loadSkillDir(path7.join(os6.homedir(), ".nexrall", "skills"), "global", out);
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 r2 = await (0, memory_1.writeMemory)(content, scope, workDir);
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
- return { output: r2.already ? `Memory already recorded (skipped duplicate): ${content}` : `Memory saved (${scope}): ${content}` };
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); /memory clear to wipe"],
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
- console.log(source_default.bold(" Global memory ") + source_default.dim(`(${stats.entries} entries, ${(stats.bytes / 1024).toFixed(1)}KB) \u2014 ${stats.file}`));
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
- console.log(source_default.bold(" Memory") + source_default.dim(` \u2014 project: ${projStats.entries} entries (${(projStats.bytes / 1024).toFixed(1)}KB) \xB7 global: ${globalStats.entries} entries (${(globalStats.bytes / 1024).toFixed(1)}KB)`));
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.93",
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.46",
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",