agent-working-memory 0.7.17 → 0.8.6

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 (188) hide show
  1. package/README.md +156 -15
  2. package/dist/adapters/common.d.ts.map +1 -1
  3. package/dist/adapters/common.js +289 -202
  4. package/dist/adapters/common.js.map +1 -1
  5. package/dist/adapters/http.js +22 -22
  6. package/dist/api/routes.d.ts +1 -1
  7. package/dist/api/routes.d.ts.map +1 -1
  8. package/dist/api/routes.js +258 -79
  9. package/dist/api/routes.js.map +1 -1
  10. package/dist/cli/migrate.d.ts +42 -0
  11. package/dist/cli/migrate.d.ts.map +1 -0
  12. package/dist/cli/migrate.js +268 -0
  13. package/dist/cli/migrate.js.map +1 -0
  14. package/dist/cli.js +147 -103
  15. package/dist/cli.js.map +1 -1
  16. package/dist/coordination/circuit-breaker.d.ts +24 -0
  17. package/dist/coordination/circuit-breaker.d.ts.map +1 -0
  18. package/dist/coordination/circuit-breaker.js +70 -0
  19. package/dist/coordination/circuit-breaker.js.map +1 -0
  20. package/dist/coordination/failure-modes.d.ts +21 -0
  21. package/dist/coordination/failure-modes.d.ts.map +1 -0
  22. package/dist/coordination/failure-modes.js +49 -0
  23. package/dist/coordination/failure-modes.js.map +1 -0
  24. package/dist/coordination/peer-decisions.js +7 -7
  25. package/dist/coordination/routes.d.ts.map +1 -1
  26. package/dist/coordination/routes.js +44 -1
  27. package/dist/coordination/routes.js.map +1 -1
  28. package/dist/coordination/schema.d.ts.map +1 -1
  29. package/dist/coordination/schema.js +18 -0
  30. package/dist/coordination/schema.js.map +1 -1
  31. package/dist/coordination/schemas.d.ts +9 -9
  32. package/dist/coordination/stale.d.ts +9 -1
  33. package/dist/coordination/stale.d.ts.map +1 -1
  34. package/dist/coordination/stale.js +53 -9
  35. package/dist/coordination/stale.js.map +1 -1
  36. package/dist/core/embeddings.d.ts +16 -10
  37. package/dist/core/embeddings.d.ts.map +1 -1
  38. package/dist/core/embeddings.js +54 -38
  39. package/dist/core/embeddings.js.map +1 -1
  40. package/dist/core/ml-worker-entry.d.ts +17 -0
  41. package/dist/core/ml-worker-entry.d.ts.map +1 -0
  42. package/dist/core/ml-worker-entry.js +193 -0
  43. package/dist/core/ml-worker-entry.js.map +1 -0
  44. package/dist/core/ml-worker.d.ts +59 -0
  45. package/dist/core/ml-worker.d.ts.map +1 -0
  46. package/dist/core/ml-worker.js +253 -0
  47. package/dist/core/ml-worker.js.map +1 -0
  48. package/dist/core/query-expander.d.ts +13 -15
  49. package/dist/core/query-expander.d.ts.map +1 -1
  50. package/dist/core/query-expander.js +48 -54
  51. package/dist/core/query-expander.js.map +1 -1
  52. package/dist/core/reranker.d.ts +9 -19
  53. package/dist/core/reranker.d.ts.map +1 -1
  54. package/dist/core/reranker.js +33 -35
  55. package/dist/core/reranker.js.map +1 -1
  56. package/dist/core/salience.d.ts +32 -5
  57. package/dist/core/salience.d.ts.map +1 -1
  58. package/dist/core/salience.js +201 -28
  59. package/dist/core/salience.js.map +1 -1
  60. package/dist/core/write-pipeline.d.ts +10 -2
  61. package/dist/core/write-pipeline.d.ts.map +1 -1
  62. package/dist/core/write-pipeline.js +218 -49
  63. package/dist/core/write-pipeline.js.map +1 -1
  64. package/dist/engine/activation.d.ts +2 -2
  65. package/dist/engine/activation.d.ts.map +1 -1
  66. package/dist/engine/activation.js +238 -115
  67. package/dist/engine/activation.js.map +1 -1
  68. package/dist/engine/confidence.d.ts +62 -0
  69. package/dist/engine/confidence.d.ts.map +1 -0
  70. package/dist/engine/confidence.js +100 -0
  71. package/dist/engine/confidence.js.map +1 -0
  72. package/dist/engine/connections.d.ts +47 -8
  73. package/dist/engine/connections.d.ts.map +1 -1
  74. package/dist/engine/connections.js +83 -22
  75. package/dist/engine/connections.js.map +1 -1
  76. package/dist/engine/consolidation-scheduler.d.ts +46 -10
  77. package/dist/engine/consolidation-scheduler.d.ts.map +1 -1
  78. package/dist/engine/consolidation-scheduler.js +170 -50
  79. package/dist/engine/consolidation-scheduler.js.map +1 -1
  80. package/dist/engine/consolidation.d.ts +16 -2
  81. package/dist/engine/consolidation.d.ts.map +1 -1
  82. package/dist/engine/consolidation.js +143 -44
  83. package/dist/engine/consolidation.js.map +1 -1
  84. package/dist/engine/eval.d.ts +2 -2
  85. package/dist/engine/eval.d.ts.map +1 -1
  86. package/dist/engine/eval.js +9 -9
  87. package/dist/engine/eval.js.map +1 -1
  88. package/dist/engine/eviction.d.ts +4 -4
  89. package/dist/engine/eviction.d.ts.map +1 -1
  90. package/dist/engine/eviction.js +15 -15
  91. package/dist/engine/eviction.js.map +1 -1
  92. package/dist/engine/retraction.d.ts +93 -5
  93. package/dist/engine/retraction.d.ts.map +1 -1
  94. package/dist/engine/retraction.js +238 -19
  95. package/dist/engine/retraction.js.map +1 -1
  96. package/dist/engine/staging.d.ts +1 -1
  97. package/dist/engine/staging.d.ts.map +1 -1
  98. package/dist/engine/staging.js +3 -3
  99. package/dist/engine/staging.js.map +1 -1
  100. package/dist/hooks/sidecar.d.ts +1 -1
  101. package/dist/hooks/sidecar.d.ts.map +1 -1
  102. package/dist/hooks/sidecar.js +4 -4
  103. package/dist/hooks/sidecar.js.map +1 -1
  104. package/dist/index.js +48 -31
  105. package/dist/index.js.map +1 -1
  106. package/dist/mcp.js +167 -141
  107. package/dist/mcp.js.map +1 -1
  108. package/dist/storage/factory.d.ts +55 -0
  109. package/dist/storage/factory.d.ts.map +1 -0
  110. package/dist/storage/factory.js +135 -0
  111. package/dist/storage/factory.js.map +1 -0
  112. package/dist/storage/pglite-schema.d.ts +20 -0
  113. package/dist/storage/pglite-schema.d.ts.map +1 -0
  114. package/dist/storage/pglite-schema.js +165 -0
  115. package/dist/storage/pglite-schema.js.map +1 -0
  116. package/dist/storage/pglite.d.ts +187 -0
  117. package/dist/storage/pglite.d.ts.map +1 -0
  118. package/dist/storage/pglite.js +1114 -0
  119. package/dist/storage/pglite.js.map +1 -0
  120. package/dist/storage/sqlite.d.ts +117 -0
  121. package/dist/storage/sqlite.d.ts.map +1 -1
  122. package/dist/storage/sqlite.js +357 -8
  123. package/dist/storage/sqlite.js.map +1 -1
  124. package/dist/storage/store.d.ts +63 -0
  125. package/dist/storage/store.d.ts.map +1 -0
  126. package/dist/storage/store.js +27 -0
  127. package/dist/storage/store.js.map +1 -0
  128. package/dist/types/engram.d.ts +92 -2
  129. package/dist/types/engram.d.ts.map +1 -1
  130. package/dist/types/engram.js.map +1 -1
  131. package/package.json +3 -1
  132. package/src/adapters/claude-code.ts +218 -218
  133. package/src/adapters/codex.ts +252 -252
  134. package/src/adapters/common.ts +498 -411
  135. package/src/adapters/cursor.ts +135 -135
  136. package/src/adapters/http.ts +93 -93
  137. package/src/adapters/index.ts +31 -31
  138. package/src/adapters/types.ts +75 -75
  139. package/src/api/index.ts +3 -3
  140. package/src/api/routes.ts +970 -714
  141. package/src/cli/migrate.ts +307 -0
  142. package/src/cli.ts +755 -719
  143. package/src/coordination/circuit-breaker.ts +83 -0
  144. package/src/coordination/events.ts +90 -90
  145. package/src/coordination/failure-modes.ts +50 -0
  146. package/src/coordination/peer-decisions.ts +105 -105
  147. package/src/coordination/plugin-loader.ts +60 -60
  148. package/src/coordination/plugin.ts +44 -44
  149. package/src/coordination/routes.ts +56 -1
  150. package/src/coordination/schema.ts +13 -0
  151. package/src/coordination/stale.ts +80 -11
  152. package/src/coordination/types.ts +311 -311
  153. package/src/coordination/write-mutex.ts +69 -69
  154. package/src/core/auto-tagger.ts +168 -168
  155. package/src/core/decay.ts +63 -63
  156. package/src/core/embeddings.ts +110 -93
  157. package/src/core/index.ts +5 -5
  158. package/src/core/logger.ts +36 -36
  159. package/src/core/ml-worker-entry.ts +194 -0
  160. package/src/core/ml-worker.ts +281 -0
  161. package/src/core/query-expander.ts +122 -128
  162. package/src/core/reranker.ts +119 -125
  163. package/src/core/salience.ts +200 -33
  164. package/src/core/write-pipeline.ts +521 -343
  165. package/src/engine/activation.ts +235 -109
  166. package/src/engine/confidence.ts +120 -0
  167. package/src/engine/connections.ts +162 -103
  168. package/src/engine/consolidation-scheduler.ts +242 -125
  169. package/src/engine/consolidation.ts +138 -45
  170. package/src/engine/eval.ts +102 -102
  171. package/src/engine/eviction.ts +101 -101
  172. package/src/engine/index.ts +8 -8
  173. package/src/engine/retraction.ts +366 -116
  174. package/src/engine/staging.ts +74 -74
  175. package/src/hooks/sidecar.ts +5 -5
  176. package/src/index.ts +226 -212
  177. package/src/mcp.ts +1145 -1121
  178. package/src/storage/factory.ts +147 -0
  179. package/src/storage/index.ts +3 -3
  180. package/src/storage/pglite-schema.ts +166 -0
  181. package/src/storage/pglite.ts +1363 -0
  182. package/src/storage/sqlite.ts +402 -7
  183. package/src/storage/store.ts +80 -0
  184. package/src/types/agent.ts +67 -67
  185. package/src/types/checkpoint.ts +46 -46
  186. package/src/types/engram.ts +101 -3
  187. package/src/types/eval.ts +100 -100
  188. package/src/types/index.ts +6 -6
@@ -1,252 +1,252 @@
1
- // Copyright 2026 Robert Winter / Complete Ideas
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- /**
5
- * Codex CLI adapter — writes TOML config, AGENTS.md instructions.
6
- *
7
- * Codex stores MCP config in ~/.codex/config.toml (global only).
8
- * Uses snake_case [mcp_servers.name] sections.
9
- */
10
-
11
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
12
- import { join, dirname, basename } from 'node:path';
13
- import type { CLIAdapter, SetupContext, DiagnosticResult } from './types.js';
14
- import { resolveMcpCommand, homedir, AWM_INSTRUCTION_CONTENT, upsertAwmSection } from './common.js';
15
-
16
- // ─── Minimal TOML read/write ──────────────────────────
17
- // Only handles the flat structure Codex uses: [section.name] with key = "value" or key = ["array"]
18
-
19
- interface TomlSection {
20
- [key: string]: string | string[];
21
- }
22
-
23
- interface TomlDoc {
24
- /** Sections: key is the full dotted section name */
25
- sections: Map<string, TomlSection>;
26
- /** Lines before the first section (top-level keys, comments) */
27
- preamble: string[];
28
- }
29
-
30
- function parseTOML(content: string): TomlDoc {
31
- const doc: TomlDoc = { sections: new Map(), preamble: [] };
32
- let currentSection = '';
33
- const lines = content.split('\n');
34
-
35
- for (const line of lines) {
36
- const trimmed = line.trim();
37
-
38
- // Section header
39
- const sectionMatch = trimmed.match(/^\[([^\]]+)\]$/);
40
- if (sectionMatch) {
41
- currentSection = sectionMatch[1];
42
- if (!doc.sections.has(currentSection)) {
43
- doc.sections.set(currentSection, {});
44
- }
45
- continue;
46
- }
47
-
48
- // Skip comments and empty lines
49
- if (!trimmed || trimmed.startsWith('#')) {
50
- if (!currentSection) doc.preamble.push(line);
51
- continue;
52
- }
53
-
54
- // Key = value
55
- const eqIdx = trimmed.indexOf('=');
56
- if (eqIdx === -1) {
57
- if (!currentSection) doc.preamble.push(line);
58
- continue;
59
- }
60
-
61
- const key = trimmed.slice(0, eqIdx).trim();
62
- const rawVal = trimmed.slice(eqIdx + 1).trim();
63
-
64
- if (!currentSection) {
65
- if (!doc.sections.has('')) doc.sections.set('', {});
66
- doc.sections.get('')![key] = parseTomlValue(rawVal);
67
- continue;
68
- }
69
-
70
- if (!doc.sections.has(currentSection)) {
71
- doc.sections.set(currentSection, {});
72
- }
73
- doc.sections.get(currentSection)![key] = parseTomlValue(rawVal);
74
- }
75
-
76
- return doc;
77
- }
78
-
79
- function parseTomlValue(raw: string): string | string[] {
80
- // Array: ["a", "b"]
81
- if (raw.startsWith('[')) {
82
- const inner = raw.slice(1, raw.lastIndexOf(']'));
83
- return inner.split(',')
84
- .map(s => s.trim().replace(/^["']|["']$/g, ''))
85
- .filter(s => s.length > 0);
86
- }
87
- // Quoted string
88
- return raw.replace(/^["']|["']$/g, '');
89
- }
90
-
91
- function serializeTOML(doc: TomlDoc): string {
92
- const lines: string[] = [];
93
-
94
- // Preamble (top-level content before any section)
95
- if (doc.preamble.length > 0) {
96
- lines.push(...doc.preamble);
97
- if (lines.length > 0 && lines[lines.length - 1].trim() !== '') {
98
- lines.push('');
99
- }
100
- }
101
-
102
- for (const [section, values] of doc.sections) {
103
- if (section === '') continue; // already in preamble
104
- lines.push(`[${section}]`);
105
- for (const [key, val] of Object.entries(values)) {
106
- if (Array.isArray(val)) {
107
- const items = val.map(v => `"${v}"`).join(', ');
108
- lines.push(`${key} = [${items}]`);
109
- } else {
110
- lines.push(`${key} = "${val}"`);
111
- }
112
- }
113
- lines.push('');
114
- }
115
-
116
- return lines.join('\n');
117
- }
118
-
119
- // ─── Adapter ──────────────────────────────────────────
120
-
121
- const adapter: CLIAdapter = {
122
- id: 'codex',
123
- name: 'Codex',
124
- supportsProjectScope: false,
125
- supportsGlobalScope: true,
126
-
127
- writeMcpConfig(ctx: SetupContext): string {
128
- if (!ctx.isGlobal) {
129
- console.log(' Note: Codex only supports global MCP config. Using --global automatically.');
130
- }
131
-
132
- const configPath = join(homedir(), '.codex', 'config.toml');
133
- const mcpCmd = resolveMcpCommand(ctx);
134
-
135
- // Read existing config or start fresh
136
- let doc: TomlDoc;
137
- if (existsSync(configPath)) {
138
- doc = parseTOML(readFileSync(configPath, 'utf-8'));
139
- } else {
140
- doc = { sections: new Map(), preamble: [] };
141
- mkdirSync(dirname(configPath), { recursive: true });
142
- }
143
-
144
- // Write the MCP server section
145
- const sectionName = 'mcp_servers.agent-working-memory';
146
- doc.sections.set(sectionName, {
147
- command: mcpCmd.command,
148
- args: mcpCmd.args,
149
- });
150
-
151
- // Write env vars in a sub-section
152
- const envSection = `${sectionName}.env`;
153
- const envEntries: TomlSection = {};
154
- for (const [key, val] of Object.entries(ctx.envVars)) {
155
- envEntries[key] = val;
156
- }
157
- doc.sections.set(envSection, envEntries);
158
-
159
- writeFileSync(configPath, serializeTOML(doc));
160
- return `MCP config: ${configPath}`;
161
- },
162
-
163
- writeInstructions(ctx: SetupContext, skip: boolean): string {
164
- const agentsMdPath = join(ctx.cwd, 'AGENTS.md');
165
-
166
- if (skip) return 'AGENTS.md: skipped (--no-instructions)';
167
-
168
- const title = `# ${basename(ctx.cwd)} — Agent Instructions`;
169
- return upsertAwmSection(agentsMdPath, AWM_INSTRUCTION_CONTENT, { titleIfNew: title });
170
- },
171
-
172
- writeHooks(_ctx: SetupContext, _skip: boolean): string {
173
- return 'Hooks: not supported by Codex (auto-checkpoint unavailable)';
174
- },
175
-
176
- diagnose(ctx: SetupContext): DiagnosticResult[] {
177
- const results: DiagnosticResult[] = [];
178
-
179
- // Check TOML config
180
- const configPath = join(homedir(), '.codex', 'config.toml');
181
- if (!existsSync(configPath)) {
182
- results.push({
183
- check: 'MCP config',
184
- status: 'fail',
185
- message: `${configPath} not found`,
186
- fix: 'Run: awm setup codex',
187
- });
188
- } else {
189
- try {
190
- const doc = parseTOML(readFileSync(configPath, 'utf-8'));
191
- if (doc.sections.has('mcp_servers.agent-working-memory')) {
192
- results.push({ check: 'MCP config', status: 'ok', message: `AWM registered in ${configPath}` });
193
-
194
- // Verify the command points to a real file
195
- const section = doc.sections.get('mcp_servers.agent-working-memory')!;
196
- const args = section.args;
197
- if (Array.isArray(args) && args.length > 0) {
198
- const entrypoint = args[args.length - 1];
199
- if (existsSync(entrypoint)) {
200
- results.push({ check: 'MCP entrypoint', status: 'ok', message: entrypoint });
201
- } else {
202
- results.push({
203
- check: 'MCP entrypoint',
204
- status: 'fail',
205
- message: `Configured entrypoint not found: ${entrypoint}`,
206
- fix: 'Run: npm run build (in AWM package) then awm setup codex',
207
- });
208
- }
209
- }
210
- } else {
211
- results.push({
212
- check: 'MCP config',
213
- status: 'fail',
214
- message: 'config.toml exists but missing agent-working-memory section',
215
- fix: 'Run: awm setup codex',
216
- });
217
- }
218
- } catch {
219
- results.push({ check: 'MCP config', status: 'fail', message: `${configPath} could not be parsed` });
220
- }
221
- }
222
-
223
- // Check database
224
- if (existsSync(ctx.dbPath)) {
225
- results.push({ check: 'Database', status: 'ok', message: ctx.dbPath });
226
- } else {
227
- results.push({ check: 'Database', status: 'warn', message: `${ctx.dbPath} not found (will be created on first use)` });
228
- }
229
-
230
- // Check AGENTS.md
231
- const agentsMdPath = join(ctx.cwd, 'AGENTS.md');
232
- if (existsSync(agentsMdPath)) {
233
- const content = readFileSync(agentsMdPath, 'utf-8');
234
- if (content.includes('## Memory (AWM)')) {
235
- results.push({ check: 'Instructions', status: 'ok', message: 'AGENTS.md has AWM section' });
236
- } else {
237
- results.push({
238
- check: 'Instructions',
239
- status: 'warn',
240
- message: 'AGENTS.md exists but missing AWM section',
241
- fix: 'Run: awm setup codex',
242
- });
243
- }
244
- } else {
245
- results.push({ check: 'Instructions', status: 'warn', message: 'AGENTS.md not found' });
246
- }
247
-
248
- return results;
249
- },
250
- };
251
-
252
- export default adapter;
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ /**
5
+ * Codex CLI adapter — writes TOML config, AGENTS.md instructions.
6
+ *
7
+ * Codex stores MCP config in ~/.codex/config.toml (global only).
8
+ * Uses snake_case [mcp_servers.name] sections.
9
+ */
10
+
11
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
12
+ import { join, dirname, basename } from 'node:path';
13
+ import type { CLIAdapter, SetupContext, DiagnosticResult } from './types.js';
14
+ import { resolveMcpCommand, homedir, AWM_INSTRUCTION_CONTENT, upsertAwmSection } from './common.js';
15
+
16
+ // ─── Minimal TOML read/write ──────────────────────────
17
+ // Only handles the flat structure Codex uses: [section.name] with key = "value" or key = ["array"]
18
+
19
+ interface TomlSection {
20
+ [key: string]: string | string[];
21
+ }
22
+
23
+ interface TomlDoc {
24
+ /** Sections: key is the full dotted section name */
25
+ sections: Map<string, TomlSection>;
26
+ /** Lines before the first section (top-level keys, comments) */
27
+ preamble: string[];
28
+ }
29
+
30
+ function parseTOML(content: string): TomlDoc {
31
+ const doc: TomlDoc = { sections: new Map(), preamble: [] };
32
+ let currentSection = '';
33
+ const lines = content.split('\n');
34
+
35
+ for (const line of lines) {
36
+ const trimmed = line.trim();
37
+
38
+ // Section header
39
+ const sectionMatch = trimmed.match(/^\[([^\]]+)\]$/);
40
+ if (sectionMatch) {
41
+ currentSection = sectionMatch[1];
42
+ if (!doc.sections.has(currentSection)) {
43
+ doc.sections.set(currentSection, {});
44
+ }
45
+ continue;
46
+ }
47
+
48
+ // Skip comments and empty lines
49
+ if (!trimmed || trimmed.startsWith('#')) {
50
+ if (!currentSection) doc.preamble.push(line);
51
+ continue;
52
+ }
53
+
54
+ // Key = value
55
+ const eqIdx = trimmed.indexOf('=');
56
+ if (eqIdx === -1) {
57
+ if (!currentSection) doc.preamble.push(line);
58
+ continue;
59
+ }
60
+
61
+ const key = trimmed.slice(0, eqIdx).trim();
62
+ const rawVal = trimmed.slice(eqIdx + 1).trim();
63
+
64
+ if (!currentSection) {
65
+ if (!doc.sections.has('')) doc.sections.set('', {});
66
+ doc.sections.get('')![key] = parseTomlValue(rawVal);
67
+ continue;
68
+ }
69
+
70
+ if (!doc.sections.has(currentSection)) {
71
+ doc.sections.set(currentSection, {});
72
+ }
73
+ doc.sections.get(currentSection)![key] = parseTomlValue(rawVal);
74
+ }
75
+
76
+ return doc;
77
+ }
78
+
79
+ function parseTomlValue(raw: string): string | string[] {
80
+ // Array: ["a", "b"]
81
+ if (raw.startsWith('[')) {
82
+ const inner = raw.slice(1, raw.lastIndexOf(']'));
83
+ return inner.split(',')
84
+ .map(s => s.trim().replace(/^["']|["']$/g, ''))
85
+ .filter(s => s.length > 0);
86
+ }
87
+ // Quoted string
88
+ return raw.replace(/^["']|["']$/g, '');
89
+ }
90
+
91
+ function serializeTOML(doc: TomlDoc): string {
92
+ const lines: string[] = [];
93
+
94
+ // Preamble (top-level content before any section)
95
+ if (doc.preamble.length > 0) {
96
+ lines.push(...doc.preamble);
97
+ if (lines.length > 0 && lines[lines.length - 1].trim() !== '') {
98
+ lines.push('');
99
+ }
100
+ }
101
+
102
+ for (const [section, values] of doc.sections) {
103
+ if (section === '') continue; // already in preamble
104
+ lines.push(`[${section}]`);
105
+ for (const [key, val] of Object.entries(values)) {
106
+ if (Array.isArray(val)) {
107
+ const items = val.map(v => `"${v}"`).join(', ');
108
+ lines.push(`${key} = [${items}]`);
109
+ } else {
110
+ lines.push(`${key} = "${val}"`);
111
+ }
112
+ }
113
+ lines.push('');
114
+ }
115
+
116
+ return lines.join('\n');
117
+ }
118
+
119
+ // ─── Adapter ──────────────────────────────────────────
120
+
121
+ const adapter: CLIAdapter = {
122
+ id: 'codex',
123
+ name: 'Codex',
124
+ supportsProjectScope: false,
125
+ supportsGlobalScope: true,
126
+
127
+ writeMcpConfig(ctx: SetupContext): string {
128
+ if (!ctx.isGlobal) {
129
+ console.log(' Note: Codex only supports global MCP config. Using --global automatically.');
130
+ }
131
+
132
+ const configPath = join(homedir(), '.codex', 'config.toml');
133
+ const mcpCmd = resolveMcpCommand(ctx);
134
+
135
+ // Read existing config or start fresh
136
+ let doc: TomlDoc;
137
+ if (existsSync(configPath)) {
138
+ doc = parseTOML(readFileSync(configPath, 'utf-8'));
139
+ } else {
140
+ doc = { sections: new Map(), preamble: [] };
141
+ mkdirSync(dirname(configPath), { recursive: true });
142
+ }
143
+
144
+ // Write the MCP server section
145
+ const sectionName = 'mcp_servers.agent-working-memory';
146
+ doc.sections.set(sectionName, {
147
+ command: mcpCmd.command,
148
+ args: mcpCmd.args,
149
+ });
150
+
151
+ // Write env vars in a sub-section
152
+ const envSection = `${sectionName}.env`;
153
+ const envEntries: TomlSection = {};
154
+ for (const [key, val] of Object.entries(ctx.envVars)) {
155
+ envEntries[key] = val;
156
+ }
157
+ doc.sections.set(envSection, envEntries);
158
+
159
+ writeFileSync(configPath, serializeTOML(doc));
160
+ return `MCP config: ${configPath}`;
161
+ },
162
+
163
+ writeInstructions(ctx: SetupContext, skip: boolean): string {
164
+ const agentsMdPath = join(ctx.cwd, 'AGENTS.md');
165
+
166
+ if (skip) return 'AGENTS.md: skipped (--no-instructions)';
167
+
168
+ const title = `# ${basename(ctx.cwd)} — Agent Instructions`;
169
+ return upsertAwmSection(agentsMdPath, AWM_INSTRUCTION_CONTENT, { titleIfNew: title });
170
+ },
171
+
172
+ writeHooks(_ctx: SetupContext, _skip: boolean): string {
173
+ return 'Hooks: not supported by Codex (auto-checkpoint unavailable)';
174
+ },
175
+
176
+ diagnose(ctx: SetupContext): DiagnosticResult[] {
177
+ const results: DiagnosticResult[] = [];
178
+
179
+ // Check TOML config
180
+ const configPath = join(homedir(), '.codex', 'config.toml');
181
+ if (!existsSync(configPath)) {
182
+ results.push({
183
+ check: 'MCP config',
184
+ status: 'fail',
185
+ message: `${configPath} not found`,
186
+ fix: 'Run: awm setup codex',
187
+ });
188
+ } else {
189
+ try {
190
+ const doc = parseTOML(readFileSync(configPath, 'utf-8'));
191
+ if (doc.sections.has('mcp_servers.agent-working-memory')) {
192
+ results.push({ check: 'MCP config', status: 'ok', message: `AWM registered in ${configPath}` });
193
+
194
+ // Verify the command points to a real file
195
+ const section = doc.sections.get('mcp_servers.agent-working-memory')!;
196
+ const args = section.args;
197
+ if (Array.isArray(args) && args.length > 0) {
198
+ const entrypoint = args[args.length - 1];
199
+ if (existsSync(entrypoint)) {
200
+ results.push({ check: 'MCP entrypoint', status: 'ok', message: entrypoint });
201
+ } else {
202
+ results.push({
203
+ check: 'MCP entrypoint',
204
+ status: 'fail',
205
+ message: `Configured entrypoint not found: ${entrypoint}`,
206
+ fix: 'Run: npm run build (in AWM package) then awm setup codex',
207
+ });
208
+ }
209
+ }
210
+ } else {
211
+ results.push({
212
+ check: 'MCP config',
213
+ status: 'fail',
214
+ message: 'config.toml exists but missing agent-working-memory section',
215
+ fix: 'Run: awm setup codex',
216
+ });
217
+ }
218
+ } catch {
219
+ results.push({ check: 'MCP config', status: 'fail', message: `${configPath} could not be parsed` });
220
+ }
221
+ }
222
+
223
+ // Check database
224
+ if (existsSync(ctx.dbPath)) {
225
+ results.push({ check: 'Database', status: 'ok', message: ctx.dbPath });
226
+ } else {
227
+ results.push({ check: 'Database', status: 'warn', message: `${ctx.dbPath} not found (will be created on first use)` });
228
+ }
229
+
230
+ // Check AGENTS.md
231
+ const agentsMdPath = join(ctx.cwd, 'AGENTS.md');
232
+ if (existsSync(agentsMdPath)) {
233
+ const content = readFileSync(agentsMdPath, 'utf-8');
234
+ if (content.includes('## Memory (AWM)')) {
235
+ results.push({ check: 'Instructions', status: 'ok', message: 'AGENTS.md has AWM section' });
236
+ } else {
237
+ results.push({
238
+ check: 'Instructions',
239
+ status: 'warn',
240
+ message: 'AGENTS.md exists but missing AWM section',
241
+ fix: 'Run: awm setup codex',
242
+ });
243
+ }
244
+ } else {
245
+ results.push({ check: 'Instructions', status: 'warn', message: 'AGENTS.md not found' });
246
+ }
247
+
248
+ return results;
249
+ },
250
+ };
251
+
252
+ export default adapter;