mirror of
https://github.com/yamadashy/repomix.git
synced 2026-09-19 06:00:49 +08:00
refactor(shared): Centralise $TMPDIR/repomix umbrella in shared/tmpDir
intent(tmp-dir): a single grep should find every consumer of the `$TMPDIR/repomix/` umbrella; previously the path was rebuilt independently in mcpToolRuntime and tokenCountCache, with no shared anchor preventing future drift decision(api-shape): expose only `getRepomixTmpDir()` + the `REPOMIX_TMP_DIR_NAME` constant — callers append their own subdirectory (`mcp-outputs`, `cache`) and own their mkdir/mkdtemp/permissions, since each consumer's lifecycle and creation pattern differs rejected(scope): folding `--remote`'s `mkdtemp(repomix-)` into the umbrella was considered but skipped — it uses a different prefix-based scheme at the $TMPDIR root, not the shared umbrella, and changing it is a user-visible path change worth handling separately
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
import fs from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { logger } from '../../shared/logger.js';
|
||||
import { getRepomixTmpDir } from '../../shared/tmpDir.js';
|
||||
import type { TokenEncoding } from './tokenEncodings.js';
|
||||
|
||||
// Cache schema version. Bump when the on-disk format changes incompatibly so
|
||||
@@ -14,10 +14,8 @@ const CACHE_VERSION = 1;
|
||||
// cap is exceeded the oldest entries are dropped at save time.
|
||||
export const MAX_CACHE_ENTRIES = 100_000;
|
||||
|
||||
// Cache lives under $TMPDIR/repomix/cache/ to share the `repomix/` parent
|
||||
// directory with other ephemeral state (e.g. mcp-outputs/), so all repomix
|
||||
// temp artifacts on a host are siblings under one umbrella.
|
||||
const CACHE_DIR_NAME = 'repomix';
|
||||
// Cache lives under $TMPDIR/repomix/cache/, sharing the `repomix/` umbrella
|
||||
// (see shared/tmpDir.ts) with other ephemeral state such as mcp-outputs/.
|
||||
const CACHE_SUBDIR_NAME = 'cache';
|
||||
const CACHE_FILE_NAME = 'token-counts.json';
|
||||
|
||||
@@ -49,7 +47,7 @@ let state = createState();
|
||||
export const getCacheFilePath = (): string => {
|
||||
const override = process.env.REPOMIX_TOKEN_CACHE_PATH;
|
||||
if (override) return override;
|
||||
return path.join(os.tmpdir(), CACHE_DIR_NAME, CACHE_SUBDIR_NAME, CACHE_FILE_NAME);
|
||||
return path.join(getRepomixTmpDir(), CACHE_SUBDIR_NAME, CACHE_FILE_NAME);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import crypto from 'node:crypto';
|
||||
import fs from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
||||
import { generateTreeString } from '../../core/file/fileTreeGenerate.js';
|
||||
import type { ProcessedFile } from '../../core/file/fileTypes.js';
|
||||
import { getRepomixTmpDir } from '../../shared/tmpDir.js';
|
||||
|
||||
// Map to store generated output files
|
||||
const outputFileRegistry = new Map<string, string>();
|
||||
@@ -48,7 +48,7 @@ type McpToolStructuredContent = (BaseMcpToolResponse & Record<string, unknown>)
|
||||
*/
|
||||
export const createToolWorkspace = async (): Promise<string> => {
|
||||
try {
|
||||
const tmpBaseDir = path.join(os.tmpdir(), 'repomix', 'mcp-outputs');
|
||||
const tmpBaseDir = path.join(getRepomixTmpDir(), 'mcp-outputs');
|
||||
await fs.mkdir(tmpBaseDir, { recursive: true });
|
||||
const tempDir = await fs.mkdtemp(`${tmpBaseDir}/`);
|
||||
return tempDir;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
||||
// Shared umbrella directory under $TMPDIR for all repomix temp artifacts
|
||||
// (MCP outputs, token-count cache, future ephemeral state). Centralised here
|
||||
// so a single grep finds every consumer and the umbrella never drifts.
|
||||
export const REPOMIX_TMP_DIR_NAME = 'repomix';
|
||||
|
||||
/**
|
||||
* Returns `$TMPDIR/repomix`. Callers append their own subdirectory and are
|
||||
* responsible for creating it (recursive mkdir, mkdtemp, permissions etc.)
|
||||
* because each consumer has different needs.
|
||||
*/
|
||||
export const getRepomixTmpDir = (): string => {
|
||||
return path.join(os.tmpdir(), REPOMIX_TMP_DIR_NAME);
|
||||
};
|
||||
@@ -63,7 +63,10 @@ describe('mcpToolRuntime', () => {
|
||||
const tempDir = await createToolWorkspace();
|
||||
|
||||
expect(os.tmpdir).toHaveBeenCalled();
|
||||
expect(path.join).toHaveBeenCalledWith('/tmp', 'repomix', 'mcp-outputs');
|
||||
// path.join is now invoked twice: once inside shared/tmpDir.getRepomixTmpDir
|
||||
// to build the umbrella, then again here to append the mcp-outputs subdir.
|
||||
expect(path.join).toHaveBeenCalledWith('/tmp', 'repomix');
|
||||
expect(path.join).toHaveBeenCalledWith('/tmp/repomix', 'mcp-outputs');
|
||||
expect(fs.mkdir).toHaveBeenCalledWith('/tmp/repomix/mcp-outputs', { recursive: true });
|
||||
expect(fs.mkdtemp).toHaveBeenCalledWith('/tmp/repomix/mcp-outputs/');
|
||||
expect(tempDir).toBe('/tmp/repomix/mcp-outputs/temp-dir');
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { getRepomixTmpDir, REPOMIX_TMP_DIR_NAME } from '../../src/shared/tmpDir.js';
|
||||
|
||||
describe('shared/tmpDir', () => {
|
||||
it('returns a path under os.tmpdir() ending with the umbrella name', () => {
|
||||
const dir = getRepomixTmpDir();
|
||||
expect(dir.startsWith(os.tmpdir())).toBe(true);
|
||||
expect(path.basename(dir)).toBe(REPOMIX_TMP_DIR_NAME);
|
||||
expect(REPOMIX_TMP_DIR_NAME).toBe('repomix');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user