diff --git a/.changeset/fix-migration-legacy-shared-slugify.md b/.changeset/fix-migration-legacy-shared-slugify.md new file mode 100644 index 000000000..a9d69fcb1 --- /dev/null +++ b/.changeset/fix-migration-legacy-shared-slugify.md @@ -0,0 +1,14 @@ +--- +"@moonshot-ai/agent-core": patch +"@moonshot-ai/kimi-code": patch +"@moonshot-ai/migration-legacy": patch +--- + +fix(migration-legacy): use shared slugifyWorkDirName from agent-core + +Exports `slugifyWorkDirName` from `@moonshot-ai/agent-core` and removes the +duplicate local implementation in `packages/migration-legacy/src/sessions/workdir-bucket.ts`. + +No user-visible behavior change. The migrator now imports the canonical +slugifier, so migrated bucket names stay byte-identical to agent-core +without manual sync. diff --git a/packages/agent-core/src/index.ts b/packages/agent-core/src/index.ts index 8c28740f3..5153d8dd2 100644 --- a/packages/agent-core/src/index.ts +++ b/packages/agent-core/src/index.ts @@ -15,6 +15,7 @@ export { resolveGlobalLogPath, } from './logging/logger'; export { resolveLoggingConfig } from './logging/resolve-config'; +export { slugifyWorkDirName } from './utils/workdir-slug'; export type { ResolveLoggingInput } from './logging/resolve-config'; export type { LogContext, diff --git a/packages/migration-legacy/src/sessions/workdir-bucket.ts b/packages/migration-legacy/src/sessions/workdir-bucket.ts index 7a8222a7a..fe1cd1a7e 100644 --- a/packages/migration-legacy/src/sessions/workdir-bucket.ts +++ b/packages/migration-legacy/src/sessions/workdir-bucket.ts @@ -1,26 +1,22 @@ import { basename, resolve } from 'node:path'; import { createHash } from 'node:crypto'; +import { slugifyWorkDirName } from '@moonshot-ai/agent-core'; + const WORKDIR_KEY_PREFIX = 'wd_'; const HASH_LENGTH = 12; /** * Compute the v2 bucket directory name `wd__` for a workdir - * path. Hash function and slug rules mirror - * `packages/kimi-core/src/utils/workdir-slug.ts` and - * `packages/kimi-core/src/harness/session-manager/workdir-key.ts:13–18`. + * path. Slug rules use `slugifyWorkDirName` from `@moonshot-ai/agent-core` + * (file: `packages/agent-core/src/utils/workdir-slug.ts`); hash and resolve + * logic mirror `packages/agent-core/src/harness/session-manager/workdir-key.ts`. * * IMPORTANT: agent-core's `encodeWorkDirKey` runs `resolve()` on the workdir * before hashing/slugifying, and the session picker locates sessions purely * by `readdir(encodeWorkDirKey(...))` — it never consults `session_index.jsonl`. * We MUST apply the same `resolve()` here or migrated sessions become * invisible in the picker. - * - * TODO: The canonical slugifier is `slugifyWorkDirName` in - * `@moonshot-ai/agent-core` (file: `src/utils/workdir-slug.ts`). It is not part - * of that package's public export surface today. When/if it becomes public, - * delete the local duplicate below and import it from agent-core directly so - * buckets stay byte-identical between the running app and this migrator. */ export function computeWorkdirBucket(workdirPath: string): string { const normalized = resolve(workdirPath); @@ -34,18 +30,4 @@ export function oldMd5BucketName(workdirPath: string): string { return createHash('md5').update(workdirPath).digest('hex'); } -const MAX_WORKDIR_SLUG_LENGTH = 40; -/** - * Local copy of kimi-core's `slugifyWorkDirName`. Keep byte-identical to the - * canonical implementation in `packages/kimi-core/src/utils/workdir-slug.ts`. - */ -function slugifyWorkDirName(name: string): string { - const slug = name - .toLowerCase() - .replaceAll(/[^a-z0-9._-]+/g, '-') - .replaceAll(/^-+|-+$/g, '') - .slice(0, MAX_WORKDIR_SLUG_LENGTH) - .replaceAll(/^-+|-+$/g, ''); - return slug === '' || slug === '.' || slug === '..' ? 'workspace' : slug; -}