@wierdbytes/pi-memory 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/index.js +27 -434
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.2] - 2026-11-10
4
+
5
+ ### Changed
6
+
7
+ - `/dream status`: shows what waits for a decision in the one review (no review ids); needs a wierd-memory server with the `dreams` branch.
8
+
9
+ ## [0.1.1] - 2026-11-10
10
+
11
+ ### Removed
12
+
13
+ - `PI_DREAM_CHILD` no longer disables the extension (pi-dream is retired); use `WMEM_DISABLE=1`.
14
+
3
15
  ## [0.1.0] - 2026-11-10
4
16
 
5
17
  ### Added
package/index.js CHANGED
@@ -90,7 +90,7 @@ ${section}
90
90
  }
91
91
 
92
92
  // packages/pi/runtime.ts
93
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
93
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
94
94
  import { join as join3 } from "node:path";
95
95
  // packages/core/src/api.ts
96
96
  var INBOX_KINDS = ["preference", "procedure", "pitfall", "fact", "decision", "reference", "other"];
@@ -100,7 +100,6 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
100
100
  // packages/core/src/layout.ts
101
101
  import { homedir } from "node:os";
102
102
  import { join, resolve } from "node:path";
103
- var GLOBAL_SCOPE = "global";
104
103
  function expandHome(p) {
105
104
  if (p === "~")
106
105
  return homedir();
@@ -123,7 +122,8 @@ function homePaths(home = wmemHome(), memoryDir) {
123
122
  local,
124
123
  state: join(local, "state.json"),
125
124
  inbox: join(local, "inbox"),
126
- reviews: join(local, "reviews"),
125
+ review: join(local, "review.json"),
126
+ decisions: join(local, "decisions.jsonl"),
127
127
  runs: join(local, "runs"),
128
128
  dreamLogs: join(local, "logs"),
129
129
  digests: join(local, "digests"),
@@ -139,7 +139,7 @@ var STAGES = ["cards", "analyze", "verify"];
139
139
  function defaults() {
140
140
  return {
141
141
  port: 7433,
142
- memory: { dir: "", branch: "main", remote: "origin", sync: true },
142
+ memory: { dir: "", branch: "main", reviewBranch: "dreams", remote: "origin", sync: true },
143
143
  language: "Russian",
144
144
  inject: true,
145
145
  models: {
@@ -181,10 +181,15 @@ function sanitize(raw) {
181
181
  cfg.port = Math.round(num(raw.port, 1, 65535, d.port));
182
182
  if (isObj(raw.memory)) {
183
183
  const m = raw.memory;
184
- const branch = typeof m.branch === "string" && /^[A-Za-z0-9._/-]{1,100}$/.test(m.branch.trim()) && !m.branch.includes("..") ? m.branch.trim() : d.memory.branch;
184
+ const branchName = (v, fallback) => typeof v === "string" && /^[A-Za-z0-9._/-]{1,100}$/.test(v.trim()) && !v.includes("..") ? v.trim() : fallback;
185
+ const branch = branchName(m.branch, d.memory.branch);
186
+ let reviewBranch = branchName(m.reviewBranch, d.memory.reviewBranch);
187
+ if (reviewBranch === branch)
188
+ reviewBranch = branch === d.memory.reviewBranch ? `${branch}-proposed` : d.memory.reviewBranch;
185
189
  cfg.memory = {
186
190
  dir: typeof m.dir === "string" ? m.dir.trim() : d.memory.dir,
187
191
  branch,
192
+ reviewBranch,
188
193
  remote: typeof m.remote === "string" && /^[A-Za-z0-9._-]*$/.test(m.remote.trim()) ? m.remote.trim() : d.memory.remote,
189
194
  sync: bool(m.sync, d.memory.sync)
190
195
  };
@@ -238,244 +243,12 @@ function loadConfig(path = homePaths().config) {
238
243
  function serverUrl(cfg = loadConfig()) {
239
244
  return (process.env.WMEM_URL || `http://127.0.0.1:${cfg.port}`).replace(/\/+$/, "");
240
245
  }
241
- // packages/core/src/notes.ts
242
- import { randomBytes } from "node:crypto";
243
- function newNoteId(taken) {
244
- for (;; ) {
245
- const id = `m-${randomBytes(3).toString("hex")}`;
246
- if (!taken.has(id)) {
247
- taken.add(id);
248
- return id;
249
- }
250
- }
251
- }
252
- function cloneNote(n) {
253
- return {
254
- ...n,
255
- supersedes: [...n.supersedes],
256
- evidence: n.evidence.map((e) => ({ ...e, e: [...e.e] })),
257
- extra: { ...n.extra },
258
- stats: n.stats ? { ...n.stats } : undefined
259
- };
260
- }
261
- function makeNote(p, date) {
262
- return {
263
- id: p.id,
264
- scope: p.scope,
265
- title: p.title,
266
- type: p.type ?? "fact",
267
- status: p.status ?? "active",
268
- index: p.index ?? "none",
269
- when: p.when || undefined,
270
- body: p.body ?? "",
271
- pinned: p.pinned ?? false,
272
- enabled: p.enabled ?? true,
273
- created: p.created || date,
274
- updated: p.updated || p.created || date,
275
- confirmed: p.confirmed || undefined,
276
- validUntil: p.validUntil || undefined,
277
- supersededBy: p.supersededBy || undefined,
278
- supersedes: p.supersedes ?? [],
279
- evidence: p.evidence ?? [],
280
- extra: p.extra ?? {},
281
- stats: p.stats
282
- };
283
- }
284
- var NOTE_COLUMNS = [
285
- "scope",
286
- "title",
287
- "type",
288
- "status",
289
- "index",
290
- "when",
291
- "body",
292
- "pinned",
293
- "enabled",
294
- "created",
295
- "updated",
296
- "confirmed",
297
- "validUntil",
298
- "supersededBy",
299
- "supersedes",
300
- "evidence",
301
- "extra"
302
- ];
303
- function canonical(v) {
304
- if (v === undefined || v === null)
305
- return "null";
306
- if (Array.isArray(v))
307
- return `[${v.map(canonical).join(",")}]`;
308
- if (typeof v === "object") {
309
- const o = v;
310
- return `{${Object.keys(o).filter((k) => o[k] !== undefined).sort().map((k) => `${JSON.stringify(k)}:${canonical(o[k])}`).join(",")}}`;
311
- }
312
- return JSON.stringify(v);
313
- }
314
- function columnValue(n, c) {
315
- const v = n[c];
316
- if (c === "evidence")
317
- return canonical(v.map((e) => ({ s: e.s, e: e.e, date: e.date, at: e.at, kind: e.kind })));
318
- if (v === undefined || v === null || v === "")
319
- return "null";
320
- if (typeof v === "string")
321
- return JSON.stringify(c === "body" || c === "title" ? v.trim() : v);
322
- return canonical(v);
323
- }
324
- function changedColumns(a, b) {
325
- return NOTE_COLUMNS.filter((c) => columnValue(a, c) !== columnValue(b, c));
326
- }
327
- function sameNote(a, b) {
328
- if (!a || !b)
329
- return a === b;
330
- return a.id === b.id && changedColumns(a, b).length === 0;
331
- }
332
246
  // packages/core/src/digest.ts
333
247
  import { homedir as homedir2 } from "node:os";
334
-
335
- // packages/core/src/sessions.ts
336
- import { createReadStream, existsSync as existsSync2, readdirSync, statSync } from "node:fs";
337
- import { createInterface } from "node:readline";
338
- function slim(content) {
339
- if (!Array.isArray(content))
340
- return content;
341
- return content.map((b) => {
342
- if (!b || typeof b !== "object")
343
- return b;
344
- const t = b.type;
345
- if (t === "image")
346
- return { type: "image" };
347
- if (t === "thinking" || t === "redacted_thinking")
348
- return { type: "thinking" };
349
- return b;
350
- });
351
- }
352
- function slimEntry(e) {
353
- if (e.message && typeof e.message === "object") {
354
- const m = e.message;
355
- if (m.role === "system")
356
- e.message = { role: "system" };
357
- else if ("content" in m)
358
- m.content = slim(m.content);
359
- }
360
- if (e.type === "custom_message" && "content" in e)
361
- e.content = slim(e.content);
362
- if (e.type === "compaction")
363
- delete e.systemMessage;
364
- return e;
365
- }
366
- async function parseSession(file) {
367
- const entries = new Map;
368
- let header;
369
- let lastId;
370
- let name;
371
- const rl = createInterface({ input: createReadStream(file, { encoding: "utf8" }), crlfDelay: Infinity });
372
- for await (const line of rl) {
373
- if (!line)
374
- continue;
375
- let e;
376
- try {
377
- e = JSON.parse(line);
378
- } catch {
379
- continue;
380
- }
381
- if (e.type === "session") {
382
- header = e;
383
- continue;
384
- }
385
- if (typeof e.id !== "string")
386
- continue;
387
- entries.set(e.id, slimEntry(e));
388
- lastId = e.id;
389
- if (e.type === "session_info" && typeof e.name === "string")
390
- name = e.name;
391
- }
392
- if (!header)
393
- return;
394
- const branch = [];
395
- const seen = new Set;
396
- let cur = lastId ? entries.get(lastId) : undefined;
397
- while (cur && !seen.has(cur.id)) {
398
- seen.add(cur.id);
399
- branch.push(cur);
400
- cur = cur.parentId ? entries.get(cur.parentId) : undefined;
401
- }
402
- branch.reverse();
403
- return { file, header, branch, name, lastEntryId: lastId };
404
- }
405
- class SessionCache {
406
- max;
407
- map = new Map;
408
- constructor(max = 8) {
409
- this.max = max;
410
- }
411
- get(file) {
412
- let p = this.map.get(file);
413
- if (p) {
414
- this.map.delete(file);
415
- this.map.set(file, p);
416
- return p;
417
- }
418
- p = parseSession(file);
419
- this.map.set(file, p);
420
- while (this.map.size > this.max)
421
- this.map.delete(this.map.keys().next().value);
422
- return p;
423
- }
424
- }
425
-
426
- // packages/core/src/digest.ts
427
248
  var HOME_PATH_RE = new RegExp(`(?:^|[\\s'"=(:])((?:~|/Users/[^/\\s'"]+|/home/[^/\\s'"]+|${homedir2().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})/[^\\s'"\`;|&)<>]+)`, "g");
428
249
  var SESSION_EVENT = "wierd-memory";
429
250
  // packages/core/src/project.ts
430
251
  var cache = new Map;
431
- // packages/core/src/projects.ts
432
- class ProjectMap {
433
- roots;
434
- byKey = new Map;
435
- constructor(entries) {
436
- const byRoot = new Map;
437
- for (const e of entries)
438
- if (e.root && e.key && e.root !== "/")
439
- byRoot.set(e.root.replace(/\/+$/, ""), { key: e.key, project: e.project ?? true });
440
- const roots = [...byRoot.entries()].map(([root, v]) => ({ root, key: v.key, project: v.project, broad: false }));
441
- for (const r of roots)
442
- r.broad = roots.some((o) => o !== r && o.root.startsWith(`${r.root}/`));
443
- roots.sort((a, b) => b.root.length - a.root.length);
444
- this.roots = roots;
445
- for (const r of roots)
446
- if (!this.byKey.has(r.key) || !r.broad)
447
- this.byKey.set(r.key, r);
448
- }
449
- projectOf(path) {
450
- return this.roots.find((r) => path === r.root || path.startsWith(`${r.root}/`));
451
- }
452
- rootOf(key) {
453
- return this.byKey.get(key);
454
- }
455
- isBroad(key) {
456
- return this.byKey.get(key)?.broad ?? false;
457
- }
458
- isProject(key) {
459
- const r = this.byKey.get(key);
460
- return !!r && r.project && !r.broad;
461
- }
462
- touched(paths) {
463
- const counts = new Map;
464
- for (const [p, n] of paths) {
465
- const r = this.projectOf(p);
466
- if (r && !r.broad && r.project)
467
- counts.set(r.key, (counts.get(r.key) ?? 0) + n);
468
- }
469
- return [...counts.entries()].map(([key, n]) => ({ key, n })).sort((a, b) => b.n - a.n);
470
- }
471
- primary(cwdKey, paths) {
472
- const touched = this.touched(paths);
473
- const workspace = this.isBroad(cwdKey);
474
- if (!workspace)
475
- return { key: cwdKey, touched, workspace };
476
- return { key: touched[0]?.key ?? cwdKey, touched, workspace };
477
- }
478
- }
479
252
  // packages/core/src/prompts.ts
480
253
  var OPS_SCHEMA = `Operations — each op has "ref" (unique, e.g. "op1"), "rationale" (why a future session needs this and how we know it is true) and "evidence" (a list of {"s": sessionId | "inbox:<id>", "e": [entryIds]} copied from the input; never invent ids). "scope" is "global", "project" (the project of this pass) or "project:<key>" (another project from the input):
481
254
  - {"op":"add","scope":"…","type":"preference|procedure|pitfall|fact|decision|reference","title":"…","body":"…","when":"…","index":"always|pointer|none", …}
@@ -523,11 +296,11 @@ var REVIEW = `You are the memory curator of wierd-memory, an offline memory syst
523
296
  ${OPS_SCHEMA}
524
297
 
525
298
  For these operations:
526
- - Notes marked "pending": true are proposed in this review and not approved yet: to drop one use deprecate (it is removed from the review), to change one use update.
299
+ - Notes marked "pending": true are proposed, not approved yet: to drop one use deprecate (the proposal is withdrawn), to change one use update.
527
300
  - To move a note to another scope use update with "scope": "global", "project:<key>" (key from the scope titles in the input) or a scope id; the note keeps its id and evidence.
528
- - A comment with "note" refers to that note; without it, to the review as a whole.
301
+ - A comment with "note" refers to that note; without it, to what is proposed as a whole.
529
302
  - "scope" may also be a scope id from the input (e.g. "projects/github.com__owner__repo").
530
- - evidence is the comment: {"s": "review:<reviewId>", "e": ["<commentId>"]} (the review id is in the input).
303
+ - evidence is the comment: {"s": "comment:<commentId>", "e": []}.
531
304
  - Follow the same writing rules: titles are one self-contained statement in {{language}} (≤ 160 chars), bodies hold the specifics (≤ 120 words).
532
305
  - A comment that asks for something you cannot express as an operation goes to "unhandled" with a short reason.
533
306
  Reply with JSON only: {"ops": [...], "unhandled": [{"comment": "<commentId>", "reason": "…"}]}`;
@@ -536,190 +309,10 @@ var MINUTE = 60000;
536
309
  var HOUR = 60 * MINUTE;
537
310
  var DAY = 24 * HOUR;
538
311
  // packages/core/src/search.ts
539
- var RU_PREFIXES = ["пере", "под", "при", "про", "раз", "рас", "за", "вы", "по", "на", "от", "до", "об", "вз", "из"];
540
312
  var STOP = new Set("и в во не что он на я с со как а то все она так его но да ты к у же вы за бы по только ее мне было вот от меня еще нет о из ему теперь когда даже ну вдруг ли если уже или ни быть был него до вас нибудь опять уж вам ведь там потом себя ничего ей может они тут где есть надо ней для мы тебя их чем была сам чтоб без будто чего раз тоже себе под будет ж тогда кто этот того потому этого какой совсем ним здесь этом один почти мой тем чтобы нее сейчас были куда зачем всех никогда можно при наконец два об другой хоть после над больше тот через эти нас про всего них какая много разве три эту моя впрочем хорошо свою этой перед иногда лучше чуть том нельзя такой им более всегда конечно всю между the a an and or of to in on for is it this that with be as at by from are was were has have had not but if then so do does did can will just".split(" "));
541
- function ruForms(word) {
542
- if (word.length <= 4)
543
- return [word];
544
- const out = [word.slice(0, 4)];
545
- if (word.length >= 6)
546
- out.push(word.slice(0, 6));
547
- for (const p of RU_PREFIXES) {
548
- if (word.startsWith(p) && word.length - p.length >= 5) {
549
- const rest = word.slice(p.length);
550
- out.push(rest.slice(0, 4));
551
- if (rest.length >= 6)
552
- out.push(rest.slice(0, 6));
553
- break;
554
- }
555
- }
556
- return out;
557
- }
558
- function enStem(word) {
559
- if (word.length > 4) {
560
- for (const suf of ["ing", "ed", "es", "s"])
561
- if (word.endsWith(suf) && word.length - suf.length >= 3)
562
- return word.slice(0, -suf.length);
563
- }
564
- return word;
565
- }
566
- function tokenize(text) {
567
- const out = [];
568
- for (const raw of text.toLowerCase().replace(/ё/g, "е").split(/[^\p{L}\p{N}_]+/u)) {
569
- if (raw.length < 2 || STOP.has(raw))
570
- continue;
571
- if (/^[а-я]+$/.test(raw))
572
- out.push(...ruForms(raw));
573
- else if (/^[a-z]+$/.test(raw))
574
- out.push(enStem(raw));
575
- else
576
- out.push(raw);
577
- }
578
- return out;
579
- }
580
-
581
- class Bm25 {
582
- docs;
583
- k1;
584
- b;
585
- postings = new Map;
586
- lengths = [];
587
- avg = 0;
588
- constructor(docs, k1 = 1.2, b = 0.75) {
589
- this.docs = docs;
590
- this.k1 = k1;
591
- this.b = b;
592
- let total = 0;
593
- docs.forEach((doc, i) => {
594
- const tf = new Map;
595
- const toks = tokenize(doc.text);
596
- for (const t of toks)
597
- tf.set(t, (tf.get(t) ?? 0) + 1);
598
- for (const [t, n] of tf) {
599
- let list = this.postings.get(t);
600
- if (!list)
601
- this.postings.set(t, list = []);
602
- list.push([i, n]);
603
- }
604
- this.lengths.push(toks.length);
605
- total += toks.length;
606
- });
607
- this.avg = docs.length ? total / docs.length : 0;
608
- }
609
- search(query, limit = 10, filter) {
610
- const terms = [...new Set(tokenize(query))];
611
- if (!terms.length || !this.docs.length)
612
- return [];
613
- const scores = new Map;
614
- const N = this.docs.length;
615
- for (const t of terms) {
616
- const list = this.postings.get(t);
617
- if (!list)
618
- continue;
619
- const idf = Math.log(1 + (N - list.length + 0.5) / (list.length + 0.5));
620
- for (const [i, tf] of list) {
621
- const len = this.lengths[i] || 1;
622
- const s = idf * tf * (this.k1 + 1) / (tf + this.k1 * (1 - this.b + this.b * len / (this.avg || 1)));
623
- scores.set(i, (scores.get(i) ?? 0) + s);
624
- }
625
- }
626
- return [...scores.entries()].filter(([i]) => !filter || filter(this.docs[i])).sort((a, b) => b[1] - a[1]).slice(0, limit).map(([i, score]) => ({ doc: this.docs[i], score }));
627
- }
628
- }
629
- // packages/core/src/workspace.ts
630
- class Workspace {
631
- date;
632
- notes = new Map;
633
- ids = new Set;
634
- pending = new Set;
635
- skills = new Map;
636
- original = new Map;
637
- dirty = new Set;
638
- gone = new Map;
639
- metas = new Map;
640
- known = new Set;
641
- constructor(notes, date, opts = {}) {
642
- this.date = date;
643
- for (const n of notes) {
644
- const copy = cloneNote(n);
645
- this.scope(copy.scope).push(copy);
646
- this.ids.add(copy.id);
647
- this.original.set(copy.id, cloneNote(n));
648
- }
649
- for (const s of opts.scopes ?? []) {
650
- this.known.add(s.id);
651
- this.scope(s.id);
652
- }
653
- for (const id of opts.pending ?? [])
654
- this.pending.add(id);
655
- this.scope(GLOBAL_SCOPE);
656
- }
657
- scope(scope) {
658
- let list = this.notes.get(scope);
659
- if (!list)
660
- this.notes.set(scope, list = []);
661
- return list;
662
- }
663
- ensureScope(scope, meta) {
664
- this.scope(scope);
665
- if (meta && !this.known.has(scope))
666
- this.metas.set(scope, { id: scope, ...meta });
667
- }
668
- all() {
669
- return [...this.notes.values()].flat();
670
- }
671
- find(id) {
672
- for (const list of this.notes.values())
673
- for (const n of list)
674
- if (n.id === id)
675
- return n;
676
- return;
677
- }
678
- createNote(scope, f, evidence) {
679
- const note = makeNote({ id: newNoteId(this.ids), scope, title: f.title, type: f.type, index: f.index, when: f.when, body: f.body ?? "", evidence: [...evidence], stats: { helpful: 0, harmful: 0 } }, this.date);
680
- this.scope(scope).push(note);
681
- this.pending.add(note.id);
682
- this.dirty.add(note);
683
- return note;
684
- }
685
- touch(n) {
686
- this.dirty.add(n);
687
- }
688
- moveNote(n, scope) {
689
- const from = this.scope(n.scope);
690
- const i = from.indexOf(n);
691
- if (i >= 0)
692
- from.splice(i, 1);
693
- n.scope = scope;
694
- this.scope(scope).push(n);
695
- this.dirty.add(n);
696
- }
697
- removeNote(n) {
698
- const list = this.scope(n.scope);
699
- const i = list.indexOf(n);
700
- if (i >= 0)
701
- list.splice(i, 1);
702
- this.dirty.delete(n);
703
- this.pending.delete(n.id);
704
- const before = this.original.get(n.id);
705
- if (before)
706
- this.gone.set(n.id, before);
707
- }
708
- changes() {
709
- const notes = [];
710
- for (const n of this.dirty) {
711
- const before = this.original.get(n.id);
712
- if (before && sameNote(before, n))
713
- continue;
714
- notes.push({ before, after: cloneNote(n) });
715
- }
716
- const scopes = [...this.metas.values()].filter((m) => this.scope(m.id).length > 0 || [...this.skills.values()].some((s) => s.scope === m.id));
717
- return { notes, removed: [...this.gone.values()], scopes, skills: [...this.skills.values()] };
718
- }
719
- }
720
313
  // packages/pi/client.ts
721
314
  import { execFile, spawn } from "node:child_process";
722
- import { accessSync, closeSync, constants, existsSync as existsSync3, mkdirSync as mkdirSync2, openSync } from "node:fs";
315
+ import { accessSync, closeSync, constants, existsSync as existsSync2, mkdirSync as mkdirSync2, openSync } from "node:fs";
723
316
  import { homedir as homedir3 } from "node:os";
724
317
  import { delimiter, dirname, join as join2, resolve as resolve2 } from "node:path";
725
318
  import { fileURLToPath } from "node:url";
@@ -815,7 +408,7 @@ class Client {
815
408
  }
816
409
  }
817
410
  async function launch() {
818
- if (process.platform === "darwin" && !process.env.WMEM_HOME && existsSync3(PLIST)) {
411
+ if (process.platform === "darwin" && !process.env.WMEM_HOME && existsSync2(PLIST)) {
819
412
  const target = `gui/${process.getuid?.() ?? 501}`;
820
413
  if (await run("launchctl", ["kickstart", `${target}/${LABEL}`]) === 0)
821
414
  return "launchctl kickstart";
@@ -867,13 +460,13 @@ function onPath(name) {
867
460
  function checkoutBin() {
868
461
  const repo = resolve2(dirname(fileURLToPath(import.meta.url)), "..", "..");
869
462
  const bin = join2(repo, "bin", "wmem");
870
- return existsSync3(bin) && existsSync3(join2(repo, "packages", "server", "src", "cli.ts")) ? bin : undefined;
463
+ return existsSync2(bin) && existsSync2(join2(repo, "packages", "server", "src", "cli.ts")) ? bin : undefined;
871
464
  }
872
465
 
873
466
  // packages/pi/runtime.ts
874
467
  var EVENT = SESSION_EVENT;
875
468
  function disabledByEnv() {
876
- return process.env.WMEM_DISABLE === "1" || process.env.WMEM_CHILD === "1" || process.env.PI_DREAM_CHILD === "1";
469
+ return process.env.WMEM_DISABLE === "1" || process.env.WMEM_CHILD === "1";
877
470
  }
878
471
  var why2 = (err) => err instanceof Error ? err.message : String(err);
879
472
 
@@ -949,7 +542,7 @@ class Runtime {
949
542
  }
950
543
  async resourcesFor(cwd) {
951
544
  const info = await Promise.race([this.contextFor(cwd), new Promise((r) => setTimeout(() => r(undefined), 2500))]);
952
- return (info?.skills ?? []).filter((d) => existsSync4(d));
545
+ return (info?.skills ?? []).filter((d) => existsSync3(d));
953
546
  }
954
547
  async guarded(fn) {
955
548
  try {
@@ -968,9 +561,9 @@ class Runtime {
968
561
  return `Memory is unavailable: ${why2(err)}`;
969
562
  }
970
563
  }
971
- search(ctx, query, scope, projects2, limit) {
564
+ search(ctx, query, scope, projects, limit) {
972
565
  return this.guarded(async () => {
973
- const p = new URLSearchParams({ q: query, scope, projects: projects2, cwd: ctx.cwd, limit: String(limit), exclude: ctx.sessionManager.getSessionId() });
566
+ const p = new URLSearchParams({ q: query, scope, projects, cwd: ctx.cwd, limit: String(limit), exclude: ctx.sessionManager.getSessionId() });
974
567
  return (await this.client.get(`/api/search?${p}`)).text;
975
568
  });
976
569
  }
@@ -997,11 +590,11 @@ class Runtime {
997
590
  }
998
591
  async dreamLog(lines = 40) {
999
592
  const s = await this.client.get("/api/dreams?limit=1");
1000
- const run2 = s.running ?? s.runs[0];
1001
- if (!run2)
593
+ const run = s.running ?? s.runs[0];
594
+ if (!run)
1002
595
  return "no dreams yet";
1003
- const text = await this.client.get(`/api/dreams/${run2.id}/log?tail=${lines}`);
1004
- return `dream ${run2.id} (${run2.status}):
596
+ const text = await this.client.get(`/api/dreams/${run.id}/log?tail=${lines}`);
597
+ return `dream ${run.id} (${run.status}):
1005
598
  ${text.trimEnd() || "(empty log)"}`;
1006
599
  }
1007
600
  async notifyReview(ctx) {
@@ -1024,7 +617,7 @@ ${text.trimEnd() || "(empty log)"}`;
1024
617
  } catch {}
1025
618
  if (last.status === "error")
1026
619
  ctx.ui.notify(`wierd-memory: the last dream failed — ${last.error ?? ""} (/dream log)`, "warning");
1027
- else if (s.review?.pending)
620
+ else if (s.review.pending)
1028
621
  ctx.ui.notify(`wierd-memory: ${s.review.pending} memory change(s) wait for your review — ${s.url}/#/review`, "info");
1029
622
  }
1030
623
  async status(ctx) {
@@ -1045,7 +638,7 @@ cwd: ${ctx.cwd}`;
1045
638
  `inbox: ${s.inbox} pending`,
1046
639
  `dream: ${d.running ? `running (${d.running.id})` : `${d.due.due ? "due" : "not due"} (${d.due.reason})`}`,
1047
640
  `last: ${d.last ? `${d.last.status} ${d.last.finishedAt ?? d.last.startedAt}${d.last.error ? ` — ${d.last.error}` : ""}` : "never"}`,
1048
- `review: ${s.review ? `${s.review.pending} to decide — ${s.url}/#/review` : "nothing to review"}`,
641
+ `review: ${s.review.pending ? `${s.review.pending} to decide — ${s.url}/#/review` : "nothing to decide"}`,
1049
642
  `cwd: ${ctx.cwd}`
1050
643
  ].join(`
1051
644
  `);
@@ -1119,7 +712,7 @@ function registerTools(pi, rt) {
1119
712
 
1120
713
  // packages/pi/index.ts
1121
714
  function piWierdMemory(pi) {
1122
- if (process.env.WMEM_CHILD === "1" || process.env.PI_DREAM_CHILD === "1")
715
+ if (process.env.WMEM_CHILD === "1")
1123
716
  return;
1124
717
  pi.registerFlag("no-memory", {
1125
718
  description: "wierd-memory: no memory injection and no memory tools in this run",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wierdbytes/pi-memory",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Long-term memory for pi: injects the approved wierd-memory index into every session and adds memory_search / memory_read / memory_inbox tools and /memory, /dream, /remember commands. Needs the wierd-memory server.",
5
5
  "type": "module",
6
6
  "files": [