Files
wehub-resource-sync adc62957a7
CI / Multi-repo Path Gate (AST-grep) (windows-latest) (push) Has been cancelled
CI / Version Consistency Check (push) Has been cancelled
CI / npm pack + install test (push) Has been cancelled
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Test (Windows path suite) (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / No Committed Build Artifacts (push) Has been cancelled
CI / Multi-repo Path Gate (AST-grep) (ubuntu-latest) (push) Has been cancelled
Upgrade Test / omc update + session-start hook (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:36:54 +08:00

91 lines
3.7 KiB
JavaScript

// Thin delegator → src/lib/worktree-paths.ts::resolveSessionStatePaths. DO NOT reimplement here.
/**
* State Root Resolver (ESM)
*
* Single authoritative entry point for resolving the .omc root directory in
* hook scripts, respecting the OMC_STATE_DIR environment variable.
*
* Delegates to getOmcRoot() from dist/lib/worktree-paths.js (the canonical
* implementation) when CLAUDE_PLUGIN_ROOT is available. Falls back to inline
* logic when dist is not built — this should never happen in production, but
* provides a safe fallback during development or first-run scenarios.
*
* Inline fallback notes:
* - Uses directory path as hash source (not git remote URL). Matches
* canonical behavior for local-only repos; may differ for remote-backed
* repos when dist is missing — acceptable since dist is always present
* in production (CLAUDE_PLUGIN_ROOT is always set).
*/
import { join, basename } from 'path';
import { existsSync } from 'fs';
import { createHash } from 'crypto';
import { pathToFileURL } from 'url';
/**
* Resolve the .omc root directory, respecting OMC_STATE_DIR.
*
* @param {string} directory - Worktree root directory
* @returns {Promise<string>} Absolute path to the .omc root
*/
export async function resolveOmcStateRoot(directory) {
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
if (pluginRoot) {
try {
const { getOmcRoot } = await import(
pathToFileURL(join(pluginRoot, 'dist', 'lib', 'worktree-paths.js')).href
);
return getOmcRoot(directory);
} catch {
// dist not built or unavailable — fall through to inline fallback
}
}
// Inline fallback: respects OMC_STATE_DIR with simplified project identifier
const customDir = process.env.OMC_STATE_DIR;
if (customDir) {
const hash = createHash('sha256').update(directory).digest('hex').slice(0, 16);
const dirName = basename(directory).replace(/[^a-zA-Z0-9_-]/g, '_');
return join(customDir, `${dirName}-${hash}`);
}
return join(directory, '.omc');
}
/**
* Resolve session-scoped state paths for a given directory, state name, and session ID.
* Delegates to resolveSessionStatePaths() in dist/lib/worktree-paths.js.
*
* @param {string} directory - Worktree root directory
* @param {string} stateName - State name (e.g., "ralph", "ultrawork")
* @param {string} [sessionId] - Optional session identifier
* @returns {Promise<{readPath: string, writePath: string}>} Unbranded path pair
*/
export async function resolveSessionStatePathsForHook(directory, stateName, sessionId) {
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
if (pluginRoot) {
try {
const { resolveSessionStatePaths } = await import(
pathToFileURL(join(pluginRoot, 'dist', 'lib', 'worktree-paths.js')).href
);
const result = resolveSessionStatePaths(stateName, sessionId, directory);
return { readPath: result.effectiveRead, writePath: result.effectiveWrite };
} catch {
// dist not built or unavailable — fall through to inline fallback
}
}
// Inline fallback: basic session-scoped path derivation (production always uses dist above)
const omcRoot = await resolveOmcStateRoot(directory);
const normalizedName = stateName.endsWith('-state') ? stateName : `${stateName}-state`;
const legacy = join(omcRoot, 'state', `${normalizedName}.json`);
if (!sessionId) {
return { readPath: legacy, writePath: legacy };
}
const sessionScoped = join(omcRoot, 'state', 'sessions', sessionId, `${normalizedName}.json`);
// effectiveRead probes the session-scoped file first and falls back to the
// legacy path when it does not exist yet (mirrors resolveSessionStatePaths).
const readPath = existsSync(sessionScoped) ? sessionScoped : legacy;
return { readPath, writePath: sessionScoped };
}