@mathew-cf/opencode-memory 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- import { createRequire } from "node:module";
2
1
  var __defProp = Object.defineProperty;
3
2
  var __returnValue = (v) => v;
4
3
  function __exportSetter(name, newValue) {
@@ -13,12 +12,14 @@ var __export = (target, all) => {
13
12
  set: __exportSetter.bind(all, name)
14
13
  });
15
14
  };
16
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
17
15
 
18
16
  // src/index.ts
19
17
  import { dirname, resolve } from "node:path";
20
18
  import { fileURLToPath } from "node:url";
21
19
 
20
+ // src/config.ts
21
+ import { posix as posix2 } from "node:path";
22
+
22
23
  // src/constants.ts
23
24
  var CATEGORIES = [
24
25
  "preferences",
@@ -46,31 +47,66 @@ var STOP_WORDS = new Set([
46
47
  ]);
47
48
 
48
49
  // src/lib/paths.ts
50
+ import { posix, win32 } from "node:path";
49
51
  function resolveHome(env = process.env) {
50
52
  const raw = env.HOME || env.USERPROFILE;
51
53
  if (!raw) {
52
54
  throw new Error("Cannot resolve home directory: neither HOME nor USERPROFILE is set. " + "On Windows, add `if (-not $env:HOME) { $env:HOME = $env:USERPROFILE }` to your PowerShell profile.");
53
55
  }
54
- return normPath(raw);
56
+ return normalizeDirPath(raw);
55
57
  }
56
58
  function normPath(p) {
57
- return p.replace(/\\/g, "/");
59
+ return posix.normalize(p.replaceAll(win32.sep, posix.sep));
60
+ }
61
+ function normalizeDirPath(p) {
62
+ return posix.join(normPath(p), ".");
63
+ }
64
+ function expandHomePath(p, env = process.env) {
65
+ const normalized = normPath(p);
66
+ if (normalized === "~")
67
+ return resolveHome(env);
68
+ if (normalized.startsWith(`~${posix.sep}`)) {
69
+ return posix.join(resolveHome(env), normalized.slice(2));
70
+ }
71
+ return normalized;
58
72
  }
59
73
  function resolveMemoryDir(env = process.env) {
60
- if (env.MEMORY_DIR && env.MEMORY_DIR.length > 0)
61
- return normPath(env.MEMORY_DIR);
62
- return `${resolveHome(env)}/${DEFAULT_MEMORY_SUBDIR}`;
74
+ if (env.OPENCODE_MEMORY_DIR && env.OPENCODE_MEMORY_DIR.length > 0) {
75
+ return normalizeDirPath(expandHomePath(env.OPENCODE_MEMORY_DIR, env));
76
+ }
77
+ return posix.join(resolveHome(env), DEFAULT_MEMORY_SUBDIR);
78
+ }
79
+ function formatMemoryDirForDisplay(memoryDir, env = process.env) {
80
+ const normalized = normalizeDirPath(memoryDir);
81
+ try {
82
+ const home = resolveHome(env);
83
+ const relativeToHome = posix.relative(home, normalized);
84
+ if (relativeToHome === "")
85
+ return "~";
86
+ if (relativeToHome && !relativeToHome.startsWith("..") && !posix.isAbsolute(relativeToHome)) {
87
+ return posix.join("~", relativeToHome);
88
+ }
89
+ } catch {}
90
+ return normalized;
91
+ }
92
+ function formatMemoryPathForDisplay(memoryDir, relPath, env = process.env) {
93
+ const root = formatMemoryDirForDisplay(memoryDir, env);
94
+ if (!relPath)
95
+ return root;
96
+ return posix.join(root, normPath(relPath));
63
97
  }
64
98
  function ragIndexDir(memoryDir) {
65
- return `${memoryDir}/${RAG_INDEX_SUBDIR}`;
99
+ return posix.join(memoryDir, RAG_INDEX_SUBDIR);
66
100
  }
67
101
 
68
102
  // src/config.ts
69
- var MEMORY_PROMPT_APPENDIX = `## Memory & Sessions
103
+ function buildMemoryPromptAppendix(memoryDir = `~/${DEFAULT_MEMORY_SUBDIR}`) {
104
+ const memoryRoot = formatMemoryDirForDisplay(memoryDir);
105
+ return `## Memory & Sessions
70
106
 
71
107
  1. **Before work:** call \`memory_search\` and \`session_search\` with your topic. Read results — don't just glance at summaries.
72
108
  2. **When something is unfamiliar mid-task** (tool, API, pattern, build system): search both \`memory_search\` and \`session_search\` BEFORE attempting. Use previous sessions to inform your approach — don't try first, search first.
73
- 3. **When you discover something reusable:** write to ~/opencode-memory/{category}/{filename}.md and \`memory_save\` immediately. Never defer, never ask.
109
+ 3. **When you discover something reusable:** write to ${memoryRoot}/{category}/{filename}.md and \`memory_save\` immediately. Never defer, never ask.
74
110
 
75
111
  If you can't write to memory, end your response with:
76
112
  ## Discoveries worth saving
@@ -87,13 +123,9 @@ End with: a clear conclusion (recommendation, diagnosis, or finding), your confi
87
123
  ## Source age
88
124
 
89
125
  Flag anything > 1 year old as potentially stale.`;
90
- var TARGET_AGENTS = [
91
- "general",
92
- "explore",
93
- "research",
94
- "review",
95
- "investigator"
96
- ];
126
+ }
127
+ var MEMORY_PROMPT_APPENDIX = buildMemoryPromptAppendix();
128
+ var TARGET_AGENTS = ["general", "explore", "research", "review", "investigator"];
97
129
  var EXPLORE_PERMISSIONS = {
98
130
  memory_search: "allow",
99
131
  memory_list: "allow",
@@ -110,7 +142,8 @@ function applyConfig(config, options) {
110
142
  config.skills.paths.push(options.skillsDir);
111
143
  }
112
144
  }
113
- const memoryGlob = `${options.memoryDir ?? resolveMemoryDir()}/**`;
145
+ const memoryDir = normalizeDirPath(options.memoryDir ?? resolveMemoryDir());
146
+ const memoryGlob = posix2.join(memoryDir, "**");
114
147
  config.permission = config.permission || {};
115
148
  if (typeof config.permission.edit !== "string") {
116
149
  const edit = config.permission.edit = config.permission.edit || {};
@@ -125,9 +158,9 @@ function applyConfig(config, options) {
125
158
  }
126
159
  }
127
160
  config.agent = config.agent || {};
161
+ const prefix = buildMemoryPromptAppendix(memoryDir);
128
162
  for (const name of TARGET_AGENTS) {
129
163
  const existing = config.agent[name] || {};
130
- const prefix = MEMORY_PROMPT_APPENDIX;
131
164
  if (!existing.prompt) {
132
165
  existing.prompt = prefix;
133
166
  } else if (!existing.prompt.includes("memory_search")) {
@@ -136,7 +169,10 @@ function applyConfig(config, options) {
136
169
  ${existing.prompt}`;
137
170
  }
138
171
  if (name === "explore") {
139
- existing.permission = { ...EXPLORE_PERMISSIONS, ...existing.permission || {} };
172
+ existing.permission = {
173
+ ...EXPLORE_PERMISSIONS,
174
+ ...existing.permission || {}
175
+ };
140
176
  } else {
141
177
  existing.permission = existing.permission || {};
142
178
  const p = existing.permission;
@@ -167,6 +203,13 @@ function matchesToolName(toolName, candidates) {
167
203
  const lower = toolName.toLowerCase();
168
204
  return candidates.some((c) => lower === c || lower.endsWith(`_${c}`) || lower.endsWith(`.${c}`));
169
205
  }
206
+ function configuredMemoryDirLabel(memoryDir) {
207
+ try {
208
+ return formatMemoryDirForDisplay(memoryDir ?? resolveMemoryDir());
209
+ } catch {
210
+ return "the configured memory directory";
211
+ }
212
+ }
170
213
  function afterToolUpdate(state, input) {
171
214
  state.toolCalls++;
172
215
  if (matchesToolName(input.tool, ["memory_search"]))
@@ -188,7 +231,8 @@ function afterToolUpdate(state, input) {
188
231
  }
189
232
  if (matchesToolName(input.tool, ["task"]) && !state.discoveryNudged && typeof input.output === "string" && input.output.includes("Discoveries worth saving")) {
190
233
  state.discoveryNudged = true;
191
- return `<system-reminder>` + `The subagent reported "Discoveries worth saving" above. ` + `Per protocol, you MUST save these to ~/opencode-memory/ now — ` + `don't defer to session end. Write the file, then call memory_save.` + `</system-reminder>`;
234
+ const memoryRoot = configuredMemoryDirLabel(input.memoryDir);
235
+ return `<system-reminder>` + `The subagent reported "Discoveries worth saving" above. ` + `Per protocol, you MUST save these to ${memoryRoot} now — ` + `don't defer to session end. Write the file, then call memory_save.` + `</system-reminder>`;
192
236
  }
193
237
  return null;
194
238
  }
@@ -253,12 +297,16 @@ __export(exports_memory, {
253
297
  runList: () => runList,
254
298
  runAccess: () => runAccess,
255
299
  parseRagHits: () => parseRagHits,
300
+ memorySearchDescription: () => memorySearchDescription,
301
+ memorySaveDescription: () => memorySaveDescription,
302
+ memoryListDescription: () => memoryListDescription,
303
+ memoryAccessPathDescription: () => memoryAccessPathDescription,
256
304
  list: () => list,
257
305
  buildRgArgs: () => buildRgArgs,
258
306
  access: () => access
259
307
  });
260
308
 
261
- // node_modules/zod/v4/classic/external.js
309
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
262
310
  var exports_external = {};
263
311
  __export(exports_external, {
264
312
  xid: () => xid2,
@@ -488,7 +536,7 @@ __export(exports_external, {
488
536
  $brand: () => $brand
489
537
  });
490
538
 
491
- // node_modules/zod/v4/core/index.js
539
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/index.js
492
540
  var exports_core2 = {};
493
541
  __export(exports_core2, {
494
542
  version: () => version,
@@ -752,7 +800,7 @@ __export(exports_core2, {
752
800
  $ZodAny: () => $ZodAny
753
801
  });
754
802
 
755
- // node_modules/zod/v4/core/core.js
803
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/core.js
756
804
  var NEVER = Object.freeze({
757
805
  status: "aborted"
758
806
  });
@@ -819,7 +867,7 @@ function config(newConfig) {
819
867
  Object.assign(globalConfig, newConfig);
820
868
  return globalConfig;
821
869
  }
822
- // node_modules/zod/v4/core/util.js
870
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/util.js
823
871
  var exports_util = {};
824
872
  __export(exports_util, {
825
873
  unwrapMessage: () => unwrapMessage,
@@ -1448,7 +1496,7 @@ class Class {
1448
1496
  constructor(..._args) {}
1449
1497
  }
1450
1498
 
1451
- // node_modules/zod/v4/core/errors.js
1499
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/errors.js
1452
1500
  var initializer = (inst, def) => {
1453
1501
  inst.name = "$ZodError";
1454
1502
  Object.defineProperty(inst, "_zod", {
@@ -1591,7 +1639,7 @@ function prettifyError(error) {
1591
1639
  `);
1592
1640
  }
1593
1641
 
1594
- // node_modules/zod/v4/core/parse.js
1642
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/parse.js
1595
1643
  var _parse = (_Err) => (schema, value, _ctx, _params) => {
1596
1644
  const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
1597
1645
  const result = schema._zod.run({ value, issues: [] }, ctx);
@@ -1678,7 +1726,7 @@ var _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => {
1678
1726
  return _safeParseAsync(_Err)(schema, value, _ctx);
1679
1727
  };
1680
1728
  var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync($ZodRealError);
1681
- // node_modules/zod/v4/core/regexes.js
1729
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/regexes.js
1682
1730
  var exports_regexes = {};
1683
1731
  __export(exports_regexes, {
1684
1732
  xid: () => xid,
@@ -1830,7 +1878,7 @@ var sha512_hex = /^[0-9a-fA-F]{128}$/;
1830
1878
  var sha512_base64 = /* @__PURE__ */ fixedBase64(86, "==");
1831
1879
  var sha512_base64url = /* @__PURE__ */ fixedBase64url(86);
1832
1880
 
1833
- // node_modules/zod/v4/core/checks.js
1881
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/checks.js
1834
1882
  var $ZodCheck = /* @__PURE__ */ $constructor("$ZodCheck", (inst, def) => {
1835
1883
  var _a;
1836
1884
  inst._zod ?? (inst._zod = {});
@@ -2371,7 +2419,7 @@ var $ZodCheckOverwrite = /* @__PURE__ */ $constructor("$ZodCheckOverwrite", (ins
2371
2419
  };
2372
2420
  });
2373
2421
 
2374
- // node_modules/zod/v4/core/doc.js
2422
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/doc.js
2375
2423
  class Doc {
2376
2424
  constructor(args = []) {
2377
2425
  this.content = [];
@@ -2409,14 +2457,14 @@ class Doc {
2409
2457
  }
2410
2458
  }
2411
2459
 
2412
- // node_modules/zod/v4/core/versions.js
2460
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/versions.js
2413
2461
  var version = {
2414
2462
  major: 4,
2415
2463
  minor: 1,
2416
2464
  patch: 8
2417
2465
  };
2418
2466
 
2419
- // node_modules/zod/v4/core/schemas.js
2467
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/schemas.js
2420
2468
  var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
2421
2469
  var _a;
2422
2470
  inst ?? (inst = {});
@@ -4239,7 +4287,7 @@ function handleRefineResult(result, payload, input, inst) {
4239
4287
  payload.issues.push(issue(_iss));
4240
4288
  }
4241
4289
  }
4242
- // node_modules/zod/v4/locales/index.js
4290
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/index.js
4243
4291
  var exports_locales = {};
4244
4292
  __export(exports_locales, {
4245
4293
  zhTW: () => zh_TW_default,
@@ -4290,7 +4338,7 @@ __export(exports_locales, {
4290
4338
  ar: () => ar_default
4291
4339
  });
4292
4340
 
4293
- // node_modules/zod/v4/locales/ar.js
4341
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ar.js
4294
4342
  var error = () => {
4295
4343
  const Sizable = {
4296
4344
  string: { unit: "حرف", verb: "أن يحوي" },
@@ -4406,7 +4454,7 @@ function ar_default() {
4406
4454
  localeError: error()
4407
4455
  };
4408
4456
  }
4409
- // node_modules/zod/v4/locales/az.js
4457
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/az.js
4410
4458
  var error2 = () => {
4411
4459
  const Sizable = {
4412
4460
  string: { unit: "simvol", verb: "olmalıdır" },
@@ -4521,7 +4569,7 @@ function az_default() {
4521
4569
  localeError: error2()
4522
4570
  };
4523
4571
  }
4524
- // node_modules/zod/v4/locales/be.js
4572
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/be.js
4525
4573
  function getBelarusianPlural(count, one, few, many) {
4526
4574
  const absCount = Math.abs(count);
4527
4575
  const lastDigit = absCount % 10;
@@ -4685,7 +4733,7 @@ function be_default() {
4685
4733
  localeError: error3()
4686
4734
  };
4687
4735
  }
4688
- // node_modules/zod/v4/locales/ca.js
4736
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ca.js
4689
4737
  var error4 = () => {
4690
4738
  const Sizable = {
4691
4739
  string: { unit: "caràcters", verb: "contenir" },
@@ -4802,7 +4850,7 @@ function ca_default() {
4802
4850
  localeError: error4()
4803
4851
  };
4804
4852
  }
4805
- // node_modules/zod/v4/locales/cs.js
4853
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/cs.js
4806
4854
  var error5 = () => {
4807
4855
  const Sizable = {
4808
4856
  string: { unit: "znaků", verb: "mít" },
@@ -4937,7 +4985,7 @@ function cs_default() {
4937
4985
  localeError: error5()
4938
4986
  };
4939
4987
  }
4940
- // node_modules/zod/v4/locales/da.js
4988
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/da.js
4941
4989
  var error6 = () => {
4942
4990
  const Sizable = {
4943
4991
  string: { unit: "tegn", verb: "havde" },
@@ -5068,7 +5116,7 @@ function da_default() {
5068
5116
  localeError: error6()
5069
5117
  };
5070
5118
  }
5071
- // node_modules/zod/v4/locales/de.js
5119
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/de.js
5072
5120
  var error7 = () => {
5073
5121
  const Sizable = {
5074
5122
  string: { unit: "Zeichen", verb: "zu haben" },
@@ -5184,7 +5232,7 @@ function de_default() {
5184
5232
  localeError: error7()
5185
5233
  };
5186
5234
  }
5187
- // node_modules/zod/v4/locales/en.js
5235
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/en.js
5188
5236
  var parsedType = (data) => {
5189
5237
  const t = typeof data;
5190
5238
  switch (t) {
@@ -5301,7 +5349,7 @@ function en_default() {
5301
5349
  localeError: error8()
5302
5350
  };
5303
5351
  }
5304
- // node_modules/zod/v4/locales/eo.js
5352
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/eo.js
5305
5353
  var parsedType2 = (data) => {
5306
5354
  const t = typeof data;
5307
5355
  switch (t) {
@@ -5417,7 +5465,7 @@ function eo_default() {
5417
5465
  localeError: error9()
5418
5466
  };
5419
5467
  }
5420
- // node_modules/zod/v4/locales/es.js
5468
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/es.js
5421
5469
  var error10 = () => {
5422
5470
  const Sizable = {
5423
5471
  string: { unit: "caracteres", verb: "tener" },
@@ -5565,7 +5613,7 @@ function es_default() {
5565
5613
  localeError: error10()
5566
5614
  };
5567
5615
  }
5568
- // node_modules/zod/v4/locales/fa.js
5616
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fa.js
5569
5617
  var error11 = () => {
5570
5618
  const Sizable = {
5571
5619
  string: { unit: "کاراکتر", verb: "داشته باشد" },
@@ -5687,7 +5735,7 @@ function fa_default() {
5687
5735
  localeError: error11()
5688
5736
  };
5689
5737
  }
5690
- // node_modules/zod/v4/locales/fi.js
5738
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fi.js
5691
5739
  var error12 = () => {
5692
5740
  const Sizable = {
5693
5741
  string: { unit: "merkkiä", subject: "merkkijonon" },
@@ -5809,7 +5857,7 @@ function fi_default() {
5809
5857
  localeError: error12()
5810
5858
  };
5811
5859
  }
5812
- // node_modules/zod/v4/locales/fr.js
5860
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fr.js
5813
5861
  var error13 = () => {
5814
5862
  const Sizable = {
5815
5863
  string: { unit: "caractères", verb: "avoir" },
@@ -5925,7 +5973,7 @@ function fr_default() {
5925
5973
  localeError: error13()
5926
5974
  };
5927
5975
  }
5928
- // node_modules/zod/v4/locales/fr-CA.js
5976
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fr-CA.js
5929
5977
  var error14 = () => {
5930
5978
  const Sizable = {
5931
5979
  string: { unit: "caractères", verb: "avoir" },
@@ -6042,7 +6090,7 @@ function fr_CA_default() {
6042
6090
  localeError: error14()
6043
6091
  };
6044
6092
  }
6045
- // node_modules/zod/v4/locales/he.js
6093
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/he.js
6046
6094
  var error15 = () => {
6047
6095
  const Sizable = {
6048
6096
  string: { unit: "אותיות", verb: "לכלול" },
@@ -6158,7 +6206,7 @@ function he_default() {
6158
6206
  localeError: error15()
6159
6207
  };
6160
6208
  }
6161
- // node_modules/zod/v4/locales/hu.js
6209
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/hu.js
6162
6210
  var error16 = () => {
6163
6211
  const Sizable = {
6164
6212
  string: { unit: "karakter", verb: "legyen" },
@@ -6274,7 +6322,7 @@ function hu_default() {
6274
6322
  localeError: error16()
6275
6323
  };
6276
6324
  }
6277
- // node_modules/zod/v4/locales/id.js
6325
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/id.js
6278
6326
  var error17 = () => {
6279
6327
  const Sizable = {
6280
6328
  string: { unit: "karakter", verb: "memiliki" },
@@ -6390,7 +6438,7 @@ function id_default() {
6390
6438
  localeError: error17()
6391
6439
  };
6392
6440
  }
6393
- // node_modules/zod/v4/locales/is.js
6441
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/is.js
6394
6442
  var parsedType3 = (data) => {
6395
6443
  const t = typeof data;
6396
6444
  switch (t) {
@@ -6507,7 +6555,7 @@ function is_default() {
6507
6555
  localeError: error18()
6508
6556
  };
6509
6557
  }
6510
- // node_modules/zod/v4/locales/it.js
6558
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/it.js
6511
6559
  var error19 = () => {
6512
6560
  const Sizable = {
6513
6561
  string: { unit: "caratteri", verb: "avere" },
@@ -6623,7 +6671,7 @@ function it_default() {
6623
6671
  localeError: error19()
6624
6672
  };
6625
6673
  }
6626
- // node_modules/zod/v4/locales/ja.js
6674
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ja.js
6627
6675
  var error20 = () => {
6628
6676
  const Sizable = {
6629
6677
  string: { unit: "文字", verb: "である" },
@@ -6738,7 +6786,7 @@ function ja_default() {
6738
6786
  localeError: error20()
6739
6787
  };
6740
6788
  }
6741
- // node_modules/zod/v4/locales/ka.js
6789
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ka.js
6742
6790
  var parsedType4 = (data) => {
6743
6791
  const t = typeof data;
6744
6792
  switch (t) {
@@ -6863,7 +6911,7 @@ function ka_default() {
6863
6911
  localeError: error21()
6864
6912
  };
6865
6913
  }
6866
- // node_modules/zod/v4/locales/km.js
6914
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/km.js
6867
6915
  var error22 = () => {
6868
6916
  const Sizable = {
6869
6917
  string: { unit: "តួអក្សរ", verb: "គួរមាន" },
@@ -6981,11 +7029,11 @@ function km_default() {
6981
7029
  };
6982
7030
  }
6983
7031
 
6984
- // node_modules/zod/v4/locales/kh.js
7032
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/kh.js
6985
7033
  function kh_default() {
6986
7034
  return km_default();
6987
7035
  }
6988
- // node_modules/zod/v4/locales/ko.js
7036
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ko.js
6989
7037
  var error23 = () => {
6990
7038
  const Sizable = {
6991
7039
  string: { unit: "문자", verb: "to have" },
@@ -7106,7 +7154,7 @@ function ko_default() {
7106
7154
  localeError: error23()
7107
7155
  };
7108
7156
  }
7109
- // node_modules/zod/v4/locales/lt.js
7157
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/lt.js
7110
7158
  var parsedType5 = (data) => {
7111
7159
  const t = typeof data;
7112
7160
  return parsedTypeFromType(t, data);
@@ -7335,7 +7383,7 @@ function lt_default() {
7335
7383
  localeError: error24()
7336
7384
  };
7337
7385
  }
7338
- // node_modules/zod/v4/locales/mk.js
7386
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/mk.js
7339
7387
  var error25 = () => {
7340
7388
  const Sizable = {
7341
7389
  string: { unit: "знаци", verb: "да имаат" },
@@ -7452,7 +7500,7 @@ function mk_default() {
7452
7500
  localeError: error25()
7453
7501
  };
7454
7502
  }
7455
- // node_modules/zod/v4/locales/ms.js
7503
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ms.js
7456
7504
  var error26 = () => {
7457
7505
  const Sizable = {
7458
7506
  string: { unit: "aksara", verb: "mempunyai" },
@@ -7568,7 +7616,7 @@ function ms_default() {
7568
7616
  localeError: error26()
7569
7617
  };
7570
7618
  }
7571
- // node_modules/zod/v4/locales/nl.js
7619
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/nl.js
7572
7620
  var error27 = () => {
7573
7621
  const Sizable = {
7574
7622
  string: { unit: "tekens" },
@@ -7685,7 +7733,7 @@ function nl_default() {
7685
7733
  localeError: error27()
7686
7734
  };
7687
7735
  }
7688
- // node_modules/zod/v4/locales/no.js
7736
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/no.js
7689
7737
  var error28 = () => {
7690
7738
  const Sizable = {
7691
7739
  string: { unit: "tegn", verb: "å ha" },
@@ -7801,7 +7849,7 @@ function no_default() {
7801
7849
  localeError: error28()
7802
7850
  };
7803
7851
  }
7804
- // node_modules/zod/v4/locales/ota.js
7852
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ota.js
7805
7853
  var error29 = () => {
7806
7854
  const Sizable = {
7807
7855
  string: { unit: "harf", verb: "olmalıdır" },
@@ -7917,7 +7965,7 @@ function ota_default() {
7917
7965
  localeError: error29()
7918
7966
  };
7919
7967
  }
7920
- // node_modules/zod/v4/locales/ps.js
7968
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ps.js
7921
7969
  var error30 = () => {
7922
7970
  const Sizable = {
7923
7971
  string: { unit: "توکي", verb: "ولري" },
@@ -8039,7 +8087,7 @@ function ps_default() {
8039
8087
  localeError: error30()
8040
8088
  };
8041
8089
  }
8042
- // node_modules/zod/v4/locales/pl.js
8090
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/pl.js
8043
8091
  var error31 = () => {
8044
8092
  const Sizable = {
8045
8093
  string: { unit: "znaków", verb: "mieć" },
@@ -8156,7 +8204,7 @@ function pl_default() {
8156
8204
  localeError: error31()
8157
8205
  };
8158
8206
  }
8159
- // node_modules/zod/v4/locales/pt.js
8207
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/pt.js
8160
8208
  var error32 = () => {
8161
8209
  const Sizable = {
8162
8210
  string: { unit: "caracteres", verb: "ter" },
@@ -8272,7 +8320,7 @@ function pt_default() {
8272
8320
  localeError: error32()
8273
8321
  };
8274
8322
  }
8275
- // node_modules/zod/v4/locales/ru.js
8323
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ru.js
8276
8324
  function getRussianPlural(count, one, few, many) {
8277
8325
  const absCount = Math.abs(count);
8278
8326
  const lastDigit = absCount % 10;
@@ -8436,7 +8484,7 @@ function ru_default() {
8436
8484
  localeError: error33()
8437
8485
  };
8438
8486
  }
8439
- // node_modules/zod/v4/locales/sl.js
8487
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/sl.js
8440
8488
  var error34 = () => {
8441
8489
  const Sizable = {
8442
8490
  string: { unit: "znakov", verb: "imeti" },
@@ -8553,7 +8601,7 @@ function sl_default() {
8553
8601
  localeError: error34()
8554
8602
  };
8555
8603
  }
8556
- // node_modules/zod/v4/locales/sv.js
8604
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/sv.js
8557
8605
  var error35 = () => {
8558
8606
  const Sizable = {
8559
8607
  string: { unit: "tecken", verb: "att ha" },
@@ -8671,7 +8719,7 @@ function sv_default() {
8671
8719
  localeError: error35()
8672
8720
  };
8673
8721
  }
8674
- // node_modules/zod/v4/locales/ta.js
8722
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ta.js
8675
8723
  var error36 = () => {
8676
8724
  const Sizable = {
8677
8725
  string: { unit: "எழுத்துக்கள்", verb: "கொண்டிருக்க வேண்டும்" },
@@ -8788,7 +8836,7 @@ function ta_default() {
8788
8836
  localeError: error36()
8789
8837
  };
8790
8838
  }
8791
- // node_modules/zod/v4/locales/th.js
8839
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/th.js
8792
8840
  var error37 = () => {
8793
8841
  const Sizable = {
8794
8842
  string: { unit: "ตัวอักษร", verb: "ควรมี" },
@@ -8905,7 +8953,7 @@ function th_default() {
8905
8953
  localeError: error37()
8906
8954
  };
8907
8955
  }
8908
- // node_modules/zod/v4/locales/tr.js
8956
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/tr.js
8909
8957
  var parsedType6 = (data) => {
8910
8958
  const t = typeof data;
8911
8959
  switch (t) {
@@ -9020,7 +9068,7 @@ function tr_default() {
9020
9068
  localeError: error38()
9021
9069
  };
9022
9070
  }
9023
- // node_modules/zod/v4/locales/uk.js
9071
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/uk.js
9024
9072
  var error39 = () => {
9025
9073
  const Sizable = {
9026
9074
  string: { unit: "символів", verb: "матиме" },
@@ -9137,11 +9185,11 @@ function uk_default() {
9137
9185
  };
9138
9186
  }
9139
9187
 
9140
- // node_modules/zod/v4/locales/ua.js
9188
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ua.js
9141
9189
  function ua_default() {
9142
9190
  return uk_default();
9143
9191
  }
9144
- // node_modules/zod/v4/locales/ur.js
9192
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ur.js
9145
9193
  var error40 = () => {
9146
9194
  const Sizable = {
9147
9195
  string: { unit: "حروف", verb: "ہونا" },
@@ -9258,7 +9306,7 @@ function ur_default() {
9258
9306
  localeError: error40()
9259
9307
  };
9260
9308
  }
9261
- // node_modules/zod/v4/locales/vi.js
9309
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/vi.js
9262
9310
  var error41 = () => {
9263
9311
  const Sizable = {
9264
9312
  string: { unit: "ký tự", verb: "có" },
@@ -9374,7 +9422,7 @@ function vi_default() {
9374
9422
  localeError: error41()
9375
9423
  };
9376
9424
  }
9377
- // node_modules/zod/v4/locales/zh-CN.js
9425
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/zh-CN.js
9378
9426
  var error42 = () => {
9379
9427
  const Sizable = {
9380
9428
  string: { unit: "字符", verb: "包含" },
@@ -9490,7 +9538,7 @@ function zh_CN_default() {
9490
9538
  localeError: error42()
9491
9539
  };
9492
9540
  }
9493
- // node_modules/zod/v4/locales/zh-TW.js
9541
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/zh-TW.js
9494
9542
  var error43 = () => {
9495
9543
  const Sizable = {
9496
9544
  string: { unit: "字元", verb: "擁有" },
@@ -9607,7 +9655,7 @@ function zh_TW_default() {
9607
9655
  localeError: error43()
9608
9656
  };
9609
9657
  }
9610
- // node_modules/zod/v4/locales/yo.js
9658
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/yo.js
9611
9659
  var error44 = () => {
9612
9660
  const Sizable = {
9613
9661
  string: { unit: "àmi", verb: "ní" },
@@ -9722,7 +9770,7 @@ function yo_default() {
9722
9770
  localeError: error44()
9723
9771
  };
9724
9772
  }
9725
- // node_modules/zod/v4/core/registries.js
9773
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/registries.js
9726
9774
  var $output = Symbol("ZodOutput");
9727
9775
  var $input = Symbol("ZodInput");
9728
9776
 
@@ -9773,7 +9821,7 @@ function registry() {
9773
9821
  return new $ZodRegistry;
9774
9822
  }
9775
9823
  var globalRegistry = /* @__PURE__ */ registry();
9776
- // node_modules/zod/v4/core/api.js
9824
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/api.js
9777
9825
  function _string(Class2, params) {
9778
9826
  return new Class2({
9779
9827
  type: "string",
@@ -10651,7 +10699,7 @@ function _stringFormat(Class2, format, fnOrRegex, _params = {}) {
10651
10699
  const inst = new Class2(def);
10652
10700
  return inst;
10653
10701
  }
10654
- // node_modules/zod/v4/core/to-json-schema.js
10702
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/to-json-schema.js
10655
10703
  class JSONSchemaGenerator {
10656
10704
  constructor(params) {
10657
10705
  this.counter = 0;
@@ -10989,7 +11037,7 @@ class JSONSchemaGenerator {
10989
11037
  if (val === undefined) {
10990
11038
  if (this.unrepresentable === "throw") {
10991
11039
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
10992
- } else {}
11040
+ }
10993
11041
  } else if (typeof val === "bigint") {
10994
11042
  if (this.unrepresentable === "throw") {
10995
11043
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -11455,9 +11503,9 @@ function isTransforming(_schema, _ctx) {
11455
11503
  }
11456
11504
  throw new Error(`Unknown schema type: ${def.type}`);
11457
11505
  }
11458
- // node_modules/zod/v4/core/json-schema.js
11506
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/json-schema.js
11459
11507
  var exports_json_schema = {};
11460
- // node_modules/zod/v4/classic/iso.js
11508
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/iso.js
11461
11509
  var exports_iso = {};
11462
11510
  __export(exports_iso, {
11463
11511
  time: () => time2,
@@ -11498,7 +11546,7 @@ function duration2(params) {
11498
11546
  return _isoDuration(ZodISODuration, params);
11499
11547
  }
11500
11548
 
11501
- // node_modules/zod/v4/classic/errors.js
11549
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/errors.js
11502
11550
  var initializer2 = (inst, issues) => {
11503
11551
  $ZodError.init(inst, issues);
11504
11552
  inst.name = "ZodError";
@@ -11533,7 +11581,7 @@ var ZodRealError = $constructor("ZodError", initializer2, {
11533
11581
  Parent: Error
11534
11582
  });
11535
11583
 
11536
- // node_modules/zod/v4/classic/parse.js
11584
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/parse.js
11537
11585
  var parse3 = /* @__PURE__ */ _parse(ZodRealError);
11538
11586
  var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
11539
11587
  var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
@@ -11547,7 +11595,7 @@ var safeDecode2 = /* @__PURE__ */ _safeDecode(ZodRealError);
11547
11595
  var safeEncodeAsync2 = /* @__PURE__ */ _safeEncodeAsync(ZodRealError);
11548
11596
  var safeDecodeAsync2 = /* @__PURE__ */ _safeDecodeAsync(ZodRealError);
11549
11597
 
11550
- // node_modules/zod/v4/classic/schemas.js
11598
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/schemas.js
11551
11599
  var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
11552
11600
  $ZodType.init(inst, def);
11553
11601
  inst.def = def;
@@ -12522,7 +12570,7 @@ function json(params) {
12522
12570
  function preprocess(fn, schema) {
12523
12571
  return pipe(transform(fn), schema);
12524
12572
  }
12525
- // node_modules/zod/v4/classic/compat.js
12573
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/compat.js
12526
12574
  var ZodIssueCode = {
12527
12575
  invalid_type: "invalid_type",
12528
12576
  too_big: "too_big",
@@ -12546,7 +12594,7 @@ function getErrorMap() {
12546
12594
  }
12547
12595
  var ZodFirstPartyTypeKind;
12548
12596
  (function(ZodFirstPartyTypeKind2) {})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
12549
- // node_modules/zod/v4/classic/coerce.js
12597
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/coerce.js
12550
12598
  var exports_coerce = {};
12551
12599
  __export(exports_coerce, {
12552
12600
  string: () => string3,
@@ -12571,13 +12619,16 @@ function date4(params) {
12571
12619
  return _coercedDate(ZodDate, params);
12572
12620
  }
12573
12621
 
12574
- // node_modules/zod/v4/classic/external.js
12622
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
12575
12623
  config(en_default());
12576
12624
  // node_modules/@opencode-ai/plugin/dist/tool.js
12577
12625
  function tool(input) {
12578
12626
  return input;
12579
12627
  }
12580
12628
  tool.schema = exports_external;
12629
+ // src/tools/memory.ts
12630
+ import { posix as posix3 } from "node:path";
12631
+
12581
12632
  // src/lib/frontmatter.ts
12582
12633
  var FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
12583
12634
  function parseFrontmatter(content) {
@@ -12642,8 +12693,8 @@ function todayISO() {
12642
12693
  }
12643
12694
 
12644
12695
  // src/lib/rag.ts
12645
- import { createRequire as createRequire2 } from "node:module";
12646
- var require2 = createRequire2(import.meta.url);
12696
+ import { createRequire } from "node:module";
12697
+ var require2 = createRequire(import.meta.url);
12647
12698
  function resolveRagBinary() {
12648
12699
  try {
12649
12700
  return require2.resolve("@mathew-cf/rag-cli/bin/rag.js");
@@ -12706,8 +12757,8 @@ async function downloadModel() {
12706
12757
  }
12707
12758
 
12708
12759
  // src/lib/ripgrep.ts
12709
- import { createRequire as createRequire3 } from "node:module";
12710
- var require3 = createRequire3(import.meta.url);
12760
+ import { createRequire as createRequire2 } from "node:module";
12761
+ var require3 = createRequire2(import.meta.url);
12711
12762
  function resolveRgBinary() {
12712
12763
  try {
12713
12764
  const mod = require3("@vscode/ripgrep");
@@ -12797,17 +12848,7 @@ function scoreCandidate(input) {
12797
12848
 
12798
12849
  // src/tools/memory.ts
12799
12850
  function buildRgArgs(terms) {
12800
- const args = [
12801
- "-il",
12802
- "--glob",
12803
- "*.md",
12804
- "--glob",
12805
- "!.git",
12806
- "--glob",
12807
- "!.rag",
12808
- "--glob",
12809
- "!**/INDEX.md"
12810
- ];
12851
+ const args = ["-il", "--glob", "*.md", "--glob", "!.git", "--glob", "!.rag", "--glob", "!**/INDEX.md"];
12811
12852
  for (const term of terms) {
12812
12853
  args.push("-e", term);
12813
12854
  }
@@ -12826,10 +12867,26 @@ function parseRagHits(ragText) {
12826
12867
  }
12827
12868
  }
12828
12869
  function toRelPath(memoryDir, absPath) {
12829
- return normPath(absPath).replace(`${memoryDir}/`, "");
12870
+ return posix3.relative(memoryDir, normPath(absPath));
12830
12871
  }
12831
- var search = tool({
12832
- description: "Search memories in ~/opencode-memory/ using both keyword (rg) and semantic (rag) search. " + "Results are summaries only (path, tags, importance, short context). " + `Use the Read tool on ~/opencode-memory/{path} to get the full content.
12872
+ function configuredMemoryDirLabel2(memoryDir) {
12873
+ try {
12874
+ return formatMemoryDirForDisplay(memoryDir ?? resolveMemoryDir());
12875
+ } catch {
12876
+ return "the configured memory directory";
12877
+ }
12878
+ }
12879
+ function configuredMemoryPathLabel(relPath, memoryDir) {
12880
+ try {
12881
+ return formatMemoryPathForDisplay(memoryDir ?? resolveMemoryDir(), relPath);
12882
+ } catch {
12883
+ return `the configured memory directory/${relPath}`;
12884
+ }
12885
+ }
12886
+ function memorySearchDescription(memoryDir) {
12887
+ const memoryRoot = configuredMemoryDirLabel2(memoryDir);
12888
+ const memoryPath = configuredMemoryPathLabel("{path}", memoryDir);
12889
+ return `Search memories in ${memoryRoot} using both keyword (rg) and semantic (rag) search. ` + "Results are summaries only (path, tags, importance, short context). " + `Use the Read tool on ${memoryPath} to get the full content.
12833
12890
 
12834
12891
  ` + "Multi-term queries match files containing ANY search term (OR logic); files matching more terms rank higher. " + `For example, 'errors retries' finds files mentioning 'errors' OR 'retries', with files containing both ranked first.
12835
12892
 
@@ -12842,9 +12899,53 @@ var search = tool({
12842
12899
  ` + `- Before writing new memory — check if a file already exists to update instead of duplicate
12843
12900
 
12844
12901
  ` + `FOLLOW-UP SEARCHES (do when results seem incomplete):
12845
- ` + `- Results include Related: files — use the Read tool on ~/opencode-memory/{path} for connected knowledge
12902
+ ` + `- Results include Related: files — use the Read tool on ${memoryPath} for connected knowledge
12846
12903
  ` + `- If few/no results, try broader terms or search without the category filter
12847
- ` + "- Check the 'Related files' section at the bottom of results for cross-references worth exploring",
12904
+ ` + "- Check the 'Related files' section at the bottom of results for cross-references worth exploring";
12905
+ }
12906
+ function memoryListDescription(memoryDir) {
12907
+ const memoryRoot = configuredMemoryDirLabel2(memoryDir);
12908
+ return `Browse memories in ${memoryRoot}. Without a category, lists all categories with file counts. ` + "With a category, lists files in that category with their summaries.";
12909
+ }
12910
+ function memoryAccessPathDescription(memoryDir) {
12911
+ const memoryRoot = configuredMemoryDirLabel2(memoryDir);
12912
+ return `Relative path within ${memoryRoot} (e.g. 'technical/build-tooling.md')`;
12913
+ }
12914
+ function memorySaveDescription(memoryDir) {
12915
+ const memoryPath = configuredMemoryPathLabel("{category}/{filename}.md", memoryDir);
12916
+ return "Commit and re-index all pending memory changes. " + `Call AFTER using Write/Edit tools on ${memoryPath}. ` + `Handles: git add -A, commit (message derived from changed files), RAG re-indexing.
12917
+
12918
+ ` + `WHEN TO SAVE (always save when you discover something reusable):
12919
+ ` + `- Learned a non-obvious API pattern, tool quirk, or workaround
12920
+ ` + `- Discovered repo structure, conventions, or gotchas that future sessions would benefit from
12921
+ ` + `- Found external tool usage patterns that weren't documented
12922
+ ` + `- Resolved a tricky debugging problem with a non-obvious root cause
12923
+ ` + `- Learned team/ownership/contact information not easily found elsewhere
12924
+ ` + `DO NOT save: one-off answers, things in public docs, or context only relevant to the current task
12925
+
12926
+ ` + `WORKFLOW:
12927
+ ` + `1. memory_search first — check if a file already exists to update
12928
+ ` + `2. Write/Edit files at ${memoryPath}
12929
+ ` + `3. Call this tool to sync all changes
12930
+
12931
+ ` + `REPO NOTES: for repository-related memory, use the path structure
12932
+ ` + "`repos/{host}/{org}/{repo}.md` — e.g. `repos/github.com/user/project.md`.\n" + `This makes it easy to find later by repo URL fragments.
12933
+
12934
+ ` + `CATEGORIES: preferences, repos, technical, people, workflows, snippets, notes
12935
+
12936
+ ` + `FRONTMATTER FORMAT (include at top of file):
12937
+ ` + `---
12938
+ ` + `title: Human-readable title
12939
+ ` + `tags: [tag1, tag2]
12940
+ ` + `summary: One-line summary
12941
+ ` + `created: YYYY-MM-DD
12942
+ ` + `updated: YYYY-MM-DD
12943
+ ` + `importance: high | medium | low
12944
+ ` + `related: [category/file.md]
12945
+ ` + "---";
12946
+ }
12947
+ var search = tool({
12948
+ description: memorySearchDescription(),
12848
12949
  args: {
12849
12950
  query: tool.schema.string().describe("Search terms or natural language query"),
12850
12951
  category: tool.schema.string().optional().describe("Filter to a specific category: preferences, repos, technical, people, workflows, snippets, notes")
@@ -12857,7 +12958,7 @@ async function runSearch(input) {
12857
12958
  const { query, category } = input;
12858
12959
  const memoryDir = resolveMemoryDir();
12859
12960
  const indexDir = ragIndexDir(memoryDir);
12860
- const searchDir = category ? `${memoryDir}/${category}` : memoryDir;
12961
+ const searchDir = category ? posix3.join(memoryDir, category) : memoryDir;
12861
12962
  const terms = parseSearchTerms(query);
12862
12963
  const rgTerms = terms.length > 0 ? terms : [query];
12863
12964
  const hasRag = ragAvailable();
@@ -12915,7 +13016,7 @@ async function runSearch(input) {
12915
13016
  }
12916
13017
  }
12917
13018
  if (resultMap.size === 0) {
12918
- const scanDir = category ? `${memoryDir}/${category}` : memoryDir;
13019
+ const scanDir = category ? posix3.join(memoryDir, category) : memoryDir;
12919
13020
  const suggestions = [];
12920
13021
  try {
12921
13022
  const fnGlob = new Bun.Glob("**/*.md");
@@ -12932,7 +13033,7 @@ async function runSearch(input) {
12932
13033
  return `No content matches for: "${query}"
12933
13034
 
12934
13035
  ` + `Files with matching names:
12935
- ${suggestions.slice(0, 5).map((s) => ` - ~/opencode-memory/${s}`).join(`
13036
+ ${suggestions.slice(0, 5).map((s) => ` - ${formatMemoryPathForDisplay(memoryDir, s)}`).join(`
12936
13037
  `)}
12937
13038
 
12938
13039
  ` + `Use the Read tool to check these.`;
@@ -12942,7 +13043,7 @@ ${suggestions.slice(0, 5).map((s) => ` - ~/opencode-memory/${s}`).join(`
12942
13043
  const results = [];
12943
13044
  for (const [path, info] of resultMap) {
12944
13045
  try {
12945
- const content = await Bun.file(`${memoryDir}/${path}`).text();
13046
+ const content = await Bun.file(posix3.join(memoryDir, path)).text();
12946
13047
  const { meta } = parseFrontmatter(content);
12947
13048
  const termMatches = terms.length > 0 ? countTermMatches(content, terms) : info.rgMatch ? 1 : 0;
12948
13049
  const score = scoreCandidate({
@@ -13003,7 +13104,7 @@ ${suggestions.slice(0, 5).map((s) => ` - ~/opencode-memory/${s}`).join(`
13003
13104
  lines.push("");
13004
13105
  }
13005
13106
  if (topResults.length > 0) {
13006
- lines.push(`_Read the top result: \`~/opencode-memory/${topResults[0].path}\`_`);
13107
+ lines.push(`_Read the top result: \`${formatMemoryPathForDisplay(memoryDir, topResults[0].path)}\`_`);
13007
13108
  lines.push("");
13008
13109
  }
13009
13110
  const shownPaths = new Set(topResults.slice(0, 7).map((r) => r.path));
@@ -13018,13 +13119,13 @@ ${suggestions.slice(0, 5).map((s) => ` - ~/opencode-memory/${s}`).join(`
13018
13119
  const verified = [];
13019
13120
  for (const rel of relatedSuggestions) {
13020
13121
  try {
13021
- if (await Bun.file(`${memoryDir}/${rel}`).exists())
13122
+ if (await Bun.file(posix3.join(memoryDir, rel)).exists())
13022
13123
  verified.push(rel);
13023
13124
  } catch {}
13024
13125
  }
13025
13126
  if (verified.length > 0) {
13026
13127
  lines.push("---");
13027
- lines.push("**Related files** (not in results — use the Read tool on ~/opencode-memory/{path}):");
13128
+ lines.push(`**Related files** (not in results — use the Read tool on ${formatMemoryPathForDisplay(memoryDir, "{path}")}):`);
13028
13129
  for (const rel of verified) {
13029
13130
  lines.push(` - ${rel}`);
13030
13131
  }
@@ -13034,7 +13135,7 @@ ${suggestions.slice(0, 5).map((s) => ` - ~/opencode-memory/${s}`).join(`
13034
13135
  `);
13035
13136
  }
13036
13137
  var list = tool({
13037
- description: "Browse memories in ~/opencode-memory/. Without a category, lists all categories with file counts. " + "With a category, lists files in that category with their summaries.",
13138
+ description: memoryListDescription(),
13038
13139
  args: {
13039
13140
  category: tool.schema.string().optional().describe("Category to list: preferences, repos, technical, people, workflows, snippets, notes")
13040
13141
  },
@@ -13053,7 +13154,7 @@ async function runList(input) {
13053
13154
  let count = 0;
13054
13155
  try {
13055
13156
  for await (const _ of glob2.scan({
13056
- cwd: `${memoryDir}/${cat}`,
13157
+ cwd: posix3.join(memoryDir, cat),
13057
13158
  dot: false
13058
13159
  })) {
13059
13160
  count++;
@@ -13064,13 +13165,13 @@ async function runList(input) {
13064
13165
  return lines2.join(`
13065
13166
  `);
13066
13167
  }
13067
- const catDir = `${memoryDir}/${category}`;
13168
+ const catDir = posix3.join(memoryDir, category);
13068
13169
  const glob = new Bun.Glob("**/*.md");
13069
13170
  const files = [];
13070
13171
  try {
13071
13172
  for await (const f of glob.scan({ cwd: catDir, dot: false })) {
13072
13173
  try {
13073
- const content = await Bun.file(`${catDir}/${f}`).text();
13174
+ const content = await Bun.file(posix3.join(catDir, f)).text();
13074
13175
  const { meta } = parseFrontmatter(content);
13075
13176
  files.push({
13076
13177
  path: `${category}/${f}`,
@@ -13103,7 +13204,7 @@ var access = tool({
13103
13204
 
13104
13205
  ` + "This helps the memory system track which memories are actively useful vs. stale.",
13105
13206
  args: {
13106
- path: tool.schema.string().describe("Relative path within ~/opencode-memory/ (e.g. 'technical/build-tooling.md')")
13207
+ path: tool.schema.string().describe(memoryAccessPathDescription())
13107
13208
  },
13108
13209
  async execute({ path }) {
13109
13210
  return runAccess({ path });
@@ -13112,7 +13213,7 @@ var access = tool({
13112
13213
  async function runAccess(input) {
13113
13214
  const memoryDir = resolveMemoryDir();
13114
13215
  const { path } = input;
13115
- const filePath = `${memoryDir}/${path}`;
13216
+ const filePath = posix3.join(memoryDir, path);
13116
13217
  try {
13117
13218
  const content = await Bun.file(filePath).text();
13118
13219
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
@@ -13132,36 +13233,7 @@ ${body}`);
13132
13233
  }
13133
13234
  }
13134
13235
  var save = tool({
13135
- description: "Commit and re-index all pending memory changes. " + "Call AFTER using Write/Edit tools on ~/opencode-memory/{category}/{filename}.md. " + `Handles: git add -A, commit (message derived from changed files), RAG re-indexing.
13136
-
13137
- ` + `WHEN TO SAVE (always save when you discover something reusable):
13138
- ` + `- Learned a non-obvious API pattern, tool quirk, or workaround
13139
- ` + `- Discovered repo structure, conventions, or gotchas that future sessions would benefit from
13140
- ` + `- Found external tool usage patterns that weren't documented
13141
- ` + `- Resolved a tricky debugging problem with a non-obvious root cause
13142
- ` + `- Learned team/ownership/contact information not easily found elsewhere
13143
- ` + `DO NOT save: one-off answers, things in public docs, or context only relevant to the current task
13144
-
13145
- ` + `WORKFLOW:
13146
- ` + `1. memory_search first — check if a file already exists to update
13147
- ` + `2. Write/Edit files at ~/opencode-memory/{category}/{filename}.md
13148
- ` + `3. Call this tool to sync all changes
13149
-
13150
- ` + `REPO NOTES: for repository-related memory, use the path structure
13151
- ` + "`repos/{host}/{org}/{repo}.md` — e.g. `repos/github.com/user/project.md`.\n" + `This makes it easy to find later by repo URL fragments.
13152
-
13153
- ` + `CATEGORIES: preferences, repos, technical, people, workflows, snippets, notes
13154
-
13155
- ` + `FRONTMATTER FORMAT (include at top of file):
13156
- ` + `---
13157
- ` + `title: Human-readable title
13158
- ` + `tags: [tag1, tag2]
13159
- ` + `summary: One-line summary
13160
- ` + `created: YYYY-MM-DD
13161
- ` + `updated: YYYY-MM-DD
13162
- ` + `importance: high | medium | low
13163
- ` + `related: [category/file.md]
13164
- ` + "---",
13236
+ description: memorySaveDescription(),
13165
13237
  args: {},
13166
13238
  async execute() {
13167
13239
  return runSave();
@@ -13560,7 +13632,10 @@ var MemoryPlugin = async () => {
13560
13632
  "experimental.session.compacting": guard.compacting
13561
13633
  };
13562
13634
  };
13563
- var src_default = MemoryPlugin;
13635
+ var src_default = {
13636
+ id: "opencode-memory",
13637
+ server: MemoryPlugin
13638
+ };
13564
13639
  export {
13565
13640
  exports_session as sessionTools,
13566
13641
  exports_memory as memoryTools,