@kevin0181/memoc 1.1.4 → 1.1.10
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/README.md +39 -5
- package/bin/cli.js +592 -83
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,6 +82,14 @@ npx @kevin0181/memoc init
|
|
|
82
82
|
# Re-scan project and refresh managed sections
|
|
83
83
|
npx @kevin0181/memoc update
|
|
84
84
|
|
|
85
|
+
# Shared repo activity tracking
|
|
86
|
+
npx @kevin0181/memoc actor
|
|
87
|
+
npx @kevin0181/memoc actor set neneee
|
|
88
|
+
npx @kevin0181/memoc work "Auth refresh fix" --from-git
|
|
89
|
+
npx @kevin0181/memoc activity
|
|
90
|
+
npx @kevin0181/memoc activity --write
|
|
91
|
+
npx @kevin0181/memoc doctor
|
|
92
|
+
|
|
85
93
|
# Print current status in ~10 lines
|
|
86
94
|
npx @kevin0181/memoc summary
|
|
87
95
|
|
|
@@ -105,7 +113,7 @@ npx @kevin0181/memoc tokens
|
|
|
105
113
|
# Archive and compact an oversized startup summary
|
|
106
114
|
npx @kevin0181/memoc trim-summary
|
|
107
115
|
|
|
108
|
-
#
|
|
116
|
+
# Legacy: archive old log.md entries before deleting/migrating log.md
|
|
109
117
|
npx @kevin0181/memoc compress
|
|
110
118
|
|
|
111
119
|
# Add the same protocol to another agent's entry file
|
|
@@ -132,7 +140,7 @@ Run it from the project root. It preserves existing project memory, including:
|
|
|
132
140
|
- `.memoc/03-decisions.md`
|
|
133
141
|
- `.memoc/04-handoff.md`
|
|
134
142
|
- `.memoc/06-project-rules.md`
|
|
135
|
-
- `.memoc/log.md`
|
|
143
|
+
- Legacy `.memoc/log.md` if present
|
|
136
144
|
- `.memoc/systems/`
|
|
137
145
|
- `.memoc/wiki/`
|
|
138
146
|
|
|
@@ -164,7 +172,9 @@ llms.txt ← LLM-facing project map
|
|
|
164
172
|
03-decisions.md ← Durable decision log
|
|
165
173
|
04-handoff.md ← Resume context, verified/unverified
|
|
166
174
|
06-project-rules.md ← User preferences
|
|
167
|
-
|
|
175
|
+
activity.md ← Short shared activity index
|
|
176
|
+
actors/ ← Actor profiles for shared repos
|
|
177
|
+
worklog/ ← Per-actor work records to reduce conflicts
|
|
168
178
|
raw/ ← Immutable source material, not a startup read
|
|
169
179
|
systems/ ← Subsystem docs
|
|
170
180
|
wiki/ ← Synthesized knowledge base
|
|
@@ -182,10 +192,14 @@ Every entry file (`CLAUDE.md`, `AGENTS.md`, `.cursorrules`, etc.) gets the same
|
|
|
182
192
|
## Session Start
|
|
183
193
|
- [ ] Read `.memoc/session-summary.md`
|
|
184
194
|
- [ ] `.pending` exists? → review changed files → update memory if needed → delete it
|
|
195
|
+
- [ ] If `memoc` is not found, use the project-local wrapper.
|
|
185
196
|
|
|
186
197
|
## Before Opening More Files
|
|
187
198
|
- [ ] Run `memoc search "<query>"` first
|
|
188
199
|
- [ ] Open on demand: `02` status · `04` resume · `06` rules · `llms.txt` map
|
|
200
|
+
- [ ] Use `memoc grep "<query>"` only when memory is not enough.
|
|
201
|
+
- [ ] For durable source/wiki work, use `memoc ingest`, `memoc note`, and `memoc lint-wiki`.
|
|
202
|
+
- [ ] In shared repos, record meaningful work with `memoc work "<title>"`.
|
|
189
203
|
- [ ] Keep output small: `summary`, `search --limit`, `search --snippets`
|
|
190
204
|
|
|
191
205
|
## Before Finishing _(update only applicable files; skip Q&A / throwaway exploration)_
|
|
@@ -194,6 +208,8 @@ Every entry file (`CLAUDE.md`, `AGENTS.md`, `.cursorrules`, etc.) gets the same
|
|
|
194
208
|
- [ ] Work incomplete or risky → `04-handoff.md` (verified commands, unverified items, next steps)
|
|
195
209
|
- [ ] Rule/preference set → `06-project-rules.md`
|
|
196
210
|
- [ ] Wiki/systems work → read `skills/project-memory-maintainer/SKILL.md`
|
|
211
|
+
- [ ] Shared repo work → prefer `memoc work "<title>" --from-git`; run `memoc activity --write` only when regenerating indexes.
|
|
212
|
+
- [ ] Keep `session-summary.md` replace-only; completed work belongs in actor worklogs.
|
|
197
213
|
```
|
|
198
214
|
|
|
199
215
|
The checklist tells agents exactly when to update, which file to update, and what to record — so nothing gets missed.
|
|
@@ -212,7 +228,7 @@ Startup cost is kept minimal by design.
|
|
|
212
228
|
|
|
213
229
|
Everything else is on-demand. Use `memoc tokens` to see the live breakdown for your project.
|
|
214
230
|
|
|
215
|
-
`session-summary.md` is a replace-only startup snapshot, not a timeline. If it grows beyond the warning threshold, run `memoc trim-summary`; completed history belongs in `.memoc/
|
|
231
|
+
`session-summary.md` is a replace-only startup snapshot, not a timeline. If it grows beyond the warning threshold, run `memoc trim-summary`; completed history belongs in `.memoc/worklog/<actor>/YYYY-MM/`, and unfinished/risky resume detail belongs in `.memoc/04-handoff.md`.
|
|
216
232
|
|
|
217
233
|
---
|
|
218
234
|
|
|
@@ -245,6 +261,24 @@ Add more agents on demand:
|
|
|
245
261
|
|
|
246
262
|
Running `update` refreshes managed blocks in all existing agent files.
|
|
247
263
|
|
|
264
|
+
## Shared Repos
|
|
265
|
+
|
|
266
|
+
Use `memoc work "<title>" --from-git` for meaningful work in shared repositories. It creates a new actor-scoped file under `.memoc/worklog/<actor>/YYYY-MM/`, prefills branch and changed files from git, and avoids append conflicts in shared files.
|
|
267
|
+
|
|
268
|
+
Actor detection order:
|
|
269
|
+
|
|
270
|
+
1. `MEMOC_ACTOR`
|
|
271
|
+
2. `.memoc/local/actor` from `memoc actor set <name>`
|
|
272
|
+
3. `git config user.name`
|
|
273
|
+
4. `git config user.email`
|
|
274
|
+
5. OS username
|
|
275
|
+
|
|
276
|
+
`.memoc/local/` is ignored by git so each machine can keep its own actor setting.
|
|
277
|
+
|
|
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
|
+
|
|
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.
|
|
281
|
+
|
|
248
282
|
---
|
|
249
283
|
|
|
250
284
|
## Supported Stacks
|
|
@@ -260,7 +294,7 @@ Node.js · Next.js · React · Vue · Svelte · Angular · Nuxt · Astro · Expr
|
|
|
260
294
|
- **New project** — scaffolds all memory files with sensible defaults.
|
|
261
295
|
- **Existing project** — detects your stack and fills in real project info (name, scripts, config files).
|
|
262
296
|
- **Already initialized** — `init` injects the managed block without touching your existing content. `update` re-scans and refreshes project-specific sections.
|
|
263
|
-
- **Long-running projects** —
|
|
297
|
+
- **Long-running projects** — use actor worklogs for history; `compress` remains only for old `log.md` files.
|
|
264
298
|
|
|
265
299
|
---
|
|
266
300
|
|
package/bin/cli.js
CHANGED
|
@@ -233,16 +233,121 @@ function markdownTitle(src, fallback) {
|
|
|
233
233
|
return m ? m[1].trim() : fallback;
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
function
|
|
237
|
-
|
|
236
|
+
function execGitConfig(dir, key) {
|
|
237
|
+
try {
|
|
238
|
+
return require('child_process')
|
|
239
|
+
.execFileSync('git', ['config', '--get', key], { cwd: dir, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] })
|
|
240
|
+
.trim();
|
|
241
|
+
} catch {
|
|
242
|
+
return '';
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function actorFile(dir) {
|
|
247
|
+
return path.join(dir, '.memoc', 'local', 'actor');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function sanitizeActor(value) {
|
|
251
|
+
return slugify(String(value || '').replace(/@.*$/, ''), 'unknown');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function detectActor(dir) {
|
|
255
|
+
if (process.env.MEMOC_ACTOR) return { actor: sanitizeActor(process.env.MEMOC_ACTOR), source: 'MEMOC_ACTOR' };
|
|
256
|
+
const localPath = actorFile(dir);
|
|
257
|
+
try {
|
|
258
|
+
const local = fs.readFileSync(localPath, 'utf8').trim();
|
|
259
|
+
if (local) return { actor: sanitizeActor(local), source: '.memoc/local/actor' };
|
|
260
|
+
} catch {}
|
|
261
|
+
const gitUser = execGitConfig(dir, 'user.name');
|
|
262
|
+
if (gitUser) return { actor: sanitizeActor(gitUser), source: 'git config user.name' };
|
|
263
|
+
const gitEmail = execGitConfig(dir, 'user.email');
|
|
264
|
+
if (gitEmail) return { actor: sanitizeActor(gitEmail), source: 'git config user.email' };
|
|
265
|
+
const osUser = process.env.USER || process.env.USERNAME || process.env.LOGNAME;
|
|
266
|
+
if (osUser) return { actor: sanitizeActor(osUser), source: 'OS user' };
|
|
267
|
+
return { actor: 'unknown', source: 'fallback' };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function gitBranch(dir) {
|
|
271
|
+
try {
|
|
272
|
+
return require('child_process')
|
|
273
|
+
.execFileSync('git', ['branch', '--show-current'], { cwd: dir, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] })
|
|
274
|
+
.trim() || 'unknown';
|
|
275
|
+
} catch {
|
|
276
|
+
return 'unknown';
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function gitStatusFiles(dir) {
|
|
281
|
+
try {
|
|
282
|
+
const out = require('child_process')
|
|
283
|
+
.execFileSync('git', ['status', '--short'], { cwd: dir, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] })
|
|
284
|
+
.trim();
|
|
285
|
+
if (!out) return [];
|
|
286
|
+
return out.split(/\r?\n/)
|
|
287
|
+
.map(line => line.slice(3).trim())
|
|
288
|
+
.filter(Boolean)
|
|
289
|
+
.filter(file => !file.startsWith('.memoc/worklog/') && !file.startsWith('.memoc/activity.md'))
|
|
290
|
+
.slice(0, 12);
|
|
291
|
+
} catch {
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function tplMemocCmdWrapper() {
|
|
297
|
+
return [
|
|
298
|
+
'@echo off',
|
|
299
|
+
'set "MEMOC_RUNTIME=%MEMOC_RUNTIME_DIR%"',
|
|
300
|
+
'if "%MEMOC_RUNTIME%"=="" (',
|
|
301
|
+
' if not "%LOCALAPPDATA%"=="" (',
|
|
302
|
+
' set "MEMOC_RUNTIME=%LOCALAPPDATA%\\memoc\\runtime"',
|
|
303
|
+
' ) else (',
|
|
304
|
+
' set "MEMOC_RUNTIME=%USERPROFILE%\\AppData\\Local\\memoc\\runtime"',
|
|
305
|
+
' )',
|
|
306
|
+
')',
|
|
307
|
+
'set "MEMOC_CLI=%MEMOC_RUNTIME%\\bin\\cli.js"',
|
|
308
|
+
'if exist "%MEMOC_CLI%" (',
|
|
309
|
+
' node "%MEMOC_CLI%" %*',
|
|
310
|
+
') else (',
|
|
311
|
+
' npx @kevin0181/memoc@latest %*',
|
|
312
|
+
')',
|
|
313
|
+
'exit /b %ERRORLEVEL%',
|
|
314
|
+
'',
|
|
315
|
+
].join('\r\n');
|
|
238
316
|
}
|
|
239
317
|
|
|
240
|
-
function tplMemocPs1Wrapper(
|
|
241
|
-
return
|
|
318
|
+
function tplMemocPs1Wrapper() {
|
|
319
|
+
return [
|
|
320
|
+
'$runtime = $env:MEMOC_RUNTIME_DIR',
|
|
321
|
+
'if (-not $runtime) {',
|
|
322
|
+
' if ($env:LOCALAPPDATA) { $runtime = Join-Path $env:LOCALAPPDATA "memoc\\runtime" }',
|
|
323
|
+
' else { $runtime = Join-Path $env:USERPROFILE "AppData\\Local\\memoc\\runtime" }',
|
|
324
|
+
'}',
|
|
325
|
+
'$cli = Join-Path $runtime "bin\\cli.js"',
|
|
326
|
+
'if (Test-Path $cli) {',
|
|
327
|
+
' & node $cli @args',
|
|
328
|
+
'} else {',
|
|
329
|
+
' & npx @kevin0181/memoc@latest @args',
|
|
330
|
+
'}',
|
|
331
|
+
'exit $LASTEXITCODE',
|
|
332
|
+
'',
|
|
333
|
+
].join('\n');
|
|
242
334
|
}
|
|
243
335
|
|
|
244
|
-
function tplMemocShWrapper(
|
|
245
|
-
return
|
|
336
|
+
function tplMemocShWrapper() {
|
|
337
|
+
return [
|
|
338
|
+
'#!/bin/sh',
|
|
339
|
+
'if [ -n "$MEMOC_RUNTIME_DIR" ]; then',
|
|
340
|
+
' memoc_runtime="$MEMOC_RUNTIME_DIR"',
|
|
341
|
+
'else',
|
|
342
|
+
' memoc_runtime="${HOME:-$PWD}/.local/share/memoc/runtime"',
|
|
343
|
+
'fi',
|
|
344
|
+
'memoc_cli="$memoc_runtime/bin/cli.js"',
|
|
345
|
+
'if [ -f "$memoc_cli" ]; then',
|
|
346
|
+
' exec node "$memoc_cli" "$@"',
|
|
347
|
+
'fi',
|
|
348
|
+
'exec npx @kevin0181/memoc@latest "$@"',
|
|
349
|
+
'',
|
|
350
|
+
].join('\n');
|
|
246
351
|
}
|
|
247
352
|
|
|
248
353
|
function defaultUserBinDir() {
|
|
@@ -274,11 +379,11 @@ function tplEnvSh() {
|
|
|
274
379
|
}
|
|
275
380
|
|
|
276
381
|
function ensurePathHelpers(dir, mark) {
|
|
277
|
-
|
|
382
|
+
ensureRuntimeInstall(mark);
|
|
278
383
|
const files = [
|
|
279
|
-
[path.join(dir, '.memoc', 'bin', 'memoc.cmd'),
|
|
280
|
-
[path.join(dir, '.memoc', 'bin', 'memoc.ps1'),
|
|
281
|
-
[path.join(dir, '.memoc', 'bin', 'memoc'),
|
|
384
|
+
[path.join(dir, '.memoc', 'bin', 'memoc.cmd'), tplMemocCmdWrapper, false],
|
|
385
|
+
[path.join(dir, '.memoc', 'bin', 'memoc.ps1'), tplMemocPs1Wrapper, false],
|
|
386
|
+
[path.join(dir, '.memoc', 'bin', 'memoc'), tplMemocShWrapper, true],
|
|
282
387
|
[path.join(dir, '.memoc', 'env.ps1'), tplEnvPs1, false],
|
|
283
388
|
[path.join(dir, '.memoc', 'env.sh'), tplEnvSh, true],
|
|
284
389
|
];
|
|
@@ -293,15 +398,16 @@ function ensurePathHelpers(dir, mark) {
|
|
|
293
398
|
|
|
294
399
|
function ensureUserLauncher(mark) {
|
|
295
400
|
const userBin = defaultUserBinDir();
|
|
296
|
-
|
|
401
|
+
ensureRuntimeInstall(mark);
|
|
402
|
+
writeLaunchers(userBin, mark, 'user bin');
|
|
297
403
|
return userBin;
|
|
298
404
|
}
|
|
299
405
|
|
|
300
|
-
function writeLaunchers(binDir, mark, label
|
|
406
|
+
function writeLaunchers(binDir, mark, label) {
|
|
301
407
|
const files = [
|
|
302
|
-
[path.join(binDir, 'memoc.cmd'),
|
|
303
|
-
[path.join(binDir, 'memoc.ps1'),
|
|
304
|
-
[path.join(binDir, 'memoc'),
|
|
408
|
+
[path.join(binDir, 'memoc.cmd'), tplMemocCmdWrapper, false],
|
|
409
|
+
[path.join(binDir, 'memoc.ps1'), tplMemocPs1Wrapper, false],
|
|
410
|
+
[path.join(binDir, 'memoc'), tplMemocShWrapper, true],
|
|
305
411
|
];
|
|
306
412
|
|
|
307
413
|
for (const [fp, tpl, executable] of files) {
|
|
@@ -398,7 +504,8 @@ function ensureCurrentPathLauncher(mark) {
|
|
|
398
504
|
mark('skip', 'active PATH launcher (no writable PATH directory found)');
|
|
399
505
|
return false;
|
|
400
506
|
}
|
|
401
|
-
|
|
507
|
+
ensureRuntimeInstall(mark);
|
|
508
|
+
writeLaunchers(target, mark, 'active PATH');
|
|
402
509
|
return true;
|
|
403
510
|
}
|
|
404
511
|
|
|
@@ -631,6 +738,7 @@ function managedBlock() {
|
|
|
631
738
|
- [ ] If memory search is not enough, search project files with \`memoc grep "<query>" --limit 5\` (or wrapper fallback)
|
|
632
739
|
- [ ] If asked to refresh/update memoc project memory, run \`memoc update\` first; this refreshes managed sections, wiki links, and Obsidian tags.
|
|
633
740
|
- [ ] For durable source material use \`memoc ingest <path-or-url>\`; for durable analysis/query results use \`memoc note "<title>"\`; after wiki edits run \`memoc lint-wiki\`.
|
|
741
|
+
- [ ] In shared repos, record meaningful work with \`memoc work "<title>"\`; actor defaults to \`MEMOC_ACTOR\`, local actor, git user, git email, or OS user.
|
|
634
742
|
- [ ] Keep output small: \`summary\`, \`search --limit\`, \`grep --limit\`, \`--snippets\`
|
|
635
743
|
|
|
636
744
|
## Before Finishing _(update only applicable files; skip Q&A / throwaway exploration)_
|
|
@@ -640,7 +748,8 @@ function managedBlock() {
|
|
|
640
748
|
- [ ] Rule/preference set? Update \`06-project-rules.md\`
|
|
641
749
|
- [ ] Wiki/systems work? Read \`skills/project-memory-maintainer/SKILL.md\`
|
|
642
750
|
- [ ] User asked to update memoc/project memory? Run \`memoc update\`, then update the smallest relevant agent-owned memory files.
|
|
643
|
-
- [ ]
|
|
751
|
+
- [ ] Shared repo work? Prefer \`memoc work "<title>" --from-git\` over appending shared files; run \`memoc activity --write\` only when regenerating indexes.
|
|
752
|
+
- [ ] Keep \`session-summary.md\` as a replace-only snapshot under 800B; move completed work to actor worklogs and resume risks to \`04-handoff.md\`. If it grew, run \`memoc trim-summary\`.
|
|
644
753
|
${MGMT_E}`;
|
|
645
754
|
}
|
|
646
755
|
|
|
@@ -675,8 +784,8 @@ function coreLlmsInner() {
|
|
|
675
784
|
- [Project Brief](.memoc/00-project-brief.md): short identity and direction.
|
|
676
785
|
- [Workflow](.memoc/01-agent-workflow.md): update trigger matrix.
|
|
677
786
|
- [Decisions](.memoc/03-decisions.md): durable decisions.
|
|
678
|
-
- [Log](.memoc/log.md): append-only history.
|
|
679
787
|
- [Systems](.memoc/systems/README.md): subsystem docs.
|
|
788
|
+
- [Activity](.memoc/activity.md): generated worklog index.
|
|
680
789
|
- [Raw Sources](.memoc/raw/README.md): immutable source material; do not read by default.
|
|
681
790
|
- [Wiki](.memoc/wiki/index.md): synthesized knowledge.`;
|
|
682
791
|
}
|
|
@@ -848,6 +957,12 @@ function obsidianFrontmatterSpec(relPath) {
|
|
|
848
957
|
} else if (rel.startsWith('.memoc/raw/')) {
|
|
849
958
|
type = 'raw';
|
|
850
959
|
tags.push('memoc/raw');
|
|
960
|
+
} else if (rel.startsWith('.memoc/worklog/')) {
|
|
961
|
+
type = 'worklog';
|
|
962
|
+
tags.push('memoc/worklog');
|
|
963
|
+
} else if (rel.startsWith('.memoc/actors/')) {
|
|
964
|
+
type = 'actor';
|
|
965
|
+
tags.push('memoc/actor');
|
|
851
966
|
} else if (rel.startsWith('skills/project-memory-maintainer/')) {
|
|
852
967
|
type = 'skill';
|
|
853
968
|
tags.push('memoc/skill');
|
|
@@ -864,10 +979,18 @@ function obsidianFrontmatterSpec(relPath) {
|
|
|
864
979
|
function mergeYamlFrontmatter(src, spec) {
|
|
865
980
|
const fm = parseYamlFrontmatter(src);
|
|
866
981
|
if (!fm) {
|
|
867
|
-
return `${formatMemocFrontmatter(spec)}\n${src}`;
|
|
982
|
+
return `${formatMemocFrontmatter(spec)}\n${String(src || '').replace(/^\uFEFF/, '')}`;
|
|
868
983
|
}
|
|
869
984
|
|
|
870
|
-
|
|
985
|
+
let body = fm.body;
|
|
986
|
+
let rest = String(src || '').slice(fm.end).replace(/^\uFEFF/, '');
|
|
987
|
+
const nested = parseYamlFrontmatter(rest);
|
|
988
|
+
if (nested) {
|
|
989
|
+
body = `${nested.body}\n${body}`;
|
|
990
|
+
rest = rest.slice(nested.end).replace(/^\uFEFF/, '');
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
const lines = body.split(/\r?\n/);
|
|
871
994
|
const existingTags = readYamlTags(lines);
|
|
872
995
|
const mergedTags = [...new Set([...existingTags, ...spec.tags])];
|
|
873
996
|
const nextLines = mergeYamlScalar(lines, 'memoc', 'true');
|
|
@@ -880,14 +1003,16 @@ function mergeYamlFrontmatter(src, spec) {
|
|
|
880
1003
|
mergeYamlTags(nextLines, mergedTags);
|
|
881
1004
|
|
|
882
1005
|
const nextFm = ['---', ...nextLines, '---'].join('\n');
|
|
883
|
-
return nextFm
|
|
1006
|
+
return `${nextFm}\n${rest.replace(/^\r?\n/, '')}`;
|
|
884
1007
|
}
|
|
885
1008
|
|
|
886
1009
|
function parseYamlFrontmatter(src) {
|
|
887
|
-
|
|
888
|
-
const
|
|
1010
|
+
const text = String(src || '').replace(/^\uFEFF/, '');
|
|
1011
|
+
const offset = text.length === src.length ? 0 : 1;
|
|
1012
|
+
if (!text.startsWith('---\n') && !text.startsWith('---\r\n')) return null;
|
|
1013
|
+
const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
889
1014
|
if (!m) return null;
|
|
890
|
-
return { body: m[1], end: m[0].length };
|
|
1015
|
+
return { body: m[1], end: m[0].length + offset };
|
|
891
1016
|
}
|
|
892
1017
|
|
|
893
1018
|
function formatMemocFrontmatter(spec) {
|
|
@@ -1097,7 +1222,9 @@ ${SNAP_E}
|
|
|
1097
1222
|
- [Done Checklist](05-done-checklist.md)
|
|
1098
1223
|
- [Project Rules](06-project-rules.md)
|
|
1099
1224
|
- [Session Summary](session-summary.md)
|
|
1100
|
-
- [
|
|
1225
|
+
- [Activity](activity.md)
|
|
1226
|
+
- [Actors](actors/README.md)
|
|
1227
|
+
- [Worklog](worklog/README.md)
|
|
1101
1228
|
- [Wiki Index](wiki/index.md)
|
|
1102
1229
|
- [Raw Sources](raw/README.md)
|
|
1103
1230
|
- [Systems Index](systems/README.md)
|
|
@@ -1137,7 +1264,7 @@ _None yet._
|
|
|
1137
1264
|
|
|
1138
1265
|
## Completed Tasks
|
|
1139
1266
|
|
|
1140
|
-
See \`.memoc/
|
|
1267
|
+
See \`.memoc/worklog/\` for full shared activity history.
|
|
1141
1268
|
|
|
1142
1269
|
## Commands
|
|
1143
1270
|
|
|
@@ -1149,7 +1276,7 @@ _None yet._
|
|
|
1149
1276
|
|
|
1150
1277
|
## Change Log
|
|
1151
1278
|
|
|
1152
|
-
See \`.memoc/
|
|
1279
|
+
See \`.memoc/worklog/\` and generated \`.memoc/activity.md\`.
|
|
1153
1280
|
`;
|
|
1154
1281
|
}
|
|
1155
1282
|
|
|
@@ -1157,7 +1284,7 @@ function tplSessionSummary() {
|
|
|
1157
1284
|
return `# Session Summary
|
|
1158
1285
|
Last: ${nowISO()}
|
|
1159
1286
|
Replace this file instead of appending to it. Keep total size <800B and each section ≤3 bullets.
|
|
1160
|
-
Completed history belongs in
|
|
1287
|
+
Completed history belongs in actor worklogs; incomplete/risky resume detail belongs in \`04-handoff.md\`.
|
|
1161
1288
|
Agent-owned — updated by you, not by \`memoc update\`.
|
|
1162
1289
|
|
|
1163
1290
|
## Status
|
|
@@ -1194,7 +1321,6 @@ On-demand reference only. The entry-file managed block is authoritative.
|
|
|
1194
1321
|
| \`.memoc/01-agent-workflow.md\` | When update routing is unclear |
|
|
1195
1322
|
| \`.memoc/05-done-checklist.md\` | Before finishing substantial work |
|
|
1196
1323
|
| \`.memoc/03-decisions.md\` | When a durable decision was made |
|
|
1197
|
-
| \`.memoc/log.md\` | For append-only history |
|
|
1198
1324
|
| \`.memoc/memoc-usage.md\` | For command details |
|
|
1199
1325
|
| \`.memoc/systems/*.md\` | Before touching a specific subsystem |
|
|
1200
1326
|
| \`.memoc/wiki/*.md\` | For synthesized project knowledge |
|
|
@@ -1227,15 +1353,16 @@ Shared protocol for any coding agent.
|
|
|
1227
1353
|
| Trigger | Update |
|
|
1228
1354
|
| --- | --- |
|
|
1229
1355
|
| User asks "update memoc", "refresh project memory", or similar | Run \`memoc update\` first, then update relevant agent-owned memory files |
|
|
1230
|
-
| User creates or changes a requirement | \`02-current-project-state.md\`, \`06-project-rules.md\`, \`
|
|
1231
|
-
| Code, config, data, or assets changed | \`02-current-project-state.md\`, relevant \`systems/*.md\`, \`
|
|
1356
|
+
| User creates or changes a requirement | \`02-current-project-state.md\`, \`06-project-rules.md\`, \`memoc work "<title>" --from-git\` |
|
|
1357
|
+
| Code, config, data, or assets changed | \`02-current-project-state.md\`, relevant \`systems/*.md\`, \`memoc work "<title>" --from-git\` |
|
|
1232
1358
|
| Architecture or system behavior changed | relevant \`systems/*.md\`, \`03-decisions.md\` |
|
|
1233
1359
|
| A decision should affect future agents | \`03-decisions.md\`, \`02-current-project-state.md\` |
|
|
1234
|
-
| Work is substantial enough to resume later | \`04-handoff.md\`, \`02-current-project-state.md\`, \`
|
|
1360
|
+
| Work is substantial enough to resume later | \`04-handoff.md\`, \`02-current-project-state.md\`, \`memoc work "<title>" --from-git\` |
|
|
1235
1361
|
| Durable knowledge was learned | \`wiki/*.md\`, \`wiki/index.md\` |
|
|
1236
1362
|
| Source material should feed the wiki | \`memoc ingest <path-or-url>\`, then synthesize affected \`wiki/topics/*.md\` |
|
|
1237
1363
|
| A useful query answer should persist | \`memoc note "<title>"\`, then link related sources/topics |
|
|
1238
|
-
|
|
|
1364
|
+
| Shared repo work should be traceable | \`memoc work "<title>"\`; avoid appending long details to shared core files |
|
|
1365
|
+
| \`session-summary.md\` exceeds 800B or starts accumulating history | Run \`memoc trim-summary\`; move completed history to worklog, resume details to \`04-handoff.md\` |
|
|
1239
1366
|
|
|
1240
1367
|
## Usually No Update Needed
|
|
1241
1368
|
|
|
@@ -1250,7 +1377,7 @@ Shared protocol for any coding agent.
|
|
|
1250
1377
|
- \`02-current-project-state.md\`: current status, tasks, commands, recent notes.
|
|
1251
1378
|
- \`04-handoff.md\`: resume context, blockers, verified/unverified checks.
|
|
1252
1379
|
- \`03-decisions.md\`: append durable decisions only.
|
|
1253
|
-
- \`
|
|
1380
|
+
- \`worklog/<actor>/YYYY-MM/*.md\`: actor-scoped append-by-new-file activity records for shared repos.
|
|
1254
1381
|
- \`systems/*.md\` and \`wiki/*.md\`: on-demand durable knowledge.
|
|
1255
1382
|
`;
|
|
1256
1383
|
}
|
|
@@ -1322,7 +1449,7 @@ Run through this before saying substantial work is complete.
|
|
|
1322
1449
|
- [ ] \`.memoc/02-current-project-state.md\` reflects the new status.
|
|
1323
1450
|
- [ ] \`.memoc/03-decisions.md\` updated if a durable decision was made.
|
|
1324
1451
|
- [ ] \`.memoc/04-handoff.md\` updated if work is incomplete or risky.
|
|
1325
|
-
- [ ] \`.memoc/
|
|
1452
|
+
- [ ] Meaningful shared work has a \`.memoc/worklog/<actor>/YYYY-MM/*.md\` entry.
|
|
1326
1453
|
- [ ] Relevant \`.memoc/systems/*.md\` or wiki pages updated.
|
|
1327
1454
|
|
|
1328
1455
|
## Communication
|
|
@@ -1347,7 +1474,7 @@ Durable user and project preferences live here. Update when the user gives a rul
|
|
|
1347
1474
|
## Agent Behavior Preferences
|
|
1348
1475
|
|
|
1349
1476
|
- Be factual and operational in memory docs.
|
|
1350
|
-
- Keep
|
|
1477
|
+
- Keep memory notes concise; do not paste temporary command output unless it changes future work.
|
|
1351
1478
|
- Preserve user changes and avoid reverting unrelated work.
|
|
1352
1479
|
- State unverified parts honestly in the final answer and handoff.
|
|
1353
1480
|
|
|
@@ -1360,9 +1487,75 @@ _None yet._
|
|
|
1360
1487
|
function tplLog() {
|
|
1361
1488
|
return `# Project Log
|
|
1362
1489
|
|
|
1363
|
-
|
|
1490
|
+
Legacy file. New memoc activity belongs in actor worklogs under \`.memoc/worklog/\`.
|
|
1491
|
+
|
|
1492
|
+
This file is no longer created for new projects. Existing projects may delete it after migrating useful entries to worklogs.
|
|
1493
|
+
`;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
function tplActivity() {
|
|
1497
|
+
return `# Activity
|
|
1498
|
+
|
|
1499
|
+
Shared activity index for memoc work logs.
|
|
1500
|
+
|
|
1501
|
+
## How To Use
|
|
1502
|
+
|
|
1503
|
+
- Use \`memoc work "<title>"\` after meaningful work so shared repos get conflict-light per-actor records.
|
|
1504
|
+
- Keep this file short; detailed work belongs in [worklog](worklog/README.md).
|
|
1505
|
+
- Actor is detected from \`MEMOC_ACTOR\`, \`.memoc/local/actor\`, git config, git email, or OS user.
|
|
1506
|
+
|
|
1507
|
+
## Recent Work
|
|
1508
|
+
|
|
1509
|
+
_None yet._
|
|
1510
|
+
|
|
1511
|
+
## Related
|
|
1512
|
+
|
|
1513
|
+
- [Actors](actors/README.md)
|
|
1514
|
+
- [Worklog](worklog/README.md)
|
|
1515
|
+
`;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
function tplActorsReadme() {
|
|
1519
|
+
return `# Actors
|
|
1364
1520
|
|
|
1365
|
-
|
|
1521
|
+
People or agents that update memoc in this shared repo.
|
|
1522
|
+
|
|
1523
|
+
## Actor Detection
|
|
1524
|
+
|
|
1525
|
+
1. \`MEMOC_ACTOR\`
|
|
1526
|
+
2. \`.memoc/local/actor\` set by \`memoc actor set <name>\`
|
|
1527
|
+
3. \`git config user.name\`
|
|
1528
|
+
4. \`git config user.email\`
|
|
1529
|
+
5. OS username
|
|
1530
|
+
|
|
1531
|
+
\`.memoc/local/\` is ignored by git so each machine can keep its own actor setting.
|
|
1532
|
+
|
|
1533
|
+
## Actors
|
|
1534
|
+
|
|
1535
|
+
_None yet. Use \`memoc actor set <name>\` or \`memoc work "<title>"\`._
|
|
1536
|
+
`;
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
function tplWorklogReadme() {
|
|
1540
|
+
return `# Worklog
|
|
1541
|
+
|
|
1542
|
+
Conflict-light per-actor work records.
|
|
1543
|
+
|
|
1544
|
+
## Rules
|
|
1545
|
+
|
|
1546
|
+
- Prefer creating new worklog files over appending shared core memory files.
|
|
1547
|
+
- Keep \`session-summary.md\` as the tiny current snapshot.
|
|
1548
|
+
- Put detailed completed work here; put only team-critical unfinished risk in \`04-handoff.md\`.
|
|
1549
|
+
|
|
1550
|
+
## Layout
|
|
1551
|
+
|
|
1552
|
+
\`\`\`text
|
|
1553
|
+
worklog/<actor>/YYYY-MM/YYYYMMDDTHHMM-title.md
|
|
1554
|
+
\`\`\`
|
|
1555
|
+
|
|
1556
|
+
## Recent Work
|
|
1557
|
+
|
|
1558
|
+
_None yet._
|
|
1366
1559
|
`;
|
|
1367
1560
|
}
|
|
1368
1561
|
|
|
@@ -1388,6 +1581,14 @@ memoc upgrade
|
|
|
1388
1581
|
memoc update
|
|
1389
1582
|
memoc trim-summary
|
|
1390
1583
|
|
|
1584
|
+
# Shared repo actor/work tracking
|
|
1585
|
+
memoc actor
|
|
1586
|
+
memoc actor set neneee
|
|
1587
|
+
memoc work "Auth refresh fix" --from-git
|
|
1588
|
+
memoc activity
|
|
1589
|
+
memoc activity --write
|
|
1590
|
+
memoc doctor
|
|
1591
|
+
|
|
1391
1592
|
# Tiny status overview
|
|
1392
1593
|
memoc summary
|
|
1393
1594
|
|
|
@@ -1420,6 +1621,12 @@ Use \`memoc search\` for known concepts, changed areas, decisions, tasks, or han
|
|
|
1420
1621
|
|
|
1421
1622
|
Raw files under \`.memoc/raw/\` are intentionally not part of normal memory search. Open them only through a linked source record when provenance is needed.
|
|
1422
1623
|
|
|
1624
|
+
## Shared Repo Activity
|
|
1625
|
+
|
|
1626
|
+
Use \`memoc work "<title>" --from-git\` to create conflict-light activity records under \`.memoc/worklog/<actor>/YYYY-MM/\`. The command prefills actor, branch, timestamp, and changed files from git so agents only need to fill short Summary/Verification notes when useful. Actor is detected in this order: \`MEMOC_ACTOR\`, \`.memoc/local/actor\`, \`git config user.name\`, \`git config user.email\`, OS username. Use \`memoc actor set <name>\` to store a local actor name without committing it.
|
|
1627
|
+
|
|
1628
|
+
\`.memoc/activity.md\`, \`.memoc/worklog/README.md\`, and \`.memoc/actors/README.md\` are regenerated indexes. Run \`memoc activity --write\` to rebuild them from worklog/actor files instead of appending to them during every task.
|
|
1629
|
+
|
|
1423
1630
|
## When To Run Memory Updates
|
|
1424
1631
|
|
|
1425
1632
|
Use \`memoc update\` or \`skills/project-memory-maintainer/SKILL.md\` when:
|
|
@@ -1431,12 +1638,13 @@ Use \`memoc update\` or \`skills/project-memory-maintainer/SKILL.md\` when:
|
|
|
1431
1638
|
- A decision was made that future agents should not revisit blindly.
|
|
1432
1639
|
- Work is partial, multi-step, blocked, or likely to be resumed by another agent.
|
|
1433
1640
|
- New durable knowledge belongs in \`.memoc/wiki/\` or a subsystem doc.
|
|
1641
|
+
- Shared work should be traceable without causing conflicts.
|
|
1434
1642
|
|
|
1435
1643
|
Usually skip for pure Q&A, throwaway exploration, or tiny edits with no future impact.
|
|
1436
1644
|
|
|
1437
|
-
When the user asks for a general memoc/project-memory refresh, run \`memoc update\` first. It refreshes managed sections, reconnects default wiki scaffold links, and applies Obsidian frontmatter tags. Then update only the agent-owned files whose content actually changed, such as \`.memoc/session-summary.md\`, \`.memoc/02-current-project-state.md\`, \`.memoc/04-handoff.md\`, \`.memoc/wiki/index.md\`, or
|
|
1645
|
+
When the user asks for a general memoc/project-memory refresh, run \`memoc update\` first. It refreshes managed sections, reconnects default wiki scaffold links, and applies Obsidian frontmatter tags. Then update only the agent-owned files whose content actually changed, such as \`.memoc/session-summary.md\`, \`.memoc/02-current-project-state.md\`, \`.memoc/04-handoff.md\`, \`.memoc/wiki/index.md\`, or actor worklogs.
|
|
1438
1646
|
|
|
1439
|
-
\`.memoc/session-summary.md\` is a startup snapshot, not a timeline. Rewrite it in place, do not append old work. If it exceeds 800B, run \`memoc trim-summary\`; it archives the previous summary and rewrites a compact version. Put completed history in
|
|
1647
|
+
\`.memoc/session-summary.md\` is a startup snapshot, not a timeline. Rewrite it in place, do not append old work. If it exceeds 800B, run \`memoc trim-summary\`; it archives the previous summary and rewrites a compact version. Put completed history in actor worklogs, and put unfinished/risky resume detail in \`.memoc/04-handoff.md\`.
|
|
1440
1648
|
|
|
1441
1649
|
## Updating The Wiki
|
|
1442
1650
|
|
|
@@ -1450,7 +1658,7 @@ Create a new Markdown file under \`.memoc/wiki/\` when synthesized knowledge sho
|
|
|
1450
1658
|
After creating or editing wiki pages:
|
|
1451
1659
|
1. Update \`.memoc/wiki/index.md\`.
|
|
1452
1660
|
2. Run \`memoc lint-wiki\`.
|
|
1453
|
-
3.
|
|
1661
|
+
3. If the change is meaningful shared work, run \`memoc work "<title>" --from-git\`.
|
|
1454
1662
|
|
|
1455
1663
|
Useful scaffolds:
|
|
1456
1664
|
|
|
@@ -1590,7 +1798,6 @@ _None yet. Use \`memoc note "<title>"\` for durable analysis or query results th
|
|
|
1590
1798
|
- [Agent Index](../00-agent-index.md)
|
|
1591
1799
|
- [Project Brief](../00-project-brief.md)
|
|
1592
1800
|
- [Current Project State](../02-current-project-state.md)
|
|
1593
|
-
- [Project Log](../log.md)
|
|
1594
1801
|
`;
|
|
1595
1802
|
}
|
|
1596
1803
|
|
|
@@ -1774,14 +1981,16 @@ Use this local skill after meaningful project work so future agents can continue
|
|
|
1774
1981
|
- Update \`.memoc/04-handoff.md\` before ending substantial work.
|
|
1775
1982
|
- Check \`.memoc/05-done-checklist.md\` before saying substantial work is complete.
|
|
1776
1983
|
- Update \`.memoc/06-project-rules.md\` when the user gives durable preferences.
|
|
1777
|
-
-
|
|
1984
|
+
- Create a short actor worklog with \`memoc work "<title>" --from-git\` for meaningful changes, decisions, and handoffs.
|
|
1778
1985
|
- Create or update \`.memoc/systems/*.md\` when a subsystem needs durable explanation.
|
|
1779
1986
|
- Create or update \`.memoc/wiki/*.md\` when synthesized knowledge should compound over time.
|
|
1780
1987
|
- Use \`memoc ingest <path-or-url>\` for source material and \`memoc note "<title>"\` for durable query results or analysis.
|
|
1988
|
+
- Use \`memoc work "<title>" --from-git\` for meaningful shared-repo work so details are saved in actor-scoped worklog files instead of causing shared-file conflicts.
|
|
1781
1989
|
- Keep the wiki graph connected: update \`.memoc/wiki/index.md\`, add relative Markdown links between related pages, and include a \`## Related\` section on every new wiki page.
|
|
1782
1990
|
- Run \`memoc lint-wiki\` after wiki/source/topic edits and address broken links before finishing.
|
|
1783
|
-
- Keep completed history in
|
|
1784
|
-
- Move completed session details out of \`session-summary.md\` into
|
|
1991
|
+
- Keep completed history in actor worklogs; keep current-state files short.
|
|
1992
|
+
- Move completed session details out of \`session-summary.md\` into \`.memoc/worklog/<actor>/YYYY-MM/\`; move incomplete/risky resume details into \`04-handoff.md\`.
|
|
1993
|
+
- In shared repos, do not use \`log.md\`; prefer new files under \`.memoc/worklog/<actor>/YYYY-MM/\` and regenerate \`.memoc/activity.md\` with \`memoc activity --write\`.
|
|
1785
1994
|
- Keep tool output small; prefer \`summary\`, file-only search, \`--limit\`, and targeted reads.
|
|
1786
1995
|
|
|
1787
1996
|
## Wiki Link Rules
|
|
@@ -1890,17 +2099,16 @@ function ensureClaudeStopHookFile(dir, mark) {
|
|
|
1890
2099
|
|
|
1891
2100
|
function ensurePendingGitignore(dir, mark) {
|
|
1892
2101
|
const gitignorePath = path.join(dir, '.gitignore');
|
|
1893
|
-
const
|
|
2102
|
+
const entries = ['.memoc/.pending', '.memoc/local/'];
|
|
1894
2103
|
const gitignoreContent = fs.existsSync(gitignorePath)
|
|
1895
2104
|
? fs.readFileSync(gitignorePath, 'utf8') : '';
|
|
1896
|
-
const
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
mark('update', '.gitignore (.memoc/.pending added)');
|
|
2105
|
+
const lines = gitignoreContent.split(/\r?\n/).map(line => line.trim());
|
|
2106
|
+
const missing = entries.filter(entry => !lines.includes(entry));
|
|
2107
|
+
if (missing.length) {
|
|
2108
|
+
fs.appendFileSync(gitignorePath, (gitignoreContent.endsWith('\n') ? '' : '\n') + missing.join('\n') + '\n', 'utf8');
|
|
2109
|
+
mark('update', `.gitignore (${missing.join(', ')} added)`);
|
|
1902
2110
|
} else {
|
|
1903
|
-
mark('skip', '.gitignore (
|
|
2111
|
+
mark('skip', '.gitignore (memoc local entries already present)');
|
|
1904
2112
|
}
|
|
1905
2113
|
}
|
|
1906
2114
|
|
|
@@ -1975,7 +2183,9 @@ function run(dir, forceUpdate, action = 'update') {
|
|
|
1975
2183
|
[path.join(memDir, '04-handoff.md'), tplHandoff],
|
|
1976
2184
|
[path.join(memDir, '05-done-checklist.md'), tplDoneChecklist],
|
|
1977
2185
|
[path.join(memDir, '06-project-rules.md'), tplProjectRules],
|
|
1978
|
-
[path.join(memDir, '
|
|
2186
|
+
[path.join(memDir, 'activity.md'), tplActivity],
|
|
2187
|
+
[path.join(memDir, 'actors/README.md'), tplActorsReadme],
|
|
2188
|
+
[path.join(memDir, 'worklog/README.md'), tplWorklogReadme],
|
|
1979
2189
|
[path.join(memDir, 'memoc-usage.md'), tplMemocUsage],
|
|
1980
2190
|
[path.join(memDir, 'systems/README.md'), tplSystemsReadme],
|
|
1981
2191
|
[path.join(memDir, 'raw/README.md'), tplRawReadme],
|
|
@@ -2081,7 +2291,9 @@ function run(dir, forceUpdate, action = 'update') {
|
|
|
2081
2291
|
[path.join(memDir, '04-handoff.md'), tplHandoff],
|
|
2082
2292
|
[path.join(memDir, '05-done-checklist.md'), tplDoneChecklist],
|
|
2083
2293
|
[path.join(memDir, '06-project-rules.md'), tplProjectRules],
|
|
2084
|
-
[path.join(memDir, '
|
|
2294
|
+
[path.join(memDir, 'activity.md'), tplActivity],
|
|
2295
|
+
[path.join(memDir, 'actors/README.md'), tplActorsReadme],
|
|
2296
|
+
[path.join(memDir, 'worklog/README.md'), tplWorklogReadme],
|
|
2085
2297
|
[path.join(memDir, 'memoc-usage.md'), tplMemocUsage],
|
|
2086
2298
|
[path.join(memDir, 'systems/README.md'), tplSystemsReadme],
|
|
2087
2299
|
[path.join(memDir, 'raw/README.md'), tplRawReadme],
|
|
@@ -2115,15 +2327,7 @@ function run(dir, forceUpdate, action = 'update') {
|
|
|
2115
2327
|
ensurePathHelpers(dir, mark);
|
|
2116
2328
|
ensurePathRegistration(dir, mark);
|
|
2117
2329
|
|
|
2118
|
-
|
|
2119
|
-
const logPath = path.join(memDir, 'log.md');
|
|
2120
|
-
if (fs.existsSync(logPath)) {
|
|
2121
|
-
fs.appendFileSync(logPath,
|
|
2122
|
-
`\n## [${nowISO()}] ${action} | Re-scanned: ${p.isEmpty ? 'nothing detected' : stackStr(p.stack)}\n`,
|
|
2123
|
-
'utf8'
|
|
2124
|
-
);
|
|
2125
|
-
mark('append', '.memoc/log.md');
|
|
2126
|
-
}
|
|
2330
|
+
mark('skip', '.memoc/log.md (legacy; shared history belongs in worklog)');
|
|
2127
2331
|
}
|
|
2128
2332
|
|
|
2129
2333
|
hideOnWindows(memDir);
|
|
@@ -2162,6 +2366,262 @@ function runAdd(dir) {
|
|
|
2162
2366
|
console.log('\n Done.');
|
|
2163
2367
|
}
|
|
2164
2368
|
|
|
2369
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
2370
|
+
// ACTOR / WORKLOG — conflict-light shared repo activity tracking
|
|
2371
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
2372
|
+
|
|
2373
|
+
function runActor(dir) {
|
|
2374
|
+
const sub = (process.argv[3] || '').toLowerCase();
|
|
2375
|
+
if (sub === 'set') {
|
|
2376
|
+
const name = process.argv.slice(4).join(' ').trim();
|
|
2377
|
+
if (!name) {
|
|
2378
|
+
console.error('\n Usage: memoc actor set <name>');
|
|
2379
|
+
process.exit(1);
|
|
2380
|
+
}
|
|
2381
|
+
const actor = sanitizeActor(name);
|
|
2382
|
+
write(actorFile(dir), `${actor}\n`);
|
|
2383
|
+
ensurePendingGitignore(dir, () => {});
|
|
2384
|
+
console.log('\n memoc actor\n');
|
|
2385
|
+
console.log(` Set local actor: ${actor}`);
|
|
2386
|
+
console.log(' Stored in .memoc/local/actor (ignored by git).');
|
|
2387
|
+
console.log();
|
|
2388
|
+
return;
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
const detected = detectActor(dir);
|
|
2392
|
+
console.log('\n memoc actor\n');
|
|
2393
|
+
console.log(` Actor ${detected.actor}`);
|
|
2394
|
+
console.log(` Source ${detected.source}`);
|
|
2395
|
+
console.log('\n Use `memoc actor set <name>` to override locally.\n');
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
function runWork(dir) {
|
|
2399
|
+
const rawArgs = process.argv.slice(3);
|
|
2400
|
+
const opts = { status: 'done', body: '', fromGit: true };
|
|
2401
|
+
const titleParts = [];
|
|
2402
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
2403
|
+
const arg = rawArgs[i];
|
|
2404
|
+
if (arg === '--status') {
|
|
2405
|
+
opts.status = sanitizeActor(rawArgs[++i] || 'done');
|
|
2406
|
+
continue;
|
|
2407
|
+
}
|
|
2408
|
+
if (arg.startsWith('--status=')) {
|
|
2409
|
+
opts.status = sanitizeActor(arg.slice('--status='.length) || 'done');
|
|
2410
|
+
continue;
|
|
2411
|
+
}
|
|
2412
|
+
if (arg === '--body') {
|
|
2413
|
+
opts.body = rawArgs.slice(i + 1).join(' ');
|
|
2414
|
+
break;
|
|
2415
|
+
}
|
|
2416
|
+
if (arg === '--from-git') {
|
|
2417
|
+
opts.fromGit = true;
|
|
2418
|
+
continue;
|
|
2419
|
+
}
|
|
2420
|
+
if (arg === '--no-git') {
|
|
2421
|
+
opts.fromGit = false;
|
|
2422
|
+
continue;
|
|
2423
|
+
}
|
|
2424
|
+
titleParts.push(arg);
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
const title = titleParts.join(' ').trim();
|
|
2428
|
+
if (!title) {
|
|
2429
|
+
console.error('\n Usage: memoc work "<title>" [--status done|wip|blocked] [--from-git|--no-git] [--body "summary"]');
|
|
2430
|
+
process.exit(1);
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
ensureMemocBase(dir);
|
|
2434
|
+
const detected = detectActor(dir);
|
|
2435
|
+
ensureActorProfile(dir, detected);
|
|
2436
|
+
const stamp = new Date().toISOString().slice(0, 16).replace(/[-:]/g, '').replace('T', 'T');
|
|
2437
|
+
const month = todayISO().slice(0, 7);
|
|
2438
|
+
const fileName = `${stamp}-${slugify(title, 'work')}.md`;
|
|
2439
|
+
const workPath = uniquePath(path.join(dir, '.memoc', 'worklog', detected.actor, month, fileName));
|
|
2440
|
+
write(workPath, worklogRecord(dir, title, detected, opts));
|
|
2441
|
+
ensureMemocFrontmatter(workPath, dir);
|
|
2442
|
+
|
|
2443
|
+
console.log('\n memoc work\n');
|
|
2444
|
+
console.log(` Actor ${detected.actor} (${detected.source})`);
|
|
2445
|
+
console.log(` Work ${normRel(dir, workPath)}`);
|
|
2446
|
+
console.log(' Next Fill only Summary/Verification if needed; run `memoc activity --write` to regenerate indexes.');
|
|
2447
|
+
console.log();
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
function runActivity(dir) {
|
|
2451
|
+
const writeIndex = process.argv.slice(3).includes('--write');
|
|
2452
|
+
const workRoot = path.join(dir, '.memoc', 'worklog');
|
|
2453
|
+
const files = listMarkdownFiles(workRoot)
|
|
2454
|
+
.filter(fp => path.basename(fp) !== 'README.md')
|
|
2455
|
+
.sort()
|
|
2456
|
+
.reverse();
|
|
2457
|
+
const recent = files.slice(0, 20);
|
|
2458
|
+
|
|
2459
|
+
if (writeIndex) {
|
|
2460
|
+
writeActivityIndexes(dir, recent);
|
|
2461
|
+
ensureObsidianFrontmatter(dir, () => {});
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
console.log('\n memoc activity\n');
|
|
2465
|
+
if (!recent.length) {
|
|
2466
|
+
console.log(' No worklog entries yet. Use `memoc work "<title>"`.');
|
|
2467
|
+
console.log();
|
|
2468
|
+
return;
|
|
2469
|
+
}
|
|
2470
|
+
for (const fp of recent) {
|
|
2471
|
+
const src = safeRead(fp);
|
|
2472
|
+
const title = markdownTitle(src, path.basename(fp, '.md'));
|
|
2473
|
+
const actor = (src.match(/^actor:\s*(.+)$/m) || [])[1] || 'unknown';
|
|
2474
|
+
const status = (src.match(/^status:\s*(.+)$/m) || [])[1] || 'unknown';
|
|
2475
|
+
console.log(` - ${normRel(dir, fp)} ${actor} ${status} ${title}`);
|
|
2476
|
+
}
|
|
2477
|
+
if (writeIndex) console.log('\n Wrote .memoc/activity.md and .memoc/worklog/README.md');
|
|
2478
|
+
console.log();
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
function ensureActorProfile(dir, detected) {
|
|
2482
|
+
const actorPath = path.join(dir, '.memoc', 'actors', `${detected.actor}.md`);
|
|
2483
|
+
if (fs.existsSync(actorPath)) return;
|
|
2484
|
+
write(actorPath, actorProfile(detected));
|
|
2485
|
+
ensureMemocFrontmatter(actorPath, dir);
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
function actorProfile(detected) {
|
|
2489
|
+
return `# ${detected.actor}
|
|
2490
|
+
|
|
2491
|
+
## Identity
|
|
2492
|
+
|
|
2493
|
+
- Actor: ${detected.actor}
|
|
2494
|
+
- First detected from: ${detected.source}
|
|
2495
|
+
- First seen: ${nowISO()}
|
|
2496
|
+
|
|
2497
|
+
## Notes
|
|
2498
|
+
|
|
2499
|
+
_Add stable collaboration preferences or ownership notes only when useful._
|
|
2500
|
+
|
|
2501
|
+
## Related
|
|
2502
|
+
|
|
2503
|
+
- [Actors](README.md)
|
|
2504
|
+
- [Activity](../activity.md)
|
|
2505
|
+
- [Worklog](../worklog/README.md)
|
|
2506
|
+
`;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
function worklogRecord(dir, title, detected, opts) {
|
|
2510
|
+
const branch = gitBranch(dir);
|
|
2511
|
+
const changedFiles = opts.fromGit ? gitStatusFiles(dir) : [];
|
|
2512
|
+
return `# ${title}
|
|
2513
|
+
|
|
2514
|
+
actor: ${detected.actor}
|
|
2515
|
+
actor_source: ${detected.source}
|
|
2516
|
+
branch: ${branch}
|
|
2517
|
+
status: ${opts.status}
|
|
2518
|
+
created: ${nowISO()}
|
|
2519
|
+
|
|
2520
|
+
## Summary
|
|
2521
|
+
|
|
2522
|
+
${opts.body ? `- ${opts.body}` : '_1-3 bullets only. Keep this as a short receipt, not a report._'}
|
|
2523
|
+
|
|
2524
|
+
## Changed Files
|
|
2525
|
+
|
|
2526
|
+
${changedFiles.length ? changedFiles.map(file => `- \`${file}\``).join('\n') : '_None detected. Use `memoc work "<title>" --from-git` after editing files to prefill this section._'}
|
|
2527
|
+
|
|
2528
|
+
## Verification
|
|
2529
|
+
|
|
2530
|
+
_Commands run or checks not run. Keep to 1-3 bullets._
|
|
2531
|
+
|
|
2532
|
+
## Follow-up
|
|
2533
|
+
|
|
2534
|
+
_None._
|
|
2535
|
+
|
|
2536
|
+
## Related
|
|
2537
|
+
|
|
2538
|
+
- [Activity](../../../activity.md)
|
|
2539
|
+
- [Worklog](../../README.md)
|
|
2540
|
+
- [Actor](../../../actors/${detected.actor}.md)
|
|
2541
|
+
`;
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
function writeActivityIndexes(dir, recentFiles) {
|
|
2545
|
+
const activityPath = path.join(dir, '.memoc', 'activity.md');
|
|
2546
|
+
const worklogReadme = path.join(dir, '.memoc', 'worklog', 'README.md');
|
|
2547
|
+
const actorsReadme = path.join(dir, '.memoc', 'actors', 'README.md');
|
|
2548
|
+
const rows = recentFiles.map(fp => {
|
|
2549
|
+
const src = safeRead(fp);
|
|
2550
|
+
const title = markdownTitle(src, path.basename(fp, '.md'));
|
|
2551
|
+
const actor = (src.match(/^actor:\s*(.+)$/m) || [])[1] || 'unknown';
|
|
2552
|
+
const status = (src.match(/^status:\s*(.+)$/m) || [])[1] || 'unknown';
|
|
2553
|
+
return { fp, title, actor, status };
|
|
2554
|
+
});
|
|
2555
|
+
const activityItems = rows.length
|
|
2556
|
+
? rows.map(row => `- [${row.title}](${pathRelativeMarkdown(path.join(dir, '.memoc'), row.fp).replace(/^\.\//, '')}) — ${row.actor} ${row.status}.`).join('\n')
|
|
2557
|
+
: '_None yet._';
|
|
2558
|
+
write(activityPath, `# Activity
|
|
2559
|
+
|
|
2560
|
+
Generated shared activity index for memoc work logs.
|
|
2561
|
+
|
|
2562
|
+
Last generated: ${nowISO()}
|
|
2563
|
+
|
|
2564
|
+
## Recent Work
|
|
2565
|
+
|
|
2566
|
+
${activityItems}
|
|
2567
|
+
|
|
2568
|
+
## Related
|
|
2569
|
+
|
|
2570
|
+
- [Actors](actors/README.md)
|
|
2571
|
+
- [Worklog](worklog/README.md)
|
|
2572
|
+
`);
|
|
2573
|
+
|
|
2574
|
+
const worklogItems = rows.length
|
|
2575
|
+
? rows.map(row => `- [${row.title}](${pathRelativeMarkdown(path.join(dir, '.memoc', 'worklog'), row.fp).replace(/^\.\//, '')}) — ${row.actor} ${row.status}.`).join('\n')
|
|
2576
|
+
: '_None yet._';
|
|
2577
|
+
write(worklogReadme, `# Worklog
|
|
2578
|
+
|
|
2579
|
+
Generated index of conflict-light per-actor work records.
|
|
2580
|
+
|
|
2581
|
+
Last generated: ${nowISO()}
|
|
2582
|
+
|
|
2583
|
+
## Layout
|
|
2584
|
+
|
|
2585
|
+
\`\`\`text
|
|
2586
|
+
worklog/<actor>/YYYY-MM/YYYYMMDDTHHMM-title.md
|
|
2587
|
+
\`\`\`
|
|
2588
|
+
|
|
2589
|
+
## Rules
|
|
2590
|
+
|
|
2591
|
+
- Prefer creating new worklog files over appending shared core memory files.
|
|
2592
|
+
- Keep worklog entries short: 1-3 summary bullets, key files, verification.
|
|
2593
|
+
|
|
2594
|
+
## Recent Work
|
|
2595
|
+
|
|
2596
|
+
${worklogItems}
|
|
2597
|
+
`);
|
|
2598
|
+
|
|
2599
|
+
const actorFiles = listMarkdownFiles(path.join(dir, '.memoc', 'actors'))
|
|
2600
|
+
.filter(fp => path.basename(fp) !== 'README.md')
|
|
2601
|
+
.sort();
|
|
2602
|
+
const actorItems = actorFiles.length
|
|
2603
|
+
? actorFiles.map(fp => `- [${markdownTitle(safeRead(fp), path.basename(fp, '.md'))}](${path.basename(fp)})`).join('\n')
|
|
2604
|
+
: '_None yet. Use `memoc actor set <name>` or `memoc work "<title>"`._';
|
|
2605
|
+
write(actorsReadme, `# Actors
|
|
2606
|
+
|
|
2607
|
+
Generated actor index for this shared repo.
|
|
2608
|
+
|
|
2609
|
+
## Actor Detection
|
|
2610
|
+
|
|
2611
|
+
1. \`MEMOC_ACTOR\`
|
|
2612
|
+
2. \`.memoc/local/actor\` set by \`memoc actor set <name>\`
|
|
2613
|
+
3. \`git config user.name\`
|
|
2614
|
+
4. \`git config user.email\`
|
|
2615
|
+
5. OS username
|
|
2616
|
+
|
|
2617
|
+
\`.memoc/local/\` is ignored by git so each machine can keep its own actor setting.
|
|
2618
|
+
|
|
2619
|
+
## Actors
|
|
2620
|
+
|
|
2621
|
+
${actorItems}
|
|
2622
|
+
`);
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2165
2625
|
// ═══════════════════════════════════════════════════════════════════
|
|
2166
2626
|
// WIKI OPERATIONS — lint, ingest, and durable topic notes
|
|
2167
2627
|
// ═══════════════════════════════════════════════════════════════════
|
|
@@ -2285,8 +2745,6 @@ function runIngest(dir) {
|
|
|
2285
2745
|
addWikiListItem(path.join(dir, '.memoc', 'wiki', 'sources.md'), 'Source Records', pathRelativeMarkdown(path.join(dir, '.memoc', 'wiki'), sourcePath), title, 'needs synthesis');
|
|
2286
2746
|
addWikiListItem(path.join(dir, '.memoc', 'wiki', 'sources', 'README.md'), 'Source Records', path.basename(sourcePath), title, 'source record');
|
|
2287
2747
|
addWikiListItem(path.join(dir, '.memoc', 'wiki', 'index.md'), 'Pages', pathRelativeMarkdown(path.join(dir, '.memoc', 'wiki'), sourcePath), title, 'source record');
|
|
2288
|
-
appendMemocLog(dir, `ingest | Added source record ${normRel(dir, sourcePath)} from ${isUrl ? target : normRel(dir, path.resolve(dir, target))}.`);
|
|
2289
|
-
|
|
2290
2748
|
console.log('\n memoc ingest\n');
|
|
2291
2749
|
console.log(` Source record ${normRel(dir, sourcePath)}`);
|
|
2292
2750
|
console.log(` Raw reference ${rawDisplay}`);
|
|
@@ -2315,8 +2773,6 @@ function runNote(dir) {
|
|
|
2315
2773
|
ensureMemocFrontmatter(topicPath, dir);
|
|
2316
2774
|
addWikiListItem(path.join(dir, '.memoc', 'wiki', 'topics', 'README.md'), 'Topic Pages', path.basename(topicPath), title, 'topic note');
|
|
2317
2775
|
addWikiListItem(path.join(dir, '.memoc', 'wiki', 'index.md'), 'Saved Queries', pathRelativeMarkdown(path.join(dir, '.memoc', 'wiki'), topicPath), title, 'saved query/topic note');
|
|
2318
|
-
appendMemocLog(dir, `note | Saved wiki topic ${normRel(dir, topicPath)}.`);
|
|
2319
|
-
|
|
2320
2776
|
console.log('\n memoc note\n');
|
|
2321
2777
|
console.log(` Topic ${normRel(dir, topicPath)}`);
|
|
2322
2778
|
console.log(' Next Link related sources/topics, then run memoc lint-wiki.');
|
|
@@ -2334,7 +2790,9 @@ function ensureMemocBase(dir) {
|
|
|
2334
2790
|
[path.join(memDir, 'raw/README.md'), tplRawReadme],
|
|
2335
2791
|
[path.join(memDir, 'raw/files/README.md'), tplRawFilesReadme],
|
|
2336
2792
|
[path.join(memDir, 'raw/urls/README.md'), tplRawUrlsReadme],
|
|
2337
|
-
[path.join(memDir, '
|
|
2793
|
+
[path.join(memDir, 'activity.md'), tplActivity],
|
|
2794
|
+
[path.join(memDir, 'actors/README.md'), tplActorsReadme],
|
|
2795
|
+
[path.join(memDir, 'worklog/README.md'), tplWorklogReadme],
|
|
2338
2796
|
[path.join(memDir, '00-agent-index.md'), () => tplAgentIndex(p)],
|
|
2339
2797
|
];
|
|
2340
2798
|
for (const [fp, tpl] of files) ensure(fp, tpl());
|
|
@@ -2488,12 +2946,6 @@ function addWikiListItem(filePath, heading, link, title, note) {
|
|
|
2488
2946
|
write(filePath, src.replace(re, `$1${replacementBody}`));
|
|
2489
2947
|
}
|
|
2490
2948
|
|
|
2491
|
-
function appendMemocLog(dir, text) {
|
|
2492
|
-
const fp = path.join(dir, '.memoc', 'log.md');
|
|
2493
|
-
ensure(fp, tplLog());
|
|
2494
|
-
fs.appendFileSync(fp, `\n## [${nowISO()}] ${text}\n`, 'utf8');
|
|
2495
|
-
}
|
|
2496
|
-
|
|
2497
2949
|
// ═══════════════════════════════════════════════════════════════════
|
|
2498
2950
|
// SEARCH
|
|
2499
2951
|
// ═══════════════════════════════════════════════════════════════════
|
|
@@ -2703,7 +3155,7 @@ function searchPriority(file, scope = 'memory') {
|
|
|
2703
3155
|
'.memoc/04-handoff.md',
|
|
2704
3156
|
'.memoc/06-project-rules.md',
|
|
2705
3157
|
'.memoc/03-decisions.md',
|
|
2706
|
-
'.memoc/
|
|
3158
|
+
'.memoc/activity.md',
|
|
2707
3159
|
'AGENTS.md',
|
|
2708
3160
|
'CLAUDE.md',
|
|
2709
3161
|
'llms.txt',
|
|
@@ -2737,7 +3189,7 @@ function runTokens(dir) {
|
|
|
2737
3189
|
['03-decisions.md', path.join(memDir, '03-decisions.md')],
|
|
2738
3190
|
['04-handoff.md', path.join(memDir, '04-handoff.md')],
|
|
2739
3191
|
['06-project-rules.md', path.join(memDir, '06-project-rules.md')],
|
|
2740
|
-
['
|
|
3192
|
+
['activity.md', path.join(memDir, 'activity.md')],
|
|
2741
3193
|
];
|
|
2742
3194
|
|
|
2743
3195
|
console.log('\n memoc tokens\n');
|
|
@@ -2770,13 +3222,62 @@ function runTokens(dir) {
|
|
|
2770
3222
|
const summaryContent = read(path.join(memDir, 'session-summary.md'));
|
|
2771
3223
|
const summaryBytes = Buffer.byteLength(summaryContent, 'utf8');
|
|
2772
3224
|
if (summaryBytes > 800) {
|
|
2773
|
-
console.log(`\n ⚠ session-summary.md is ${summaryBytes}B — recommended <800B. Run \`memoc trim-summary\`, then move completed history to
|
|
3225
|
+
console.log(`\n ⚠ session-summary.md is ${summaryBytes}B — recommended <800B. Run \`memoc trim-summary\`, then move completed history to worklog and resume details to 04-handoff.md.`);
|
|
3226
|
+
}
|
|
3227
|
+
console.log();
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
3231
|
+
// DOCTOR — quick health checks for shared memoc repos
|
|
3232
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
3233
|
+
|
|
3234
|
+
function runDoctor(dir) {
|
|
3235
|
+
const issues = [];
|
|
3236
|
+
const warnings = [];
|
|
3237
|
+
const memDir = path.join(dir, '.memoc');
|
|
3238
|
+
const summaryPath = path.join(memDir, 'session-summary.md');
|
|
3239
|
+
const summary = safeRead(summaryPath);
|
|
3240
|
+
if (!summary) issues.push('Missing .memoc/session-summary.md');
|
|
3241
|
+
else if (Buffer.byteLength(summary, 'utf8') > 800) warnings.push('session-summary.md exceeds 800B; run memoc trim-summary');
|
|
3242
|
+
|
|
3243
|
+
for (const fp of [
|
|
3244
|
+
path.join(dir, '.memoc', 'bin', 'memoc'),
|
|
3245
|
+
path.join(dir, '.memoc', 'bin', 'memoc.cmd'),
|
|
3246
|
+
path.join(dir, '.memoc', 'bin', 'memoc.ps1'),
|
|
3247
|
+
]) {
|
|
3248
|
+
const src = safeRead(fp);
|
|
3249
|
+
if (src && (/C:\\Users\\|\/Users\/[^/]+\/\.local\/share\/memoc\/runtime/.test(src))) {
|
|
3250
|
+
issues.push(`${normRel(dir, fp)} contains a user-specific runtime path; run memoc upgrade`);
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3254
|
+
for (const fp of collectMemocMarkdownFiles(dir)) {
|
|
3255
|
+
const src = safeRead(fp);
|
|
3256
|
+
const fenceCount = (src.match(/^---$/gm) || []).length;
|
|
3257
|
+
if (fenceCount > 2) warnings.push(`${normRel(dir, fp)} may have nested frontmatter; run memoc upgrade`);
|
|
3258
|
+
}
|
|
3259
|
+
|
|
3260
|
+
const actor = detectActor(dir);
|
|
3261
|
+
if (actor.actor === 'unknown') warnings.push('Actor could not be detected; run memoc actor set <name>');
|
|
3262
|
+
|
|
3263
|
+
console.log('\n memoc doctor\n');
|
|
3264
|
+
console.log(` Actor ${actor.actor} (${actor.source})`);
|
|
3265
|
+
console.log(` Issues ${issues.length}`);
|
|
3266
|
+
console.log(` Warnings ${warnings.length}`);
|
|
3267
|
+
if (issues.length) {
|
|
3268
|
+
console.log('\n Issues:');
|
|
3269
|
+
for (const issue of issues) console.log(` - ${issue}`);
|
|
3270
|
+
}
|
|
3271
|
+
if (warnings.length) {
|
|
3272
|
+
console.log('\n Warnings:');
|
|
3273
|
+
for (const warning of warnings.slice(0, 20)) console.log(` - ${warning}`);
|
|
2774
3274
|
}
|
|
3275
|
+
if (!issues.length && !warnings.length) console.log('\n Looks good.');
|
|
2775
3276
|
console.log();
|
|
2776
3277
|
}
|
|
2777
3278
|
|
|
2778
3279
|
// ═══════════════════════════════════════════════════════════════════
|
|
2779
|
-
// COMPRESS —
|
|
3280
|
+
// COMPRESS — legacy log.md archiver
|
|
2780
3281
|
// ═══════════════════════════════════════════════════════════════════
|
|
2781
3282
|
|
|
2782
3283
|
function runCompress(dir) {
|
|
@@ -2812,6 +3313,7 @@ function runCompress(dir) {
|
|
|
2812
3313
|
write(logPath, header.trimEnd() + '\n' + toKeep.join('') + '\n');
|
|
2813
3314
|
|
|
2814
3315
|
console.log(`\n memoc compress\n`);
|
|
3316
|
+
console.log(' Legacy command: new activity should use .memoc/worklog/ instead of log.md.');
|
|
2815
3317
|
console.log(` Archived ${toArchive.length} entries → .memoc/log-archive.md`);
|
|
2816
3318
|
console.log(` Kept ${toKeep.length} recent entries in log.md`);
|
|
2817
3319
|
const saved = Buffer.byteLength(toArchive.join(''), 'utf8');
|
|
@@ -2851,12 +3353,11 @@ function runTrimSummary(dir) {
|
|
|
2851
3353
|
: '# Session Summary Archive\n\nOlder oversized startup summaries moved by `memoc trim-summary`.\n';
|
|
2852
3354
|
fs.appendFileSync(archivePath, `${archiveHeader}\n## [${nowISO()}] archived summary (${beforeBytes}B)\n\n${src.trimEnd()}\n`, 'utf8');
|
|
2853
3355
|
write(summaryPath, compact);
|
|
2854
|
-
appendMemocLog(dir, `trim-summary | Archived oversized session summary (${beforeBytes}B → ${afterBytes}B).`);
|
|
2855
3356
|
|
|
2856
3357
|
console.log('\n memoc trim-summary\n');
|
|
2857
3358
|
console.log(` Archived .memoc/session-summary-archive.md`);
|
|
2858
3359
|
console.log(` Rewrote .memoc/session-summary.md (${beforeBytes}B → ${afterBytes}B)`);
|
|
2859
|
-
console.log(' Reminder Completed history belongs in
|
|
3360
|
+
console.log(' Reminder Completed history belongs in worklog; resume details belong in 04-handoff.md.');
|
|
2860
3361
|
console.log('\n Done.\n');
|
|
2861
3362
|
}
|
|
2862
3363
|
|
|
@@ -2866,7 +3367,7 @@ function compactSessionSummary(src) {
|
|
|
2866
3367
|
'# Session Summary',
|
|
2867
3368
|
`Last: ${nowISO()}`,
|
|
2868
3369
|
'Replace this file instead of appending to it. Keep total size <800B and each section ≤3 bullets.',
|
|
2869
|
-
'Completed history belongs in
|
|
3370
|
+
'Completed history belongs in actor worklogs; incomplete/risky resume detail belongs in `04-handoff.md`.',
|
|
2870
3371
|
'',
|
|
2871
3372
|
];
|
|
2872
3373
|
|
|
@@ -2980,8 +3481,12 @@ if (!cmd || cmd === '--help' || cmd === '-h' || cmd === 'help') {
|
|
|
2980
3481
|
console.log(' summary Print a tiny status/resume overview');
|
|
2981
3482
|
console.log(' tokens Estimate token cost of current memory files');
|
|
2982
3483
|
console.log(' trim-summary Archive and compact oversized session-summary.md');
|
|
2983
|
-
console.log(' compress
|
|
3484
|
+
console.log(' compress Legacy: archive old log.md entries');
|
|
2984
3485
|
console.log(' add <agent> Add entry file for a specific agent (run without args to list)');
|
|
3486
|
+
console.log(' actor [set <name>] Show or set the local memoc actor');
|
|
3487
|
+
console.log(' work "<title>" Create a conflict-light actor worklog entry');
|
|
3488
|
+
console.log(' activity List recent memoc worklog entries');
|
|
3489
|
+
console.log(' doctor Check common memoc health issues');
|
|
2985
3490
|
console.log(' search "<query>" Search memory/agent docs (use --snippets for line matches)');
|
|
2986
3491
|
console.log(' grep "<query>" Search project source/text files (use --snippets for line matches)');
|
|
2987
3492
|
console.log(' ingest <path|url> Create a raw/source record scaffold for wiki synthesis');
|
|
@@ -3005,6 +3510,10 @@ if (cmd === 'tokens') { runTokens(cwd); process.exit(0); }
|
|
|
3005
3510
|
if (cmd === 'trim-summary') { runTrimSummary(cwd); process.exit(0); }
|
|
3006
3511
|
if (cmd === 'compress') { runCompress(cwd); process.exit(0); }
|
|
3007
3512
|
if (cmd === 'add') { runAdd(cwd); process.exit(0); }
|
|
3513
|
+
if (cmd === 'actor') { runActor(cwd); process.exit(0); }
|
|
3514
|
+
if (cmd === 'work') { runWork(cwd); process.exit(0); }
|
|
3515
|
+
if (cmd === 'activity') { runActivity(cwd); process.exit(0); }
|
|
3516
|
+
if (cmd === 'doctor') { runDoctor(cwd); process.exit(0); }
|
|
3008
3517
|
if (cmd === 'search') { runSearch(cwd, 'memory'); process.exit(0); }
|
|
3009
3518
|
if (cmd === 'grep') { runSearch(cwd, 'project'); process.exit(0); }
|
|
3010
3519
|
if (cmd === 'ingest') { runIngest(cwd); process.exit(0); }
|