* Get post-compaction context state for a workspace. * Returns info about what will be injected after compaction. * Prefers cached paths from pending compaction, falls back to history extraction.
(workspaceId: string)
| 2888 | * Prefers cached paths from pending compaction, falls back to history extraction. |
| 2889 | */ |
| 2890 | public async getPostCompactionState(workspaceId: string): Promise<{ |
| 2891 | planPath: string | null; |
| 2892 | trackedFilePaths: string[]; |
| 2893 | excludedItems: string[]; |
| 2894 | }> { |
| 2895 | // Get workspace metadata to create runtime for plan file check |
| 2896 | const metadata = await this.getInfo(workspaceId); |
| 2897 | if (!metadata) { |
| 2898 | // Can't get metadata, return empty state |
| 2899 | const exclusions = await this.getPostCompactionExclusions(workspaceId); |
| 2900 | return { planPath: null, trackedFilePaths: [], excludedItems: exclusions.excludedItems }; |
| 2901 | } |
| 2902 | |
| 2903 | const runtime = createRuntimeForWorkspace(metadata); |
| 2904 | const muxHome = runtime.getMuxHome(); |
| 2905 | const planPath = getPlanFilePath(metadata.name, metadata.projectName, muxHome); |
| 2906 | // For local/SSH: expand tilde for comparison with message history paths |
| 2907 | // For Docker: paths are already absolute (/var/mux/...), no expansion needed |
| 2908 | const expandedPlanPath = muxHome.startsWith("~") ? expandTilde(planPath) : planPath; |
| 2909 | // Legacy plan path (stored by workspace ID) for filtering |
| 2910 | const legacyPlanPath = getLegacyPlanFilePath(workspaceId); |
| 2911 | const expandedLegacyPlanPath = expandTilde(legacyPlanPath); |
| 2912 | |
| 2913 | // Check both new and legacy plan paths, prefer new path |
| 2914 | const newPlanExists = await fileExists(runtime, planPath); |
| 2915 | const legacyPlanExists = !newPlanExists && (await fileExists(runtime, legacyPlanPath)); |
| 2916 | // Resolve plan path via runtime to get correct absolute path for deep links. |
| 2917 | // Local: expands ~ to local home. SSH: expands ~ on remote host. |
| 2918 | const activePlanPath = newPlanExists |
| 2919 | ? await runtime.resolvePath(planPath) |
| 2920 | : legacyPlanExists |
| 2921 | ? await runtime.resolvePath(legacyPlanPath) |
| 2922 | : null; |
| 2923 | |
| 2924 | // Load exclusions |
| 2925 | const exclusions = await this.getPostCompactionExclusions(workspaceId); |
| 2926 | |
| 2927 | // Helper to check if a path is a plan file (new or legacy format) |
| 2928 | const isPlanPath = (p: string) => |
| 2929 | p === planPath || |
| 2930 | p === expandedPlanPath || |
| 2931 | p === legacyPlanPath || |
| 2932 | p === expandedLegacyPlanPath; |
| 2933 | |
| 2934 | // If session has pending compaction attachments, use cached paths |
| 2935 | // (history is cleared after compaction, but cache survives) |
| 2936 | const session = this.sessions.get(workspaceId); |
| 2937 | const pendingPaths = session?.getPendingTrackedFilePaths(); |
| 2938 | if (pendingPaths) { |
| 2939 | // Filter out both new and legacy plan file paths |
| 2940 | const trackedFilePaths = pendingPaths.filter((p) => !isPlanPath(p)); |
| 2941 | return { |
| 2942 | planPath: activePlanPath, |
| 2943 | trackedFilePaths, |
| 2944 | excludedItems: exclusions.excludedItems, |
| 2945 | }; |
| 2946 | } |
| 2947 |
no test coverage detected