@kevin0181/memoc 1.1.10 → 1.1.11

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/README.md +2 -2
  2. package/bin/cli.js +77 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -144,7 +144,7 @@ Run it from the project root. It preserves existing project memory, including:
144
144
  - `.memoc/systems/`
145
145
  - `.memoc/wiki/`
146
146
 
147
- It refreshes the managed blocks, project-local wrappers, runtime copy, PATH helpers, and missing template files. If `memoc` is not on PATH after upgrading, keep using:
147
+ It refreshes the managed blocks, project-local wrappers, runtime copy, PATH helpers, and memoc-owned protocol templates. User-owned memory files such as `session-summary.md`, `03-decisions.md`, `04-handoff.md`, `06-project-rules.md`, and wiki topic/source pages are preserved. If `memoc` is not on PATH after upgrading, keep using:
148
148
 
149
149
  ```bash
150
150
  # Windows
@@ -277,7 +277,7 @@ Actor detection order:
277
277
 
278
278
  `activity.md`, `actors/README.md`, and `worklog/README.md` are regenerated indexes. Run `memoc activity --write` when you want to refresh them from worklog files.
279
279
 
280
- `log.md` is legacy. New installs do not create it, and shared activity should live in worklog files. Existing projects can delete `.memoc/log.md` after preserving any useful history in worklogs or archives.
280
+ `log.md` is legacy. New installs do not create it, and shared activity should live in worklog files. On upgrade, an existing `.memoc/log.md` is moved to `.memoc/raw/legacy-log.md` so old history is preserved but no longer part of the normal memory flow.
281
281
 
282
282
  ---
283
283
 
package/bin/cli.js CHANGED
@@ -209,6 +209,12 @@ function write(filePath, content) {
209
209
  fs.writeFileSync(filePath, content, 'utf8');
210
210
  }
211
211
 
212
+ function writeChanged(filePath, content) {
213
+ if (fs.existsSync(filePath) && fs.readFileSync(filePath, 'utf8') === content) return false;
214
+ write(filePath, content);
215
+ return true;
216
+ }
217
+
212
218
  function slugify(value, fallback = 'note') {
213
219
  const slug = String(value || '')
214
220
  .toLowerCase()
@@ -228,6 +234,35 @@ function uniquePath(filePath) {
228
234
  return `${base}-${i}${ext}`;
229
235
  }
230
236
 
237
+ function archiveLegacyLog(dir, mark) {
238
+ const logPath = path.join(dir, '.memoc', 'log.md');
239
+ if (!fs.existsSync(logPath)) {
240
+ mark('skip', '.memoc/log.md (legacy; no file)');
241
+ return;
242
+ }
243
+ const archivePath = uniquePath(path.join(dir, '.memoc', 'raw', 'legacy-log.md'));
244
+ fs.mkdirSync(path.dirname(archivePath), { recursive: true });
245
+ fs.renameSync(logPath, archivePath);
246
+ mark('move', `${path.relative(dir, logPath)} -> ${path.relative(dir, archivePath)}`);
247
+ }
248
+
249
+ function migrateLegacyLogReferences(filePath) {
250
+ if (!fs.existsSync(filePath)) return false;
251
+ const before = fs.readFileSync(filePath, 'utf8');
252
+ let after = before
253
+ .replace(/- \[Project Log\]\(log\.md\)\n/g, '- [Activity](activity.md)\n- [Worklog](worklog/README.md)\n')
254
+ .replace(/\| `\.memoc\/log\.md` \| For append-only history \|\n/g, '| `.memoc/activity.md` | Generated worklog index |\n| `.memoc/worklog/` | Actor-scoped work history |\n')
255
+ .replace(/See `\.memoc\/log\.md` for full history\./g, 'See `.memoc/worklog/` for full shared activity history.')
256
+ .replace(/See `\.memoc\/log\.md`\./g, 'See `.memoc/worklog/` and generated `.memoc/activity.md`.')
257
+ .replace(/- \[ \] `\.memoc\/log\.md` has a new entry for meaningful work\./g, '- [ ] Meaningful shared work has a `.memoc/worklog/<actor>/YYYY-MM/*.md` entry.')
258
+ .replace(/Append `\.memoc\/log\.md` for meaningful changes, decisions, and handoffs\./g, 'Create a short actor worklog with `memoc work "<title>" --from-git` for meaningful changes, decisions, and handoffs.')
259
+ .replace(/Keep completed history in `\.memoc\/log\.md`; keep current-state files short\./g, 'Keep completed history in actor worklogs; keep current-state files short.')
260
+ .replace(/Append `\.memoc\/log\.md`\./g, 'If the change is meaningful shared work, run `memoc work "<title>" --from-git`.');
261
+ if (after === before) return false;
262
+ write(filePath, after);
263
+ return true;
264
+ }
265
+
231
266
  function markdownTitle(src, fallback) {
232
267
  const m = String(src || '').match(/^#\s+(.+)$/m);
233
268
  return m ? m[1].trim() : fallback;
@@ -2252,10 +2287,18 @@ function run(dir, forceUpdate, action = 'update') {
2252
2287
  mark('add', 'llms.txt');
2253
2288
  }
2254
2289
 
2255
- // Dynamic memory filesupdate managed sections only
2290
+ // Generated memory mapsreplace so old protocols do not linger.
2291
+ const generatedRefresh = [
2292
+ [path.join(memDir, '00-project-brief.md'), () => tplProjectBrief(p)],
2293
+ [path.join(memDir, '00-agent-index.md'), () => tplAgentIndex(p)],
2294
+ ];
2295
+ for (const [fp, tpl] of generatedRefresh) {
2296
+ const rel = path.relative(dir, fp);
2297
+ mark(writeChanged(fp, tpl()) ? 'update' : 'skip', rel);
2298
+ }
2299
+
2300
+ // Dynamic user-owned memory files — update managed sections only
2256
2301
  const dynUpdates = [
2257
- [path.join(memDir, '00-project-brief.md'), () => tplProjectBrief(p), ID_S, ID_E, identityInner(p)],
2258
- [path.join(memDir, '00-agent-index.md'), () => tplAgentIndex(p), SNAP_S, SNAP_E, snapshotInner(p)],
2259
2302
  [path.join(memDir, '02-current-project-state.md'), () => tplCurrentState(p), SNAP_S, SNAP_E, snapshotInner(p)],
2260
2303
  ];
2261
2304
  for (const [fp, tpl, s, e, inner] of dynUpdates) {
@@ -2283,18 +2326,27 @@ function run(dir, forceUpdate, action = 'update') {
2283
2326
  mark('add', '.memoc/session-summary.md');
2284
2327
  }
2285
2328
 
2286
- // Static + user-owned files — only add if missing
2287
- const addIfMissing = [
2329
+ // Protocol/template files — replace on update so old instructions are removed.
2330
+ const templateRefresh = [
2288
2331
  [path.join(memDir, 'boot.md'), tplBoot],
2289
2332
  [path.join(memDir, '01-agent-workflow.md'), tplWorkflow],
2333
+ [path.join(memDir, '05-done-checklist.md'), tplDoneChecklist],
2334
+ [path.join(memDir, 'memoc-usage.md'), tplMemocUsage],
2335
+ [path.join(dir, 'skills/project-memory-maintainer/SKILL.md'), tplSkillMaintainer],
2336
+ ];
2337
+ for (const [fp, tpl] of templateRefresh) {
2338
+ const rel = path.relative(dir, fp);
2339
+ mark(writeChanged(fp, tpl()) ? 'update' : 'skip', rel);
2340
+ }
2341
+
2342
+ // Static indexes/scaffolds — add if missing; content may be user- or command-owned.
2343
+ const addIfMissing = [
2290
2344
  [path.join(memDir, '03-decisions.md'), tplDecisions],
2291
2345
  [path.join(memDir, '04-handoff.md'), tplHandoff],
2292
- [path.join(memDir, '05-done-checklist.md'), tplDoneChecklist],
2293
2346
  [path.join(memDir, '06-project-rules.md'), tplProjectRules],
2294
2347
  [path.join(memDir, 'activity.md'), tplActivity],
2295
2348
  [path.join(memDir, 'actors/README.md'), tplActorsReadme],
2296
2349
  [path.join(memDir, 'worklog/README.md'), tplWorklogReadme],
2297
- [path.join(memDir, 'memoc-usage.md'), tplMemocUsage],
2298
2350
  [path.join(memDir, 'systems/README.md'), tplSystemsReadme],
2299
2351
  [path.join(memDir, 'raw/README.md'), tplRawReadme],
2300
2352
  [path.join(memDir, 'raw/files/README.md'), tplRawFilesReadme],
@@ -2309,7 +2361,6 @@ function run(dir, forceUpdate, action = 'update') {
2309
2361
  [path.join(memDir, 'wiki/sources/README.md'), tplWikiSourcesReadme],
2310
2362
  [path.join(memDir, 'wiki/topics/README.md'), tplWikiTopicsReadme],
2311
2363
  [path.join(memDir, 'wiki/global/README.md'), tplWikiGlobalReadme],
2312
- [path.join(dir, 'skills/project-memory-maintainer/SKILL.md'), tplSkillMaintainer],
2313
2364
  ];
2314
2365
  for (const [fp, tpl] of addIfMissing) {
2315
2366
  const rel = path.relative(dir, fp);
@@ -2318,8 +2369,20 @@ function run(dir, forceUpdate, action = 'update') {
2318
2369
  }
2319
2370
  ensureWikiScaffoldLinks(memDir, mark);
2320
2371
 
2321
- // Obsidian graph filters — add/merge memoc tags for existing installs too
2322
- ensureObsidianFrontmatter(dir, mark);
2372
+ const legacyReferenceFiles = [
2373
+ path.join(memDir, '02-current-project-state.md'),
2374
+ path.join(memDir, '04-handoff.md'),
2375
+ path.join(memDir, '06-project-rules.md'),
2376
+ path.join(memDir, 'systems/README.md'),
2377
+ path.join(memDir, 'wiki/index.md'),
2378
+ path.join(memDir, 'wiki/sources.md'),
2379
+ path.join(memDir, 'wiki/glossary.md'),
2380
+ path.join(memDir, 'wiki/questions.md'),
2381
+ path.join(memDir, 'wiki/lint.md'),
2382
+ ];
2383
+ for (const fp of legacyReferenceFiles) {
2384
+ if (migrateLegacyLogReferences(fp)) mark('update', `${path.relative(dir, fp)} (legacy refs)`);
2385
+ }
2323
2386
 
2324
2387
  // PATH helpers — let agents run memoc even when the npm bin is not on PATH
2325
2388
  ensureClaudeStopHookFile(dir, mark);
@@ -2327,7 +2390,10 @@ function run(dir, forceUpdate, action = 'update') {
2327
2390
  ensurePathHelpers(dir, mark);
2328
2391
  ensurePathRegistration(dir, mark);
2329
2392
 
2330
- mark('skip', '.memoc/log.md (legacy; shared history belongs in worklog)');
2393
+ archiveLegacyLog(dir, mark);
2394
+
2395
+ // Obsidian graph filters — add/merge memoc tags for existing installs too
2396
+ ensureObsidianFrontmatter(dir, mark);
2331
2397
  }
2332
2398
 
2333
2399
  hideOnWindows(memDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevin0181/memoc",
3
- "version": "1.1.10",
3
+ "version": "1.1.11",
4
4
  "description": "Give AI agents a memory. Scaffolds session-to-session context for Claude Code, Codex, Cursor, and more.",
5
5
  "keywords": [
6
6
  "ai",