Fix npx search and default Codex context to workspace-local AGENTS (#1780)

* Fix npx search query parameter mismatch

* Use workspace-local Codex AGENTS context by default

---------

Co-authored-by: bnb <bnb>
This commit is contained in:
enma998
2026-04-15 16:58:08 +09:00
committed by GitHub
parent f44605658d
commit 471e1f62f9
5 changed files with 78 additions and 56 deletions
+2 -2
View File
@@ -102,7 +102,7 @@ export function runStatusCommand(): void {
}
/**
* Search the worker API at `GET /api/search?q=<query>`.
* Search the worker API at `GET /api/search?query=<query>`.
*/
export async function runSearchCommand(queryParts: string[]): Promise<void> {
ensureInstalledOrExit();
@@ -114,7 +114,7 @@ export async function runSearchCommand(queryParts: string[]): Promise<void> {
}
const workerPort = process.env.CLAUDE_MEM_WORKER_PORT || '37777';
const searchUrl = `http://127.0.0.1:${workerPort}/api/search?q=${encodeURIComponent(query)}`;
const searchUrl = `http://127.0.0.1:${workerPort}/api/search?query=${encodeURIComponent(query)}`;
try {
const response = await fetch(searchUrl);
+24 -53
View File
@@ -6,7 +6,7 @@
*
* 1. Writes/merges transcript-watch config to ~/.claude-mem/transcript-watch.json
* 2. Sets up watch for ~/.codex/sessions/**\/*.jsonl using existing watcher
* 3. Injects context via ~/.codex/AGENTS.md (Codex reads this natively)
* 3. Injects context via workspace-local AGENTS.md files (Codex reads these natively)
*
* Anti-patterns:
* - Does NOT add notify hooks -- transcript watching is sufficient
@@ -67,7 +67,7 @@ function loadExistingTranscriptWatchConfig(): TranscriptWatchConfig {
return parsed;
} catch (parseError) {
logger.error('CODEX', 'Corrupt transcript-watch.json, creating backup', { path: configPath }, parseError as Error);
logger.error('SYSTEM', 'Corrupt transcript-watch.json, creating backup', { path: configPath }, parseError as Error);
// Back up corrupt file
const backupPath = `${configPath}.backup.${Date.now()}`;
@@ -130,42 +130,10 @@ function writeTranscriptWatchConfig(config: TranscriptWatchConfig): void {
// ---------------------------------------------------------------------------
/**
* Inject claude-mem context section into ~/.codex/AGENTS.md.
* Uses the same <claude-mem-context> tag pattern as CLAUDE.md and GEMINI.md.
* Remove legacy claude-mem context from ~/.codex/AGENTS.md.
* Codex now uses workspace-local AGENTS.md files to avoid cross-project bleed.
* Preserves any existing user content outside the tags.
*/
function injectCodexAgentsMdContext(): void {
try {
mkdirSync(CODEX_DIR, { recursive: true });
let existingContent = '';
if (existsSync(CODEX_AGENTS_MD_PATH)) {
existingContent = readFileSync(CODEX_AGENTS_MD_PATH, 'utf-8');
}
// Initial placeholder content -- will be populated after first session
const contextContent = [
'# Recent Activity',
'',
'<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->',
'',
'*No context yet. Complete your first session and context will appear here.*',
].join('\n');
const finalContent = replaceTaggedContent(existingContent, contextContent);
writeFileSync(CODEX_AGENTS_MD_PATH, finalContent);
console.log(` Injected context placeholder into ${CODEX_AGENTS_MD_PATH}`);
} catch (error) {
// Non-fatal -- transcript watching still works without context injection
logger.warn('CODEX', 'Failed to inject AGENTS.md context', { error: (error as Error).message });
console.warn(` Warning: Could not inject context into AGENTS.md: ${(error as Error).message}`);
}
}
/**
* Remove claude-mem context section from AGENTS.md.
* Preserves user content outside the <claude-mem-context> tags.
*/
function removeCodexAgentsMdContext(): void {
try {
if (!existsSync(CODEX_AGENTS_MD_PATH)) return;
@@ -179,7 +147,6 @@ function removeCodexAgentsMdContext(): void {
if (startIdx === -1 || endIdx === -1) return;
// Remove the tagged section and any surrounding blank lines
const before = content.substring(0, startIdx).replace(/\n+$/, '');
const after = content.substring(endIdx + endTag.length).replace(/^\n+/, '');
const finalContent = (before + (after ? '\n\n' + after : '')).trim();
@@ -187,17 +154,21 @@ function removeCodexAgentsMdContext(): void {
if (finalContent) {
writeFileSync(CODEX_AGENTS_MD_PATH, finalContent + '\n');
} else {
// File would be empty -- leave it empty rather than deleting
// (user may have other tooling that expects it to exist)
writeFileSync(CODEX_AGENTS_MD_PATH, '');
}
console.log(` Removed context section from ${CODEX_AGENTS_MD_PATH}`);
console.log(` Removed legacy global context from ${CODEX_AGENTS_MD_PATH}`);
} catch (error) {
logger.warn('CODEX', 'Failed to clean AGENTS.md context', { error: (error as Error).message });
logger.warn('SYSTEM', 'Failed to clean AGENTS.md context', { error: (error as Error).message });
}
}
/**
* @deprecated Codex now uses workspace-local AGENTS.md via transcript processor fallback.
* Preserves user content outside the <claude-mem-context> tags.
*/
const cleanupLegacyCodexAgentsMdContext = removeCodexAgentsMdContext;
// ---------------------------------------------------------------------------
// Public API: Install
// ---------------------------------------------------------------------------
@@ -206,7 +177,7 @@ function removeCodexAgentsMdContext(): void {
* Install Codex CLI integration for claude-mem.
*
* 1. Merges Codex transcript-watch config into ~/.claude-mem/transcript-watch.json
* 2. Injects context placeholder into ~/.codex/AGENTS.md
* 2. Cleans up any legacy global context block in ~/.codex/AGENTS.md
*
* @returns 0 on success, 1 on failure
*/
@@ -222,19 +193,19 @@ export async function installCodexCli(): Promise<number> {
console.log(` Watch path: ~/.codex/sessions/**/*.jsonl`);
console.log(` Schema: codex (v${SAMPLE_CONFIG.schemas?.codex?.version ?? '?'})`);
// Step 2: Inject context into AGENTS.md
injectCodexAgentsMdContext();
// Step 2: Clean up legacy global AGENTS.md context
cleanupLegacyCodexAgentsMdContext();
console.log(`
Installation complete!
Transcript watch config: ${DEFAULT_CONFIG_PATH}
Context file: ${CODEX_AGENTS_MD_PATH}
Context files: <workspace>/AGENTS.md
How it works:
- claude-mem watches Codex session JSONL files for new activity
- No hooks needed -- transcript watching is fully automatic
- Context from past sessions is injected via ${CODEX_AGENTS_MD_PATH}
- Context from past sessions is injected via AGENTS.md in the active Codex workspace
Next steps:
1. Start claude-mem worker: npx claude-mem start
@@ -284,8 +255,8 @@ export function uninstallCodexCli(): number {
console.log(' No transcript-watch.json found -- nothing to remove.');
}
// Step 2: Remove context section from AGENTS.md
removeCodexAgentsMdContext();
// Step 2: Remove legacy global context section from AGENTS.md
cleanupLegacyCodexAgentsMdContext();
console.log('\nUninstallation complete!');
console.log('Restart claude-mem worker to apply changes.\n');
@@ -340,20 +311,20 @@ export function checkCodexCliStatus(): number {
// Check context config
if (codexWatch.context) {
console.log(` Context mode: ${codexWatch.context.mode}`);
console.log(` Context path: ${codexWatch.context.path ?? 'default'}`);
console.log(` Context path: ${codexWatch.context.path ?? '<workspace>/AGENTS.md (default)'}`);
console.log(` Context updates on: ${codexWatch.context.updateOn?.join(', ') ?? 'none'}`);
}
// Check AGENTS.md
// Check legacy global AGENTS.md usage
if (existsSync(CODEX_AGENTS_MD_PATH)) {
const mdContent = readFileSync(CODEX_AGENTS_MD_PATH, 'utf-8');
if (mdContent.includes('<claude-mem-context>')) {
console.log(` Context: Active (${CODEX_AGENTS_MD_PATH})`);
console.log(` Legacy global context: Present (${CODEX_AGENTS_MD_PATH})`);
} else {
console.log(` Context: AGENTS.md exists but no context tags`);
console.log(` Legacy global context: Not active`);
}
} else {
console.log(` Context: No AGENTS.md file`);
console.log(` Legacy global context: None`);
}
// Check if ~/.codex/sessions exists (indicates Codex has been used)
-1
View File
@@ -97,7 +97,6 @@ export const SAMPLE_CONFIG: TranscriptWatchConfig = {
startAtEnd: true,
context: {
mode: 'agents',
path: '~/.codex/AGENTS.md',
updateOn: ['session_start', 'session_end']
}
}
+28
View File
@@ -0,0 +1,28 @@
import { describe, it, expect } from 'bun:test';
import { readFileSync } from 'fs';
import { join } from 'path';
const configSource = readFileSync(
join(__dirname, '..', 'src', 'services', 'transcripts', 'config.ts'),
'utf-8',
);
const installerSource = readFileSync(
join(__dirname, '..', 'src', 'services', 'integrations', 'CodexCliInstaller.ts'),
'utf-8',
);
describe('Codex workspace-local context', () => {
it('does not hardcode ~/.codex/AGENTS.md in the sample transcript watch config', () => {
expect(configSource).not.toContain("path: '~/.codex/AGENTS.md'");
});
it('documents workspace-local AGENTS.md injection for Codex', () => {
expect(installerSource).toContain('workspace-local AGENTS.md');
expect(installerSource).toContain('Context files: <workspace>/AGENTS.md');
});
it('cleans legacy global Codex context during install', () => {
expect(installerSource).toContain('cleanupLegacyCodexAgentsMdContext();');
expect(installerSource).toContain('Removed legacy global context');
});
});
+24
View File
@@ -0,0 +1,24 @@
import { describe, it, expect } from 'bun:test';
import { readFileSync } from 'fs';
import { join } from 'path';
const runtimeSourcePath = join(
__dirname,
'..',
'src',
'npx-cli',
'commands',
'runtime.ts',
);
const runtimeSource = readFileSync(runtimeSourcePath, 'utf-8');
describe('NPX search query param', () => {
it('documents the search endpoint with query param', () => {
expect(runtimeSource).toContain('GET /api/search?query=<query>');
});
it('uses query param instead of q param for worker search requests', () => {
expect(runtimeSource).toContain('/api/search?query=${encodeURIComponent(query)}');
expect(runtimeSource).not.toContain('/api/search?q=${encodeURIComponent(query)}');
});
});