package artifacts import ( "path/filepath" "gitea.maximumdirect.net/eric/narratio/internal/config" ) // SessionPaths contains canonical local paths for one session work directory. type SessionPaths struct { WorkspaceRoot string CampaignID string SessionID string Root string InputsDir string AudioDir string TranscriptsDir string TranscriptsRawDir string TranscriptsTrimmedDir string ArtifactsDir string ReportsDir string ConfigDir string LogsDir string CurrentDir string RunsDir string ManifestPath string LockPath string } // SessionWorkDirForCampaign returns the canonical campaign-aware work directory for one session. func SessionWorkDirForCampaign(rootDir, campaign, sessionID string) string { return filepath.Join(rootDir, config.PathWorkDirSegment, campaign, sessionID) } // SessionManifestPathForCampaign returns the canonical session manifest path. func SessionManifestPathForCampaign(rootDir, campaign, sessionID string) string { return filepath.Join(SessionWorkDirForCampaign(rootDir, campaign, sessionID), config.PathManifestFile) } // SessionRunsDirForCampaign returns the canonical runs directory for one session. func SessionRunsDirForCampaign(rootDir, campaign, sessionID string) string { return filepath.Join(SessionWorkDirForCampaign(rootDir, campaign, sessionID), config.PathRunsDirSegment) } // SessionRunRootForCampaign returns the canonical run root under runs/{run_id}. func SessionRunRootForCampaign(rootDir, campaign, sessionID, runID string) string { return filepath.Join(SessionRunsDirForCampaign(rootDir, campaign, sessionID), runID) } // SessionRunManifestPathForCampaign returns the canonical run manifest path under runs/{run_id}/manifest.json. func SessionRunManifestPathForCampaign(rootDir, campaign, sessionID, runID string) string { return filepath.Join(SessionRunRootForCampaign(rootDir, campaign, sessionID, runID), config.PathManifestFile) } // SessionRunStageDirForCampaign returns the canonical stage directory under runs/{run_id}/{stage}. func SessionRunStageDirForCampaign(rootDir, campaign, sessionID, runID, stageName string) string { return filepath.Join(SessionRunRootForCampaign(rootDir, campaign, sessionID, runID), stageName) } // SessionSpoolAudioDir returns the campaign/session/run scoped local spool audio path. func SessionSpoolAudioDir(spoolRoot, campaign, sessionID, runID string) string { return filepath.Join(spoolRoot, campaign, sessionID, runID, config.PathAudioDirSegment) } func buildSessionPaths(workspaceRoot, campaign, sessionID string) SessionPaths { root := SessionWorkDirForCampaign(workspaceRoot, campaign, sessionID) return buildSessionPathsFromRoot(workspaceRoot, campaign, sessionID, root) } func buildSessionPathsFromRoot(workspaceRoot, campaign, sessionID, root string) SessionPaths { return SessionPaths{ WorkspaceRoot: workspaceRoot, CampaignID: campaign, SessionID: sessionID, Root: root, InputsDir: filepath.Join(root, config.PathInputsDirSegment), AudioDir: filepath.Join(root, config.PathAudioDirSegment), TranscriptsDir: filepath.Join(root, config.PathTranscriptsSegment), TranscriptsRawDir: filepath.Join(root, filepath.FromSlash(config.PathTranscriptsRaw)), TranscriptsTrimmedDir: filepath.Join(root, filepath.FromSlash(config.PathTranscriptsTrimmed)), ArtifactsDir: filepath.Join(root, config.PathArtifactsDirSegment), ReportsDir: filepath.Join(root, config.PathReportsDirSegment), ConfigDir: filepath.Join(root, config.PathConfigDirSegment), LogsDir: filepath.Join(root, config.PathLogsDirSegment), CurrentDir: filepath.Join(root, config.PathCurrentDirSegment), RunsDir: filepath.Join(root, config.PathRunsDirSegment), ManifestPath: filepath.Join(root, config.PathManifestFile), LockPath: filepath.Join(root, config.PathLockFile), } }