@mathew-cf/opencode-memory 0.3.1 → 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/cli.js CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env bun
2
- import { createRequire } from "node:module";
3
2
  var __defProp = Object.defineProperty;
4
3
  var __returnValue = (v) => v;
5
4
  function __exportSetter(name, newValue) {
@@ -14,11 +13,13 @@ var __export = (target, all) => {
14
13
  set: __exportSetter.bind(all, name)
15
14
  });
16
15
  };
17
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
18
16
 
19
17
  // src/cli.ts
20
- import { existsSync } from "node:fs";
21
- import { mkdir, writeFile } from "node:fs/promises";
18
+ import { existsSync, lstatSync, readlinkSync } from "node:fs";
19
+ import { mkdir, symlink, writeFile } from "node:fs/promises";
20
+ import { homedir } from "node:os";
21
+ import { dirname, resolve as resolvePath } from "node:path";
22
+ import { fileURLToPath } from "node:url";
22
23
 
23
24
  // src/constants.ts
24
25
  var CATEGORIES = [
@@ -47,28 +48,61 @@ var STOP_WORDS = new Set([
47
48
  ]);
48
49
 
49
50
  // src/lib/paths.ts
51
+ import { posix, win32 } from "node:path";
50
52
  function resolveHome(env = process.env) {
51
53
  const raw = env.HOME || env.USERPROFILE;
52
54
  if (!raw) {
53
55
  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.");
54
56
  }
55
- return normPath(raw);
57
+ return normalizeDirPath(raw);
56
58
  }
57
59
  function normPath(p) {
58
- return p.replace(/\\/g, "/");
60
+ return posix.normalize(p.replaceAll(win32.sep, posix.sep));
61
+ }
62
+ function normalizeDirPath(p) {
63
+ return posix.join(normPath(p), ".");
64
+ }
65
+ function expandHomePath(p, env = process.env) {
66
+ const normalized = normPath(p);
67
+ if (normalized === "~")
68
+ return resolveHome(env);
69
+ if (normalized.startsWith(`~${posix.sep}`)) {
70
+ return posix.join(resolveHome(env), normalized.slice(2));
71
+ }
72
+ return normalized;
59
73
  }
60
74
  function resolveMemoryDir(env = process.env) {
61
- if (env.MEMORY_DIR && env.MEMORY_DIR.length > 0)
62
- return normPath(env.MEMORY_DIR);
63
- return `${resolveHome(env)}/${DEFAULT_MEMORY_SUBDIR}`;
75
+ if (env.OPENCODE_MEMORY_DIR && env.OPENCODE_MEMORY_DIR.length > 0) {
76
+ return normalizeDirPath(expandHomePath(env.OPENCODE_MEMORY_DIR, env));
77
+ }
78
+ return posix.join(resolveHome(env), DEFAULT_MEMORY_SUBDIR);
79
+ }
80
+ function formatMemoryDirForDisplay(memoryDir, env = process.env) {
81
+ const normalized = normalizeDirPath(memoryDir);
82
+ try {
83
+ const home = resolveHome(env);
84
+ const relativeToHome = posix.relative(home, normalized);
85
+ if (relativeToHome === "")
86
+ return "~";
87
+ if (relativeToHome && !relativeToHome.startsWith("..") && !posix.isAbsolute(relativeToHome)) {
88
+ return posix.join("~", relativeToHome);
89
+ }
90
+ } catch {}
91
+ return normalized;
92
+ }
93
+ function formatMemoryPathForDisplay(memoryDir, relPath, env = process.env) {
94
+ const root = formatMemoryDirForDisplay(memoryDir, env);
95
+ if (!relPath)
96
+ return root;
97
+ return posix.join(root, normPath(relPath));
64
98
  }
65
99
  function ragIndexDir(memoryDir) {
66
- return `${memoryDir}/${RAG_INDEX_SUBDIR}`;
100
+ return posix.join(memoryDir, RAG_INDEX_SUBDIR);
67
101
  }
68
102
 
69
103
  // src/lib/rag.ts
70
- import { createRequire as createRequire2 } from "node:module";
71
- var require2 = createRequire2(import.meta.url);
104
+ import { createRequire } from "node:module";
105
+ var require2 = createRequire(import.meta.url);
72
106
  function resolveRagBinary() {
73
107
  try {
74
108
  return require2.resolve("@mathew-cf/rag-cli/bin/rag.js");
@@ -131,8 +165,8 @@ async function downloadModel() {
131
165
  }
132
166
 
133
167
  // src/lib/ripgrep.ts
134
- import { createRequire as createRequire3 } from "node:module";
135
- var require3 = createRequire3(import.meta.url);
168
+ import { createRequire as createRequire2 } from "node:module";
169
+ var require3 = createRequire2(import.meta.url);
136
170
  function resolveRgBinary() {
137
171
  try {
138
172
  const mod = require3("@vscode/ripgrep");
@@ -179,12 +213,16 @@ __export(exports_memory, {
179
213
  runList: () => runList,
180
214
  runAccess: () => runAccess,
181
215
  parseRagHits: () => parseRagHits,
216
+ memorySearchDescription: () => memorySearchDescription,
217
+ memorySaveDescription: () => memorySaveDescription,
218
+ memoryListDescription: () => memoryListDescription,
219
+ memoryAccessPathDescription: () => memoryAccessPathDescription,
182
220
  list: () => list,
183
221
  buildRgArgs: () => buildRgArgs,
184
222
  access: () => access
185
223
  });
186
224
 
187
- // node_modules/zod/v4/classic/external.js
225
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
188
226
  var exports_external = {};
189
227
  __export(exports_external, {
190
228
  xid: () => xid2,
@@ -414,7 +452,7 @@ __export(exports_external, {
414
452
  $brand: () => $brand
415
453
  });
416
454
 
417
- // node_modules/zod/v4/core/index.js
455
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/index.js
418
456
  var exports_core2 = {};
419
457
  __export(exports_core2, {
420
458
  version: () => version,
@@ -678,7 +716,7 @@ __export(exports_core2, {
678
716
  $ZodAny: () => $ZodAny
679
717
  });
680
718
 
681
- // node_modules/zod/v4/core/core.js
719
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/core.js
682
720
  var NEVER = Object.freeze({
683
721
  status: "aborted"
684
722
  });
@@ -745,7 +783,7 @@ function config(newConfig) {
745
783
  Object.assign(globalConfig, newConfig);
746
784
  return globalConfig;
747
785
  }
748
- // node_modules/zod/v4/core/util.js
786
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/util.js
749
787
  var exports_util = {};
750
788
  __export(exports_util, {
751
789
  unwrapMessage: () => unwrapMessage,
@@ -1374,7 +1412,7 @@ class Class {
1374
1412
  constructor(..._args) {}
1375
1413
  }
1376
1414
 
1377
- // node_modules/zod/v4/core/errors.js
1415
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/errors.js
1378
1416
  var initializer = (inst, def) => {
1379
1417
  inst.name = "$ZodError";
1380
1418
  Object.defineProperty(inst, "_zod", {
@@ -1517,7 +1555,7 @@ function prettifyError(error) {
1517
1555
  `);
1518
1556
  }
1519
1557
 
1520
- // node_modules/zod/v4/core/parse.js
1558
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/parse.js
1521
1559
  var _parse = (_Err) => (schema, value, _ctx, _params) => {
1522
1560
  const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
1523
1561
  const result = schema._zod.run({ value, issues: [] }, ctx);
@@ -1604,7 +1642,7 @@ var _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => {
1604
1642
  return _safeParseAsync(_Err)(schema, value, _ctx);
1605
1643
  };
1606
1644
  var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync($ZodRealError);
1607
- // node_modules/zod/v4/core/regexes.js
1645
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/regexes.js
1608
1646
  var exports_regexes = {};
1609
1647
  __export(exports_regexes, {
1610
1648
  xid: () => xid,
@@ -1756,7 +1794,7 @@ var sha512_hex = /^[0-9a-fA-F]{128}$/;
1756
1794
  var sha512_base64 = /* @__PURE__ */ fixedBase64(86, "==");
1757
1795
  var sha512_base64url = /* @__PURE__ */ fixedBase64url(86);
1758
1796
 
1759
- // node_modules/zod/v4/core/checks.js
1797
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/checks.js
1760
1798
  var $ZodCheck = /* @__PURE__ */ $constructor("$ZodCheck", (inst, def) => {
1761
1799
  var _a;
1762
1800
  inst._zod ?? (inst._zod = {});
@@ -2297,7 +2335,7 @@ var $ZodCheckOverwrite = /* @__PURE__ */ $constructor("$ZodCheckOverwrite", (ins
2297
2335
  };
2298
2336
  });
2299
2337
 
2300
- // node_modules/zod/v4/core/doc.js
2338
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/doc.js
2301
2339
  class Doc {
2302
2340
  constructor(args = []) {
2303
2341
  this.content = [];
@@ -2335,14 +2373,14 @@ class Doc {
2335
2373
  }
2336
2374
  }
2337
2375
 
2338
- // node_modules/zod/v4/core/versions.js
2376
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/versions.js
2339
2377
  var version = {
2340
2378
  major: 4,
2341
2379
  minor: 1,
2342
2380
  patch: 8
2343
2381
  };
2344
2382
 
2345
- // node_modules/zod/v4/core/schemas.js
2383
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/schemas.js
2346
2384
  var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
2347
2385
  var _a;
2348
2386
  inst ?? (inst = {});
@@ -4165,7 +4203,7 @@ function handleRefineResult(result, payload, input, inst) {
4165
4203
  payload.issues.push(issue(_iss));
4166
4204
  }
4167
4205
  }
4168
- // node_modules/zod/v4/locales/index.js
4206
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/index.js
4169
4207
  var exports_locales = {};
4170
4208
  __export(exports_locales, {
4171
4209
  zhTW: () => zh_TW_default,
@@ -4216,7 +4254,7 @@ __export(exports_locales, {
4216
4254
  ar: () => ar_default
4217
4255
  });
4218
4256
 
4219
- // node_modules/zod/v4/locales/ar.js
4257
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ar.js
4220
4258
  var error = () => {
4221
4259
  const Sizable = {
4222
4260
  string: { unit: "حرف", verb: "أن يحوي" },
@@ -4332,7 +4370,7 @@ function ar_default() {
4332
4370
  localeError: error()
4333
4371
  };
4334
4372
  }
4335
- // node_modules/zod/v4/locales/az.js
4373
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/az.js
4336
4374
  var error2 = () => {
4337
4375
  const Sizable = {
4338
4376
  string: { unit: "simvol", verb: "olmalıdır" },
@@ -4447,7 +4485,7 @@ function az_default() {
4447
4485
  localeError: error2()
4448
4486
  };
4449
4487
  }
4450
- // node_modules/zod/v4/locales/be.js
4488
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/be.js
4451
4489
  function getBelarusianPlural(count, one, few, many) {
4452
4490
  const absCount = Math.abs(count);
4453
4491
  const lastDigit = absCount % 10;
@@ -4611,7 +4649,7 @@ function be_default() {
4611
4649
  localeError: error3()
4612
4650
  };
4613
4651
  }
4614
- // node_modules/zod/v4/locales/ca.js
4652
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ca.js
4615
4653
  var error4 = () => {
4616
4654
  const Sizable = {
4617
4655
  string: { unit: "caràcters", verb: "contenir" },
@@ -4728,7 +4766,7 @@ function ca_default() {
4728
4766
  localeError: error4()
4729
4767
  };
4730
4768
  }
4731
- // node_modules/zod/v4/locales/cs.js
4769
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/cs.js
4732
4770
  var error5 = () => {
4733
4771
  const Sizable = {
4734
4772
  string: { unit: "znaků", verb: "mít" },
@@ -4863,7 +4901,7 @@ function cs_default() {
4863
4901
  localeError: error5()
4864
4902
  };
4865
4903
  }
4866
- // node_modules/zod/v4/locales/da.js
4904
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/da.js
4867
4905
  var error6 = () => {
4868
4906
  const Sizable = {
4869
4907
  string: { unit: "tegn", verb: "havde" },
@@ -4994,7 +5032,7 @@ function da_default() {
4994
5032
  localeError: error6()
4995
5033
  };
4996
5034
  }
4997
- // node_modules/zod/v4/locales/de.js
5035
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/de.js
4998
5036
  var error7 = () => {
4999
5037
  const Sizable = {
5000
5038
  string: { unit: "Zeichen", verb: "zu haben" },
@@ -5110,7 +5148,7 @@ function de_default() {
5110
5148
  localeError: error7()
5111
5149
  };
5112
5150
  }
5113
- // node_modules/zod/v4/locales/en.js
5151
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/en.js
5114
5152
  var parsedType = (data) => {
5115
5153
  const t = typeof data;
5116
5154
  switch (t) {
@@ -5227,7 +5265,7 @@ function en_default() {
5227
5265
  localeError: error8()
5228
5266
  };
5229
5267
  }
5230
- // node_modules/zod/v4/locales/eo.js
5268
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/eo.js
5231
5269
  var parsedType2 = (data) => {
5232
5270
  const t = typeof data;
5233
5271
  switch (t) {
@@ -5343,7 +5381,7 @@ function eo_default() {
5343
5381
  localeError: error9()
5344
5382
  };
5345
5383
  }
5346
- // node_modules/zod/v4/locales/es.js
5384
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/es.js
5347
5385
  var error10 = () => {
5348
5386
  const Sizable = {
5349
5387
  string: { unit: "caracteres", verb: "tener" },
@@ -5491,7 +5529,7 @@ function es_default() {
5491
5529
  localeError: error10()
5492
5530
  };
5493
5531
  }
5494
- // node_modules/zod/v4/locales/fa.js
5532
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fa.js
5495
5533
  var error11 = () => {
5496
5534
  const Sizable = {
5497
5535
  string: { unit: "کاراکتر", verb: "داشته باشد" },
@@ -5613,7 +5651,7 @@ function fa_default() {
5613
5651
  localeError: error11()
5614
5652
  };
5615
5653
  }
5616
- // node_modules/zod/v4/locales/fi.js
5654
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fi.js
5617
5655
  var error12 = () => {
5618
5656
  const Sizable = {
5619
5657
  string: { unit: "merkkiä", subject: "merkkijonon" },
@@ -5735,7 +5773,7 @@ function fi_default() {
5735
5773
  localeError: error12()
5736
5774
  };
5737
5775
  }
5738
- // node_modules/zod/v4/locales/fr.js
5776
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fr.js
5739
5777
  var error13 = () => {
5740
5778
  const Sizable = {
5741
5779
  string: { unit: "caractères", verb: "avoir" },
@@ -5851,7 +5889,7 @@ function fr_default() {
5851
5889
  localeError: error13()
5852
5890
  };
5853
5891
  }
5854
- // node_modules/zod/v4/locales/fr-CA.js
5892
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fr-CA.js
5855
5893
  var error14 = () => {
5856
5894
  const Sizable = {
5857
5895
  string: { unit: "caractères", verb: "avoir" },
@@ -5968,7 +6006,7 @@ function fr_CA_default() {
5968
6006
  localeError: error14()
5969
6007
  };
5970
6008
  }
5971
- // node_modules/zod/v4/locales/he.js
6009
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/he.js
5972
6010
  var error15 = () => {
5973
6011
  const Sizable = {
5974
6012
  string: { unit: "אותיות", verb: "לכלול" },
@@ -6084,7 +6122,7 @@ function he_default() {
6084
6122
  localeError: error15()
6085
6123
  };
6086
6124
  }
6087
- // node_modules/zod/v4/locales/hu.js
6125
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/hu.js
6088
6126
  var error16 = () => {
6089
6127
  const Sizable = {
6090
6128
  string: { unit: "karakter", verb: "legyen" },
@@ -6200,7 +6238,7 @@ function hu_default() {
6200
6238
  localeError: error16()
6201
6239
  };
6202
6240
  }
6203
- // node_modules/zod/v4/locales/id.js
6241
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/id.js
6204
6242
  var error17 = () => {
6205
6243
  const Sizable = {
6206
6244
  string: { unit: "karakter", verb: "memiliki" },
@@ -6316,7 +6354,7 @@ function id_default() {
6316
6354
  localeError: error17()
6317
6355
  };
6318
6356
  }
6319
- // node_modules/zod/v4/locales/is.js
6357
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/is.js
6320
6358
  var parsedType3 = (data) => {
6321
6359
  const t = typeof data;
6322
6360
  switch (t) {
@@ -6433,7 +6471,7 @@ function is_default() {
6433
6471
  localeError: error18()
6434
6472
  };
6435
6473
  }
6436
- // node_modules/zod/v4/locales/it.js
6474
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/it.js
6437
6475
  var error19 = () => {
6438
6476
  const Sizable = {
6439
6477
  string: { unit: "caratteri", verb: "avere" },
@@ -6549,7 +6587,7 @@ function it_default() {
6549
6587
  localeError: error19()
6550
6588
  };
6551
6589
  }
6552
- // node_modules/zod/v4/locales/ja.js
6590
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ja.js
6553
6591
  var error20 = () => {
6554
6592
  const Sizable = {
6555
6593
  string: { unit: "文字", verb: "である" },
@@ -6664,7 +6702,7 @@ function ja_default() {
6664
6702
  localeError: error20()
6665
6703
  };
6666
6704
  }
6667
- // node_modules/zod/v4/locales/ka.js
6705
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ka.js
6668
6706
  var parsedType4 = (data) => {
6669
6707
  const t = typeof data;
6670
6708
  switch (t) {
@@ -6789,7 +6827,7 @@ function ka_default() {
6789
6827
  localeError: error21()
6790
6828
  };
6791
6829
  }
6792
- // node_modules/zod/v4/locales/km.js
6830
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/km.js
6793
6831
  var error22 = () => {
6794
6832
  const Sizable = {
6795
6833
  string: { unit: "តួអក្សរ", verb: "គួរមាន" },
@@ -6907,11 +6945,11 @@ function km_default() {
6907
6945
  };
6908
6946
  }
6909
6947
 
6910
- // node_modules/zod/v4/locales/kh.js
6948
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/kh.js
6911
6949
  function kh_default() {
6912
6950
  return km_default();
6913
6951
  }
6914
- // node_modules/zod/v4/locales/ko.js
6952
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ko.js
6915
6953
  var error23 = () => {
6916
6954
  const Sizable = {
6917
6955
  string: { unit: "문자", verb: "to have" },
@@ -7032,7 +7070,7 @@ function ko_default() {
7032
7070
  localeError: error23()
7033
7071
  };
7034
7072
  }
7035
- // node_modules/zod/v4/locales/lt.js
7073
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/lt.js
7036
7074
  var parsedType5 = (data) => {
7037
7075
  const t = typeof data;
7038
7076
  return parsedTypeFromType(t, data);
@@ -7261,7 +7299,7 @@ function lt_default() {
7261
7299
  localeError: error24()
7262
7300
  };
7263
7301
  }
7264
- // node_modules/zod/v4/locales/mk.js
7302
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/mk.js
7265
7303
  var error25 = () => {
7266
7304
  const Sizable = {
7267
7305
  string: { unit: "знаци", verb: "да имаат" },
@@ -7378,7 +7416,7 @@ function mk_default() {
7378
7416
  localeError: error25()
7379
7417
  };
7380
7418
  }
7381
- // node_modules/zod/v4/locales/ms.js
7419
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ms.js
7382
7420
  var error26 = () => {
7383
7421
  const Sizable = {
7384
7422
  string: { unit: "aksara", verb: "mempunyai" },
@@ -7494,7 +7532,7 @@ function ms_default() {
7494
7532
  localeError: error26()
7495
7533
  };
7496
7534
  }
7497
- // node_modules/zod/v4/locales/nl.js
7535
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/nl.js
7498
7536
  var error27 = () => {
7499
7537
  const Sizable = {
7500
7538
  string: { unit: "tekens" },
@@ -7611,7 +7649,7 @@ function nl_default() {
7611
7649
  localeError: error27()
7612
7650
  };
7613
7651
  }
7614
- // node_modules/zod/v4/locales/no.js
7652
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/no.js
7615
7653
  var error28 = () => {
7616
7654
  const Sizable = {
7617
7655
  string: { unit: "tegn", verb: "å ha" },
@@ -7727,7 +7765,7 @@ function no_default() {
7727
7765
  localeError: error28()
7728
7766
  };
7729
7767
  }
7730
- // node_modules/zod/v4/locales/ota.js
7768
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ota.js
7731
7769
  var error29 = () => {
7732
7770
  const Sizable = {
7733
7771
  string: { unit: "harf", verb: "olmalıdır" },
@@ -7843,7 +7881,7 @@ function ota_default() {
7843
7881
  localeError: error29()
7844
7882
  };
7845
7883
  }
7846
- // node_modules/zod/v4/locales/ps.js
7884
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ps.js
7847
7885
  var error30 = () => {
7848
7886
  const Sizable = {
7849
7887
  string: { unit: "توکي", verb: "ولري" },
@@ -7965,7 +8003,7 @@ function ps_default() {
7965
8003
  localeError: error30()
7966
8004
  };
7967
8005
  }
7968
- // node_modules/zod/v4/locales/pl.js
8006
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/pl.js
7969
8007
  var error31 = () => {
7970
8008
  const Sizable = {
7971
8009
  string: { unit: "znaków", verb: "mieć" },
@@ -8082,7 +8120,7 @@ function pl_default() {
8082
8120
  localeError: error31()
8083
8121
  };
8084
8122
  }
8085
- // node_modules/zod/v4/locales/pt.js
8123
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/pt.js
8086
8124
  var error32 = () => {
8087
8125
  const Sizable = {
8088
8126
  string: { unit: "caracteres", verb: "ter" },
@@ -8198,7 +8236,7 @@ function pt_default() {
8198
8236
  localeError: error32()
8199
8237
  };
8200
8238
  }
8201
- // node_modules/zod/v4/locales/ru.js
8239
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ru.js
8202
8240
  function getRussianPlural(count, one, few, many) {
8203
8241
  const absCount = Math.abs(count);
8204
8242
  const lastDigit = absCount % 10;
@@ -8362,7 +8400,7 @@ function ru_default() {
8362
8400
  localeError: error33()
8363
8401
  };
8364
8402
  }
8365
- // node_modules/zod/v4/locales/sl.js
8403
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/sl.js
8366
8404
  var error34 = () => {
8367
8405
  const Sizable = {
8368
8406
  string: { unit: "znakov", verb: "imeti" },
@@ -8479,7 +8517,7 @@ function sl_default() {
8479
8517
  localeError: error34()
8480
8518
  };
8481
8519
  }
8482
- // node_modules/zod/v4/locales/sv.js
8520
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/sv.js
8483
8521
  var error35 = () => {
8484
8522
  const Sizable = {
8485
8523
  string: { unit: "tecken", verb: "att ha" },
@@ -8597,7 +8635,7 @@ function sv_default() {
8597
8635
  localeError: error35()
8598
8636
  };
8599
8637
  }
8600
- // node_modules/zod/v4/locales/ta.js
8638
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ta.js
8601
8639
  var error36 = () => {
8602
8640
  const Sizable = {
8603
8641
  string: { unit: "எழுத்துக்கள்", verb: "கொண்டிருக்க வேண்டும்" },
@@ -8714,7 +8752,7 @@ function ta_default() {
8714
8752
  localeError: error36()
8715
8753
  };
8716
8754
  }
8717
- // node_modules/zod/v4/locales/th.js
8755
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/th.js
8718
8756
  var error37 = () => {
8719
8757
  const Sizable = {
8720
8758
  string: { unit: "ตัวอักษร", verb: "ควรมี" },
@@ -8831,7 +8869,7 @@ function th_default() {
8831
8869
  localeError: error37()
8832
8870
  };
8833
8871
  }
8834
- // node_modules/zod/v4/locales/tr.js
8872
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/tr.js
8835
8873
  var parsedType6 = (data) => {
8836
8874
  const t = typeof data;
8837
8875
  switch (t) {
@@ -8946,7 +8984,7 @@ function tr_default() {
8946
8984
  localeError: error38()
8947
8985
  };
8948
8986
  }
8949
- // node_modules/zod/v4/locales/uk.js
8987
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/uk.js
8950
8988
  var error39 = () => {
8951
8989
  const Sizable = {
8952
8990
  string: { unit: "символів", verb: "матиме" },
@@ -9063,11 +9101,11 @@ function uk_default() {
9063
9101
  };
9064
9102
  }
9065
9103
 
9066
- // node_modules/zod/v4/locales/ua.js
9104
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ua.js
9067
9105
  function ua_default() {
9068
9106
  return uk_default();
9069
9107
  }
9070
- // node_modules/zod/v4/locales/ur.js
9108
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ur.js
9071
9109
  var error40 = () => {
9072
9110
  const Sizable = {
9073
9111
  string: { unit: "حروف", verb: "ہونا" },
@@ -9184,7 +9222,7 @@ function ur_default() {
9184
9222
  localeError: error40()
9185
9223
  };
9186
9224
  }
9187
- // node_modules/zod/v4/locales/vi.js
9225
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/vi.js
9188
9226
  var error41 = () => {
9189
9227
  const Sizable = {
9190
9228
  string: { unit: "ký tự", verb: "có" },
@@ -9300,7 +9338,7 @@ function vi_default() {
9300
9338
  localeError: error41()
9301
9339
  };
9302
9340
  }
9303
- // node_modules/zod/v4/locales/zh-CN.js
9341
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/zh-CN.js
9304
9342
  var error42 = () => {
9305
9343
  const Sizable = {
9306
9344
  string: { unit: "字符", verb: "包含" },
@@ -9416,7 +9454,7 @@ function zh_CN_default() {
9416
9454
  localeError: error42()
9417
9455
  };
9418
9456
  }
9419
- // node_modules/zod/v4/locales/zh-TW.js
9457
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/zh-TW.js
9420
9458
  var error43 = () => {
9421
9459
  const Sizable = {
9422
9460
  string: { unit: "字元", verb: "擁有" },
@@ -9533,7 +9571,7 @@ function zh_TW_default() {
9533
9571
  localeError: error43()
9534
9572
  };
9535
9573
  }
9536
- // node_modules/zod/v4/locales/yo.js
9574
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/yo.js
9537
9575
  var error44 = () => {
9538
9576
  const Sizable = {
9539
9577
  string: { unit: "àmi", verb: "ní" },
@@ -9648,7 +9686,7 @@ function yo_default() {
9648
9686
  localeError: error44()
9649
9687
  };
9650
9688
  }
9651
- // node_modules/zod/v4/core/registries.js
9689
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/registries.js
9652
9690
  var $output = Symbol("ZodOutput");
9653
9691
  var $input = Symbol("ZodInput");
9654
9692
 
@@ -9699,7 +9737,7 @@ function registry() {
9699
9737
  return new $ZodRegistry;
9700
9738
  }
9701
9739
  var globalRegistry = /* @__PURE__ */ registry();
9702
- // node_modules/zod/v4/core/api.js
9740
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/api.js
9703
9741
  function _string(Class2, params) {
9704
9742
  return new Class2({
9705
9743
  type: "string",
@@ -10577,7 +10615,7 @@ function _stringFormat(Class2, format, fnOrRegex, _params = {}) {
10577
10615
  const inst = new Class2(def);
10578
10616
  return inst;
10579
10617
  }
10580
- // node_modules/zod/v4/core/to-json-schema.js
10618
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/to-json-schema.js
10581
10619
  class JSONSchemaGenerator {
10582
10620
  constructor(params) {
10583
10621
  this.counter = 0;
@@ -10915,7 +10953,7 @@ class JSONSchemaGenerator {
10915
10953
  if (val === undefined) {
10916
10954
  if (this.unrepresentable === "throw") {
10917
10955
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
10918
- } else {}
10956
+ }
10919
10957
  } else if (typeof val === "bigint") {
10920
10958
  if (this.unrepresentable === "throw") {
10921
10959
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -11381,9 +11419,9 @@ function isTransforming(_schema, _ctx) {
11381
11419
  }
11382
11420
  throw new Error(`Unknown schema type: ${def.type}`);
11383
11421
  }
11384
- // node_modules/zod/v4/core/json-schema.js
11422
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/json-schema.js
11385
11423
  var exports_json_schema = {};
11386
- // node_modules/zod/v4/classic/iso.js
11424
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/iso.js
11387
11425
  var exports_iso = {};
11388
11426
  __export(exports_iso, {
11389
11427
  time: () => time2,
@@ -11424,7 +11462,7 @@ function duration2(params) {
11424
11462
  return _isoDuration(ZodISODuration, params);
11425
11463
  }
11426
11464
 
11427
- // node_modules/zod/v4/classic/errors.js
11465
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/errors.js
11428
11466
  var initializer2 = (inst, issues) => {
11429
11467
  $ZodError.init(inst, issues);
11430
11468
  inst.name = "ZodError";
@@ -11459,7 +11497,7 @@ var ZodRealError = $constructor("ZodError", initializer2, {
11459
11497
  Parent: Error
11460
11498
  });
11461
11499
 
11462
- // node_modules/zod/v4/classic/parse.js
11500
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/parse.js
11463
11501
  var parse3 = /* @__PURE__ */ _parse(ZodRealError);
11464
11502
  var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
11465
11503
  var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
@@ -11473,7 +11511,7 @@ var safeDecode2 = /* @__PURE__ */ _safeDecode(ZodRealError);
11473
11511
  var safeEncodeAsync2 = /* @__PURE__ */ _safeEncodeAsync(ZodRealError);
11474
11512
  var safeDecodeAsync2 = /* @__PURE__ */ _safeDecodeAsync(ZodRealError);
11475
11513
 
11476
- // node_modules/zod/v4/classic/schemas.js
11514
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/schemas.js
11477
11515
  var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
11478
11516
  $ZodType.init(inst, def);
11479
11517
  inst.def = def;
@@ -12448,7 +12486,7 @@ function json(params) {
12448
12486
  function preprocess(fn, schema) {
12449
12487
  return pipe(transform(fn), schema);
12450
12488
  }
12451
- // node_modules/zod/v4/classic/compat.js
12489
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/compat.js
12452
12490
  var ZodIssueCode = {
12453
12491
  invalid_type: "invalid_type",
12454
12492
  too_big: "too_big",
@@ -12472,7 +12510,7 @@ function getErrorMap() {
12472
12510
  }
12473
12511
  var ZodFirstPartyTypeKind;
12474
12512
  (function(ZodFirstPartyTypeKind2) {})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
12475
- // node_modules/zod/v4/classic/coerce.js
12513
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/coerce.js
12476
12514
  var exports_coerce = {};
12477
12515
  __export(exports_coerce, {
12478
12516
  string: () => string3,
@@ -12497,13 +12535,16 @@ function date4(params) {
12497
12535
  return _coercedDate(ZodDate, params);
12498
12536
  }
12499
12537
 
12500
- // node_modules/zod/v4/classic/external.js
12538
+ // node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
12501
12539
  config(en_default());
12502
12540
  // node_modules/@opencode-ai/plugin/dist/tool.js
12503
12541
  function tool(input) {
12504
12542
  return input;
12505
12543
  }
12506
12544
  tool.schema = exports_external;
12545
+ // src/tools/memory.ts
12546
+ import { posix as posix2 } from "node:path";
12547
+
12507
12548
  // src/lib/frontmatter.ts
12508
12549
  var FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
12509
12550
  function parseFrontmatter(content) {
@@ -12623,17 +12664,7 @@ function scoreCandidate(input) {
12623
12664
 
12624
12665
  // src/tools/memory.ts
12625
12666
  function buildRgArgs(terms) {
12626
- const args = [
12627
- "-il",
12628
- "--glob",
12629
- "*.md",
12630
- "--glob",
12631
- "!.git",
12632
- "--glob",
12633
- "!.rag",
12634
- "--glob",
12635
- "!**/INDEX.md"
12636
- ];
12667
+ const args = ["-il", "--glob", "*.md", "--glob", "!.git", "--glob", "!.rag", "--glob", "!**/INDEX.md"];
12637
12668
  for (const term of terms) {
12638
12669
  args.push("-e", term);
12639
12670
  }
@@ -12652,10 +12683,26 @@ function parseRagHits(ragText) {
12652
12683
  }
12653
12684
  }
12654
12685
  function toRelPath(memoryDir, absPath) {
12655
- return normPath(absPath).replace(`${memoryDir}/`, "");
12686
+ return posix2.relative(memoryDir, normPath(absPath));
12656
12687
  }
12657
- var search = tool({
12658
- 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.
12688
+ function configuredMemoryDirLabel(memoryDir) {
12689
+ try {
12690
+ return formatMemoryDirForDisplay(memoryDir ?? resolveMemoryDir());
12691
+ } catch {
12692
+ return "the configured memory directory";
12693
+ }
12694
+ }
12695
+ function configuredMemoryPathLabel(relPath, memoryDir) {
12696
+ try {
12697
+ return formatMemoryPathForDisplay(memoryDir ?? resolveMemoryDir(), relPath);
12698
+ } catch {
12699
+ return `the configured memory directory/${relPath}`;
12700
+ }
12701
+ }
12702
+ function memorySearchDescription(memoryDir) {
12703
+ const memoryRoot = configuredMemoryDirLabel(memoryDir);
12704
+ const memoryPath = configuredMemoryPathLabel("{path}", memoryDir);
12705
+ 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.
12659
12706
 
12660
12707
  ` + "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.
12661
12708
 
@@ -12668,9 +12715,53 @@ var search = tool({
12668
12715
  ` + `- Before writing new memory — check if a file already exists to update instead of duplicate
12669
12716
 
12670
12717
  ` + `FOLLOW-UP SEARCHES (do when results seem incomplete):
12671
- ` + `- Results include Related: files — use the Read tool on ~/opencode-memory/{path} for connected knowledge
12718
+ ` + `- Results include Related: files — use the Read tool on ${memoryPath} for connected knowledge
12672
12719
  ` + `- If few/no results, try broader terms or search without the category filter
12673
- ` + "- Check the 'Related files' section at the bottom of results for cross-references worth exploring",
12720
+ ` + "- Check the 'Related files' section at the bottom of results for cross-references worth exploring";
12721
+ }
12722
+ function memoryListDescription(memoryDir) {
12723
+ const memoryRoot = configuredMemoryDirLabel(memoryDir);
12724
+ 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.";
12725
+ }
12726
+ function memoryAccessPathDescription(memoryDir) {
12727
+ const memoryRoot = configuredMemoryDirLabel(memoryDir);
12728
+ return `Relative path within ${memoryRoot} (e.g. 'technical/build-tooling.md')`;
12729
+ }
12730
+ function memorySaveDescription(memoryDir) {
12731
+ const memoryPath = configuredMemoryPathLabel("{category}/{filename}.md", memoryDir);
12732
+ 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.
12733
+
12734
+ ` + `WHEN TO SAVE (always save when you discover something reusable):
12735
+ ` + `- Learned a non-obvious API pattern, tool quirk, or workaround
12736
+ ` + `- Discovered repo structure, conventions, or gotchas that future sessions would benefit from
12737
+ ` + `- Found external tool usage patterns that weren't documented
12738
+ ` + `- Resolved a tricky debugging problem with a non-obvious root cause
12739
+ ` + `- Learned team/ownership/contact information not easily found elsewhere
12740
+ ` + `DO NOT save: one-off answers, things in public docs, or context only relevant to the current task
12741
+
12742
+ ` + `WORKFLOW:
12743
+ ` + `1. memory_search first — check if a file already exists to update
12744
+ ` + `2. Write/Edit files at ${memoryPath}
12745
+ ` + `3. Call this tool to sync all changes
12746
+
12747
+ ` + `REPO NOTES: for repository-related memory, use the path structure
12748
+ ` + "`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.
12749
+
12750
+ ` + `CATEGORIES: preferences, repos, technical, people, workflows, snippets, notes
12751
+
12752
+ ` + `FRONTMATTER FORMAT (include at top of file):
12753
+ ` + `---
12754
+ ` + `title: Human-readable title
12755
+ ` + `tags: [tag1, tag2]
12756
+ ` + `summary: One-line summary
12757
+ ` + `created: YYYY-MM-DD
12758
+ ` + `updated: YYYY-MM-DD
12759
+ ` + `importance: high | medium | low
12760
+ ` + `related: [category/file.md]
12761
+ ` + "---";
12762
+ }
12763
+ var search = tool({
12764
+ description: memorySearchDescription(),
12674
12765
  args: {
12675
12766
  query: tool.schema.string().describe("Search terms or natural language query"),
12676
12767
  category: tool.schema.string().optional().describe("Filter to a specific category: preferences, repos, technical, people, workflows, snippets, notes")
@@ -12683,7 +12774,7 @@ async function runSearch(input) {
12683
12774
  const { query, category } = input;
12684
12775
  const memoryDir = resolveMemoryDir();
12685
12776
  const indexDir = ragIndexDir(memoryDir);
12686
- const searchDir = category ? `${memoryDir}/${category}` : memoryDir;
12777
+ const searchDir = category ? posix2.join(memoryDir, category) : memoryDir;
12687
12778
  const terms = parseSearchTerms(query);
12688
12779
  const rgTerms = terms.length > 0 ? terms : [query];
12689
12780
  const hasRag = ragAvailable();
@@ -12741,7 +12832,7 @@ async function runSearch(input) {
12741
12832
  }
12742
12833
  }
12743
12834
  if (resultMap.size === 0) {
12744
- const scanDir = category ? `${memoryDir}/${category}` : memoryDir;
12835
+ const scanDir = category ? posix2.join(memoryDir, category) : memoryDir;
12745
12836
  const suggestions = [];
12746
12837
  try {
12747
12838
  const fnGlob = new Bun.Glob("**/*.md");
@@ -12758,7 +12849,7 @@ async function runSearch(input) {
12758
12849
  return `No content matches for: "${query}"
12759
12850
 
12760
12851
  ` + `Files with matching names:
12761
- ${suggestions.slice(0, 5).map((s) => ` - ~/opencode-memory/${s}`).join(`
12852
+ ${suggestions.slice(0, 5).map((s) => ` - ${formatMemoryPathForDisplay(memoryDir, s)}`).join(`
12762
12853
  `)}
12763
12854
 
12764
12855
  ` + `Use the Read tool to check these.`;
@@ -12768,7 +12859,7 @@ ${suggestions.slice(0, 5).map((s) => ` - ~/opencode-memory/${s}`).join(`
12768
12859
  const results = [];
12769
12860
  for (const [path, info] of resultMap) {
12770
12861
  try {
12771
- const content = await Bun.file(`${memoryDir}/${path}`).text();
12862
+ const content = await Bun.file(posix2.join(memoryDir, path)).text();
12772
12863
  const { meta } = parseFrontmatter(content);
12773
12864
  const termMatches = terms.length > 0 ? countTermMatches(content, terms) : info.rgMatch ? 1 : 0;
12774
12865
  const score = scoreCandidate({
@@ -12829,7 +12920,7 @@ ${suggestions.slice(0, 5).map((s) => ` - ~/opencode-memory/${s}`).join(`
12829
12920
  lines.push("");
12830
12921
  }
12831
12922
  if (topResults.length > 0) {
12832
- lines.push(`_Read the top result: \`~/opencode-memory/${topResults[0].path}\`_`);
12923
+ lines.push(`_Read the top result: \`${formatMemoryPathForDisplay(memoryDir, topResults[0].path)}\`_`);
12833
12924
  lines.push("");
12834
12925
  }
12835
12926
  const shownPaths = new Set(topResults.slice(0, 7).map((r) => r.path));
@@ -12844,13 +12935,13 @@ ${suggestions.slice(0, 5).map((s) => ` - ~/opencode-memory/${s}`).join(`
12844
12935
  const verified = [];
12845
12936
  for (const rel of relatedSuggestions) {
12846
12937
  try {
12847
- if (await Bun.file(`${memoryDir}/${rel}`).exists())
12938
+ if (await Bun.file(posix2.join(memoryDir, rel)).exists())
12848
12939
  verified.push(rel);
12849
12940
  } catch {}
12850
12941
  }
12851
12942
  if (verified.length > 0) {
12852
12943
  lines.push("---");
12853
- lines.push("**Related files** (not in results — use the Read tool on ~/opencode-memory/{path}):");
12944
+ lines.push(`**Related files** (not in results — use the Read tool on ${formatMemoryPathForDisplay(memoryDir, "{path}")}):`);
12854
12945
  for (const rel of verified) {
12855
12946
  lines.push(` - ${rel}`);
12856
12947
  }
@@ -12860,7 +12951,7 @@ ${suggestions.slice(0, 5).map((s) => ` - ~/opencode-memory/${s}`).join(`
12860
12951
  `);
12861
12952
  }
12862
12953
  var list = tool({
12863
- 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.",
12954
+ description: memoryListDescription(),
12864
12955
  args: {
12865
12956
  category: tool.schema.string().optional().describe("Category to list: preferences, repos, technical, people, workflows, snippets, notes")
12866
12957
  },
@@ -12879,7 +12970,7 @@ async function runList(input) {
12879
12970
  let count = 0;
12880
12971
  try {
12881
12972
  for await (const _ of glob2.scan({
12882
- cwd: `${memoryDir}/${cat}`,
12973
+ cwd: posix2.join(memoryDir, cat),
12883
12974
  dot: false
12884
12975
  })) {
12885
12976
  count++;
@@ -12890,13 +12981,13 @@ async function runList(input) {
12890
12981
  return lines2.join(`
12891
12982
  `);
12892
12983
  }
12893
- const catDir = `${memoryDir}/${category}`;
12984
+ const catDir = posix2.join(memoryDir, category);
12894
12985
  const glob = new Bun.Glob("**/*.md");
12895
12986
  const files = [];
12896
12987
  try {
12897
12988
  for await (const f of glob.scan({ cwd: catDir, dot: false })) {
12898
12989
  try {
12899
- const content = await Bun.file(`${catDir}/${f}`).text();
12990
+ const content = await Bun.file(posix2.join(catDir, f)).text();
12900
12991
  const { meta } = parseFrontmatter(content);
12901
12992
  files.push({
12902
12993
  path: `${category}/${f}`,
@@ -12929,7 +13020,7 @@ var access = tool({
12929
13020
 
12930
13021
  ` + "This helps the memory system track which memories are actively useful vs. stale.",
12931
13022
  args: {
12932
- path: tool.schema.string().describe("Relative path within ~/opencode-memory/ (e.g. 'technical/build-tooling.md')")
13023
+ path: tool.schema.string().describe(memoryAccessPathDescription())
12933
13024
  },
12934
13025
  async execute({ path }) {
12935
13026
  return runAccess({ path });
@@ -12938,7 +13029,7 @@ var access = tool({
12938
13029
  async function runAccess(input) {
12939
13030
  const memoryDir = resolveMemoryDir();
12940
13031
  const { path } = input;
12941
- const filePath = `${memoryDir}/${path}`;
13032
+ const filePath = posix2.join(memoryDir, path);
12942
13033
  try {
12943
13034
  const content = await Bun.file(filePath).text();
12944
13035
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
@@ -12958,36 +13049,7 @@ ${body}`);
12958
13049
  }
12959
13050
  }
12960
13051
  var save = tool({
12961
- 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.
12962
-
12963
- ` + `WHEN TO SAVE (always save when you discover something reusable):
12964
- ` + `- Learned a non-obvious API pattern, tool quirk, or workaround
12965
- ` + `- Discovered repo structure, conventions, or gotchas that future sessions would benefit from
12966
- ` + `- Found external tool usage patterns that weren't documented
12967
- ` + `- Resolved a tricky debugging problem with a non-obvious root cause
12968
- ` + `- Learned team/ownership/contact information not easily found elsewhere
12969
- ` + `DO NOT save: one-off answers, things in public docs, or context only relevant to the current task
12970
-
12971
- ` + `WORKFLOW:
12972
- ` + `1. memory_search first — check if a file already exists to update
12973
- ` + `2. Write/Edit files at ~/opencode-memory/{category}/{filename}.md
12974
- ` + `3. Call this tool to sync all changes
12975
-
12976
- ` + `REPO NOTES: for repository-related memory, use the path structure
12977
- ` + "`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.
12978
-
12979
- ` + `CATEGORIES: preferences, repos, technical, people, workflows, snippets, notes
12980
-
12981
- ` + `FRONTMATTER FORMAT (include at top of file):
12982
- ` + `---
12983
- ` + `title: Human-readable title
12984
- ` + `tags: [tag1, tag2]
12985
- ` + `summary: One-line summary
12986
- ` + `created: YYYY-MM-DD
12987
- ` + `updated: YYYY-MM-DD
12988
- ` + `importance: high | medium | low
12989
- ` + `related: [category/file.md]
12990
- ` + "---",
13052
+ description: memorySaveDescription(),
12991
13053
  args: {},
12992
13054
  async execute() {
12993
13055
  return runSave();
@@ -13047,13 +13109,62 @@ async function runSetup() {
13047
13109
  }
13048
13110
 
13049
13111
  // src/cli.ts
13112
+ var __dirname = "/home/runner/work/opencode-memory/opencode-memory/src";
13113
+ function resolveBundledSkillsDir() {
13114
+ try {
13115
+ const here = typeof import.meta !== "undefined" && import.meta.url ? dirname(fileURLToPath(import.meta.url)) : typeof __dirname !== "undefined" ? __dirname : undefined;
13116
+ if (!here)
13117
+ return;
13118
+ const candidate = resolvePath(here, "..", "skills");
13119
+ return existsSync(candidate) ? candidate : undefined;
13120
+ } catch {
13121
+ return;
13122
+ }
13123
+ }
13124
+ async function installSkill(options) {
13125
+ const linkDir = options.linkDir ?? `${homedir()}/.agents/skills`;
13126
+ const linkPath = `${linkDir}/opencode-memory`;
13127
+ if (!options.bundledSkillsDir) {
13128
+ return {
13129
+ status: "unavailable",
13130
+ linkPath,
13131
+ targetPath: ""
13132
+ };
13133
+ }
13134
+ const targetPath = `${options.bundledSkillsDir}/opencode-memory`;
13135
+ if (!existsSync(targetPath)) {
13136
+ return { status: "unavailable", linkPath, targetPath };
13137
+ }
13138
+ await mkdir(linkDir, { recursive: true });
13139
+ let existing;
13140
+ try {
13141
+ existing = lstatSync(linkPath);
13142
+ } catch {
13143
+ existing = undefined;
13144
+ }
13145
+ if (existing) {
13146
+ if (existing.isSymbolicLink()) {
13147
+ try {
13148
+ const current = readlinkSync(linkPath);
13149
+ const resolved = resolvePath(linkDir, current);
13150
+ if (resolved === targetPath) {
13151
+ return { status: "already-installed", linkPath, targetPath };
13152
+ }
13153
+ } catch {}
13154
+ }
13155
+ return { status: "skipped-existing", linkPath, targetPath };
13156
+ }
13157
+ await symlink(targetPath, linkPath);
13158
+ return { status: "created", linkPath, targetPath };
13159
+ }
13050
13160
  async function initMemory(memoryDir, options = {}, log = (msg) => process.stdout.write(msg + `
13051
13161
  `)) {
13052
13162
  const result = {
13053
13163
  memoryDir,
13054
13164
  gitInitialized: false,
13055
13165
  createdCategories: [],
13056
- modelDownloadAttempted: false
13166
+ modelDownloadAttempted: false,
13167
+ skillInstall: null
13057
13168
  };
13058
13169
  const note = options.quiet ? () => {} : log;
13059
13170
  note(`Memory dir: ${memoryDir}`);
@@ -13089,6 +13200,29 @@ async function initMemory(memoryDir, options = {}, log = (msg) => process.stdout
13089
13200
  result.modelDownloadOutput = out;
13090
13201
  note(out);
13091
13202
  }
13203
+ if (!options.skipSkills) {
13204
+ note("");
13205
+ const install = await installSkill({
13206
+ bundledSkillsDir: resolveBundledSkillsDir(),
13207
+ linkDir: options.skillLinkDir
13208
+ });
13209
+ result.skillInstall = install;
13210
+ switch (install.status) {
13211
+ case "created":
13212
+ note(`✓ skill installed: ${install.linkPath} → ${install.targetPath}`);
13213
+ note(" Zed (~/.agents/skills) and Pi (~/.agents/skills, ~/.pi/agent/skills) auto-discover this path on next launch.");
13214
+ break;
13215
+ case "already-installed":
13216
+ note(`✓ skill already installed at ${install.linkPath}`);
13217
+ break;
13218
+ case "skipped-existing":
13219
+ note(`⚠ ${install.linkPath} already exists (not our symlink) — left untouched`);
13220
+ break;
13221
+ case "unavailable":
13222
+ note("⚠ bundled skill directory not resolvable — skill install skipped (unusual; check package layout)");
13223
+ break;
13224
+ }
13225
+ }
13092
13226
  return result;
13093
13227
  }
13094
13228
  function usage() {
@@ -13096,17 +13230,25 @@ function usage() {
13096
13230
  "Usage: opencode-memory <command>",
13097
13231
  "",
13098
13232
  "Commands:",
13099
- " init [--skip-model] [--quiet]",
13100
- " Initialize the memory directory ($MEMORY_DIR or",
13101
- " ~/opencode-memory): mkdir, git init, create category",
13102
- " subdirs, pre-cache the embedding model. Idempotent.",
13233
+ " init [--skip-model] [--skip-skills] [--quiet]",
13234
+ " Initialize the memory directory ($OPENCODE_MEMORY_DIR or",
13235
+ ` ~/${DEFAULT_MEMORY_SUBDIR} by default): mkdir, git init, create category`,
13236
+ " subdirs, pre-cache the embedding model, install the",
13237
+ " bundled skill into ~/.agents/skills/ (used by Zed and",
13238
+ " Pi). Idempotent.",
13103
13239
  "",
13104
13240
  " status",
13105
13241
  " Report which search backends (ripgrep, rag-cli) are",
13106
13242
  " resolvable. Same output as the memory_setup tool.",
13107
13243
  "",
13108
13244
  " help",
13109
- " Show this message."
13245
+ " Show this message.",
13246
+ "",
13247
+ "MCP server (for Zed / Pi / Claude Code / any MCP host):",
13248
+ " bunx @mathew-cf/opencode-memory opencode-memory-mcp",
13249
+ "",
13250
+ " Speaks MCP over stdio. Exposes the five memory_* tools.",
13251
+ " Wire it into your host's MCP config (see README)."
13110
13252
  ].join(`
13111
13253
  `);
13112
13254
  }
@@ -13115,27 +13257,32 @@ function parseInitFlags(argv) {
13115
13257
  for (const arg of argv) {
13116
13258
  if (arg === "--skip-model" || arg === "-s")
13117
13259
  opts.skipModel = true;
13260
+ else if (arg === "--skip-skills")
13261
+ opts.skipSkills = true;
13118
13262
  else if (arg === "--quiet" || arg === "-q")
13119
13263
  opts.quiet = true;
13120
13264
  }
13121
13265
  return opts;
13122
13266
  }
13123
- async function dispatch(argv) {
13267
+ async function dispatch(argv, io = {}) {
13268
+ const out = io.out ?? ((chunk) => void process.stdout.write(chunk));
13269
+ const err = io.err ?? ((chunk) => void process.stderr.write(chunk));
13124
13270
  const cmd = argv[0];
13125
13271
  switch (cmd) {
13126
13272
  case "init": {
13127
13273
  const opts = parseInitFlags(argv.slice(1));
13128
13274
  try {
13129
- await initMemory(resolveMemoryDir(), opts);
13275
+ await initMemory(resolveMemoryDir(), opts, (msg) => out(msg + `
13276
+ `));
13130
13277
  return 0;
13131
- } catch (err) {
13132
- process.stderr.write(`opencode-memory init failed: ${String(err)}
13278
+ } catch (e) {
13279
+ err(`opencode-memory init failed: ${String(e)}
13133
13280
  `);
13134
13281
  return 1;
13135
13282
  }
13136
13283
  }
13137
13284
  case "status": {
13138
- process.stdout.write(await runSetup() + `
13285
+ out(await runSetup() + `
13139
13286
  `);
13140
13287
  const ok = resolveRagBinary() !== null && resolveRgBinary() !== null;
13141
13288
  return ok ? 0 : 1;
@@ -13144,15 +13291,15 @@ async function dispatch(argv) {
13144
13291
  case "help":
13145
13292
  case "--help":
13146
13293
  case "-h": {
13147
- process.stdout.write(usage() + `
13294
+ out(usage() + `
13148
13295
  `);
13149
13296
  return 0;
13150
13297
  }
13151
13298
  default: {
13152
- process.stderr.write(`Unknown command: ${cmd}
13299
+ err(`Unknown command: ${cmd}
13153
13300
 
13154
13301
  `);
13155
- process.stdout.write(usage() + `
13302
+ out(usage() + `
13156
13303
  `);
13157
13304
  return 1;
13158
13305
  }
@@ -13160,7 +13307,10 @@ async function dispatch(argv) {
13160
13307
  }
13161
13308
  var isDirect = (() => {
13162
13309
  try {
13163
- return __require.main == __require.module === true || typeof process.argv[1] === "string" && (process.argv[1].endsWith("/cli.js") || process.argv[1].endsWith("\\cli.js") || process.argv[1].endsWith("/opencode-memory") || process.argv[1].endsWith("\\opencode-memory"));
13310
+ const arg = process.argv[1];
13311
+ if (typeof arg !== "string" || arg.length === 0)
13312
+ return false;
13313
+ return arg.endsWith("/cli.js") || arg.endsWith("\\cli.js") || arg.endsWith("/cli.ts") || arg.endsWith("\\cli.ts") || arg.endsWith("/opencode-memory") || arg.endsWith("\\opencode-memory");
13164
13314
  } catch {
13165
13315
  return false;
13166
13316
  }
@@ -13174,7 +13324,9 @@ if (isDirect) {
13174
13324
  }
13175
13325
  export {
13176
13326
  usage,
13327
+ resolveBundledSkillsDir,
13177
13328
  parseInitFlags,
13329
+ installSkill,
13178
13330
  initMemory,
13179
13331
  dispatch
13180
13332
  };