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
91 lines
3.7 KiB
JavaScript
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 };
|
|
}
|