reasonix 0.4.19 → 0.4.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ MemoryStore,
3
4
  PROJECT_MEMORY_FILE,
4
- applyProjectMemory,
5
+ applyMemoryStack,
5
6
  memoryEnabled,
6
- readProjectMemory
7
- } from "./chunk-HNEWBEWZ.js";
7
+ readProjectMemory,
8
+ sanitizeMemoryName
9
+ } from "./chunk-DDIKQZVD.js";
8
10
 
9
11
  // src/cli/index.ts
10
12
  import { Command } from "commander";
@@ -2206,7 +2208,7 @@ function registerFilesystemTools(registry, opts) {
2206
2208
  });
2207
2209
  registry.register({
2208
2210
  name: "edit_file",
2209
- description: "Apply a SEARCH/REPLACE edit to an existing file. `search` must match exactly (whitespace sensitive) \u2014 no regex. The match must be unique in the file; otherwise the edit is refused to avoid surprise rewrites. This flat-string shape replaces the `{oldText, newText}[]` JSON array form that previously triggered R1 DSML hallucinations.",
2211
+ description: "Apply a SEARCH/REPLACE edit to an existing file. `search` must match exactly (whitespace sensitive) \u2014 no regex. The match must be unique in the file; otherwise the edit is refused to avoid surprise rewrites.",
2210
2212
  parameters: {
2211
2213
  type: "object",
2212
2214
  properties: {
@@ -2323,6 +2325,127 @@ function lineDiff(a, b) {
2323
2325
  return out;
2324
2326
  }
2325
2327
 
2328
+ // src/tools/memory.ts
2329
+ function registerMemoryTools(registry, opts = {}) {
2330
+ const store = new MemoryStore({ homeDir: opts.homeDir, projectRoot: opts.projectRoot });
2331
+ const hasProject = store.hasProjectScope();
2332
+ registry.register({
2333
+ name: "remember",
2334
+ description: "Save a memory for future sessions. Use when the user states a preference, corrects your approach, shares a non-obvious fact about this project, or explicitly asks you to remember something. Don't remember transient task state \u2014 only things worth recalling next session. The memory is written now but won't re-load into the system prompt until the next `/new` or launch.",
2335
+ parameters: {
2336
+ type: "object",
2337
+ properties: {
2338
+ type: {
2339
+ type: "string",
2340
+ enum: ["user", "feedback", "project", "reference"],
2341
+ description: "'user' = role/skills/prefs; 'feedback' = corrections or confirmed approaches; 'project' = facts/decisions about the current work; 'reference' = pointers to external systems the user uses."
2342
+ },
2343
+ scope: {
2344
+ type: "string",
2345
+ enum: ["global", "project"],
2346
+ description: "'global' = applies across every project (preferences, tooling); 'project' = scoped to the current sandbox (decisions, local facts). Only available in `reasonix code`."
2347
+ },
2348
+ name: {
2349
+ type: "string",
2350
+ description: "filename-safe identifier, 3-40 chars, alnum + _ - . (no path separators, no leading dot)."
2351
+ },
2352
+ description: {
2353
+ type: "string",
2354
+ description: "One-line summary shown in MEMORY.md (under ~150 chars)."
2355
+ },
2356
+ content: {
2357
+ type: "string",
2358
+ description: "Full memory body in markdown. For feedback/project types, structure as: rule/fact, then **Why:** line, then **How to apply:** line."
2359
+ }
2360
+ },
2361
+ required: ["type", "scope", "name", "description", "content"]
2362
+ },
2363
+ fn: async (args) => {
2364
+ if (args.scope === "project" && !hasProject) {
2365
+ return JSON.stringify({
2366
+ error: "scope='project' is unavailable in this session (no sandbox root). Retry with scope='global', or ask the user to switch to `reasonix code` for project-scoped memory."
2367
+ });
2368
+ }
2369
+ try {
2370
+ const path = store.write({
2371
+ name: args.name,
2372
+ type: args.type,
2373
+ scope: args.scope,
2374
+ description: args.description,
2375
+ body: args.content
2376
+ });
2377
+ const key = sanitizeMemoryName(args.name);
2378
+ return [
2379
+ `\u2713 REMEMBERED (${args.scope}/${key}): ${args.description}`,
2380
+ "",
2381
+ "TREAT THIS AS ESTABLISHED FACT for the rest of this session.",
2382
+ "The user just told you \u2014 don't re-explore the filesystem to re-derive it.",
2383
+ `(Saved to ${path}; pins into the system prompt on next /new or launch.)`
2384
+ ].join("\n");
2385
+ } catch (err) {
2386
+ return JSON.stringify({ error: `remember failed: ${err.message}` });
2387
+ }
2388
+ }
2389
+ });
2390
+ registry.register({
2391
+ name: "forget",
2392
+ description: "Delete a memory file and remove it from MEMORY.md. Use when the user explicitly asks to forget something, or when a previously-remembered fact has become wrong. Irreversible \u2014 no tombstone.",
2393
+ parameters: {
2394
+ type: "object",
2395
+ properties: {
2396
+ name: { type: "string", description: "Memory name (the identifier used in `remember`)." },
2397
+ scope: { type: "string", enum: ["global", "project"] }
2398
+ },
2399
+ required: ["name", "scope"]
2400
+ },
2401
+ fn: async (args) => {
2402
+ if (args.scope === "project" && !hasProject) {
2403
+ return JSON.stringify({
2404
+ error: "scope='project' is unavailable in this session (no sandbox root)."
2405
+ });
2406
+ }
2407
+ try {
2408
+ const existed = store.delete(args.scope, args.name);
2409
+ return existed ? `forgot (${args.scope}/${sanitizeMemoryName(args.name)}). Re-load on next /new or launch.` : `no such memory: ${args.scope}/${args.name} (nothing to forget).`;
2410
+ } catch (err) {
2411
+ return JSON.stringify({ error: `forget failed: ${err.message}` });
2412
+ }
2413
+ }
2414
+ });
2415
+ registry.register({
2416
+ name: "recall_memory",
2417
+ description: "Read the full body of a memory file when its MEMORY.md one-liner (already in the system prompt) isn't enough detail. Most of the time the index suffices \u2014 only call this when the user's question genuinely requires the full context.",
2418
+ readOnly: true,
2419
+ parameters: {
2420
+ type: "object",
2421
+ properties: {
2422
+ name: { type: "string" },
2423
+ scope: { type: "string", enum: ["global", "project"] }
2424
+ },
2425
+ required: ["name", "scope"]
2426
+ },
2427
+ fn: async (args) => {
2428
+ if (args.scope === "project" && !hasProject) {
2429
+ return JSON.stringify({
2430
+ error: "scope='project' is unavailable in this session (no sandbox root)."
2431
+ });
2432
+ }
2433
+ try {
2434
+ const entry = store.read(args.scope, args.name);
2435
+ return [
2436
+ `# ${entry.name} (${entry.scope}/${entry.type}, created ${entry.createdAt || "?"})`,
2437
+ entry.description ? `> ${entry.description}` : "",
2438
+ "",
2439
+ entry.body
2440
+ ].filter(Boolean).join("\n");
2441
+ } catch (err) {
2442
+ return JSON.stringify({ error: `recall failed: ${err.message}` });
2443
+ }
2444
+ }
2445
+ });
2446
+ return registry;
2447
+ }
2448
+
2326
2449
  // src/tools/plan.ts
2327
2450
  var PlanProposedError = class extends Error {
2328
2451
  plan;
@@ -2540,7 +2663,7 @@ function resolveExecutable(cmd, opts = {}) {
2540
2663
  const isFile = opts.isFile ?? defaultIsFile;
2541
2664
  for (const dir of pathDirs) {
2542
2665
  for (const ext of pathExt) {
2543
- const full = pathMod2.join(dir, cmd + ext);
2666
+ const full = pathMod2.win32.join(dir, cmd + ext);
2544
2667
  if (isFile(full)) return full;
2545
2668
  }
2546
2669
  }
@@ -2598,7 +2721,7 @@ function registerShellTools(registry, opts) {
2598
2721
  const allowAll = opts.allowAll ?? false;
2599
2722
  registry.register({
2600
2723
  name: "run_command",
2601
- description: "Run a shell command in the project root and return its combined stdout+stderr. Read-only and test commands (git status, ls, npm test, pytest, cargo test, grep, etc.) run immediately. Anything that could mutate state (npm install, git commit, rm, chmod) is refused and the user has to confirm in the TUI. Prefer this over asking the user to run a command manually \u2014 after edits, run the project's tests to verify.",
2724
+ description: "Run a shell command in the project root and return its combined stdout+stderr. Common read-only inspection and test/lint/typecheck commands run immediately; anything that could mutate state, install dependencies, or touch the network is refused until the user confirms it in the TUI. Prefer this over asking the user to run a command manually \u2014 after edits, run the project's tests to verify.",
2602
2725
  // Plan-mode gate: allow allowlisted commands through (git status,
2603
2726
  // cargo check, ls, grep …) so the model can actually investigate
2604
2727
  // during planning. Anything that would otherwise trigger a
@@ -2614,7 +2737,7 @@ function registerShellTools(registry, opts) {
2614
2737
  properties: {
2615
2738
  command: {
2616
2739
  type: "string",
2617
- description: "Full command line, e.g. 'npm test' or 'git diff src/foo.ts'. Tokenized with POSIX-ish quoting; no shell expansion, no pipes, no redirects."
2740
+ description: "Full command line. Tokenized with POSIX-ish quoting; no shell expansion, no pipes, no redirects."
2618
2741
  },
2619
2742
  timeoutSec: {
2620
2743
  type: "integer",
@@ -4119,7 +4242,7 @@ function sep() {
4119
4242
  }
4120
4243
 
4121
4244
  // src/index.ts
4122
- var VERSION = "0.4.19";
4245
+ var VERSION = "0.4.20";
4123
4246
 
4124
4247
  // src/cli/commands/chat.tsx
4125
4248
  import { existsSync as existsSync4, statSync as statSync3 } from "fs";
@@ -5093,7 +5216,11 @@ var SLASH_COMMANDS = [
5093
5216
  { cmd: "branch", argsHint: "<N|off>", summary: "run N parallel samples per turn (N>=2)" },
5094
5217
  { cmd: "mcp", summary: "list MCP servers + tools attached to this session" },
5095
5218
  { cmd: "tool", argsHint: "[N]", summary: "dump full output of the Nth tool call (1=latest)" },
5096
- { cmd: "memory", summary: "show the project's REASONIX.md (pinned into the system prompt)" },
5219
+ {
5220
+ cmd: "memory",
5221
+ argsHint: "[list|show <name>|forget <name>|clear <scope> confirm]",
5222
+ summary: "show / manage pinned memory (REASONIX.md + ~/.reasonix/memory)"
5223
+ },
5097
5224
  { cmd: "think", summary: "dump the last turn's full R1 reasoning (reasoner only)" },
5098
5225
  { cmd: "retry", summary: "truncate & resend your last message (fresh sample)" },
5099
5226
  { cmd: "compact", argsHint: "[cap]", summary: "shrink oversized tool results in the log" },
@@ -5173,7 +5300,8 @@ function handleSlash(cmd, args, loop, ctx = {}) {
5173
5300
  " /compact [cap] shrink large tool results in history (default 4k/result)",
5174
5301
  " /think dump the most recent turn's full R1 reasoning (reasoner only)",
5175
5302
  " /tool [N] list tool calls (or dump full output of #N, 1=most recent)",
5176
- " /memory show the project's REASONIX.md (pinned into the system prompt)",
5303
+ " /memory [sub] show pinned memory (REASONIX.md + ~/.reasonix/memory).",
5304
+ " subs: list | show <name> | forget <name> | clear <scope> confirm",
5177
5305
  " /retry truncate & resend your last message (fresh sample from the model)",
5178
5306
  " /apply (code mode) commit the pending edit blocks to disk",
5179
5307
  " /discard (code mode) drop pending edits without writing",
@@ -5258,43 +5386,7 @@ function handleSlash(cmd, args, loop, ctx = {}) {
5258
5386
  };
5259
5387
  }
5260
5388
  case "memory": {
5261
- if (!memoryEnabled()) {
5262
- return {
5263
- info: "project memory is disabled (REASONIX_MEMORY=off in env). Unset the var to re-enable; no REASONIX.md will be pinned in the meantime."
5264
- };
5265
- }
5266
- if (!ctx.memoryRoot) {
5267
- return {
5268
- info: "no project root on this session \u2014 `/memory` needs a working directory to resolve REASONIX.md from."
5269
- };
5270
- }
5271
- const mem = readProjectMemory(ctx.memoryRoot);
5272
- if (!mem) {
5273
- return {
5274
- info: [
5275
- `no ${PROJECT_MEMORY_FILE} in ${ctx.memoryRoot}.`,
5276
- "",
5277
- "Project memory is an optional file you pin notes into \u2014 project conventions,",
5278
- "things the model keeps forgetting, domain glossary, setup gotchas. When present,",
5279
- "its contents are appended to the system prompt (the immutable-prefix region)",
5280
- "so every turn sees it without eating per-turn context, and the prefix cache stays",
5281
- "warm as long as the file is stable.",
5282
- "",
5283
- `Create it with: echo "# Project notes for Reasonix" > ${PROJECT_MEMORY_FILE}`,
5284
- "Re-launch (or `/new`) to pick up changes \u2014 the prefix is hashed at session start."
5285
- ].join("\n")
5286
- };
5287
- }
5288
- const header = mem.truncated ? `\u25B8 project memory: ${mem.path} (${mem.originalChars.toLocaleString()} chars, truncated for the prefix)` : `\u25B8 project memory: ${mem.path} (${mem.originalChars.toLocaleString()} chars)`;
5289
- return {
5290
- info: [
5291
- header,
5292
- "",
5293
- mem.content,
5294
- "",
5295
- "Changes take effect on the next launch or `/new` \u2014 the system prompt is hashed once per session to keep the prefix cache warm."
5296
- ].join("\n")
5297
- };
5389
+ return handleMemorySlash(args, ctx);
5298
5390
  }
5299
5391
  case "think":
5300
5392
  case "reasoning": {
@@ -5532,6 +5624,158 @@ ${entry.text}`
5532
5624
  return { unknown: true, info: `unknown command: /${cmd} (try /help)` };
5533
5625
  }
5534
5626
  }
5627
+ function handleMemorySlash(args, ctx) {
5628
+ if (!memoryEnabled()) {
5629
+ return {
5630
+ info: "memory is disabled (REASONIX_MEMORY=off in env). Unset the var to re-enable \u2014 no REASONIX.md or ~/.reasonix/memory content will be pinned in the meantime."
5631
+ };
5632
+ }
5633
+ if (!ctx.memoryRoot) {
5634
+ return {
5635
+ info: "no working directory on this session \u2014 `/memory` needs a root to resolve REASONIX.md from. (Running in a test harness?)"
5636
+ };
5637
+ }
5638
+ const store = new MemoryStore({ projectRoot: ctx.codeRoot });
5639
+ const sub = (args[0] ?? "").toLowerCase();
5640
+ if (sub === "list" || sub === "ls") {
5641
+ const entries = store.list();
5642
+ if (entries.length === 0) {
5643
+ return {
5644
+ info: "no user memories yet. The model can call `remember` to save one, or you can create files by hand in ~/.reasonix/memory/global/ or the per-project subdir."
5645
+ };
5646
+ }
5647
+ const lines = [`User memories (${entries.length}):`];
5648
+ for (const e of entries) {
5649
+ const tag = `${e.scope}/${e.type}`.padEnd(18);
5650
+ const name = e.name.padEnd(28);
5651
+ const desc = e.description.length > 70 ? `${e.description.slice(0, 69)}\u2026` : e.description;
5652
+ lines.push(` ${tag} ${name} ${desc}`);
5653
+ }
5654
+ lines.push("");
5655
+ lines.push("View body: /memory show <name> Delete: /memory forget <name>");
5656
+ return { info: lines.join("\n") };
5657
+ }
5658
+ if (sub === "show" || sub === "cat") {
5659
+ const target = args[1];
5660
+ if (!target) return { info: "usage: /memory show <name> or /memory show <scope>/<name>" };
5661
+ const resolved = resolveMemoryTarget(store, target);
5662
+ if (!resolved) return { info: `no memory found: ${target}` };
5663
+ try {
5664
+ const entry = store.read(resolved.scope, resolved.name);
5665
+ return {
5666
+ info: [
5667
+ `\u25B8 ${entry.scope}/${entry.name} (${entry.type}, created ${entry.createdAt || "?"})`,
5668
+ entry.description ? ` ${entry.description}` : "",
5669
+ "",
5670
+ entry.body
5671
+ ].filter((l) => l !== "").concat("").join("\n")
5672
+ };
5673
+ } catch (err) {
5674
+ return { info: `show failed: ${err.message}` };
5675
+ }
5676
+ }
5677
+ if (sub === "forget" || sub === "rm" || sub === "delete") {
5678
+ const target = args[1];
5679
+ if (!target) return { info: "usage: /memory forget <name> or /memory forget <scope>/<name>" };
5680
+ const resolved = resolveMemoryTarget(store, target);
5681
+ if (!resolved) return { info: `no memory found: ${target}` };
5682
+ try {
5683
+ const ok = store.delete(resolved.scope, resolved.name);
5684
+ return {
5685
+ info: ok ? `\u25B8 forgot ${resolved.scope}/${resolved.name}. Next /new or launch won't see it.` : `could not forget ${resolved.scope}/${resolved.name} (already gone?)`
5686
+ };
5687
+ } catch (err) {
5688
+ return { info: `forget failed: ${err.message}` };
5689
+ }
5690
+ }
5691
+ if (sub === "clear") {
5692
+ const rawScope = (args[1] ?? "").toLowerCase();
5693
+ if (rawScope !== "global" && rawScope !== "project") {
5694
+ return { info: "usage: /memory clear <global|project> confirm" };
5695
+ }
5696
+ if ((args[2] ?? "").toLowerCase() !== "confirm") {
5697
+ return {
5698
+ info: `about to delete every memory in scope=${rawScope}. Re-run with the word 'confirm' to proceed: /memory clear ${rawScope} confirm`
5699
+ };
5700
+ }
5701
+ const scope = rawScope;
5702
+ const entries = store.list().filter((e) => e.scope === scope);
5703
+ let deleted = 0;
5704
+ for (const e of entries) {
5705
+ try {
5706
+ if (store.delete(scope, e.name)) deleted++;
5707
+ } catch {
5708
+ }
5709
+ }
5710
+ return { info: `\u25B8 cleared scope=${scope} \u2014 deleted ${deleted} memory file(s).` };
5711
+ }
5712
+ const parts = [];
5713
+ const projMem = readProjectMemory(ctx.memoryRoot);
5714
+ if (projMem) {
5715
+ const hdr = projMem.truncated ? `\u25B8 ${PROJECT_MEMORY_FILE}: ${projMem.path} (${projMem.originalChars.toLocaleString()} chars, truncated)` : `\u25B8 ${PROJECT_MEMORY_FILE}: ${projMem.path} (${projMem.originalChars.toLocaleString()} chars)`;
5716
+ parts.push(hdr, "", projMem.content);
5717
+ }
5718
+ const globalIdx = store.loadIndex("global");
5719
+ if (globalIdx) {
5720
+ parts.push(
5721
+ "",
5722
+ `\u25B8 global memory (${globalIdx.originalChars.toLocaleString()} chars${globalIdx.truncated ? ", truncated" : ""})`,
5723
+ "",
5724
+ globalIdx.content
5725
+ );
5726
+ }
5727
+ const projectIdx = store.loadIndex("project");
5728
+ if (projectIdx) {
5729
+ parts.push(
5730
+ "",
5731
+ `\u25B8 project memory (${projectIdx.originalChars.toLocaleString()} chars${projectIdx.truncated ? ", truncated" : ""})`,
5732
+ "",
5733
+ projectIdx.content
5734
+ );
5735
+ }
5736
+ if (parts.length === 0) {
5737
+ return {
5738
+ info: [
5739
+ `no memory pinned in ${ctx.memoryRoot}.`,
5740
+ "",
5741
+ "Three layers are available:",
5742
+ ` 1. ${PROJECT_MEMORY_FILE} \u2014 committable team memory (in the repo).`,
5743
+ " 2. ~/.reasonix/memory/global/ \u2014 your cross-project private memory.",
5744
+ ` 3. ~/.reasonix/memory/<project-hash>/ \u2014 this project's private memory.`,
5745
+ "",
5746
+ "Ask the model to `remember` something, or hand-edit files directly.",
5747
+ "Changes take effect on next /new or launch \u2014 the system prompt is hashed once per session to keep the prefix cache warm.",
5748
+ "",
5749
+ "Subcommands: /memory list | /memory show <name> | /memory forget <name> | /memory clear <scope> confirm"
5750
+ ].join("\n")
5751
+ };
5752
+ }
5753
+ parts.push(
5754
+ "",
5755
+ "Changes take effect on next /new or launch. Subcommands: /memory list | show | forget | clear"
5756
+ );
5757
+ return { info: parts.join("\n") };
5758
+ }
5759
+ function resolveMemoryTarget(store, raw) {
5760
+ const slash = raw.indexOf("/");
5761
+ if (slash > 0) {
5762
+ const scopeRaw = raw.slice(0, slash).toLowerCase();
5763
+ const name = raw.slice(slash + 1);
5764
+ if (scopeRaw !== "global" && scopeRaw !== "project") return null;
5765
+ const scope = scopeRaw;
5766
+ if (scope === "project" && !store.hasProjectScope()) return null;
5767
+ return { scope, name };
5768
+ }
5769
+ for (const scope of ["project", "global"]) {
5770
+ if (scope === "project" && !store.hasProjectScope()) continue;
5771
+ try {
5772
+ store.read(scope, raw);
5773
+ return { scope, name: raw };
5774
+ } catch {
5775
+ }
5776
+ }
5777
+ return null;
5778
+ }
5535
5779
  function appendSection(lines, label, section) {
5536
5780
  if (!section || !section.supported) {
5537
5781
  lines.push(
@@ -6611,6 +6855,10 @@ async function chatCommand(opts) {
6611
6855
  if (!tools) tools = new ToolRegistry();
6612
6856
  registerWebTools(tools);
6613
6857
  }
6858
+ if (!opts.seedTools) {
6859
+ if (!tools) tools = new ToolRegistry();
6860
+ registerMemoryTools(tools, {});
6861
+ }
6614
6862
  let sessionPreview;
6615
6863
  if (opts.session && !opts.forceResume && !opts.forceNew) {
6616
6864
  const prior = loadSessionMessages(opts.session);
@@ -6649,7 +6897,7 @@ async function chatCommand(opts) {
6649
6897
  // src/cli/commands/code.tsx
6650
6898
  import { basename, resolve as resolve5 } from "path";
6651
6899
  async function codeCommand(opts = {}) {
6652
- const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-JNNNJLYF.js");
6900
+ const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-YEJEJ3IZ.js");
6653
6901
  const rootDir = resolve5(opts.dir ?? process.cwd());
6654
6902
  const session = opts.noSession ? void 0 : `code-${sanitizeName(basename(rootDir))}`;
6655
6903
  const tools = new ToolRegistry();
@@ -6661,6 +6909,7 @@ async function codeCommand(opts = {}) {
6661
6909
  extraAllowed: loadProjectShellAllowed(rootDir)
6662
6910
  });
6663
6911
  registerPlanTool(tools);
6912
+ registerMemoryTools(tools, { projectRoot: rootDir });
6664
6913
  process.stderr.write(
6665
6914
  `\u25B8 reasonix code: rooted at ${rootDir}, session "${session ?? "(ephemeral)"}" \xB7 ${tools.size} native tool(s)
6666
6915
  `
@@ -7710,7 +7959,7 @@ program.action(async () => {
7710
7959
  const defaults = resolveDefaults({});
7711
7960
  await chatCommand({
7712
7961
  model: defaults.model,
7713
- system: applyProjectMemory(DEFAULT_SYSTEM, process.cwd()),
7962
+ system: applyMemoryStack(DEFAULT_SYSTEM, process.cwd()),
7714
7963
  harvest: defaults.harvest,
7715
7964
  branch: defaults.branch,
7716
7965
  session: defaults.session,
@@ -7762,7 +8011,7 @@ program.command("chat").description("Interactive Ink TUI with live cache/cost pa
7762
8011
  });
7763
8012
  await chatCommand({
7764
8013
  model: defaults.model,
7765
- system: applyProjectMemory(opts.system, process.cwd()),
8014
+ system: applyMemoryStack(opts.system, process.cwd()),
7766
8015
  transcript: opts.transcript,
7767
8016
  harvest: defaults.harvest,
7768
8017
  branch: defaults.branch,
@@ -7797,7 +8046,7 @@ program.command("run <task>").description("Run a single task non-interactively,
7797
8046
  await runCommand2({
7798
8047
  task,
7799
8048
  model: defaults.model,
7800
- system: applyProjectMemory(opts.system, process.cwd()),
8049
+ system: applyMemoryStack(opts.system, process.cwd()),
7801
8050
  harvest: defaults.harvest,
7802
8051
  branch: defaults.branch,
7803
8052
  transcript: opts.transcript,