mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-10-10 03:28:03 +00:00
fix: persist task history in Dev Containers across rebuilds
- Add Dev Container detection logic to identify when running in containers - Implement automatic storage path detection for persistent storage locations - Add user notification system to warn about ephemeral storage in Dev Containers - Integrate Dev Container support into existing storage utility - Add comprehensive test coverage for Dev Container scenarios Fixes #8681
This commit is contained in:
parent
270dce5050
commit
e361447c26
4 changed files with 565 additions and 1 deletions
|
|
@ -31,6 +31,7 @@ import { MdmService } from "./services/mdm/MdmService"
|
|||
import { migrateSettings } from "./utils/migrateSettings"
|
||||
import { autoImportSettings } from "./utils/autoImportSettings"
|
||||
import { API } from "./extension/api"
|
||||
import { notifyDevContainerStorageSetup } from "./utils/devContainer"
|
||||
|
||||
import {
|
||||
handleUri,
|
||||
|
|
@ -68,6 +69,22 @@ export async function activate(context: vscode.ExtensionContext) {
|
|||
// Migrate old settings to new
|
||||
await migrateSettings(context, outputChannel)
|
||||
|
||||
// Check for Dev Container and notify user about storage setup
|
||||
const devContainerNotificationDismissed = context.globalState.get<boolean>(
|
||||
"devContainerStorageNotificationDismissed",
|
||||
false,
|
||||
)
|
||||
if (!devContainerNotificationDismissed) {
|
||||
// Run this asynchronously so it doesn't block activation
|
||||
setTimeout(() => {
|
||||
notifyDevContainerStorageSetup(context).catch((error) => {
|
||||
outputChannel.appendLine(
|
||||
`[DevContainer] Failed to check Dev Container storage: ${error instanceof Error ? error.message : String(error)}`,
|
||||
)
|
||||
})
|
||||
}, 3000) // Delay slightly to let the extension fully activate
|
||||
}
|
||||
|
||||
// Initialize telemetry service.
|
||||
const telemetryService = TelemetryService.createInstance()
|
||||
|
||||
|
|
|
|||
393
src/utils/__tests__/devContainer.spec.ts
Normal file
393
src/utils/__tests__/devContainer.spec.ts
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"
|
||||
import * as vscode from "vscode"
|
||||
import * as fs from "fs/promises"
|
||||
|
||||
// Mock vscode module
|
||||
vi.mock("vscode", () => ({
|
||||
env: {
|
||||
remoteName: undefined,
|
||||
},
|
||||
workspace: {
|
||||
workspaceFolders: undefined,
|
||||
getConfiguration: vi.fn(),
|
||||
},
|
||||
window: {
|
||||
showWarningMessage: vi.fn(),
|
||||
showInformationMessage: vi.fn(),
|
||||
},
|
||||
ConfigurationTarget: {
|
||||
Global: 1,
|
||||
},
|
||||
}))
|
||||
|
||||
// Mock fs/promises
|
||||
vi.mock("fs/promises", () => ({
|
||||
default: {
|
||||
mkdir: vi.fn(),
|
||||
access: vi.fn(),
|
||||
constants: {
|
||||
R_OK: 4,
|
||||
W_OK: 2,
|
||||
X_OK: 1,
|
||||
},
|
||||
},
|
||||
mkdir: vi.fn(),
|
||||
access: vi.fn(),
|
||||
constants: {
|
||||
R_OK: 4,
|
||||
W_OK: 2,
|
||||
X_OK: 1,
|
||||
},
|
||||
}))
|
||||
|
||||
// Mock fs module
|
||||
vi.mock("fs", () => ({
|
||||
accessSync: vi.fn(),
|
||||
constants: {
|
||||
F_OK: 0,
|
||||
},
|
||||
}))
|
||||
|
||||
// Import after mocks are set up
|
||||
import {
|
||||
isRunningInDevContainer,
|
||||
getDevContainerPersistentPath,
|
||||
isEphemeralStoragePath,
|
||||
notifyDevContainerStorageSetup,
|
||||
} from "../devContainer"
|
||||
|
||||
describe("devContainer", () => {
|
||||
beforeEach(() => {
|
||||
// Reset all mocks
|
||||
vi.clearAllMocks()
|
||||
// Reset environment variables
|
||||
delete process.env.REMOTE_CONTAINERS
|
||||
delete process.env.CODESPACES
|
||||
delete process.env.DEVCONTAINER
|
||||
// Reset vscode.env.remoteName
|
||||
;(vscode.env as any).remoteName = undefined
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
describe("isRunningInDevContainer", () => {
|
||||
it("should return true when REMOTE_CONTAINERS env var is set", () => {
|
||||
process.env.REMOTE_CONTAINERS = "true"
|
||||
expect(isRunningInDevContainer()).toBe(true)
|
||||
})
|
||||
|
||||
it("should return true when CODESPACES env var is set", () => {
|
||||
process.env.CODESPACES = "true"
|
||||
expect(isRunningInDevContainer()).toBe(true)
|
||||
})
|
||||
|
||||
it("should return true when DEVCONTAINER env var is set", () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
expect(isRunningInDevContainer()).toBe(true)
|
||||
})
|
||||
|
||||
it("should return true when /.dockerenv file exists", async () => {
|
||||
const fsModule = vi.mocked(await import("fs"))
|
||||
fsModule.accessSync.mockImplementation(() => {
|
||||
// Success - file exists
|
||||
return undefined
|
||||
})
|
||||
expect(isRunningInDevContainer()).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false when /.dockerenv file does not exist", async () => {
|
||||
const fsModule = vi.mocked(await import("fs"))
|
||||
fsModule.accessSync.mockImplementation(() => {
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(vscode.env as any).remoteName = undefined
|
||||
expect(isRunningInDevContainer()).toBe(false)
|
||||
})
|
||||
|
||||
it("should return true when VSCode remoteName contains 'container'", async () => {
|
||||
const fsModule = vi.mocked(await import("fs"))
|
||||
;(vscode.env as any).remoteName = "dev-container"
|
||||
fsModule.accessSync.mockImplementation(() => {
|
||||
throw new Error("File not found")
|
||||
})
|
||||
expect(isRunningInDevContainer()).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false when not in a container", async () => {
|
||||
const fsModule = vi.mocked(await import("fs"))
|
||||
fsModule.accessSync.mockImplementation(() => {
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(vscode.env as any).remoteName = "ssh-remote"
|
||||
expect(isRunningInDevContainer()).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("getDevContainerPersistentPath", () => {
|
||||
it("should return null when not in a Dev Container", async () => {
|
||||
// Ensure we're not in a Dev Container
|
||||
const fsModule = vi.mocked(await import("fs"))
|
||||
fsModule.accessSync.mockImplementation(() => {
|
||||
throw new Error("File not found")
|
||||
})
|
||||
const result = await getDevContainerPersistentPath()
|
||||
expect(result).toBe(null)
|
||||
})
|
||||
|
||||
it("should return workspace-relative path when available and writable", async () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
;(vscode.workspace as any).workspaceFolders = [
|
||||
{
|
||||
uri: {
|
||||
fsPath: "/workspace/myproject",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const mockMkdir = vi.mocked(fs.mkdir)
|
||||
const mockAccess = vi.mocked(fs.access)
|
||||
|
||||
mockMkdir.mockResolvedValue(undefined)
|
||||
mockAccess.mockResolvedValue(undefined)
|
||||
|
||||
const result = await getDevContainerPersistentPath()
|
||||
expect(result).toBe("/workspace/myproject/.roo-data")
|
||||
expect(mockMkdir).toHaveBeenCalledWith("/workspace/myproject/.roo-data", { recursive: true })
|
||||
})
|
||||
|
||||
it("should try alternative paths when primary path fails", async () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
;(vscode.workspace as any).workspaceFolders = [
|
||||
{
|
||||
uri: {
|
||||
fsPath: "/workspace/myproject",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const mockMkdir = vi.mocked(fs.mkdir)
|
||||
const mockAccess = vi.mocked(fs.access)
|
||||
|
||||
// First path fails
|
||||
mockMkdir.mockRejectedValueOnce(new Error("Permission denied"))
|
||||
// Second path succeeds
|
||||
mockMkdir.mockResolvedValueOnce(undefined)
|
||||
mockAccess.mockResolvedValueOnce(undefined)
|
||||
|
||||
const result = await getDevContainerPersistentPath()
|
||||
expect(result).toBe("/workspaces/.roo-data")
|
||||
})
|
||||
|
||||
it("should return null when all paths fail", async () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
;(vscode.workspace as any).workspaceFolders = [
|
||||
{
|
||||
uri: {
|
||||
fsPath: "/workspace/myproject",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const mockMkdir = vi.mocked(fs.mkdir)
|
||||
mockMkdir.mockRejectedValue(new Error("Permission denied"))
|
||||
|
||||
const result = await getDevContainerPersistentPath()
|
||||
expect(result).toBe(null)
|
||||
})
|
||||
})
|
||||
|
||||
describe("isEphemeralStoragePath", () => {
|
||||
it("should return false when not in a Dev Container", async () => {
|
||||
const fsModule = vi.mocked(await import("fs"))
|
||||
fsModule.accessSync.mockImplementation(() => {
|
||||
throw new Error("File not found")
|
||||
})
|
||||
expect(isEphemeralStoragePath("/some/path")).toBe(false)
|
||||
})
|
||||
|
||||
it("should return true for /tmp paths in Dev Container", () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
expect(isEphemeralStoragePath("/tmp/storage")).toBe(true)
|
||||
})
|
||||
|
||||
it("should return true for VSCode server paths in Dev Container", () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
expect(isEphemeralStoragePath("/.vscode-server/data")).toBe(true)
|
||||
expect(isEphemeralStoragePath("/.vscode-remote/extensions")).toBe(true)
|
||||
expect(isEphemeralStoragePath("/home/user/.vscode/storage")).toBe(true)
|
||||
})
|
||||
|
||||
it("should return true for paths containing temp directories", () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
expect(isEphemeralStoragePath("/var/tmp/storage")).toBe(true)
|
||||
expect(isEphemeralStoragePath("/home/user/tmp/data")).toBe(true)
|
||||
expect(isEphemeralStoragePath("/dev/shm/cache")).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false for persistent paths in Dev Container", () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
expect(isEphemeralStoragePath("/workspace/.roo-data")).toBe(false)
|
||||
expect(isEphemeralStoragePath("/home/user/.roo-data")).toBe(false)
|
||||
expect(isEphemeralStoragePath("/data/storage")).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("notifyDevContainerStorageSetup", () => {
|
||||
it("should not show notification when not in Dev Container", async () => {
|
||||
const fsModule = vi.mocked(await import("fs"))
|
||||
fsModule.accessSync.mockImplementation(() => {
|
||||
throw new Error("File not found")
|
||||
})
|
||||
|
||||
const mockContext = {
|
||||
globalStorageUri: { fsPath: "/normal/storage" },
|
||||
globalState: {
|
||||
update: vi.fn(),
|
||||
get: vi.fn(),
|
||||
},
|
||||
}
|
||||
|
||||
await notifyDevContainerStorageSetup(mockContext as any)
|
||||
expect(vscode.window.showWarningMessage).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should not show notification when storage path is not ephemeral", async () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
|
||||
const mockContext = {
|
||||
globalStorageUri: { fsPath: "/workspace/.roo-data" },
|
||||
globalState: {
|
||||
update: vi.fn(),
|
||||
get: vi.fn(),
|
||||
},
|
||||
}
|
||||
|
||||
await notifyDevContainerStorageSetup(mockContext as any)
|
||||
expect(vscode.window.showWarningMessage).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should show notification when in Dev Container with ephemeral storage", async () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
;(vscode.workspace as any).workspaceFolders = [
|
||||
{
|
||||
uri: {
|
||||
fsPath: "/workspace/myproject",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const mockMkdir = vi.mocked(fs.mkdir)
|
||||
const mockAccess = vi.mocked(fs.access)
|
||||
mockMkdir.mockResolvedValue(undefined)
|
||||
mockAccess.mockResolvedValue(undefined)
|
||||
|
||||
const mockShowWarningMessage = vi.mocked(vscode.window.showWarningMessage)
|
||||
mockShowWarningMessage.mockResolvedValue("Configure Now" as any)
|
||||
|
||||
const mockConfig = {
|
||||
update: vi.fn().mockResolvedValue(undefined),
|
||||
}
|
||||
vi.mocked(vscode.workspace.getConfiguration).mockReturnValue(mockConfig as any)
|
||||
|
||||
const mockContext = {
|
||||
globalStorageUri: { fsPath: "/.vscode-server/data/storage" },
|
||||
globalState: {
|
||||
update: vi.fn(),
|
||||
get: vi.fn().mockReturnValue(false),
|
||||
},
|
||||
}
|
||||
|
||||
await notifyDevContainerStorageSetup(mockContext as any)
|
||||
|
||||
expect(mockShowWarningMessage).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Dev Container"),
|
||||
"Configure Now",
|
||||
"Remind Me Later",
|
||||
"Don't Show Again",
|
||||
)
|
||||
|
||||
expect(mockConfig.update).toHaveBeenCalledWith(
|
||||
"customStoragePath",
|
||||
"/workspace/myproject/.roo-data",
|
||||
vscode.ConfigurationTarget.Global,
|
||||
)
|
||||
|
||||
expect(vscode.window.showInformationMessage).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Storage path set to"),
|
||||
)
|
||||
})
|
||||
|
||||
it("should update global state when user chooses 'Don't Show Again'", async () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
;(vscode.workspace as any).workspaceFolders = [
|
||||
{
|
||||
uri: {
|
||||
fsPath: "/workspace/myproject",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const mockMkdir = vi.mocked(fs.mkdir)
|
||||
const mockAccess = vi.mocked(fs.access)
|
||||
mockMkdir.mockResolvedValue(undefined)
|
||||
mockAccess.mockResolvedValue(undefined)
|
||||
|
||||
const mockShowWarningMessage = vi.mocked(vscode.window.showWarningMessage)
|
||||
mockShowWarningMessage.mockResolvedValue("Don't Show Again" as any)
|
||||
|
||||
const mockContext = {
|
||||
globalStorageUri: { fsPath: "/.vscode-server/data/storage" },
|
||||
globalState: {
|
||||
update: vi.fn(),
|
||||
get: vi.fn().mockReturnValue(false),
|
||||
},
|
||||
}
|
||||
|
||||
await notifyDevContainerStorageSetup(mockContext as any)
|
||||
|
||||
expect(mockContext.globalState.update).toHaveBeenCalledWith(
|
||||
"devContainerStorageNotificationDismissed",
|
||||
true,
|
||||
)
|
||||
})
|
||||
|
||||
it("should not configure when user chooses 'Remind Me Later'", async () => {
|
||||
process.env.DEVCONTAINER = "true"
|
||||
;(vscode.workspace as any).workspaceFolders = [
|
||||
{
|
||||
uri: {
|
||||
fsPath: "/workspace/myproject",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const mockMkdir = vi.mocked(fs.mkdir)
|
||||
const mockAccess = vi.mocked(fs.access)
|
||||
mockMkdir.mockResolvedValue(undefined)
|
||||
mockAccess.mockResolvedValue(undefined)
|
||||
|
||||
const mockShowWarningMessage = vi.mocked(vscode.window.showWarningMessage)
|
||||
mockShowWarningMessage.mockResolvedValue("Remind Me Later" as any)
|
||||
|
||||
const mockConfig = {
|
||||
update: vi.fn(),
|
||||
}
|
||||
vi.mocked(vscode.workspace.getConfiguration).mockReturnValue(mockConfig as any)
|
||||
|
||||
const mockContext = {
|
||||
globalStorageUri: { fsPath: "/.vscode-server/data/storage" },
|
||||
globalState: {
|
||||
update: vi.fn(),
|
||||
get: vi.fn().mockReturnValue(false),
|
||||
},
|
||||
}
|
||||
|
||||
await notifyDevContainerStorageSetup(mockContext as any)
|
||||
|
||||
expect(mockConfig.update).not.toHaveBeenCalled()
|
||||
expect(mockContext.globalState.update).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
143
src/utils/devContainer.ts
Normal file
143
src/utils/devContainer.ts
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
import * as vscode from "vscode"
|
||||
import * as fs from "fs/promises"
|
||||
import * as fsSync from "fs"
|
||||
import * as path from "path"
|
||||
|
||||
/**
|
||||
* Checks if the current environment is running inside a Dev Container
|
||||
* @returns true if running in a Dev Container, false otherwise
|
||||
*/
|
||||
export function isRunningInDevContainer(): boolean {
|
||||
// Check for common Dev Container environment variables
|
||||
if (process.env.REMOTE_CONTAINERS || process.env.CODESPACES || process.env.DEVCONTAINER) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if running in a container by looking for .dockerenv file
|
||||
try {
|
||||
const dockerEnvPath = "/.dockerenv"
|
||||
fsSync.accessSync(dockerEnvPath, fsSync.constants.F_OK)
|
||||
return true
|
||||
} catch {
|
||||
// File doesn't exist, not in Docker container
|
||||
}
|
||||
|
||||
// Check VSCode's remote name for devcontainer
|
||||
const remoteName = vscode.env.remoteName
|
||||
if (remoteName && remoteName.toLowerCase().includes("container")) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the recommended persistent storage path for Dev Containers
|
||||
* This should be a path that persists across container rebuilds
|
||||
* @returns Recommended storage path or null if not applicable
|
||||
*/
|
||||
export async function getDevContainerPersistentPath(): Promise<string | null> {
|
||||
if (!isRunningInDevContainer()) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Check for workspace folder that might be mounted from host
|
||||
const workspaceFolders = vscode.workspace.workspaceFolders
|
||||
if (workspaceFolders && workspaceFolders.length > 0) {
|
||||
const workspaceRoot = workspaceFolders[0].uri.fsPath
|
||||
|
||||
// Try common persistent mount points in Dev Containers
|
||||
const possiblePaths = [
|
||||
path.join(workspaceRoot, ".roo-data"), // Within workspace (persists if workspace is mounted)
|
||||
"/workspaces/.roo-data", // Common devcontainer workspace mount
|
||||
"/home/vscode/.roo-data", // User home in standard devcontainer
|
||||
"/root/.roo-data", // Root user home
|
||||
]
|
||||
|
||||
for (const testPath of possiblePaths) {
|
||||
try {
|
||||
// Test if we can create and access this directory
|
||||
await fs.mkdir(testPath, { recursive: true })
|
||||
await fs.access(testPath, fs.constants.R_OK | fs.constants.W_OK)
|
||||
return testPath
|
||||
} catch {
|
||||
// This path is not suitable, try next
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the storage path will be lost on container rebuild
|
||||
* @param storagePath The current storage path
|
||||
* @returns true if the path is ephemeral (will be lost on rebuild)
|
||||
*/
|
||||
export function isEphemeralStoragePath(storagePath: string): boolean {
|
||||
if (!isRunningInDevContainer()) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Common ephemeral paths in containers
|
||||
const ephemeralPaths = [
|
||||
"/tmp",
|
||||
"/var/tmp",
|
||||
"/dev/shm",
|
||||
"/.vscode-server",
|
||||
"/.vscode-remote",
|
||||
"/.vscode-server-insiders",
|
||||
]
|
||||
|
||||
const normalizedPath = path.normalize(storagePath).toLowerCase()
|
||||
|
||||
return ephemeralPaths.some(
|
||||
(ephemeral) =>
|
||||
normalizedPath.startsWith(ephemeral.toLowerCase()) ||
|
||||
normalizedPath.includes("/.vscode") ||
|
||||
normalizedPath.includes("/vscode-") ||
|
||||
normalizedPath.includes("/tmp/") ||
|
||||
normalizedPath.includes("/temp/"),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a notification to the user about Dev Container storage configuration
|
||||
* @param context The extension context
|
||||
*/
|
||||
export async function notifyDevContainerStorageSetup(context: vscode.ExtensionContext): Promise<void> {
|
||||
const currentStoragePath = context.globalStorageUri.fsPath
|
||||
|
||||
if (!isRunningInDevContainer() || !isEphemeralStoragePath(currentStoragePath)) {
|
||||
return
|
||||
}
|
||||
|
||||
const recommendedPath = await getDevContainerPersistentPath()
|
||||
if (!recommendedPath) {
|
||||
return
|
||||
}
|
||||
|
||||
const message =
|
||||
"You're using Roo Code in a Dev Container. Your task history may be lost when the container is rebuilt. Would you like to configure a persistent storage path?"
|
||||
|
||||
const choice = await vscode.window.showWarningMessage(
|
||||
message,
|
||||
"Configure Now",
|
||||
"Remind Me Later",
|
||||
"Don't Show Again",
|
||||
)
|
||||
|
||||
if (choice === "Configure Now") {
|
||||
// Set the recommended path
|
||||
const config = vscode.workspace.getConfiguration("roo-code")
|
||||
await config.update("customStoragePath", recommendedPath, vscode.ConfigurationTarget.Global)
|
||||
|
||||
vscode.window.showInformationMessage(
|
||||
`Storage path set to: ${recommendedPath}. Your task history will now persist across container rebuilds.`,
|
||||
)
|
||||
} else if (choice === "Don't Show Again") {
|
||||
// Store a flag to not show this again
|
||||
await context.globalState.update("devContainerStorageNotificationDismissed", true)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,10 +5,12 @@ import { constants as fsConstants } from "fs"
|
|||
|
||||
import { Package } from "../shared/package"
|
||||
import { t } from "../i18n"
|
||||
import { isRunningInDevContainer, getDevContainerPersistentPath, isEphemeralStoragePath } from "./devContainer"
|
||||
|
||||
/**
|
||||
* Gets the base storage path for conversations
|
||||
* If a custom path is configured, uses that path
|
||||
* For Dev Containers with ephemeral storage, suggests a persistent path
|
||||
* Otherwise uses the default VSCode extension global storage path
|
||||
*/
|
||||
export async function getStorageBasePath(defaultPath: string): Promise<string> {
|
||||
|
|
@ -24,8 +26,17 @@ export async function getStorageBasePath(defaultPath: string): Promise<string> {
|
|||
return defaultPath
|
||||
}
|
||||
|
||||
// If no custom path is set, use default path
|
||||
// If no custom path is set, check for Dev Container
|
||||
if (!customStoragePath) {
|
||||
// Check if we're in a Dev Container with ephemeral storage
|
||||
if (isRunningInDevContainer() && isEphemeralStoragePath(defaultPath)) {
|
||||
// Try to get a persistent path for Dev Container
|
||||
const persistentPath = await getDevContainerPersistentPath()
|
||||
if (persistentPath) {
|
||||
console.info(`Dev Container detected: Using persistent storage path ${persistentPath}`)
|
||||
return persistentPath
|
||||
}
|
||||
}
|
||||
return defaultPath
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue