forked from dirac-run/dirac
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvscode-context.ts
More file actions
163 lines (143 loc) · 5.16 KB
/
vscode-context.ts
File metadata and controls
163 lines (143 loc) · 5.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/**
* VSCode context stub for CLI mode
* Provides mock implementations of VSCode extension context.
*/
import { fileURLToPath } from "node:url"
import os from "os"
import path from "path"
import { ExtensionRegistryInfo } from "@/registry"
import { DiracExtensionContext } from "@/shared/dirac"
import type { DiracMemento } from "@/shared/storage/DiracStorage"
import { createStorageContext, type StorageContext } from "@/shared/storage/storage-context"
import { EnvironmentVariableCollection, ExtensionKind, ExtensionMode, readJson, URI } from "./vscode-shim"
// ES module equivalent of __dirname
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
/**
* CLI-specific state overrides.
* These values are always returned regardless of what's stored,
* and writes to these keys are silently ignored.
*/
const CLI_STATE_OVERRIDES: Record<string, any> = {
// CLI always uses background execution, not VSCode terminal
vscodeTerminalExecutionMode: "backgroundExec",
backgroundEditEnabled: true,
multiRootEnabled: false,
enableCheckpointsSetting: false,
browserSettings: {
disableToolUse: true,
},
}
/**
* Memento adapter that wraps a DiracFileStorage with optional key overrides.
* Used for globalState where CLI needs to inject hardcoded overrides.
*/
class MementoAdapter implements DiracMemento {
constructor(
private readonly store: DiracMemento,
private readonly overrides: Record<string, any> = {},
) {}
get<T>(key: string): T | undefined
get<T>(key: string, defaultValue: T): T
get<T>(key: string, defaultValue?: T): T | undefined {
if (key in this.overrides) {
return this.overrides[key] as T
}
const value = this.store.get<T>(key)
return value !== undefined ? value : defaultValue
}
update(key: string, value: any): Thenable<void> {
return this.setBatch({ [key]: value })
}
keys(): readonly string[] {
return this.store.keys()
}
setBatch(entries: Record<string, any>): Thenable<void> {
// Filter out overridden keys and delegate to underlying store
const filteredEntries: Record<string, any> = {}
for (const [key, value] of Object.entries(entries)) {
if (!(key in this.overrides)) {
filteredEntries[key] = value
}
}
this.store.setBatch(filteredEntries)
return Promise.resolve()
}
setKeysForSync(_keys: readonly string[]): void {
// No-op for CLI
}
}
export interface CliContextConfig {
diracDir?: string
/** The workspace directory being worked in (used to compute workspace storage hash) */
workspaceDir?: string
}
export interface CliContextResult {
extensionContext: DiracExtensionContext
storageContext: StorageContext
DATA_DIR: string
EXTENSION_DIR: string
WORKSPACE_STORAGE_DIR: string
}
/**
* Initialize the VSCode-like context for CLI mode.
*
* Creates a shared StorageContext (the single source of truth for all storage)
* and wraps it in a DiracExtensionContext shell for legacy APIs that still
* expect the VSCode ExtensionContext shape.
*/
export function initializeCliContext(config: CliContextConfig = {}): CliContextResult {
const DIRAC_DIR = config.diracDir || process.env.DIRAC_DIR || path.join(os.homedir(), ".dirac")
// Create the shared StorageContext — this owns all DiracFileStorage instances.
// CLI, JetBrains, and VSCode all share this same file-backed implementation.
let storageContext = createStorageContext({
diracDir: DIRAC_DIR,
workspacePath: config.workspaceDir || process.cwd(),
workspaceStorageDir: process.env.WORKSPACE_STORAGE_DIR || undefined,
})
storageContext = {
...storageContext,
// Storage — delegates to storageContext stores (with CLI overrides for globalState)
globalState: new MementoAdapter(storageContext.globalState, CLI_STATE_OVERRIDES),
}
const DATA_DIR = storageContext.dataDir
const WORKSPACE_STORAGE_DIR = storageContext.workspaceStoragePath
// For CLI, extension dir is the package root (one level up from dist/)
const EXTENSION_DIR = path.resolve(__dirname, "..")
const EXTENSION_MODE = process.env.IS_DEV === "true" ? ExtensionMode.Development : ExtensionMode.Production
const extension: DiracExtensionContext["extension"] = {
id: ExtensionRegistryInfo.id,
isActive: true,
extensionPath: EXTENSION_DIR,
extensionUri: URI.file(EXTENSION_DIR),
packageJSON: readJson(path.join(EXTENSION_DIR, "package.json")),
exports: undefined,
activate: async () => {},
extensionKind: ExtensionKind.UI,
}
// Build the DiracExtensionContext shell. All storage delegates to storageContext —
// there are NO separate DiracFileStorage instances here.
const extensionContext: DiracExtensionContext = {
extension: extension,
extensionMode: EXTENSION_MODE,
// URIs / paths
storageUri: URI.file(WORKSPACE_STORAGE_DIR),
storagePath: WORKSPACE_STORAGE_DIR,
globalStorageUri: URI.file(DATA_DIR),
globalStoragePath: DATA_DIR,
logUri: URI.file(DATA_DIR),
logPath: DATA_DIR,
extensionUri: URI.file(EXTENSION_DIR),
extensionPath: EXTENSION_DIR,
asAbsolutePath: (relPath: string) => path.join(EXTENSION_DIR, relPath),
subscriptions: [],
environmentVariableCollection: new EnvironmentVariableCollection() as any,
}
return {
extensionContext,
storageContext,
DATA_DIR,
EXTENSION_DIR,
WORKSPACE_STORAGE_DIR,
}
}