coding-friend-cli 1.37.0 → 1.38.0

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 (71) hide show
  1. package/README.md +7 -2
  2. package/dist/{chunk-GZT3YPAP.js → chunk-32UAW3NX.js} +1 -1
  3. package/dist/chunk-5QCGEPQO.js +238 -0
  4. package/dist/{chunk-YIXAQ4R2.js → chunk-6NXZKAOV.js} +1 -1
  5. package/dist/{chunk-676YCW6T.js → chunk-776ZY62N.js} +99 -7
  6. package/dist/{chunk-DP6DFQ4G.js → chunk-BXSCYGWE.js} +2 -2
  7. package/dist/{chunk-W6D3J5DX.js → chunk-CGEMETKQ.js} +8 -6
  8. package/dist/{chunk-XEKQW4RN.js → chunk-ETTZRJ55.js} +1 -1
  9. package/dist/{chunk-IKLMHJH6.js → chunk-GIH6E7GJ.js} +62 -1
  10. package/dist/{chunk-6S7352JG.js → chunk-ONG4KRYP.js} +1 -1
  11. package/dist/{chunk-X2H7JJMR.js → chunk-PLSJW7QJ.js} +29 -1
  12. package/dist/{chunk-O5ZKLFSL.js → chunk-RCE4OWNX.js} +1 -1
  13. package/dist/{chunk-PI4P34KF.js → chunk-RFNKPAJW.js} +3 -1
  14. package/dist/{clean-WEYQZB34.js → clean-YWEMYDE5.js} +2 -2
  15. package/dist/{config-ZMR2AOBB.js → config-NG7SICM4.js} +12 -24
  16. package/dist/{dev-IGHMMEP4.js → dev-PTBNMKZT.js} +3 -3
  17. package/dist/{disable-HL5OEURT.js → disable-MO7AXYYF.js} +20 -3
  18. package/dist/{enable-CZIOCKKJ.js → enable-4GXLQEHD.js} +20 -3
  19. package/dist/{guide-CO2V4ZLZ.js → guide-HCR43LJN.js} +1 -1
  20. package/dist/{host-SSRI4JZV.js → host-EV6QIVTI.js} +2 -2
  21. package/dist/index.js +59 -47
  22. package/dist/{init-6MFQWPOP.js → init-KYE5CJMW.js} +115 -12
  23. package/dist/{install-37NN4CQH.js → install-XAFQY5YF.js} +79 -6
  24. package/dist/{learn-OPH3CI67.js → learn-MC4VDHZH.js} +2 -2
  25. package/dist/{mcp-DWKVMNC7.js → mcp-FV6YX3ZT.js} +7 -7
  26. package/dist/{mcp-serve-5GODJ4DJ.js → mcp-serve-PXREYQRZ.js} +2 -2
  27. package/dist/{mcp-serve-learn-OF3ZJUJC.js → mcp-serve-learn-UVXIDOEZ.js} +1 -1
  28. package/dist/{memory-TRDLADUM.js → memory-DF7OUOTV.js} +6 -6
  29. package/dist/{permission-I3OFJUYA.js → permission-VISPGMUK.js} +38 -4
  30. package/dist/{permissions-J46VP6US.js → permissions-2SBACQHV.js} +2 -2
  31. package/dist/{session-S4WKA4P5.js → session-QK6OZO3X.js} +2 -2
  32. package/dist/{status-YZEOUX46.js → status-FVFTJ6GS.js} +11 -10
  33. package/dist/{statusline-KKFJPTI7.js → statusline-AOZHEQSV.js} +2 -2
  34. package/dist/{uninstall-AVA3J554.js → uninstall-MF6FRUBO.js} +51 -4
  35. package/dist/{update-Q3ACCK4Z.js → update-QNUCSDSA.js} +6 -5
  36. package/dist/{update-check-25SCLHZO.js → update-check-7LKJLJPM.js} +1 -1
  37. package/lib/cf-memory/src/lib/claude-md.ts +82 -70
  38. package/lib/cf-memory/src/lib/status-frame.ts +2 -2
  39. package/lib/cf-memory/src/tools/delete.ts +1 -1
  40. package/lib/cf-memory/src/tools/store.ts +6 -6
  41. package/lib/cf-memory/src/tools/update.ts +5 -11
  42. package/package.json +32 -4
  43. package/lib/cf-memory/README.md +0 -317
  44. package/lib/cf-memory/src/__tests__/claude-md.test.ts +0 -343
  45. package/lib/cf-memory/src/__tests__/daemon-client.test.ts +0 -146
  46. package/lib/cf-memory/src/__tests__/daemon-e2e.test.ts +0 -223
  47. package/lib/cf-memory/src/__tests__/daemon.test.ts +0 -407
  48. package/lib/cf-memory/src/__tests__/dedup.test.ts +0 -103
  49. package/lib/cf-memory/src/__tests__/embeddings.test.ts +0 -292
  50. package/lib/cf-memory/src/__tests__/lazy-install.test.ts +0 -210
  51. package/lib/cf-memory/src/__tests__/markdown-backend.test.ts +0 -450
  52. package/lib/cf-memory/src/__tests__/migration.test.ts +0 -255
  53. package/lib/cf-memory/src/__tests__/migrations.test.ts +0 -288
  54. package/lib/cf-memory/src/__tests__/minisearch-backend.test.ts +0 -262
  55. package/lib/cf-memory/src/__tests__/ollama.test.ts +0 -48
  56. package/lib/cf-memory/src/__tests__/project-id.test.ts +0 -43
  57. package/lib/cf-memory/src/__tests__/schema.test.ts +0 -128
  58. package/lib/cf-memory/src/__tests__/search.test.ts +0 -115
  59. package/lib/cf-memory/src/__tests__/sqlite-lazy-db.test.ts +0 -213
  60. package/lib/cf-memory/src/__tests__/status-frame.test.ts +0 -136
  61. package/lib/cf-memory/src/__tests__/temporal-decay.test.ts +0 -54
  62. package/lib/cf-memory/src/__tests__/tier.test.ts +0 -388
  63. package/lib/cf-memory/src/__tests__/tools.test.ts +0 -83
  64. package/lib/cf-memory/vitest.config.ts +0 -7
  65. package/lib/learn-host/.prettierignore +0 -4
  66. package/lib/learn-host/.prettierrc +0 -8
  67. package/lib/learn-host/README.md +0 -113
  68. package/lib/learn-host/eslint.config.mjs +0 -6
  69. package/lib/learn-mcp/README.md +0 -187
  70. package/lib/learn-mcp/src/__tests__/docs.test.ts +0 -117
  71. package/lib/learn-mcp/vitest.config.ts +0 -8
@@ -4,15 +4,22 @@ import {
4
4
  } from "./chunk-667NMPN4.js";
5
5
  import {
6
6
  removeMemoryMcpEntry
7
- } from "./chunk-DP6DFQ4G.js";
7
+ } from "./chunk-BXSCYGWE.js";
8
8
  import "./chunk-RZRT7NGT.js";
9
9
  import {
10
10
  isMarketplaceRegistered,
11
11
  isPluginInstalled
12
- } from "./chunk-GZT3YPAP.js";
12
+ } from "./chunk-32UAW3NX.js";
13
13
  import {
14
+ CODEX_MARKETPLACE_NAME,
15
+ removeCodexMemoryMcpConfig,
16
+ removeDeployedCodexAgents,
17
+ setCodexPluginEnabled
18
+ } from "./chunk-5QCGEPQO.js";
19
+ import {
20
+ resolveHostFlags,
14
21
  resolveScope
15
- } from "./chunk-IKLMHJH6.js";
22
+ } from "./chunk-GIH6E7GJ.js";
16
23
  import {
17
24
  commandExists,
18
25
  run
@@ -28,7 +35,7 @@ import {
28
35
  marketplaceCachePath,
29
36
  marketplaceClonePath,
30
37
  memoryDepsDir
31
- } from "./chunk-X2H7JJMR.js";
38
+ } from "./chunk-PLSJW7QJ.js";
32
39
  import {
33
40
  log,
34
41
  printBanner
@@ -128,6 +135,11 @@ async function uninstallScoped(scope) {
128
135
  log.dim("Restart Claude Code to complete the uninstall.");
129
136
  }
130
137
  async function uninstallCommand(opts = {}) {
138
+ const { host } = resolveHostFlags(opts);
139
+ if (host === "codex") {
140
+ uninstallCodexCommand(opts);
141
+ return;
142
+ }
131
143
  console.log();
132
144
  printBanner("\u{1F44B} Coding Friend Uninstall \u{1F44B}", { color: chalk.red });
133
145
  if (!commandExists("claude")) {
@@ -295,6 +307,41 @@ async function uninstallCommand(opts = {}) {
295
307
  log.dim("To also remove the CLI tool globally, run:");
296
308
  console.log(` ${chalk.bold("npm uninstall -g coding-friend-cli")}`);
297
309
  }
310
+ function uninstallCodexCommand(opts) {
311
+ console.log();
312
+ printBanner("\u{1F44B} Coding Friend Codex Uninstall \u{1F44B}", { color: chalk.red });
313
+ setCodexPluginEnabled(false);
314
+ log.success("Disabled coding-friend in ~/.codex/config.toml.");
315
+ const removedAgents = removeDeployedCodexAgents();
316
+ if (removedAgents > 0) {
317
+ log.success(
318
+ `Removed ${removedAgents} deployed Coding Friend agent definition(s) from ~/.codex/agents/.`
319
+ );
320
+ }
321
+ if (removeCodexMemoryMcpConfig()) {
322
+ log.success(
323
+ "Removed coding-friend-memory registration from ~/.codex/config.toml."
324
+ );
325
+ }
326
+ if (opts.removeMarketplace) {
327
+ if (!commandExists("codex")) {
328
+ log.warn("Codex CLI not found; could not remove marketplace via CLI.");
329
+ } else {
330
+ const result = run("codex", [
331
+ "plugin",
332
+ "marketplace",
333
+ "remove",
334
+ CODEX_MARKETPLACE_NAME
335
+ ]);
336
+ if (result === null) {
337
+ log.warn("Could not remove Codex marketplace registration.");
338
+ } else {
339
+ log.success("Removed Codex marketplace registration.");
340
+ }
341
+ }
342
+ }
343
+ log.dim("Restart Codex CLI for the change to take effect.");
344
+ }
298
345
  export {
299
346
  uninstallCommand
300
347
  };
@@ -4,16 +4,17 @@ import {
4
4
  getLatestVersion,
5
5
  semverCompare,
6
6
  updateCommand
7
- } from "./chunk-676YCW6T.js";
8
- import "./chunk-XEKQW4RN.js";
7
+ } from "./chunk-776ZY62N.js";
8
+ import "./chunk-ETTZRJ55.js";
9
9
  import "./chunk-3WIZA5OZ.js";
10
10
  import "./chunk-667NMPN4.js";
11
- import "./chunk-DP6DFQ4G.js";
11
+ import "./chunk-BXSCYGWE.js";
12
12
  import "./chunk-RZRT7NGT.js";
13
- import "./chunk-IKLMHJH6.js";
13
+ import "./chunk-5QCGEPQO.js";
14
+ import "./chunk-GIH6E7GJ.js";
14
15
  import "./chunk-EVGXUDX4.js";
15
16
  import "./chunk-5UVDWG5L.js";
16
- import "./chunk-X2H7JJMR.js";
17
+ import "./chunk-PLSJW7QJ.js";
17
18
  import "./chunk-NREZK463.js";
18
19
  export {
19
20
  getCliVersion,
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-EVGXUDX4.js";
4
4
  import {
5
5
  globalConfigDir
6
- } from "./chunk-X2H7JJMR.js";
6
+ } from "./chunk-PLSJW7QJ.js";
7
7
  import {
8
8
  log
9
9
  } from "./chunk-NREZK463.js";
@@ -1,8 +1,9 @@
1
1
  /**
2
- * Sync convention memories to the project's CLAUDE.md file.
2
+ * Sync convention memories to the project's host instruction files.
3
3
  *
4
4
  * When a memory of type "preference" (category "conventions") is stored,
5
- * updated, or deleted, the corresponding entry in CLAUDE.md is kept in sync.
5
+ * updated, or deleted, the corresponding entry in CLAUDE.md and/or AGENTS.md
6
+ * is kept in sync.
6
7
  *
7
8
  * Entries are tracked via HTML comments: <!-- cf:<memory-id> -->
8
9
  * All entries live under a dedicated section header.
@@ -46,6 +47,20 @@ export function claudeMdPath(docsDir: string): string {
46
47
  return path.join(projectRoot(docsDir), "CLAUDE.md");
47
48
  }
48
49
 
50
+ export function agentsMdPath(docsDir: string): string {
51
+ return path.join(projectRoot(docsDir), "AGENTS.md");
52
+ }
53
+
54
+ function instructionFilePaths(
55
+ docsDir: string,
56
+ createClaudeFallback: boolean,
57
+ ): string[] {
58
+ const candidates = [claudeMdPath(docsDir), agentsMdPath(docsDir)];
59
+ const existing = candidates.filter((filePath) => fs.existsSync(filePath));
60
+ if (existing.length > 0 || !createClaudeFallback) return existing;
61
+ return [candidates[0]];
62
+ }
63
+
49
64
  /**
50
65
  * Parse a CLAUDE.md file into: before the section, section entries, and after the section.
51
66
  */
@@ -143,84 +158,81 @@ export function syncToClaudeMd(
143
158
  docsDir: string,
144
159
  id: string,
145
160
  description: string,
146
- ): void {
147
- const filePath = claudeMdPath(docsDir);
148
- const existing = fs.existsSync(filePath)
149
- ? fs.readFileSync(filePath, "utf-8")
150
- : "";
151
-
152
- const { before, entries, after, untrackedLines } = parseClaudeMd(existing);
153
-
154
- // Remove any existing entry with the same ID
155
- const filtered = entries.filter((e) => {
156
- const match = e.match(ENTRY_RE);
157
- return !match || match[1] !== id;
158
- });
159
-
160
- // Add the new/updated entry
161
- filtered.push(formatEntry(id, description));
162
-
163
- fs.writeFileSync(
164
- filePath,
165
- buildClaudeMd(before, filtered, after, untrackedLines),
166
- "utf-8",
167
- );
161
+ ): string[] {
162
+ const updated: string[] = [];
163
+ for (const filePath of instructionFilePaths(docsDir, true)) {
164
+ const existing = fs.existsSync(filePath)
165
+ ? fs.readFileSync(filePath, "utf-8")
166
+ : "";
167
+
168
+ const { before, entries, after, untrackedLines } = parseClaudeMd(existing);
169
+ const filtered = entries.filter((entry) => {
170
+ const match = entry.match(ENTRY_RE);
171
+ return !match || match[1] !== id;
172
+ });
173
+ filtered.push(formatEntry(id, description));
174
+
175
+ fs.writeFileSync(
176
+ filePath,
177
+ buildClaudeMd(before, filtered, after, untrackedLines),
178
+ "utf-8",
179
+ );
180
+ updated.push(filePath);
181
+ }
182
+ return updated;
168
183
  }
169
184
 
170
185
  /**
171
- * Remove a convention entry from the project's CLAUDE.md.
186
+ * Remove a convention entry from the project's host instruction files.
172
187
  */
173
- export function removeFromClaudeMd(docsDir: string, id: string): void {
174
- const filePath = claudeMdPath(docsDir);
175
- if (!fs.existsSync(filePath)) return;
176
-
177
- const content = fs.readFileSync(filePath, "utf-8");
178
- const { before, entries, after, untrackedLines } = parseClaudeMd(content);
179
-
180
- if (entries.length === 0) return;
181
-
182
- const filtered = entries.filter((e) => {
183
- const match = e.match(ENTRY_RE);
184
- return !match || match[1] !== id;
185
- });
186
-
187
- // Only write if something actually changed
188
- if (filtered.length === entries.length) return;
189
-
190
- fs.writeFileSync(
191
- filePath,
192
- buildClaudeMd(before, filtered, after, untrackedLines),
193
- "utf-8",
194
- );
188
+ export function removeFromClaudeMd(docsDir: string, id: string): string[] {
189
+ const updated: string[] = [];
190
+ for (const filePath of instructionFilePaths(docsDir, false)) {
191
+ const content = fs.readFileSync(filePath, "utf-8");
192
+ const { before, entries, after, untrackedLines } = parseClaudeMd(content);
193
+ if (entries.length === 0) continue;
194
+
195
+ const filtered = entries.filter((entry) => {
196
+ const match = entry.match(ENTRY_RE);
197
+ return !match || match[1] !== id;
198
+ });
199
+ if (filtered.length === entries.length) continue;
200
+
201
+ fs.writeFileSync(
202
+ filePath,
203
+ buildClaudeMd(before, filtered, after, untrackedLines),
204
+ "utf-8",
205
+ );
206
+ updated.push(filePath);
207
+ }
208
+ return updated;
195
209
  }
196
210
 
197
211
  /**
198
- * Update an existing convention entry in CLAUDE.md (no upsert).
212
+ * Update an existing convention entry in the host instruction files (no upsert).
199
213
  */
200
214
  export function updateInClaudeMd(
201
215
  docsDir: string,
202
216
  id: string,
203
217
  description: string,
204
- ): void {
205
- const filePath = claudeMdPath(docsDir);
206
- if (!fs.existsSync(filePath)) return;
207
-
208
- const content = fs.readFileSync(filePath, "utf-8");
209
- const { before, entries, after, untrackedLines } = parseClaudeMd(content);
210
-
211
- // Check if entry exists
212
- const idx = entries.findIndex((e) => {
213
- const match = e.match(ENTRY_RE);
214
- return match && match[1] === id;
215
- });
216
-
217
- if (idx === -1) return;
218
-
219
- entries[idx] = formatEntry(id, description);
220
-
221
- fs.writeFileSync(
222
- filePath,
223
- buildClaudeMd(before, entries, after, untrackedLines),
224
- "utf-8",
225
- );
218
+ ): string[] {
219
+ const updated: string[] = [];
220
+ for (const filePath of instructionFilePaths(docsDir, false)) {
221
+ const content = fs.readFileSync(filePath, "utf-8");
222
+ const { before, entries, after, untrackedLines } = parseClaudeMd(content);
223
+ const index = entries.findIndex((entry) => {
224
+ const match = entry.match(ENTRY_RE);
225
+ return match && match[1] === id;
226
+ });
227
+ if (index === -1) continue;
228
+
229
+ entries[index] = formatEntry(id, description);
230
+ fs.writeFileSync(
231
+ filePath,
232
+ buildClaudeMd(before, entries, after, untrackedLines),
233
+ "utf-8",
234
+ );
235
+ updated.push(filePath);
236
+ }
237
+ return updated;
226
238
  }
@@ -33,7 +33,7 @@ export function buildStoreStatus(input: StoreStatusInput): string {
33
33
  }
34
34
 
35
35
  if (input.claudeMdUpdated) {
36
- lines.push(`📋 CLAUDE.md updated`);
36
+ lines.push(`📋 Project instructions updated`);
37
37
  }
38
38
 
39
39
  if (input.warning) {
@@ -56,7 +56,7 @@ export function buildUpdateStatus(input: UpdateStatusInput): string {
56
56
  }
57
57
 
58
58
  if (input.claudeMdUpdated) {
59
- lines.push(`📋 CLAUDE.md updated`);
59
+ lines.push(`📋 Project instructions updated`);
60
60
  }
61
61
 
62
62
  return lines.join("\n");
@@ -28,7 +28,7 @@ export function registerDelete(
28
28
  isError: true,
29
29
  };
30
30
  }
31
- // Remove from CLAUDE.md (any category may have been synced via sync_to_claude_md)
31
+ // Remove from host instruction files if this memory was synced.
32
32
  if (ctx?.docsDir) {
33
33
  try {
34
34
  removeFromClaudeMd(ctx.docsDir, id);
@@ -44,8 +44,8 @@ export function registerStore(
44
44
  .boolean()
45
45
  .optional()
46
46
  .describe(
47
- "When true, sync this memory to the project's CLAUDE.md regardless of category. " +
48
- "Use for memories containing project-wide rules, conventions, or decisions that should be visible in CLAUDE.md. " +
47
+ "Compatibility alias: when true, sync this memory to the project's host instruction files (CLAUDE.md and/or AGENTS.md) regardless of category. " +
48
+ "Use for memories containing project-wide rules, conventions, or decisions that should be visible to coding agents. " +
49
49
  "Convention memories (type: preference) are always synced automatically.",
50
50
  ),
51
51
  },
@@ -82,17 +82,17 @@ export function registerStore(
82
82
 
83
83
  const memory = await backend.store(input);
84
84
 
85
- // Sync to CLAUDE.md: auto for conventions, opt-in for other categories
85
+ // Sync host instruction files: auto for conventions, opt-in for others.
86
86
  let claudeMdUpdated = false;
87
87
  const shouldSync =
88
88
  (memory.category === "conventions" || sync_to_claude_md) &&
89
89
  ctx?.docsDir;
90
90
  if (shouldSync) {
91
91
  try {
92
- syncToClaudeMd(ctx.docsDir, memory.id, description);
93
- claudeMdUpdated = true;
92
+ claudeMdUpdated =
93
+ syncToClaudeMd(ctx.docsDir, memory.id, description).length > 0;
94
94
  } catch {
95
- // Best-effort — don't block store on CLAUDE.md sync errors
95
+ // Best-effort — don't block store on instruction sync errors.
96
96
  }
97
97
  }
98
98
 
@@ -3,7 +3,7 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { z } from "zod";
4
4
  import type { MemoryBackend } from "../lib/backend.js";
5
5
  import { buildUpdateStatus } from "../lib/status-frame.js";
6
- import { updateInClaudeMd, syncToClaudeMd } from "../lib/claude-md.js";
6
+ import { syncToClaudeMd } from "../lib/claude-md.js";
7
7
  import type { ToolRegistrationContext } from "../server.js";
8
8
 
9
9
  export function registerUpdate(
@@ -33,7 +33,7 @@ export function registerUpdate(
33
33
  .boolean()
34
34
  .optional()
35
35
  .describe(
36
- "When true, sync this memory to the project's CLAUDE.md regardless of category. " +
36
+ "Compatibility alias: when true, sync this memory to the project's host instruction files (CLAUDE.md and/or AGENTS.md) regardless of category. " +
37
37
  "Convention memories (type: preference) are always synced automatically.",
38
38
  ),
39
39
  },
@@ -66,25 +66,19 @@ export function registerUpdate(
66
66
  };
67
67
  }
68
68
 
69
- // Sync to CLAUDE.md: auto for conventions, opt-in for other categories
69
+ // Sync host instruction files: auto for conventions, opt-in for others.
70
70
  let claudeMdUpdated = false;
71
71
  const shouldSync =
72
72
  (memory.category === "conventions" || sync_to_claude_md) &&
73
73
  ctx?.docsDir;
74
74
  if (shouldSync) {
75
75
  try {
76
- if (description) {
77
- // Description changed — update the CLAUDE.md entry
78
- updateInClaudeMd(ctx.docsDir, memory.id, description);
79
- } else {
80
- // Ensure entry exists (e.g. if memory was created before this feature)
76
+ claudeMdUpdated =
81
77
  syncToClaudeMd(
82
78
  ctx.docsDir,
83
79
  memory.id,
84
80
  memory.frontmatter.description,
85
- );
86
- }
87
- claudeMdUpdated = true;
81
+ ).length > 0;
88
82
  } catch {
89
83
  // Best-effort
90
84
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coding-friend-cli",
3
- "version": "1.37.0",
3
+ "version": "1.38.0",
4
4
  "description": "CLI for coding-friend — host learning docs, setup MCP server, initialize projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,7 +10,8 @@
10
10
  "scripts": {
11
11
  "build": "tsup src/index.ts src/postinstall.ts --format esm --dts --clean",
12
12
  "postinstall": "node -e \"import('./dist/postinstall.js').catch(()=>{})\"",
13
- "prepublishOnly": "npm run build",
13
+ "prepublishOnly": "npm run build && npm run check:package",
14
+ "check:package": "node scripts/check-package.mjs",
14
15
  "dev": "tsx src/index.ts",
15
16
  "watch": "tsup src/index.ts src/postinstall.ts --format esm --dts --watch",
16
17
  "test": "vitest run && vitest run --config vitest.hooks.config.ts",
@@ -20,14 +21,41 @@
20
21
  },
21
22
  "files": [
22
23
  "dist",
23
- "lib"
24
+ "lib/cf-memory/package.json",
25
+ "lib/cf-memory/package-lock.json",
26
+ "lib/cf-memory/scripts",
27
+ "lib/cf-memory/src/backends",
28
+ "lib/cf-memory/src/bin",
29
+ "lib/cf-memory/src/daemon",
30
+ "lib/cf-memory/src/index.ts",
31
+ "lib/cf-memory/src/lib",
32
+ "lib/cf-memory/src/resources",
33
+ "lib/cf-memory/src/server.ts",
34
+ "lib/cf-memory/src/tools",
35
+ "lib/cf-memory/tsconfig.json",
36
+ "lib/learn-host/next.config.ts",
37
+ "lib/learn-host/package.json",
38
+ "lib/learn-host/package-lock.json",
39
+ "lib/learn-host/postcss.config.mjs",
40
+ "lib/learn-host/public/logo.svg",
41
+ "lib/learn-host/src",
42
+ "lib/learn-host/tsconfig.json",
43
+ "lib/learn-mcp/package.json",
44
+ "lib/learn-mcp/package-lock.json",
45
+ "lib/learn-mcp/src/bin",
46
+ "lib/learn-mcp/src/index.ts",
47
+ "lib/learn-mcp/src/lib",
48
+ "lib/learn-mcp/src/server.ts",
49
+ "lib/learn-mcp/src/tools",
50
+ "lib/learn-mcp/tsconfig.json"
24
51
  ],
25
52
  "keywords": [
26
53
  "coding-friend",
27
54
  "cli",
28
55
  "learning",
29
56
  "mcp",
30
- "claude"
57
+ "claude",
58
+ "codex"
31
59
  ],
32
60
  "author": {
33
61
  "name": "Anh-Thi Dinh",