cumora 0.1.44 → 0.1.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +46 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -56,8 +56,17 @@ async function exists(p) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
async function ensureCommonHome(home) {
|
|
59
|
+
await mkdir(join(home, "memory"), { recursive: true });
|
|
59
60
|
await mkdir(join(home, "notes"), { recursive: true });
|
|
60
61
|
await mkdir(join(home, "workspace"), { recursive: true });
|
|
62
|
+
const memoryIndex = join(home, "memory", "MEMORY.md");
|
|
63
|
+
if (!await exists(memoryIndex)) {
|
|
64
|
+
await writeFile(
|
|
65
|
+
memoryIndex,
|
|
66
|
+
"# Memory index\n\nOne line per durable fact, pointing at the file that holds it:\n`- [Title](file.md) \u2014 one-line hook`\n\nWrite the fact itself in its own `memory/<topic>.md` file; keep this index short.\n",
|
|
67
|
+
"utf8"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
61
70
|
}
|
|
62
71
|
function spawnEngine(bin, args, { home, env, onLog, signal }) {
|
|
63
72
|
return new Promise((resolve, reject) => {
|
|
@@ -92,7 +101,13 @@ var PERSONA_HEADER = (p) => `# ${p.name}${p.role ? ` \u2014 ${p.role}` : ""}
|
|
|
92
101
|
You are **${p.name}**, a member of a team that collaborates in Cumora (a team chat).
|
|
93
102
|
This directory is your private home and your working directory \u2014 it persists
|
|
94
103
|
across wakes and is yours alone. Its layout:
|
|
95
|
-
- \`CLAUDE.md\` (this file)
|
|
104
|
+
- \`CLAUDE.md\` (this file) \u2014 always loaded each wake; keep it short.
|
|
105
|
+
- \`memory/\` \u2014 your durable memory. There is NO hidden memory store: to remember
|
|
106
|
+
something across wakes you MUST write it to a file here (e.g. \`memory/<topic>.md\`)
|
|
107
|
+
and add a one-line pointer in \`memory/MEMORY.md\`. Saying "I'll remember" without
|
|
108
|
+
writing a file means you will NOT remember. At the start of each wake, read
|
|
109
|
+
\`memory/MEMORY.md\` (and the files it points to) to recall what you know.
|
|
110
|
+
- \`notes/\` \u2014 scratch notes and drafts.
|
|
96
111
|
- \`.claude/skills/\` \u2014 your skills.
|
|
97
112
|
- \`workspace/\` \u2014 **put all project files and scratch here**: git clones, builds,
|
|
98
113
|
downloads, temp files. Always \`cd workspace\` (or use \`workspace/\u2026\` paths) for
|
|
@@ -332,7 +347,21 @@ var AgentRunner = class {
|
|
|
332
347
|
CUMORA_AGENT_ID: this.agent.id
|
|
333
348
|
};
|
|
334
349
|
}
|
|
335
|
-
|
|
350
|
+
/** Preload the memory index (memory/MEMORY.md) so it's ALWAYS in the wake
|
|
351
|
+
* prompt — the lightweight BYOA analog of the cloud agent's RAG memory
|
|
352
|
+
* preload. We inject only the small index; the agent opens detail files on
|
|
353
|
+
* demand. Capped so a runaway index can't blow up the prompt. */
|
|
354
|
+
async memoryDigest() {
|
|
355
|
+
try {
|
|
356
|
+
const txt = (await readFile(join2(this.home, "memory", "MEMORY.md"), "utf8")).trim();
|
|
357
|
+
if (!txt) return "";
|
|
358
|
+
return txt.length > 4e3 ? `${txt.slice(0, 4e3)}
|
|
359
|
+
\u2026(truncated \u2014 cat the file for the rest)` : txt;
|
|
360
|
+
} catch {
|
|
361
|
+
return "";
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
prompt(memoryDigest) {
|
|
336
365
|
return `You've been woken because there's new activity in your Cumora conversations.
|
|
337
366
|
|
|
338
367
|
Use the \`cumora\` tool to catch up and respond:
|
|
@@ -340,6 +369,19 @@ Use the \`cumora\` tool to catch up and respond:
|
|
|
340
369
|
2. \`cumora messages <conversationId> --tail 30\` \u2014 read the relevant thread(s)
|
|
341
370
|
3. \`cumora reply <conversationId> '<text>'\` \u2014 reply, in your own voice, only where you add something
|
|
342
371
|
|
|
372
|
+
` + (memoryDigest ? `Your memory index (\`memory/MEMORY.md\`) \u2014 consult before replying; \`cat memory/<file>\` for any detail it points to:
|
|
373
|
+
${memoryDigest}
|
|
374
|
+
|
|
375
|
+
` : ``) + `Memory is your ONLY durable store. When the operator asks you to remember something (or you learn a durable fact), you MUST write it to a file under \`memory/\` and add a one-line pointer in \`memory/MEMORY.md\` \u2014 actually run the write. Saying "got it, I'll remember" does NOT persist anything.
|
|
376
|
+
|
|
377
|
+
Mentions: to notify or address a specific teammate, write @<their-id> using their participant id (the short id shown in \`cumora messages\` and \`cumora participants\`), NOT their display name. "@Alex P" does nothing; "@alex-3f9a" actually pings them. Run \`cumora participants\` if you need to look up an id.
|
|
378
|
+
|
|
379
|
+
Know when to stay quiet \u2014 this is how teams avoid endless back-and-forth:
|
|
380
|
+
- Read the WHOLE thread first, including your own past replies. If you've already made your point, don't repeat it. Saying nothing is better than echoing.
|
|
381
|
+
- Only reply where you genuinely add something the thread doesn't already have. Don't reply just to acknowledge, agree, thank, or sign off ("sounds good", "great idea", "\u{1F44D}").
|
|
382
|
+
- Be especially restrained with OTHER AGENTS: do not keep a conversation going with a peer agent out of politeness. If the useful exchange is done, let it end \u2014 silence ends the loop, another reply restarts it.
|
|
383
|
+
- If a teammate already has it covered, or nothing genuinely needs YOU specifically, do nothing and stop.
|
|
384
|
+
|
|
343
385
|
Privacy: stay inside your home directory. Never read files outside it, and never expose the contents or paths of anything outside your home in Cumora \u2014 this machine holds the operator's private files.
|
|
344
386
|
|
|
345
387
|
If nothing genuinely needs you, it's fine to do nothing and stop. When finished, stop.`;
|
|
@@ -358,6 +400,7 @@ If nothing genuinely needs you, it's fine to do nothing and stop. When finished,
|
|
|
358
400
|
await this.ensureToken();
|
|
359
401
|
const token = this.token;
|
|
360
402
|
const convo = this.lastWakeConvo;
|
|
403
|
+
this.lastWakeConvo = null;
|
|
361
404
|
await runtimeBest(this.cfg.serverUrl, "/status", token, { status: "thinking" });
|
|
362
405
|
let typingTimer;
|
|
363
406
|
if (convo) {
|
|
@@ -375,7 +418,7 @@ If nothing genuinely needs you, it's fine to do nothing and stop. When finished,
|
|
|
375
418
|
try {
|
|
376
419
|
const result = await this.adapter.run({
|
|
377
420
|
home: this.home,
|
|
378
|
-
prompt: this.prompt(),
|
|
421
|
+
prompt: this.prompt(await this.memoryDigest()),
|
|
379
422
|
env: this.engineEnv(),
|
|
380
423
|
model: this.agent.model,
|
|
381
424
|
fastModel: this.agent.fastModel,
|