@nexrall/code-core 1.4.27 → 1.4.29

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.
@@ -19,7 +19,25 @@ export interface AgentType {
19
19
  * permission gate, where it is a real refusal rather than a request.
20
20
  */
21
21
  testFilesOnly?: boolean;
22
+ /**
23
+ * Opt-in per-agent persistent notes: `memory: project | user | local`.
24
+ *
25
+ * Distinct from the SHARED memory store that memory_read/memory_write use. This
26
+ * gives one named agent its own file that only it reads and writes, so a
27
+ * repeatedly-invoked agent (a reviewer that keeps meeting the same anti-pattern)
28
+ * accumulates expertise without polluting — or being drowned out by — the main
29
+ * agent's memory. The trade-off is deliberate and worth stating: these stores are
30
+ * ISOLATED, so two agents learn nothing from each other.
31
+ *
32
+ * Scopes mirror the shared store's own split plus a not-committed variant:
33
+ * project — .nexrall/agent-memory/<name>.md (shareable via git)
34
+ * local — .nexrall/agent-memory-local/<name>.md (gitignored)
35
+ * user — ~/.nexrall/agent-memory/<name>.md (follows you everywhere)
36
+ */
37
+ memory?: AgentMemoryScope;
22
38
  }
39
+ /** Where a sub-agent's own persistent notes live. */
40
+ export type AgentMemoryScope = 'project' | 'user' | 'local';
23
41
  /**
24
42
  * A problem found while loading an agent definition.
25
43
  *
@@ -1 +1 @@
1
- {"version":3,"file":"agentTypes.d.ts","sourceRoot":"","sources":["../../src/agent/agentTypes.ts"],"names":[],"mappings":"AAiCA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;IAClC,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACpD;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AA6QD;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AA0JD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAE3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;CAAE,CAqB5G;AAED,yFAAyF;AACzF,wBAAgB,cAAc,IAAI,MAAM,EAAE,CAEzC;AAED,2FAA2F;AAC3F,wBAAgB,aAAa,IAAI,SAAS,EAAE,CAE3C;AACD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,CAY1D;AAQD,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAIjG"}
1
+ {"version":3,"file":"agentTypes.d.ts","sourceRoot":"","sources":["../../src/agent/agentTypes.ts"],"names":[],"mappings":"AAiCA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;IAClC,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACpD;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,qDAAqD;AACrD,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAwS5D;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAyKD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAE3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;CAAE,CAqB5G;AAED,yFAAyF;AACzF,wBAAgB,cAAc,IAAI,MAAM,EAAE,CAEzC;AAED,2FAA2F;AAC3F,wBAAgB,aAAa,IAAI,SAAS,EAAE,CAE3C;AACD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,CAY1D;AAQD,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAIjG"}
@@ -43,6 +43,11 @@ const fs = __importStar(require("fs"));
43
43
  const path = __importStar(require("path"));
44
44
  const os = __importStar(require("os"));
45
45
  const index_1 = require("../plugins/index");
46
+ const VALID_MEMORY_SCOPES = ['project', 'user', 'local'];
47
+ function parseMemoryScope(v) {
48
+ const s = (v ?? '').trim().toLowerCase();
49
+ return VALID_MEMORY_SCOPES.includes(s) ? s : undefined;
50
+ }
46
51
  // ── Built-in agent types ──────────────────────────────────────────────────────
47
52
  // Shipped defaults; lowest precedence (project > global > builtin), so a user
48
53
  // can override any of them with a same-name .nexrall/agents/<name>.md file.
@@ -65,6 +70,22 @@ const READ_ONLY_TOOLS = [
65
70
  // lifetime. Stopping a shell you started is not a write to the repo.
66
71
  'kill_shell',
67
72
  'notebook_read', 'todo_write', 'todo_read',
73
+ // memory_READ, deliberately without memory_write.
74
+ //
75
+ // Reading is free capability: a sub-agent that knows "tests run with X" or "never
76
+ // edit Z directly" does better work, and withholding it meant every sub-agent
77
+ // rediscovered project conventions from scratch. Writing is a different thing
78
+ // entirely — memory is durable, cross-session, SHARED state, while sub-agents run
79
+ // up to 4-wide in parallel with their reasoning hidden from the user. A wrong fact
80
+ // written there is invisible and permanent, and it competes for a capped, shared
81
+ // budget that gets periodically condensed.
82
+ //
83
+ // So the parent owns writes: a sub-agent that learns something durable says so in
84
+ // its report, and the main agent — the one actually talking to the user — decides.
85
+ // A sub-agent that needs its own persistent notes gets the per-agent store instead
86
+ // (see `memory:` in the frontmatter), which is scoped to itself and cannot pollute
87
+ // the shared file.
88
+ 'memory_read',
68
89
  // Skills are reusable prompt playbooks, and loop.ts advertises the skills
69
90
  // catalogue to sub-agents at EVERY depth — so withholding the tool that loads
70
91
  // one meant showing every sub-agent a menu it could not order from.
@@ -289,12 +310,16 @@ const KNOWN_TOOL_NAMES = new Set([
289
310
  'todo_write', 'todo_read', 'memory_write', 'memory_read', 'use_skill',
290
311
  'fetch_url', 'web_search', 'generate_image', 'stock_photo', 'open_in_browser',
291
312
  'task',
313
+ // Granted by a `memory:` scope rather than listed in a `tools:` line, but a user may
314
+ // still name it explicitly — so it must validate rather than be flagged as a typo.
315
+ 'agent_memory_write',
292
316
  'get_symbols', 'get_workspace_symbols', 'find_references', 'go_to_definition',
293
317
  'get_hover', 'get_diagnostics',
294
318
  ]);
295
319
  /** Frontmatter keys this parser understands, for typo detection. */
296
320
  const KNOWN_META_KEYS = new Set([
297
321
  'name', 'description', 'tools', 'model', 'test_files_only', 'testfilesonly',
322
+ 'memory',
298
323
  ]);
299
324
  const VALID_MODELS = ['turbo', 'pro', 'ultra'];
300
325
  function parseFrontmatter(raw) {
@@ -391,6 +416,15 @@ function loadDir(dir, source, into, warnings) {
391
416
  message: 'has no `description:` — that text is the ONLY thing the model uses to decide when to delegate to this agent, so it will rarely be picked.',
392
417
  });
393
418
  }
419
+ // Same class of mistake as an invalid model: silently ignoring it would leave
420
+ // the agent with no memory while its prompt tells it to keep notes.
421
+ if (meta.memory !== undefined && parseMemoryScope(meta.memory) === undefined) {
422
+ warnings.push({
423
+ file: full,
424
+ agent: name,
425
+ message: `has memory: "${meta.memory}", which is not a valid scope — use one of ${VALID_MEMORY_SCOPES.join(', ')}, or omit the line to give this agent no persistent notes.`,
426
+ });
427
+ }
394
428
  if (meta.model !== undefined && parseModel(meta.model) === undefined) {
395
429
  warnings.push({
396
430
  file: full,
@@ -438,6 +472,12 @@ function loadDir(dir, source, into, warnings) {
438
472
  // cannot touch production source, rather than only the builtin getting
439
473
  // that guarantee.
440
474
  ...(parseBool(meta.test_files_only ?? meta.testfilesonly) ? { testFilesOnly: true } : {}),
475
+ // The `ok &&` is defensive, not load-bearing: parseFrontmatter already returns an
476
+ // EMPTY meta when it cannot find a `---` block, so `meta.memory` is undefined on
477
+ // that path regardless. It stays because the guarantee we want — an unreadable
478
+ // definition never receives a writable store — should survive parseFrontmatter
479
+ // being changed to salvage partial metadata, which is a plausible future edit.
480
+ ...(ok && parseMemoryScope(meta.memory) ? { memory: parseMemoryScope(meta.memory) } : {}),
441
481
  });
442
482
  }
443
483
  }
@@ -1,4 +1,5 @@
1
- import type { Message, AgentLoopOptions, EnvContext } from '../types';
1
+ import type { Message, ToolResult, AgentLoopOptions, EnvContext } from '../types';
2
+ import { type AgentMemoryScope } from './agentTypes';
2
3
  /**
3
4
  * Fingerprint one round's tool failures, for the repeated-failure runaway guard.
4
5
  *
@@ -19,6 +20,70 @@ export declare const _stallLimits: {
19
20
  STALL_LIMIT: number;
20
21
  REPEAT_STALL_LIMIT: number;
21
22
  };
23
+ /**
24
+ * The single tool granted by a `memory:` frontmatter scope.
25
+ *
26
+ * Named distinctly from `memory_write` on purpose: they write to DIFFERENT stores, and
27
+ * a model that saw one name for both would reasonably assume its notes were visible to
28
+ * the main agent. They are not.
29
+ */
30
+ export declare const AGENT_MEMORY_TOOL = "agent_memory_write";
31
+ /**
32
+ * Schema advertised to the model, only for a sub-agent with a declared memory scope.
33
+ *
34
+ * The description does the load-bearing work of keeping the two stores apart in the
35
+ * model's head: it must not believe these notes reach the user or the main agent.
36
+ */
37
+ export declare const AGENT_MEMORY_TOOL_SCHEMA: {
38
+ readonly name: "agent_memory_write";
39
+ readonly description: string;
40
+ readonly input_schema: {
41
+ readonly type: "object";
42
+ readonly properties: {
43
+ readonly content: {
44
+ readonly type: "string";
45
+ readonly description: "The single fact to remember, 1-2 sentences.";
46
+ };
47
+ };
48
+ readonly required: readonly ["content"];
49
+ };
50
+ };
51
+ /** Identifies whose notes an agent_memory_write call may touch. */
52
+ export interface AgentMemoryBinding {
53
+ agentName: string;
54
+ scope: AgentMemoryScope;
55
+ }
56
+ /**
57
+ * Execute an `agent_memory_write` call.
58
+ *
59
+ * Pure-ish and exported so the refusal paths are testable without spawning a real
60
+ * sub-agent: the binding is data, so "no binding" and "unsafe agent name" can both be
61
+ * exercised directly.
62
+ */
63
+ export declare function executeAgentMemoryWrite(input: Record<string, unknown>, binding: AgentMemoryBinding | undefined, workDir?: string): Promise<ToolResult>;
64
+ /**
65
+ * Why an agent run stopped.
66
+ *
67
+ * `'clean'` and `'aborted'` are the two silent-by-design outcomes: the model gave a
68
+ * final answer, or the user pressed Ctrl+C and already knows why it stopped.
69
+ * EVERYTHING else owes the user an explanation, which is what stopReasonNotice covers.
70
+ */
71
+ export type StopReason = 'clean' | 'aborted' | 'reported-elsewhere' | 'empty-response' | 'no-balance' | 'stalled' | 'stalled-repeat' | 'budget' | 'unknown';
72
+ /**
73
+ * The message shown when a run ends for any reason other than a clean finish.
74
+ *
75
+ * Pure and exported so every branch is testable: reaching some of these for real needs
76
+ * an empty wallet, a dead upstream, or hundreds of iterations. Returns null only for
77
+ * the two outcomes that are deliberately silent.
78
+ *
79
+ * `'unknown'` deliberately produces a message rather than nothing. If a future `break`
80
+ * forgets to set a reason, the symptom should be a visible "ended unexpectedly" line —
81
+ * annoying and reportable — not the silent stop that made this refactor necessary.
82
+ */
83
+ export declare function stopReasonNotice(reason: StopReason, ctx?: {
84
+ budget?: number;
85
+ repeatError?: string | null;
86
+ }): string | null;
22
87
  export declare function resolveMaxIterations(optionValue: number | undefined, settingsRaw: Record<string, unknown>): number;
23
88
  /**
24
89
  * Minimal concurrency gate. Hand-rolled rather than pulling in `p-limit` because
@@ -1 +1 @@
1
- {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
@@ -33,8 +33,10 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.VERIFY_CMD_RE = exports.WRITE_TOOL_NAMES = exports.ToolNotAllowedError = exports._stallLimits = void 0;
36
+ exports.VERIFY_CMD_RE = exports.WRITE_TOOL_NAMES = exports.ToolNotAllowedError = exports.AGENT_MEMORY_TOOL_SCHEMA = exports.AGENT_MEMORY_TOOL = exports._stallLimits = void 0;
37
37
  exports.errorRoundSignature = errorRoundSignature;
38
+ exports.executeAgentMemoryWrite = executeAgentMemoryWrite;
39
+ exports.stopReasonNotice = stopReasonNotice;
38
40
  exports.resolveMaxIterations = resolveMaxIterations;
39
41
  exports.createLimiter = createLimiter;
40
42
  exports.extractSubTaskText = extractSubTaskText;
@@ -214,6 +216,116 @@ function errorRoundSignature(errored) {
214
216
  }
215
217
  /** Runaway-guard limits, exposed for tests. */
216
218
  exports._stallLimits = { STALL_LIMIT, REPEAT_STALL_LIMIT };
219
+ /**
220
+ * The single tool granted by a `memory:` frontmatter scope.
221
+ *
222
+ * Named distinctly from `memory_write` on purpose: they write to DIFFERENT stores, and
223
+ * a model that saw one name for both would reasonably assume its notes were visible to
224
+ * the main agent. They are not.
225
+ */
226
+ exports.AGENT_MEMORY_TOOL = 'agent_memory_write';
227
+ /**
228
+ * Schema advertised to the model, only for a sub-agent with a declared memory scope.
229
+ *
230
+ * The description does the load-bearing work of keeping the two stores apart in the
231
+ * model's head: it must not believe these notes reach the user or the main agent.
232
+ */
233
+ exports.AGENT_MEMORY_TOOL_SCHEMA = {
234
+ name: exports.AGENT_MEMORY_TOOL,
235
+ description: 'Save a durable note to YOUR OWN persistent notes, which are injected into your prompt on ' +
236
+ 'future runs. Use this for lessons that will still be true next time — a convention this repo ' +
237
+ 'follows, a recurring bug pattern, a command that works, a dead end not worth retrying. ' +
238
+ 'These notes are PRIVATE to you: they are NOT shown to the user and NOT read by the main agent, ' +
239
+ 'so anything the user or the main agent needs to know must still go in your final message. ' +
240
+ 'One self-contained fact per call, a sentence or two. Do not save transient task details.',
241
+ input_schema: {
242
+ type: 'object',
243
+ properties: {
244
+ content: { type: 'string', description: 'The single fact to remember, 1-2 sentences.' },
245
+ },
246
+ required: ['content'],
247
+ },
248
+ };
249
+ /**
250
+ * Execute an `agent_memory_write` call.
251
+ *
252
+ * Pure-ish and exported so the refusal paths are testable without spawning a real
253
+ * sub-agent: the binding is data, so "no binding" and "unsafe agent name" can both be
254
+ * exercised directly.
255
+ */
256
+ async function executeAgentMemoryWrite(input, binding, workDir) {
257
+ // Belt-and-braces: the permission gate already refuses this tool without a binding.
258
+ // Re-checked because this is the function that actually touches the filesystem, and
259
+ // it must not depend on a caller elsewhere having got the check right.
260
+ if (!binding) {
261
+ return {
262
+ error: `${exports.AGENT_MEMORY_TOOL} is only available to a sub-agent whose definition declares a \`memory:\` ` +
263
+ 'scope. Put anything worth remembering in your final message instead.',
264
+ };
265
+ }
266
+ const content = typeof input.content === 'string' ? input.content.trim() : '';
267
+ if (!content)
268
+ return { error: `${exports.AGENT_MEMORY_TOOL} requires a non-empty \`content\` string.` };
269
+ const res = await (0, memory_1.writeAgentMemory)(binding.agentName, binding.scope, content, workDir);
270
+ if (!res.ok) {
271
+ // The realistic cause is a repo-scoped store with no workDir, or an agent name that
272
+ // is not a safe single path segment. Say which, rather than a bare failure.
273
+ return {
274
+ error: `Could not save to the "${binding.agentName}" agent's ${binding.scope} notes. ` +
275
+ 'Either this scope needs a project directory (use `memory: user` for a store that ' +
276
+ 'works anywhere) or the agent name is not usable as a filename.',
277
+ };
278
+ }
279
+ return {
280
+ output: res.already
281
+ ? 'Already saved (a near-identical note exists) — nothing added.'
282
+ : `Saved to your ${binding.scope} notes. It will be in your prompt on your next run.`,
283
+ };
284
+ }
285
+ /**
286
+ * The message shown when a run ends for any reason other than a clean finish.
287
+ *
288
+ * Pure and exported so every branch is testable: reaching some of these for real needs
289
+ * an empty wallet, a dead upstream, or hundreds of iterations. Returns null only for
290
+ * the two outcomes that are deliberately silent.
291
+ *
292
+ * `'unknown'` deliberately produces a message rather than nothing. If a future `break`
293
+ * forgets to set a reason, the symptom should be a visible "ended unexpectedly" line —
294
+ * annoying and reportable — not the silent stop that made this refactor necessary.
295
+ */
296
+ function stopReasonNotice(reason, ctx = {}) {
297
+ switch (reason) {
298
+ case 'clean':
299
+ case 'aborted':
300
+ // A dedicated channel (e.g. the zero-balance bubble via onBalanceStatus) has already
301
+ // told the user why this stopped. Naming this case explicitly — rather than reusing
302
+ // 'aborted' — keeps "the user cancelled" from silently coming to mean two things.
303
+ case 'reported-elsewhere':
304
+ return null;
305
+ case 'empty-response':
306
+ return `\n\u26a0\ufe0f The model returned an empty response, so nothing was done. This is usually a transient ` +
307
+ `upstream hiccup \u2014 send "continue" to retry.\n`;
308
+ case 'no-balance':
309
+ return `\n\ud83d\udcb3 Stopped: your balance is empty, so the request was rejected before it started. ` +
310
+ `Top up and send "continue" \u2014 no tokens were used for this turn.\n`;
311
+ case 'stalled':
312
+ return `\n\ud83d\uded1 Stopped: the last ${STALL_LIMIT} tool rounds all failed, so the agent looked stuck. ` +
313
+ `Fix the underlying error (or grant the needed permission) and send "continue".\n`;
314
+ case 'stalled-repeat':
315
+ return `\n\ud83d\uded1 Stopped: the same tool error repeated ${REPEAT_STALL_LIMIT} rounds in a row, so the agent ` +
316
+ `was looping without making progress.` +
317
+ (ctx.repeatError ? ` The recurring error was:\n${ctx.repeatError}\n` : '\n') +
318
+ `Fix that underlying cause (or grant the needed permission) and send "continue".\n`;
319
+ case 'budget':
320
+ return `\n\u23f8\ufe0f Stopped at the ${ctx.budget}-step safety limit \u2014 the task may be incomplete. ` +
321
+ `Send "continue" to resume, or raise the limit via "maxIterations" in .nexrall/settings.json ` +
322
+ `(or the NEXRALL_MAX_ITERATIONS env var). Auto-continue can be disabled with "autoContinue": false.\n`;
323
+ case 'unknown':
324
+ default:
325
+ return `\n\u26a0\ufe0f The run ended unexpectedly without completing. Your work so far is preserved \u2014 ` +
326
+ `send "continue" to resume.\n`;
327
+ }
328
+ }
217
329
  // Resolve the soft iteration budget. Precedence:
218
330
  // options.maxIterations → env NEXRALL_MAX_ITERATIONS → settings.maxIterations → default
219
331
  //
@@ -628,8 +740,24 @@ async function runSubTask(input, options, agentTypes) {
628
740
  // A custom agent's persona is delivered through the project-instructions
629
741
  // channel (authoritative in the system prompt), layered above the project's
630
742
  // own nexrall.md so it keeps project conventions.
743
+ // ── Per-agent memory (`memory:` frontmatter) ────────────────────────────────
744
+ //
745
+ // When an agent declares a memory scope, its own notes from previous runs are
746
+ // injected ahead of its role prompt, and it gains ONE extra tool to append to them.
747
+ //
748
+ // Claude Code implements the equivalent by auto-enabling Read/Write/Edit "regardless
749
+ // of what the tools allowlist says". We deliberately do NOT copy that: silently
750
+ // widening a declared allowlist is fail-OPEN, and this repo already fixed the
751
+ // mirror-image bug (an unparseable agent file used to receive FULL access). So the
752
+ // grant here is a single purpose-built tool that can only ever touch this agent's
753
+ // own notes file — declaring `memory:` cannot hand anything write access to the repo.
754
+ const memoryScope = agent?.memory;
755
+ const agentMemoryNotes = agent && memoryScope
756
+ ? (0, memory_1.agentMemoryPreamble)(agent.name, memoryScope, options.workDir)
757
+ : '';
631
758
  const subNexrallMd = agent
632
759
  ? `# Sub-agent role: ${agent.name}\n${agent.prompt}` +
760
+ (agentMemoryNotes ? `\n\n---\n\n${agentMemoryNotes}` : '') +
633
761
  (options.nexrallMd ? `\n\n---\n\n${options.nexrallMd}` : '')
634
762
  : options.nexrallMd;
635
763
  // Optional tool allowlist — deny anything outside it for this sub-agent.
@@ -639,7 +767,19 @@ async function runSubTask(input, options, agentTypes) {
639
767
  // nothing, and a model told that will re-ask for approval instead of noticing
640
768
  // that the agent's own allowlist (often a typo'd tool name) is what stopped it.
641
769
  const allowed = agent?.tools ? new Set(agent.tools) : null;
770
+ // The ONE capability `memory:` grants. Added to the allowlist rather than bypassing
771
+ // it, so the allowlist stays the single source of truth for what this agent can do.
772
+ if (allowed && memoryScope)
773
+ allowed.add(exports.AGENT_MEMORY_TOOL);
642
774
  const gatedPermission = async (req) => {
775
+ // Guard against the tool being reachable without a declared scope — e.g. an agent
776
+ // that lists it in `tools:` by hand, or a general-purpose sub-task with no
777
+ // allowlist at all (`allowed === null` permits everything).
778
+ if (req.tool === exports.AGENT_MEMORY_TOOL && !(agent && memoryScope)) {
779
+ throw new ToolNotAllowedError(`\`${exports.AGENT_MEMORY_TOOL}\` is only available to a sub-agent whose definition declares a ` +
780
+ '`memory:` scope (project, user or local). Report anything worth remembering in your final ' +
781
+ 'message instead — the main agent decides what to persist.');
782
+ }
643
783
  if (allowed && !allowed.has(req.tool)) {
644
784
  throw new ToolNotAllowedError(`The "${agent.name}" sub-agent is not allowed to use \`${req.tool}\` — it is not in that agent's ` +
645
785
  'tool allowlist. This is a restriction of the agent definition, NOT a user decision: do not ask ' +
@@ -683,6 +823,11 @@ async function runSubTask(input, options, agentTypes) {
683
823
  ...options,
684
824
  _depth: depth + 1,
685
825
  _agentScope: `sub_${++_subTaskCounter}`, // isolated todo store per sub-agent
826
+ // Only set when the agent opted in, so the tool is inert for everyone else.
827
+ ...(agent && memoryScope ? { _agentMemory: { agentName: agent.name, scope: memoryScope } } : {}),
828
+ // The same set `gatedPermission` enforces above, so prompt and permission agree
829
+ // by construction instead of by two people remembering to update both.
830
+ ...(allowed ? { _allowedTools: allowed } : {}),
686
831
  editorContext: null, // fresh isolated context for sub-agent
687
832
  model: agent?.model ?? options.model,
688
833
  // Plan mode is inherited, never relaxed. If the main agent could spawn a
@@ -1535,16 +1680,28 @@ async function runAgentLoop(initialMessages, options) {
1535
1680
  // condition where one sub-agent's chdir overwrites another's, making every tool
1536
1681
  // that falls back to process.cwd() resolve paths against the wrong directory.
1537
1682
  // workDir is now threaded explicitly through executeTool → resolvePath instead.
1538
- // Distinguish a clean finish (model produced a final answer) from hitting the
1539
- // iteration backstop, so we can tell the user what happened rather than
1540
- // silently returning a half-done task.
1541
- let completedCleanly = false;
1683
+ // ─── Why did this run stop? ───────────────────────────────────────────────────
1684
+ //
1685
+ // The epilogue used to INFER the reason by re-testing state (`stalledOut`, then
1686
+ // `iteration >= budget`). Inference only covers the cases someone thought to test,
1687
+ // so any `break` that matched none of them fell through and the run ended in total
1688
+ // silence — the worst possible outcome after an hour of work, because the user
1689
+ // cannot tell "finished" from "died". Two such holes existed:
1690
+ //
1691
+ // • the pre-flight 402 (wallet empty) broke out with no flag set at all, leaving
1692
+ // the optional onBalanceStatus callback as the ONLY signal;
1693
+ // • a thinking-only/empty model turn set completedCleanly = true, actively
1694
+ // claiming success for a turn that produced nothing.
1695
+ //
1696
+ // So the reason is now RECORDED at each exit instead of reconstructed after it.
1697
+ // Anything that isn't an explicit clean finish or a user abort must name itself,
1698
+ // and `default` in the switch below means a future `break` cannot go silent.
1699
+ let stopReason = 'unknown';
1542
1700
  // Tool rounds actually completed in this call. Counted explicitly rather than derived
1543
1701
  // from `messages.length` because auto-compaction splices the history SHORTER mid-run:
1544
1702
  // a long session that compacted and then lost its connection would show a negative
1545
1703
  // length delta and be judged "no progress", discarding the work it most needs to keep.
1546
1704
  let completedRounds = 0;
1547
- let stalledOut = false; // tripped the runaway guard (all-failed rounds)
1548
1705
  let consecutiveErrorRounds = 0; // rounds where every tool call errored
1549
1706
  // Repeated-identical-failure guard: see the runaway guards below. Tracked
1550
1707
  // separately from consecutiveErrorRounds because a round can contain a succeeding
@@ -1605,8 +1762,10 @@ async function runAgentLoop(initialMessages, options) {
1605
1762
  let compactDisabled = false;
1606
1763
  try {
1607
1764
  for (; iteration < budget; iteration++) {
1608
- if (options.abortSignal?.aborted)
1765
+ if (options.abortSignal?.aborted) {
1766
+ stopReason = 'aborted';
1609
1767
  break;
1768
+ }
1610
1769
  // Auto-compact: keep the resent prompt small BEFORE the next stream so we
1611
1770
  // never hit the context-window wall — or the backend body-size limit — and,
1612
1771
  // just as importantly, so we stop paying cache-read on an ever-growing prefix
@@ -1791,7 +1950,23 @@ async function runAgentLoop(initialMessages, options) {
1791
1950
  nexrallMd: planAwareNexrallMd,
1792
1951
  clientType: options.clientType,
1793
1952
  abortSignal: options.abortSignal,
1794
- extraTools: options.mcpManager?.getAnthropicTools(),
1953
+ // MCP tools, plus the per-agent memory tool when (and only when) this run
1954
+ // is a sub-agent that declared a `memory:` scope. Declaring it through
1955
+ // extraTools rather than the backend's static catalogue keeps it invisible
1956
+ // to every other run: a tool the model cannot see is one it cannot try,
1957
+ // which is better than advertising it everywhere and refusing it at the gate.
1958
+ extraTools: [
1959
+ ...(options.mcpManager?.getAnthropicTools() ?? []),
1960
+ ...(options._agentMemory ? [exports.AGENT_MEMORY_TOOL_SCHEMA] : []),
1961
+ ],
1962
+ // Derived from the run's ACTUAL allowlist rather than asserted separately,
1963
+ // so the prompt's memory instructions cannot drift from what is permitted.
1964
+ // That drift is the bug being fixed: sub-agents were told they MUST call
1965
+ // memory_write, which no sub-agent allowlist contains.
1966
+ canWriteSharedMemory: options._allowedTools
1967
+ ? options._allowedTools.has('memory_write')
1968
+ : true, // no allowlist = main agent = may write
1969
+ hasOwnAgentStore: !!options._agentMemory,
1795
1970
  agents: agentsCatalogue || undefined,
1796
1971
  skills: skillsCatalogue || undefined,
1797
1972
  // Only allow a post-render restart when the caller actually implements the
@@ -1802,8 +1977,10 @@ async function runAgentLoop(initialMessages, options) {
1802
1977
  }, onEvent);
1803
1978
  }
1804
1979
  catch (err) {
1805
- if (options.abortSignal?.aborted || err.name === 'AbortError')
1980
+ if (options.abortSignal?.aborted || err.name === 'AbortError') {
1981
+ stopReason = 'aborted';
1806
1982
  break;
1983
+ }
1807
1984
  // Pre-flight 402 (routes/code.js — wallet already empty, the turn couldn't even
1808
1985
  // start) is tagged with `status`/`balance` by client.ts. Surface it as the same
1809
1986
  // low/zero-balance nudge a mid-turn 'balance_status' event would, instead of a
@@ -1811,7 +1988,16 @@ async function runAgentLoop(initialMessages, options) {
1811
1988
  const status = err.status;
1812
1989
  if (status === 402) {
1813
1990
  const balance = err.balance ?? 0;
1991
+ // Prefer the rich, actionable UI (a persistent bubble with a link to Billing)
1992
+ // where the client implements it…
1814
1993
  options.onBalanceStatus?.(balance, true);
1994
+ // …but do not DEPEND on it. The callback is optional, so a client without it
1995
+ // used to show the user absolutely nothing — the run simply stopped mid-task.
1996
+ //
1997
+ // Set the reason ONLY when there is no richer channel, so clients that do
1998
+ // render the bubble don't also get a redundant plain-text line saying the same
1999
+ // thing. Either way the user is told something, which is the actual guarantee.
2000
+ stopReason = options.onBalanceStatus ? 'reported-elsewhere' : 'no-balance';
1815
2001
  break;
1816
2002
  }
1817
2003
  runSimpleHooks(hooks.OnError, options.workDir);
@@ -1824,8 +2010,10 @@ async function runAgentLoop(initialMessages, options) {
1824
2010
  // assistant→tool_result pair here, so it is valid to resend as-is.
1825
2011
  throw new types_1.AgentTurnError(`Stream failed: ${err.message}`, trimToResumableBoundary(messages), completedRounds, err);
1826
2012
  }
1827
- if (options.abortSignal?.aborted)
2013
+ if (options.abortSignal?.aborted) {
2014
+ stopReason = 'aborted';
1828
2015
  break;
2016
+ }
1829
2017
  // 2. Strip thinking blocks — API rejects them in message history
1830
2018
  assistantMessage.content = assistantMessage.content.filter((b) => b.type !== 'thinking' && b.type !== 'redacted_thinking');
1831
2019
  // If the model returned nothing usable (e.g. thinking-only, then stopped), the
@@ -1841,8 +2029,12 @@ async function runAgentLoop(initialMessages, options) {
1841
2029
  messages.push({ role: 'user', content: [{ type: 'text', text }] });
1842
2030
  continue;
1843
2031
  }
2032
+ // NOT a clean finish. This used to set completedCleanly = true, which told the
2033
+ // caller the task succeeded when the model had in fact produced nothing at all
2034
+ // — indistinguishable, to the user, from a finished job with no summary. An
2035
+ // empty turn is a (usually transient) upstream failure, so name it and say so.
1844
2036
  runSimpleHooks(hooks.PostMessageComplete, options.workDir);
1845
- completedCleanly = true;
2037
+ stopReason = 'empty-response';
1846
2038
  break;
1847
2039
  }
1848
2040
  // stopReason is transient, single-turn metadata for the truncated-tool-call guard
@@ -1990,7 +2182,7 @@ async function runAgentLoop(initialMessages, options) {
1990
2182
  }
1991
2183
  }
1992
2184
  runSimpleHooks(hooks.PostMessageComplete, options.workDir);
1993
- completedCleanly = true;
2185
+ stopReason = 'clean';
1994
2186
  break;
1995
2187
  }
1996
2188
  // 5. Execute all tool uses in parallel
@@ -2084,6 +2276,15 @@ async function runAgentLoop(initialMessages, options) {
2084
2276
  }
2085
2277
  else {
2086
2278
  try {
2279
+ // 0. Per-agent memory append. Handled HERE rather than in the executor
2280
+ // because only this loop knows which agent is running and what scope it
2281
+ // declared — the executor's TOOL_MAP is keyed by tool name alone, so it
2282
+ // could not tell whose notes to write to (and must not be able to).
2283
+ if (name === exports.AGENT_MEMORY_TOOL) {
2284
+ result = await executeAgentMemoryWrite(input, options._agentMemory, options.workDir);
2285
+ options.onToolResult(name, result);
2286
+ return { block: { ...block, id }, result };
2287
+ }
2087
2288
  // 1. Try platform-specific tools (e.g. VS Code semantic tools)
2088
2289
  const external = options.executeExternalTool
2089
2290
  ? await options.executeExternalTool(name, input)
@@ -2235,7 +2436,7 @@ async function runAgentLoop(initialMessages, options) {
2235
2436
  const allErrored = toolResults.length > 0 && errored.length === toolResults.length;
2236
2437
  consecutiveErrorRounds = allErrored ? consecutiveErrorRounds + 1 : 0;
2237
2438
  if (consecutiveErrorRounds >= STALL_LIMIT) {
2238
- stalledOut = true;
2439
+ stopReason = 'stalled';
2239
2440
  break;
2240
2441
  }
2241
2442
  // Signature of this round's failures, order-independent and truncated so a long
@@ -2249,7 +2450,7 @@ async function runAgentLoop(initialMessages, options) {
2249
2450
  lastErrorSignature = errSignature;
2250
2451
  }
2251
2452
  if (repeatedErrorRounds >= REPEAT_STALL_LIMIT) {
2252
- stalledOut = true;
2453
+ stopReason = 'stalled-repeat';
2253
2454
  stalledRepeatError = errored[0] ? String(errored[0].result.error).slice(0, 300) : null;
2254
2455
  break;
2255
2456
  }
@@ -2264,27 +2465,23 @@ async function runAgentLoop(initialMessages, options) {
2264
2465
  }
2265
2466
  // Loop back to step 1
2266
2467
  }
2267
- // Explain why we stopped when it wasn't a clean finish or a user abort, so a
2268
- // long run never just goes silent. History ends on a tool_result turn, so
2269
- // "continue" resumes exactly where it left off.
2270
- if (!options.abortSignal?.aborted && !completedCleanly) {
2271
- // Routed through onNotice (falling back to onText) like every other housekeeping
2272
- // message in this file these are statements from the harness, not from the model,
2273
- // and splicing them into the assistant's own bubble reads as if it said them.
2274
- if (stalledOut) {
2275
- (options.onNotice ?? options.onText)(stalledRepeatError
2276
- ? `\n🛑 Stopped: the same tool error repeated ${REPEAT_STALL_LIMIT} rounds in a row, so the agent ` +
2277
- `was looping without making progress. The recurring error was:\n${stalledRepeatError}\n` +
2278
- `Fix that underlying cause (or grant the needed permission) and send "continue".\n`
2279
- : `\n🛑 Stopped: the last ${STALL_LIMIT} tool rounds all failed, so the agent looked stuck. ` +
2280
- `Fix the underlying error (or grant the needed permission) and send "continue".\n`);
2281
- }
2282
- else if (iteration >= budget) {
2283
- (options.onNotice ?? options.onText)(`\n⏸️ Stopped at the ${budget}-step safety limit — the task may be incomplete. ` +
2284
- `Send "continue" to resume, or raise the limit via "maxIterations" in .nexrall/settings.json ` +
2285
- `(or the NEXRALL_MAX_ITERATIONS env var). Auto-continue can be disabled with "autoContinue": false.\n`);
2286
- }
2287
- }
2468
+ // Explain why we stopped, so a long run never just goes silent. History ends on a
2469
+ // tool_result turn, so "continue" resumes exactly where it left off.
2470
+ //
2471
+ // The budget case is resolved HERE rather than at a break: exhausting the `for`
2472
+ // condition is a normal loop exit, not a branch we can annotate. Everything else
2473
+ // named itself on the way out, and 'unknown' is the loud fallback for a break that
2474
+ // forgot to.
2475
+ if (stopReason === 'unknown' && iteration >= budget)
2476
+ stopReason = 'budget';
2477
+ if (options.abortSignal?.aborted)
2478
+ stopReason = 'aborted';
2479
+ // Routed through onNotice (falling back to onText) like every other housekeeping
2480
+ // message in this file these are statements from the harness, not from the model,
2481
+ // and splicing them into the assistant's own bubble reads as if it said them.
2482
+ const notice = stopReasonNotice(stopReason, { budget, repeatError: stalledRepeatError });
2483
+ if (notice)
2484
+ (options.onNotice ?? options.onText)(notice);
2288
2485
  }
2289
2486
  catch (err) {
2290
2487
  // Every other failure path (a tool executor blowing up, a hook throwing, an
@@ -41,5 +41,49 @@ export declare function memoryStats(scope: MemoryScope, workDir?: string): {
41
41
  * pulling api/client.ts's network/auth machinery into every consumer of this
42
42
  * module and to keep this file trivially unit-testable.
43
43
  */
44
+ /** Max chars injected into a sub-agent's prompt from its own notes. */
45
+ export declare const AGENT_MEMORY_INJECT_MAX = 8000;
46
+ /** Hard cap on one agent's notes file. Same eviction-on-overflow rule as above. */
47
+ export declare const AGENT_MEMORY_MAX_BYTES = 24000;
48
+ /**
49
+ * Reject anything that isn't a plain, single-segment agent name.
50
+ *
51
+ * The name reaches this module from a FILENAME or a `name:` frontmatter field, and it
52
+ * is about to become a path segment — so `../../.ssh/authorized_keys` as an agent name
53
+ * would otherwise let a checked-in repo file choose where we write. Allowing only
54
+ * [A-Za-z0-9._-] and rejecting any form of separator or `..` makes traversal
55
+ * impossible rather than merely unlikely; the containment assertion in
56
+ * agentMemoryPath is the second line of defence.
57
+ */
58
+ export declare function isSafeAgentName(name: string): boolean;
59
+ /**
60
+ * Resolve where one agent's notes live, or null if the name is unsafe.
61
+ *
62
+ * `project` and `local` live under the repo (only `project` is meant to be committed);
63
+ * `user` follows the person across every checkout.
64
+ */
65
+ export declare function agentMemoryPath(agentName: string, scope: 'project' | 'user' | 'local', workDir?: string): string | null;
66
+ /** Read an agent's own notes (empty string when it has none). */
67
+ export declare function readAgentMemory(agentName: string, scope: 'project' | 'user' | 'local', workDir?: string): string;
68
+ /**
69
+ * Append a fact to an agent's own notes.
70
+ *
71
+ * Same shape as writeMemory (dated bullets, per-entry cap, near-duplicate skip, file
72
+ * lock) so behaviour is predictable across both stores — but bounded by simple
73
+ * eviction rather than LLM compaction: this file is small, per-agent, and not worth a
74
+ * model call to condense.
75
+ */
76
+ export declare function writeAgentMemory(agentName: string, scope: 'project' | 'user' | 'local', content: string, workDir?: string): Promise<{
77
+ ok: boolean;
78
+ already: boolean;
79
+ file: string;
80
+ }>;
81
+ /**
82
+ * The block prepended to a sub-agent's instructions, or '' when it has no notes.
83
+ *
84
+ * Truncated from the TAIL: the newest entries are the ones worth keeping when a store
85
+ * outgrows the injection budget.
86
+ */
87
+ export declare function agentMemoryPreamble(agentName: string, scope: 'project' | 'user' | 'local', workDir?: string): string;
44
88
  export declare function compactMemoryIfNeeded(scope: MemoryScope, workDir: string | undefined, summarize: (prompt: string) => Promise<string>): Promise<boolean>;
45
89
  //# sourceMappingURL=memory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/agent/memory.ts"],"names":[],"mappings":"AAiCA,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/C;;;sDAGsD;AACtD,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAI3E;AAED,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,gBAAgB,QAAS,CAAC;AACvC,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAMnD,eAAO,MAAM,qBAAqB,QAAmC,CAAC;AA4CtE,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuBnH;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAGvE;AAED;gFACgF;AAChF,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAStD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAGtE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAKlH;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAC7C,OAAO,CAAC,OAAO,CAAC,CA+BlB"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/agent/memory.ts"],"names":[],"mappings":"AAiCA,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/C;;;sDAGsD;AACtD,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAI3E;AAED,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,gBAAgB,QAAS,CAAC;AACvC,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAMnD,eAAO,MAAM,qBAAqB,QAAmC,CAAC;AA4CtE,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuBnH;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAGvE;AAED;gFACgF;AAChF,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAStD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAGtE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAKlH;AAED;;;;;;;;;;;;;;;GAeG;AAUH,uEAAuE;AACvE,eAAO,MAAM,uBAAuB,OAAQ,CAAC;AAC7C,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAE7C;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,EACnC,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAqBf;AAED,iEAAiE;AACjE,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,EACnC,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAIR;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,EACnC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAuB1D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,EACnC,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAYR;AAED,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAC7C,OAAO,CAAC,OAAO,CAAC,CA+BlB"}
@@ -33,13 +33,18 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.MEMORY_HARD_CAP_BYTES = exports.MEMORY_COMPACT_TRIGGER_BYTES = exports.MEMORY_MAX_BYTES = exports.MEMORY_ENTRY_MAX_CHARS = void 0;
36
+ exports.AGENT_MEMORY_MAX_BYTES = exports.AGENT_MEMORY_INJECT_MAX = exports.MEMORY_HARD_CAP_BYTES = exports.MEMORY_COMPACT_TRIGGER_BYTES = exports.MEMORY_MAX_BYTES = exports.MEMORY_ENTRY_MAX_CHARS = void 0;
37
37
  exports.memoryFilePath = memoryFilePath;
38
38
  exports.writeMemory = writeMemory;
39
39
  exports.readMemory = readMemory;
40
40
  exports.readAllMemory = readAllMemory;
41
41
  exports.clearMemory = clearMemory;
42
42
  exports.memoryStats = memoryStats;
43
+ exports.isSafeAgentName = isSafeAgentName;
44
+ exports.agentMemoryPath = agentMemoryPath;
45
+ exports.readAgentMemory = readAgentMemory;
46
+ exports.writeAgentMemory = writeAgentMemory;
47
+ exports.agentMemoryPreamble = agentMemoryPreamble;
43
48
  exports.compactMemoryIfNeeded = compactMemoryIfNeeded;
44
49
  const fs = __importStar(require("fs"));
45
50
  const os = __importStar(require("os"));
@@ -209,6 +214,117 @@ function memoryStats(scope, workDir) {
209
214
  * pulling api/client.ts's network/auth machinery into every consumer of this
210
215
  * module and to keep this file trivially unit-testable.
211
216
  */
217
+ // ─── Per-agent memory (the `memory:` frontmatter field) ──────────────────────
218
+ //
219
+ // A SEPARATE store from the shared global/project memory above. The shared store is
220
+ // the main agent's, written while the user watches; this one belongs to a single
221
+ // named sub-agent so a repeatedly-invoked agent can accumulate its own expertise
222
+ // without polluting the shared file (and without 4 parallel sub-agents fighting over
223
+ // it). The cost, stated plainly: these stores are ISOLATED — two agents learn nothing
224
+ // from one another.
225
+ /** Max chars injected into a sub-agent's prompt from its own notes. */
226
+ exports.AGENT_MEMORY_INJECT_MAX = 8000;
227
+ /** Hard cap on one agent's notes file. Same eviction-on-overflow rule as above. */
228
+ exports.AGENT_MEMORY_MAX_BYTES = 24000;
229
+ /**
230
+ * Reject anything that isn't a plain, single-segment agent name.
231
+ *
232
+ * The name reaches this module from a FILENAME or a `name:` frontmatter field, and it
233
+ * is about to become a path segment — so `../../.ssh/authorized_keys` as an agent name
234
+ * would otherwise let a checked-in repo file choose where we write. Allowing only
235
+ * [A-Za-z0-9._-] and rejecting any form of separator or `..` makes traversal
236
+ * impossible rather than merely unlikely; the containment assertion in
237
+ * agentMemoryPath is the second line of defence.
238
+ */
239
+ function isSafeAgentName(name) {
240
+ return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name) && !name.includes('..');
241
+ }
242
+ /**
243
+ * Resolve where one agent's notes live, or null if the name is unsafe.
244
+ *
245
+ * `project` and `local` live under the repo (only `project` is meant to be committed);
246
+ * `user` follows the person across every checkout.
247
+ */
248
+ function agentMemoryPath(agentName, scope, workDir) {
249
+ if (!isSafeAgentName(agentName))
250
+ return null;
251
+ const file = `${agentName}.md`;
252
+ let dir;
253
+ if (scope === 'user') {
254
+ dir = path.join(MEMORY_ROOT, 'agent-memory');
255
+ }
256
+ else {
257
+ // Repo-scoped stores need a workDir; without one there is no repo to scope to.
258
+ if (!workDir)
259
+ return null;
260
+ dir = path.join(path.resolve(workDir), '.nexrall', scope === 'local' ? 'agent-memory-local' : 'agent-memory');
261
+ }
262
+ const full = path.join(dir, file);
263
+ // Defence in depth: even if the name check above were ever loosened, the resolved
264
+ // path must still sit inside the directory we intended.
265
+ const rel = path.relative(dir, full);
266
+ if (rel.startsWith('..') || path.isAbsolute(rel))
267
+ return null;
268
+ return full;
269
+ }
270
+ /** Read an agent's own notes (empty string when it has none). */
271
+ function readAgentMemory(agentName, scope, workDir) {
272
+ const file = agentMemoryPath(agentName, scope, workDir);
273
+ if (!file)
274
+ return '';
275
+ return readMemoryFile(file).trim();
276
+ }
277
+ /**
278
+ * Append a fact to an agent's own notes.
279
+ *
280
+ * Same shape as writeMemory (dated bullets, per-entry cap, near-duplicate skip, file
281
+ * lock) so behaviour is predictable across both stores — but bounded by simple
282
+ * eviction rather than LLM compaction: this file is small, per-agent, and not worth a
283
+ * model call to condense.
284
+ */
285
+ async function writeAgentMemory(agentName, scope, content, workDir) {
286
+ let trimmed = content.trim();
287
+ if (!trimmed)
288
+ return { ok: false, already: false, file: '' };
289
+ if (trimmed.length > exports.MEMORY_ENTRY_MAX_CHARS) {
290
+ trimmed = trimmed.slice(0, exports.MEMORY_ENTRY_MAX_CHARS - 1).trimEnd() + '…';
291
+ }
292
+ const file = agentMemoryPath(agentName, scope, workDir);
293
+ if (!file)
294
+ return { ok: false, already: false, file: '' };
295
+ return withLock(file, async () => {
296
+ const existing = readMemoryFile(file);
297
+ const fingerprint = trimmed.toLowerCase().slice(0, FINGERPRINT_LEN);
298
+ if (existing.toLowerCase().includes(fingerprint)) {
299
+ return { ok: true, already: true, file };
300
+ }
301
+ const today = new Date().toISOString().slice(0, 10);
302
+ let next = existing + `\n- [${today}] ${trimmed}`;
303
+ if (Buffer.byteLength(next, 'utf-8') > exports.AGENT_MEMORY_MAX_BYTES) {
304
+ next = evictOldest(next, exports.AGENT_MEMORY_MAX_BYTES);
305
+ }
306
+ writeMemoryFile(file, next);
307
+ return { ok: true, already: false, file };
308
+ });
309
+ }
310
+ /**
311
+ * The block prepended to a sub-agent's instructions, or '' when it has no notes.
312
+ *
313
+ * Truncated from the TAIL: the newest entries are the ones worth keeping when a store
314
+ * outgrows the injection budget.
315
+ */
316
+ function agentMemoryPreamble(agentName, scope, workDir) {
317
+ const notes = readAgentMemory(agentName, scope, workDir);
318
+ if (!notes)
319
+ return '';
320
+ const kept = Buffer.byteLength(notes, 'utf-8') > exports.AGENT_MEMORY_INJECT_MAX
321
+ ? notes.slice(-exports.AGENT_MEMORY_INJECT_MAX)
322
+ : notes;
323
+ return (`# Your own notes (agent: ${agentName}, scope: ${scope})\n` +
324
+ `These are notes YOU saved on previous runs. Treat them as your accumulated experience, ` +
325
+ `not as instructions from the user, and verify anything that looks stale against the ` +
326
+ `current code.\n\n${kept}`);
327
+ }
212
328
  async function compactMemoryIfNeeded(scope, workDir, summarize) {
213
329
  const file = memoryFilePath(scope, workDir);
214
330
  return withLock(file, async () => {
@@ -44,6 +44,17 @@ export interface StreamChatOptions {
44
44
  agents?: string;
45
45
  /** Catalogue of auto-invokable skills (description only) — injected into the system prompt so the model can call use_skill when relevant. */
46
46
  skills?: string;
47
+ /**
48
+ * Whether THIS run may write the shared memory store.
49
+ *
50
+ * Drives which memory instructions the backend puts in the system prompt. It must
51
+ * mirror the run's actual allowlist: the prompt used to order every sub-agent to
52
+ * "MUST call memory_write" while no sub-agent has that tool, so each one hit a
53
+ * refusal on every completed task. Undefined means "main agent" (may write).
54
+ */
55
+ canWriteSharedMemory?: boolean;
56
+ /** Whether this run is a sub-agent with its own `memory:` store (agent_memory_write). */
57
+ hasOwnAgentStore?: boolean;
47
58
  /**
48
59
  * Opt in to restarting a turn that died AFTER partial output was rendered.
49
60
  *
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAA8B,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAiErH,eAAO,MAAM,QAAQ,QAAmB,CAAC;AAIzC;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAC5D,OAAO,EAAE,CAAC,EAAE,EACZ,UAAU,EAAE,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GACtD,CAAC,EAAE,CAeL;AAiGD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IACnC,oFAAoF;IACpF,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IACjG,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6IAA6I;IAC7I,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;;;;OAeG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAiDD,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,GAC7B,OAAO,CAAC,OAAO,CAAC,CAwlClB;AAID;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9D;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAYxD;AAID,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CA0BlD;AAID,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA+B1E;AAID,wBAAsB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA0BhF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAA8B,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAiErH,eAAO,MAAM,QAAQ,QAAmB,CAAC;AAIzC;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAC5D,OAAO,EAAE,CAAC,EAAE,EACZ,UAAU,EAAE,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GACtD,CAAC,EAAE,CAeL;AAiGD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IACnC,oFAAoF;IACpF,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IACjG,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6IAA6I;IAC7I,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,yFAAyF;IACzF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;;;;;;;;OAeG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAiDD,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,GAC7B,OAAO,CAAC,OAAO,CAAC,CAwlClB;AAID;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9D;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAYxD;AAID,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CA0BlD;AAID,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA+B1E;AAID,wBAAsB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA0BhF"}
@@ -243,7 +243,7 @@ function sleep(ms) {
243
243
  * the nested product (36) exists to bound pathological cases, not to be reached. */
244
244
  const MAX_TOTAL_ATTEMPTS = (MAX_RETRIES + 1) * (MAX_RETRIES + 1);
245
245
  async function streamChat(messages, options, onEvent) {
246
- const { model, env, editorContext, nexrallMd, mode, effort, clientType, abortSignal, extraTools, agents, skills, allowRestartAfterRender } = options;
246
+ const { model, env, editorContext, nexrallMd, mode, effort, clientType, abortSignal, extraTools, agents, skills, allowRestartAfterRender, canWriteSharedMemory, hasOwnAgentStore } = options;
247
247
  // IDEMPOTENCY KEY for this logical turn, generated ONCE and reused by every retry
248
248
  // below (that reuse is the entire point — a fresh id per attempt would be useless).
249
249
  //
@@ -331,7 +331,7 @@ async function streamChat(messages, options, onEvent) {
331
331
  {
332
332
  method: 'POST',
333
333
  headers: authHeaders(),
334
- body: JSON.stringify({ messages, model, env, editorContext, nexrallMd, mode, effort, clientType, extraTools, agents, skills, turnId }),
334
+ body: JSON.stringify({ messages, model, env, editorContext, nexrallMd, mode, effort, clientType, extraTools, agents, skills, turnId, canWriteSharedMemory, hasOwnAgentStore }),
335
335
  signal: controller.signal,
336
336
  },
337
337
  ];
package/dist/types.d.ts CHANGED
@@ -389,6 +389,25 @@ export interface AgentLoopOptions {
389
389
  * sub-agents don't clobber each other's todo lists.
390
390
  */
391
391
  _agentScope?: string;
392
+ /**
393
+ * Internal: which agent's own notes `agent_memory_write` may append to.
394
+ *
395
+ * Set by runSubTask only for a sub-agent whose definition declares a `memory:`
396
+ * scope; absent everywhere else, which is what makes the tool unusable by the main
397
+ * agent and by agents that never opted in. Carried as a binding (name + scope)
398
+ * rather than a path so the loop cannot be tricked into writing outside the store.
399
+ */
400
+ _agentMemory?: {
401
+ agentName: string;
402
+ scope: 'project' | 'user' | 'local';
403
+ };
404
+ /**
405
+ * Internal: this run's effective tool allowlist, or undefined for the main agent
406
+ * (which has none). Passed so the loop can derive prompt content from the SAME set
407
+ * the permission gate enforces — the alternative, declaring capability separately,
408
+ * is exactly how the prompt came to order sub-agents to use a tool they lacked.
409
+ */
410
+ _allowedTools?: Set<string>;
392
411
  }
393
412
  /**
394
413
  * Thrown by `runAgentLoop` when a turn cannot continue (stream died, upstream
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAKD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAKD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,UAAU,EAAE,iBAAiB,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACzE;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,YAAY,GAAG,eAAe,GAAG,UAAU,GAAG,aAAa,CAAC;AAInG,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAID,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,0HAA0H;AAC1H,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,QAAQ,GAChB,YAAY,GACZ,eAAe,GACf,uBAAuB,GACvB,aAAa,GACb,YAAY,GACZ,aAAa,GACb,gBAAgB,GAChB,wBAAwB,GACxB,qBAAqB,GACrB,aAAa,GACb,qBAAqB,GACrB,qBAAqB,GACrB,qBAAqB,CAAC;AAI1B,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,gEAAgE;IAChE,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvF,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChH,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IACnC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACvF,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9E;;;;;;;;;OASG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/E;;;;;OAKG;IACH,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACnD;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,+FAA+F;IAC/F,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IACnE;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClE;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChE,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnG,+EAA+E;IAC/E,UAAU,CAAC,EAAE,OAAO,eAAe,EAAE,UAAU,CAAC;IAChD,qFAAqF;IACrF,iBAAiB,CAAC,EAAE,OAAO,sBAAsB,EAAE,iBAAiB,CAAC;IACrE;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,MAAM,EAAE,CAAC;IAClC,+FAA+F;IAC/F,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAC3C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;IAC7B;;;;;;;;OAQG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAOzF;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,cAAc,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,EAAE,GAAG,IAAI,CAG7D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexrall/code-core",
3
- "version": "1.4.27",
3
+ "version": "1.4.29",
4
4
  "description": "Core agent loop, tools, and extension primitives for Nexrall Code — embed an AI coding agent in any Node.js application.",
5
5
  "license": "MIT",
6
6
  "author": "Nexrall <support@nexrall.com> (https://nexrall.com)",