agent-working-memory 0.7.15 → 0.7.17
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 +16 -0
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +2 -16
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/codex.d.ts.map +1 -1
- package/dist/adapters/codex.js +2 -11
- package/dist/adapters/codex.js.map +1 -1
- package/dist/adapters/common.d.ts +18 -0
- package/dist/adapters/common.d.ts.map +1 -1
- package/dist/adapters/common.js +177 -15
- package/dist/adapters/common.js.map +1 -1
- package/dist/adapters/cursor.d.ts.map +1 -1
- package/dist/adapters/cursor.js +2 -15
- package/dist/adapters/cursor.js.map +1 -1
- package/dist/adapters/http.d.ts.map +1 -1
- package/dist/adapters/http.js +6 -12
- package/dist/adapters/http.js.map +1 -1
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +45 -57
- package/dist/api/routes.js.map +1 -1
- package/dist/cli.js +103 -103
- package/dist/core/write-pipeline.d.ts +120 -0
- package/dist/core/write-pipeline.d.ts.map +1 -0
- package/dist/core/write-pipeline.js +236 -0
- package/dist/core/write-pipeline.js.map +1 -0
- package/dist/engine/activation.d.ts.map +1 -1
- package/dist/engine/activation.js +5 -11
- package/dist/engine/activation.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp.js +107 -178
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/claude-code.ts +2 -18
- package/src/adapters/codex.ts +2 -12
- package/src/adapters/common.ts +191 -15
- package/src/adapters/cursor.ts +2 -17
- package/src/adapters/http.ts +5 -12
- package/src/api/routes.ts +714 -723
- package/src/cli.ts +719 -719
- package/src/core/write-pipeline.ts +343 -0
- package/src/engine/activation.ts +5 -11
- package/src/index.ts +212 -212
- package/src/mcp.ts +1121 -1192
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
12
12
|
import { join, dirname, basename } from 'node:path';
|
|
13
13
|
import type { CLIAdapter, SetupContext, DiagnosticResult } from './types.js';
|
|
14
|
-
import { resolveMcpCommand, homedir, AWM_INSTRUCTION_CONTENT } from './common.js';
|
|
14
|
+
import { resolveMcpCommand, homedir, AWM_INSTRUCTION_CONTENT, upsertAwmSection } from './common.js';
|
|
15
15
|
|
|
16
16
|
const adapter: CLIAdapter = {
|
|
17
17
|
id: 'claude-code',
|
|
@@ -56,24 +56,8 @@ const adapter: CLIAdapter = {
|
|
|
56
56
|
|
|
57
57
|
if (skip) return 'CLAUDE.md: skipped (--no-instructions)';
|
|
58
58
|
|
|
59
|
-
// Ensure parent directory exists
|
|
60
|
-
const dir = dirname(claudeMdPath);
|
|
61
|
-
if (!existsSync(dir)) {
|
|
62
|
-
mkdirSync(dir, { recursive: true });
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (existsSync(claudeMdPath)) {
|
|
66
|
-
const content = readFileSync(claudeMdPath, 'utf-8');
|
|
67
|
-
if (content.includes('## Memory (AWM)')) {
|
|
68
|
-
return 'CLAUDE.md: already has AWM section (skipped)';
|
|
69
|
-
}
|
|
70
|
-
writeFileSync(claudeMdPath, content.trimEnd() + '\n\n' + AWM_INSTRUCTION_CONTENT);
|
|
71
|
-
return 'CLAUDE.md: appended AWM workflow section';
|
|
72
|
-
}
|
|
73
|
-
|
|
74
59
|
const title = ctx.isGlobal ? '# Global Instructions' : `# ${basename(ctx.cwd)}`;
|
|
75
|
-
|
|
76
|
-
return 'CLAUDE.md: created with AWM workflow section';
|
|
60
|
+
return upsertAwmSection(claudeMdPath, AWM_INSTRUCTION_CONTENT, { titleIfNew: title });
|
|
77
61
|
},
|
|
78
62
|
|
|
79
63
|
writeHooks(ctx: SetupContext, skip: boolean): string {
|
package/src/adapters/codex.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
12
12
|
import { join, dirname, basename } from 'node:path';
|
|
13
13
|
import type { CLIAdapter, SetupContext, DiagnosticResult } from './types.js';
|
|
14
|
-
import { resolveMcpCommand, homedir, AWM_INSTRUCTION_CONTENT } from './common.js';
|
|
14
|
+
import { resolveMcpCommand, homedir, AWM_INSTRUCTION_CONTENT, upsertAwmSection } from './common.js';
|
|
15
15
|
|
|
16
16
|
// ─── Minimal TOML read/write ──────────────────────────
|
|
17
17
|
// Only handles the flat structure Codex uses: [section.name] with key = "value" or key = ["array"]
|
|
@@ -165,18 +165,8 @@ const adapter: CLIAdapter = {
|
|
|
165
165
|
|
|
166
166
|
if (skip) return 'AGENTS.md: skipped (--no-instructions)';
|
|
167
167
|
|
|
168
|
-
if (existsSync(agentsMdPath)) {
|
|
169
|
-
const content = readFileSync(agentsMdPath, 'utf-8');
|
|
170
|
-
if (content.includes('## Memory (AWM)')) {
|
|
171
|
-
return 'AGENTS.md: already has AWM section (skipped)';
|
|
172
|
-
}
|
|
173
|
-
writeFileSync(agentsMdPath, content.trimEnd() + '\n\n' + AWM_INSTRUCTION_CONTENT);
|
|
174
|
-
return 'AGENTS.md: appended AWM workflow section';
|
|
175
|
-
}
|
|
176
|
-
|
|
177
168
|
const title = `# ${basename(ctx.cwd)} — Agent Instructions`;
|
|
178
|
-
|
|
179
|
-
return 'AGENTS.md: created with AWM workflow section';
|
|
169
|
+
return upsertAwmSection(agentsMdPath, AWM_INSTRUCTION_CONTENT, { titleIfNew: title });
|
|
180
170
|
},
|
|
181
171
|
|
|
182
172
|
writeHooks(_ctx: SetupContext, _skip: boolean): string {
|
package/src/adapters/common.ts
CHANGED
|
@@ -140,15 +140,96 @@ export function homedir(): string {
|
|
|
140
140
|
* Core AWM instruction snippet — shared across all adapters.
|
|
141
141
|
* Each adapter wraps this in the appropriate file format.
|
|
142
142
|
*/
|
|
143
|
+
/**
|
|
144
|
+
* Upsert the AWM section into an instruction file (CLAUDE.md, AGENTS.md, .cursorrules).
|
|
145
|
+
*
|
|
146
|
+
* Behavior:
|
|
147
|
+
* - File doesn't exist -> create with title + AWM_INSTRUCTION_CONTENT
|
|
148
|
+
* - Section absent -> append
|
|
149
|
+
* - Section present + identical -> skip
|
|
150
|
+
* - Section present + stale -> REPLACE in place, preserve content above/below
|
|
151
|
+
*
|
|
152
|
+
* Section is bounded by `## Memory (AWM)` (with optional trailing modifier) at the
|
|
153
|
+
* start, and the next `## ` heading or EOF at the end.
|
|
154
|
+
*
|
|
155
|
+
* Returns a short human-readable status string for the setup command output.
|
|
156
|
+
*/
|
|
157
|
+
export function upsertAwmSection(
|
|
158
|
+
filePath: string,
|
|
159
|
+
newContent: string,
|
|
160
|
+
options: { titleIfNew?: string; suffix?: string } = {},
|
|
161
|
+
): string {
|
|
162
|
+
const fname = basename(filePath);
|
|
163
|
+
const suffix = options.suffix ?? '';
|
|
164
|
+
|
|
165
|
+
if (!existsSync(filePath)) {
|
|
166
|
+
const title = options.titleIfNew ?? `# ${basename(dirname(filePath))}`;
|
|
167
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
168
|
+
writeFileSync(filePath, `${title}\n\n${newContent}${suffix}`);
|
|
169
|
+
return `${fname}: created with AWM workflow section`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const existing = readFileSync(filePath, 'utf-8');
|
|
173
|
+
|
|
174
|
+
// Find section bounds: `## Memory (AWM)` (possibly with ` — MANDATORY` etc.) until next `## ` or EOF
|
|
175
|
+
const startRegex = /^## Memory \(AWM\)[^\n]*$/m;
|
|
176
|
+
const startMatch = startRegex.exec(existing);
|
|
177
|
+
|
|
178
|
+
if (!startMatch) {
|
|
179
|
+
// Section not present — append
|
|
180
|
+
writeFileSync(filePath, existing.trimEnd() + '\n\n' + newContent + suffix);
|
|
181
|
+
return `${fname}: appended AWM workflow section`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Find end: next `## ` heading after the section start, or EOF
|
|
185
|
+
const afterStart = startMatch.index + startMatch[0].length;
|
|
186
|
+
const nextHeadingRegex = /^## (?!Memory \(AWM\))/m;
|
|
187
|
+
nextHeadingRegex.lastIndex = afterStart;
|
|
188
|
+
const tail = existing.slice(afterStart);
|
|
189
|
+
const nextMatch = nextHeadingRegex.exec(tail);
|
|
190
|
+
const sectionEnd = nextMatch ? afterStart + nextMatch.index : existing.length;
|
|
191
|
+
|
|
192
|
+
const currentSection = existing.slice(startMatch.index, sectionEnd).trimEnd();
|
|
193
|
+
const desiredSection = (newContent + suffix).trimEnd();
|
|
194
|
+
|
|
195
|
+
if (currentSection === desiredSection) {
|
|
196
|
+
return `${fname}: AWM section already up-to-date (skipped)`;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const before = existing.slice(0, startMatch.index).trimEnd();
|
|
200
|
+
const after = existing.slice(sectionEnd).replace(/^\s*\n/, '');
|
|
201
|
+
const rebuilt =
|
|
202
|
+
(before ? before + '\n\n' : '') +
|
|
203
|
+
desiredSection +
|
|
204
|
+
(after ? '\n\n' + after : '\n');
|
|
205
|
+
writeFileSync(filePath, rebuilt);
|
|
206
|
+
return `${fname}: AWM section updated (preserved surrounding content)`;
|
|
207
|
+
}
|
|
208
|
+
|
|
143
209
|
export const AWM_INSTRUCTION_CONTENT = `
|
|
144
|
-
## Memory (AWM)
|
|
145
|
-
|
|
210
|
+
## Memory (AWM) — MANDATORY
|
|
211
|
+
|
|
212
|
+
**AWM is THE memory system.** Use it via the \`agent-working-memory\` MCP server
|
|
213
|
+
(preferred) or HTTP at \`http://127.0.0.1:8400\` (fallback). The file-based
|
|
214
|
+
auto-memory at \`~/.claude/projects/.../memory/*.md\` is a LEGACY bootstrap path —
|
|
215
|
+
**do not write new memories to it.** All persistent knowledge goes through AWM.
|
|
146
216
|
|
|
147
|
-
|
|
148
|
-
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
217
|
+
If MCP tools aren't loaded at session start, use ToolSearch with
|
|
218
|
+
\`select:mcp__agent-working-memory__memory_recall,mcp__agent-working-memory__memory_write\`
|
|
219
|
+
to load them. If the MCP server isn't responsive, restart with \`/mcp\` or use
|
|
220
|
+
the HTTP endpoints (\`POST /memory/write-batch\`, \`POST /memory/activate\`)
|
|
221
|
+
directly — but **DO NOT fall back to markdown files**. Files drift the moment
|
|
222
|
+
you write them; AWM stays current because every agent reads + writes the same store.
|
|
223
|
+
|
|
224
|
+
### Lifecycle (always do these, in this order)
|
|
225
|
+
1. **Session start**: call \`memory_restore\` to recover previous context.
|
|
226
|
+
2. **Starting a task**: call \`memory_task_begin\` (checkpoints + recalls relevant memories).
|
|
227
|
+
3. **During work**: call \`memory_recall\` BEFORE stating any fact, BEFORE searching
|
|
228
|
+
the filesystem, BEFORE making architectural decisions. Recall is ~300ms — cheaper
|
|
229
|
+
than one filesystem search.
|
|
230
|
+
4. **As you learn things**: call \`memory_write\` proactively. Don't batch.
|
|
231
|
+
5. **Finishing a task**: call \`memory_task_end\` with a summary.
|
|
232
|
+
6. **Auto-checkpoint** is handled by hooks (compaction, session-end, 15-min timer). No action needed.
|
|
152
233
|
|
|
153
234
|
### Write memory when:
|
|
154
235
|
- A project decision is made or changed
|
|
@@ -158,13 +239,62 @@ You have persistent memory via the agent-working-memory MCP server.
|
|
|
158
239
|
- A prior assumption is found to be wrong
|
|
159
240
|
- A significant piece of work is completed
|
|
160
241
|
|
|
161
|
-
###
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
-
|
|
166
|
-
|
|
167
|
-
|
|
242
|
+
### Writing for recall (the highest-leverage section)
|
|
243
|
+
A memory's recall quality is set the moment you write it. AWM is fast at
|
|
244
|
+
finding what's findable — but if the write is shaped wrong, no retriever
|
|
245
|
+
can rescue it. Be slightly more verbose at the front than feels natural:
|
|
246
|
+
the first 1-2 sentences are what BM25, the embedding model, and concept
|
|
247
|
+
extraction all see most strongly.
|
|
248
|
+
|
|
249
|
+
- **Lead with the rule or fact.** Don't open with context or backstory.
|
|
250
|
+
"Don't mock the database in integration tests." comes first; the reason
|
|
251
|
+
comes second. Recall scans the head of the body, not the tail.
|
|
252
|
+
- **Pick the most specific topic.** Not \`auth\` — \`auth-magic-link-rate-limit\`.
|
|
253
|
+
Topic is a hard filter at recall time. Generic topics hide the memory in
|
|
254
|
+
a noisy bucket where it competes with everything else in the area.
|
|
255
|
+
- **Include 2+ retrievable identifiers.** File paths, function names, table
|
|
256
|
+
columns, ticket IDs, exact error strings, the literal terms a future query
|
|
257
|
+
will use. \`AccountingService.closePeriod()\` beats "the accounting code."
|
|
258
|
+
\`tblMemberDetails.activation_date\` beats "the activation column."
|
|
259
|
+
\`schema/072-period-close.sql\` beats "the migration."
|
|
260
|
+
- **Write in the vocabulary of the future question.** When you imagine asking
|
|
261
|
+
this in three months, what nouns will you use? Use those nouns. Don't
|
|
262
|
+
paraphrase the user's domain language into your own neutral summary.
|
|
263
|
+
- **Reserve canonical for stable invariants.** Decisions, requirements,
|
|
264
|
+
hard facts, cross-agent shared context. Working class (default) is correct
|
|
265
|
+
for findings, observations, and progress notes. The canonical floor is
|
|
266
|
+
0.7 salience — overusing it pollutes the canonical layer and the floor
|
|
267
|
+
loses meaning.
|
|
268
|
+
- **Include the why for feedback memories.** A rule without a reason can't
|
|
269
|
+
be applied to edge cases. "Don't mock the database" is brittle. "Don't
|
|
270
|
+
mock the database — last quarter mocked tests masked a broken migration"
|
|
271
|
+
is portable to new situations.
|
|
272
|
+
|
|
273
|
+
### Tagging rules (REQUIRED — AWM's prefix-tag retrieval boost depends on these)
|
|
274
|
+
|
|
275
|
+
Every \`memory_write\` should pass these structured fields. AWM stores each as a
|
|
276
|
+
prefix-tag like \`proj=\`, \`topic=\`, \`intent=\`, etc. and uses them for BM25
|
|
277
|
+
and entity-bridge boosts at recall time.
|
|
278
|
+
|
|
279
|
+
| Field | Required? | Format | Example |
|
|
280
|
+
|---|---|---|---|
|
|
281
|
+
| \`project\` | **YES** | one short word matching the current project | \`"EquiHub"\`, \`"AWM"\`, \`"USEA-Agent"\` |
|
|
282
|
+
| \`topic\` | **YES** | one or more lowercase area words | \`"database-migration"\`, \`"benchmarks"\` |
|
|
283
|
+
| \`intent\` | **YES** | one of: \`decision\` / \`finding\` / \`todo\` / \`question\` / \`context\` | \`"finding"\` |
|
|
284
|
+
| \`confidence_level\` | **YES** | \`verified\` (tested) / \`observed\` (read in code) / \`assumed\` (reasoning) | \`"verified"\` |
|
|
285
|
+
| \`source\` | recommended | \`code-reading\` / \`debugging\` / \`discussion\` / \`research\` / \`testing\` / \`observation\` | \`"testing"\` |
|
|
286
|
+
| \`memory_class\` | when stable | \`canonical\` (source-of-truth, 0.7 floor, never staged) / \`working\` (default) / \`ephemeral\` | \`"canonical"\` |
|
|
287
|
+
| \`session_id\` | recommended | current conversation ID for entity-bridge boost | autogenerated |
|
|
288
|
+
| \`tags\` | when applicable | extra prefix-tags for IDs and dates | \`["ticket=18360", "date=2026-05-11"]\` |
|
|
289
|
+
|
|
290
|
+
**Always add identifier tags when present in the content:**
|
|
291
|
+
- \`ticket=<id>\` for Freshdesk tickets
|
|
292
|
+
- \`member=<id>\` for member IDs
|
|
293
|
+
- \`horse=<id>\` for horse_member_id
|
|
294
|
+
- \`usef=<id>\` for USEF lookups
|
|
295
|
+
- \`date=YYYY-MM-DD\` for temporal anchoring (ISO format)
|
|
296
|
+
- \`person=<Name>\` for stakeholder quotes / decisions
|
|
297
|
+
- \`version=<X.Y.Z>\` for release-specific findings
|
|
168
298
|
|
|
169
299
|
### Memory classes (controls how strictly the salience filter gates the write)
|
|
170
300
|
- \`memory_class: canonical\` — source-of-truth memories. Floor 0.7 salience, never staged.
|
|
@@ -202,7 +332,25 @@ If neither pattern applies and you want a memory to definitely survive, set
|
|
|
202
332
|
- Before refactoring or making architectural changes
|
|
203
333
|
- When a topic comes up that you might have prior context on
|
|
204
334
|
|
|
205
|
-
Recall is fast (~
|
|
335
|
+
Recall is fast (~300ms typical). Use it freely.
|
|
336
|
+
|
|
337
|
+
### Recall strategy (when one query isn't enough)
|
|
338
|
+
AWM's adaptive retrieval handles most query variations natively — synonym
|
|
339
|
+
expansion, multi-channel scoring, embedding + BM25 + reranker agreement.
|
|
340
|
+
A single recall is usually enough.
|
|
341
|
+
|
|
342
|
+
When it isn't:
|
|
343
|
+
- **If the first recall returns nothing or returns the wrong things, reformulate.**
|
|
344
|
+
Try a second query with different phrasing — synonyms, more specific nouns,
|
|
345
|
+
the exact identifier from the code rather than the conceptual name. Two or
|
|
346
|
+
three recalls cost less than one filesystem search.
|
|
347
|
+
- **Use the words a domain expert would use, not generic English.** "Period
|
|
348
|
+
close lock" not "accounting feature"; "magic link rate limit" not "auth issue."
|
|
349
|
+
- **For broad exploration, pass \`mode: "exploratory"\`** — wider candidate
|
|
350
|
+
pool, lower precision floor. For specific lookups, leave mode unset (auto).
|
|
351
|
+
- **Don't ensemble more than 3 reformulations.** If three different phrasings
|
|
352
|
+
return nothing, the memory probably isn't there — read the code instead of
|
|
353
|
+
burning more recalls.
|
|
206
354
|
|
|
207
355
|
### Keep memory fresh
|
|
208
356
|
- After recalling a memory, if you observe the real state is different → call
|
|
@@ -210,6 +358,34 @@ Recall is fast (~1s typical). Use it freely.
|
|
|
210
358
|
- After using a recalled memory: call \`memory_feedback\` (useful/not-useful) so the
|
|
211
359
|
activation engine learns what's valuable.
|
|
212
360
|
- If you discover a memory is factually wrong: \`memory_retract\` to remove it.
|
|
361
|
+
- **If you bypass AWM (file-memory, in-context notes, "I'll just remember"), the memory
|
|
362
|
+
drifts out of date. The system relies on you to keep it current. This is the #1
|
|
363
|
+
failure mode.**
|
|
364
|
+
|
|
365
|
+
### Example — good vs bad memory_write
|
|
366
|
+
|
|
367
|
+
**BAD** (no prefix tags, vague concept, can't be recalled by future queries):
|
|
368
|
+
\`\`\`
|
|
369
|
+
memory_write(
|
|
370
|
+
concept="found a bug",
|
|
371
|
+
content="The thing I was looking at was broken so I fixed it."
|
|
372
|
+
)
|
|
373
|
+
\`\`\`
|
|
374
|
+
|
|
375
|
+
**GOOD** (rich identifiers, structured metadata, prefix tags):
|
|
376
|
+
\`\`\`
|
|
377
|
+
memory_write(
|
|
378
|
+
concept="EquiHub period-close BLOCKED check missing server-side",
|
|
379
|
+
content="apps/web/app/(accounting)/accounting/period-close/page.tsx had client-only BLOCKED enforcement. Fixed by adding server-side check in AccountingService.closePeriod() per schema/072-period-close.sql. Without server-side check a malicious request could bypass via direct API call.",
|
|
380
|
+
project="EquiHub",
|
|
381
|
+
topic="accounting",
|
|
382
|
+
intent="finding",
|
|
383
|
+
confidence_level="verified",
|
|
384
|
+
source="debugging",
|
|
385
|
+
memory_class="canonical",
|
|
386
|
+
tags=["ticket=18360", "person=Robert", "date=2026-05-11", "topic=period-close", "topic=security"]
|
|
387
|
+
)
|
|
388
|
+
\`\`\`
|
|
213
389
|
|
|
214
390
|
### Also:
|
|
215
391
|
- To track work items: memory_task_add, memory_task_update, memory_task_list, memory_task_next
|
package/src/adapters/cursor.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
12
12
|
import { join, dirname, basename } from 'node:path';
|
|
13
13
|
import type { CLIAdapter, SetupContext, DiagnosticResult } from './types.js';
|
|
14
|
-
import { resolveMcpCommand, homedir, AWM_INSTRUCTION_CONTENT } from './common.js';
|
|
14
|
+
import { resolveMcpCommand, homedir, AWM_INSTRUCTION_CONTENT, upsertAwmSection } from './common.js';
|
|
15
15
|
|
|
16
16
|
const adapter: CLIAdapter = {
|
|
17
17
|
id: 'cursor',
|
|
@@ -54,22 +54,7 @@ const adapter: CLIAdapter = {
|
|
|
54
54
|
|
|
55
55
|
if (skip) return '.cursorrules: skipped (--no-instructions)';
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
if (!existsSync(dir)) {
|
|
59
|
-
mkdirSync(dir, { recursive: true });
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (existsSync(rulesPath)) {
|
|
63
|
-
const content = readFileSync(rulesPath, 'utf-8');
|
|
64
|
-
if (content.includes('## Memory (AWM)')) {
|
|
65
|
-
return '.cursorrules: already has AWM section (skipped)';
|
|
66
|
-
}
|
|
67
|
-
writeFileSync(rulesPath, content.trimEnd() + '\n\n' + AWM_INSTRUCTION_CONTENT);
|
|
68
|
-
return '.cursorrules: appended AWM workflow section';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
writeFileSync(rulesPath, AWM_INSTRUCTION_CONTENT);
|
|
72
|
-
return '.cursorrules: created with AWM workflow section';
|
|
57
|
+
return upsertAwmSection(rulesPath, AWM_INSTRUCTION_CONTENT, { titleIfNew: '# Agent Working Memory' });
|
|
73
58
|
},
|
|
74
59
|
|
|
75
60
|
writeHooks(_ctx: SetupContext, _skip: boolean): string {
|
package/src/adapters/http.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
12
12
|
import { join } from 'node:path';
|
|
13
13
|
import type { CLIAdapter, SetupContext, DiagnosticResult } from './types.js';
|
|
14
|
-
import { AWM_INSTRUCTION_CONTENT } from './common.js';
|
|
14
|
+
import { AWM_INSTRUCTION_CONTENT, upsertAwmSection } from './common.js';
|
|
15
15
|
|
|
16
16
|
const HTTP_ADDENDUM = `
|
|
17
17
|
### HTTP API (for tools without MCP support)
|
|
@@ -53,17 +53,10 @@ const adapter: CLIAdapter = {
|
|
|
53
53
|
|
|
54
54
|
if (skip) return 'AWM-INSTRUCTIONS.md: skipped (--no-instructions)';
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
writeFileSync(instrPath, content.trimEnd() + '\n\n' + AWM_INSTRUCTION_CONTENT + HTTP_ADDENDUM);
|
|
62
|
-
return 'AWM-INSTRUCTIONS.md: appended AWM + HTTP API section';
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
writeFileSync(instrPath, `# Agent Working Memory\n\n${AWM_INSTRUCTION_CONTENT}${HTTP_ADDENDUM}`);
|
|
66
|
-
return 'AWM-INSTRUCTIONS.md: created with AWM + HTTP API section';
|
|
56
|
+
return upsertAwmSection(instrPath, AWM_INSTRUCTION_CONTENT, {
|
|
57
|
+
titleIfNew: '# Agent Working Memory',
|
|
58
|
+
suffix: HTTP_ADDENDUM,
|
|
59
|
+
});
|
|
67
60
|
},
|
|
68
61
|
|
|
69
62
|
writeHooks(_ctx: SetupContext, _skip: boolean): string {
|