@mariozechner/pi-coding-agent 0.52.11 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -1
- package/README.md +3 -3
- package/dist/core/auth-storage.d.ts +34 -7
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +189 -93
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +2 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +45 -7
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +227 -134
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +13 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +5 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/sdk.md +12 -5
- package/docs/settings.md +3 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/02-custom-model.ts +1 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/examples/sdk/10-settings.ts +13 -0
- package/examples/sdk/12-full-control.ts +1 -1
- package/examples/sdk/README.md +3 -3
- package/package.json +4 -4
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
2
2
|
import { dirname, join } from "path";
|
|
3
|
+
import lockfile from "proper-lockfile";
|
|
3
4
|
import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
|
|
4
5
|
/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
|
|
5
6
|
function deepMergeSettings(base, overrides) {
|
|
@@ -26,54 +27,116 @@ function deepMergeSettings(base, overrides) {
|
|
|
26
27
|
}
|
|
27
28
|
return result;
|
|
28
29
|
}
|
|
29
|
-
export class
|
|
30
|
-
|
|
30
|
+
export class FileSettingsStorage {
|
|
31
|
+
globalSettingsPath;
|
|
31
32
|
projectSettingsPath;
|
|
33
|
+
constructor(cwd = process.cwd(), agentDir = getAgentDir()) {
|
|
34
|
+
this.globalSettingsPath = join(agentDir, "settings.json");
|
|
35
|
+
this.projectSettingsPath = join(cwd, CONFIG_DIR_NAME, "settings.json");
|
|
36
|
+
}
|
|
37
|
+
withLock(scope, fn) {
|
|
38
|
+
const path = scope === "global" ? this.globalSettingsPath : this.projectSettingsPath;
|
|
39
|
+
const dir = dirname(path);
|
|
40
|
+
if (!existsSync(dir)) {
|
|
41
|
+
mkdirSync(dir, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
let release;
|
|
44
|
+
try {
|
|
45
|
+
release = lockfile.lockSync(path, { realpath: false });
|
|
46
|
+
const current = existsSync(path) ? readFileSync(path, "utf-8") : undefined;
|
|
47
|
+
const next = fn(current);
|
|
48
|
+
if (next !== undefined) {
|
|
49
|
+
writeFileSync(path, next, "utf-8");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
if (release) {
|
|
54
|
+
release();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export class InMemorySettingsStorage {
|
|
60
|
+
global;
|
|
61
|
+
project;
|
|
62
|
+
withLock(scope, fn) {
|
|
63
|
+
const current = scope === "global" ? this.global : this.project;
|
|
64
|
+
const next = fn(current);
|
|
65
|
+
if (next !== undefined) {
|
|
66
|
+
if (scope === "global") {
|
|
67
|
+
this.global = next;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
this.project = next;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export class SettingsManager {
|
|
76
|
+
storage;
|
|
32
77
|
globalSettings;
|
|
33
|
-
|
|
78
|
+
projectSettings;
|
|
34
79
|
settings;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
this.
|
|
80
|
+
modifiedFields = new Set(); // Track global fields modified during session
|
|
81
|
+
modifiedNestedFields = new Map(); // Track global nested field modifications
|
|
82
|
+
modifiedProjectFields = new Set(); // Track project fields modified during session
|
|
83
|
+
modifiedProjectNestedFields = new Map(); // Track project nested field modifications
|
|
84
|
+
globalSettingsLoadError = null; // Track if global settings file had parse errors
|
|
85
|
+
projectSettingsLoadError = null; // Track if project settings file had parse errors
|
|
86
|
+
writeQueue = Promise.resolve();
|
|
87
|
+
errors;
|
|
88
|
+
constructor(storage, initialGlobal, initialProject, globalLoadError = null, projectLoadError = null, initialErrors = []) {
|
|
89
|
+
this.storage = storage;
|
|
90
|
+
this.globalSettings = initialGlobal;
|
|
91
|
+
this.projectSettings = initialProject;
|
|
92
|
+
this.globalSettingsLoadError = globalLoadError;
|
|
93
|
+
this.projectSettingsLoadError = projectLoadError;
|
|
94
|
+
this.errors = [...initialErrors];
|
|
95
|
+
this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);
|
|
48
96
|
}
|
|
49
97
|
/** Create a SettingsManager that loads from files */
|
|
50
98
|
static create(cwd = process.cwd(), agentDir = getAgentDir()) {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
99
|
+
const storage = new FileSettingsStorage(cwd, agentDir);
|
|
100
|
+
return SettingsManager.fromStorage(storage);
|
|
101
|
+
}
|
|
102
|
+
/** Create a SettingsManager from an arbitrary storage backend */
|
|
103
|
+
static fromStorage(storage) {
|
|
104
|
+
const globalLoad = SettingsManager.tryLoadFromStorage(storage, "global");
|
|
105
|
+
const projectLoad = SettingsManager.tryLoadFromStorage(storage, "project");
|
|
106
|
+
const initialErrors = [];
|
|
107
|
+
if (globalLoad.error) {
|
|
108
|
+
initialErrors.push({ scope: "global", error: globalLoad.error });
|
|
57
109
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
console.error(`Warning: Invalid JSON in ${settingsPath}: ${error}`);
|
|
61
|
-
console.error(`Fix the syntax error to enable settings persistence.`);
|
|
110
|
+
if (projectLoad.error) {
|
|
111
|
+
initialErrors.push({ scope: "project", error: projectLoad.error });
|
|
62
112
|
}
|
|
63
|
-
return new SettingsManager(
|
|
113
|
+
return new SettingsManager(storage, globalLoad.settings, projectLoad.settings, globalLoad.error, projectLoad.error, initialErrors);
|
|
64
114
|
}
|
|
65
115
|
/** Create an in-memory SettingsManager (no file I/O) */
|
|
66
116
|
static inMemory(settings = {}) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
117
|
+
const storage = new InMemorySettingsStorage();
|
|
118
|
+
return new SettingsManager(storage, settings, {});
|
|
119
|
+
}
|
|
120
|
+
static loadFromStorage(storage, scope) {
|
|
121
|
+
let content;
|
|
122
|
+
storage.withLock(scope, (current) => {
|
|
123
|
+
content = current;
|
|
124
|
+
return undefined;
|
|
125
|
+
});
|
|
126
|
+
if (!content) {
|
|
71
127
|
return {};
|
|
72
128
|
}
|
|
73
|
-
const content = readFileSync(path, "utf-8");
|
|
74
129
|
const settings = JSON.parse(content);
|
|
75
130
|
return SettingsManager.migrateSettings(settings);
|
|
76
131
|
}
|
|
132
|
+
static tryLoadFromStorage(storage, scope) {
|
|
133
|
+
try {
|
|
134
|
+
return { settings: SettingsManager.loadFromStorage(storage, scope), error: null };
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
return { settings: {}, error: error };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
77
140
|
/** Migrate old settings format to new format */
|
|
78
141
|
static migrateSettings(settings) {
|
|
79
142
|
// Migrate queueMode -> steeringMode
|
|
@@ -81,6 +144,11 @@ export class SettingsManager {
|
|
|
81
144
|
settings.steeringMode = settings.queueMode;
|
|
82
145
|
delete settings.queueMode;
|
|
83
146
|
}
|
|
147
|
+
// Migrate legacy websockets boolean -> transport enum
|
|
148
|
+
if (!("transport" in settings) && typeof settings.websockets === "boolean") {
|
|
149
|
+
settings.transport = settings.websockets ? "websocket" : "sse";
|
|
150
|
+
delete settings.websockets;
|
|
151
|
+
}
|
|
84
152
|
// Migrate old skills object format to new array format
|
|
85
153
|
if ("skills" in settings &&
|
|
86
154
|
typeof settings.skills === "object" &&
|
|
@@ -99,54 +167,42 @@ export class SettingsManager {
|
|
|
99
167
|
}
|
|
100
168
|
return settings;
|
|
101
169
|
}
|
|
102
|
-
loadProjectSettings() {
|
|
103
|
-
// In-memory mode: return stored in-memory project settings
|
|
104
|
-
if (!this.persist) {
|
|
105
|
-
return structuredClone(this.inMemoryProjectSettings);
|
|
106
|
-
}
|
|
107
|
-
if (!this.projectSettingsPath || !existsSync(this.projectSettingsPath)) {
|
|
108
|
-
return {};
|
|
109
|
-
}
|
|
110
|
-
try {
|
|
111
|
-
const content = readFileSync(this.projectSettingsPath, "utf-8");
|
|
112
|
-
const settings = JSON.parse(content);
|
|
113
|
-
return SettingsManager.migrateSettings(settings);
|
|
114
|
-
}
|
|
115
|
-
catch (error) {
|
|
116
|
-
console.error(`Warning: Could not read project settings file: ${error}`);
|
|
117
|
-
return {};
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
170
|
getGlobalSettings() {
|
|
121
171
|
return structuredClone(this.globalSettings);
|
|
122
172
|
}
|
|
123
173
|
getProjectSettings() {
|
|
124
|
-
return this.
|
|
174
|
+
return structuredClone(this.projectSettings);
|
|
125
175
|
}
|
|
126
176
|
reload() {
|
|
127
|
-
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
this.globalSettingsLoadError = null;
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
this.globalSettingsLoadError = error;
|
|
135
|
-
}
|
|
177
|
+
const globalLoad = SettingsManager.tryLoadFromStorage(this.storage, "global");
|
|
178
|
+
if (!globalLoad.error) {
|
|
179
|
+
this.globalSettings = globalLoad.settings;
|
|
180
|
+
this.globalSettingsLoadError = null;
|
|
136
181
|
}
|
|
137
|
-
|
|
138
|
-
this.
|
|
182
|
+
else {
|
|
183
|
+
this.globalSettingsLoadError = globalLoad.error;
|
|
184
|
+
this.recordError("global", globalLoad.error);
|
|
139
185
|
}
|
|
140
186
|
this.modifiedFields.clear();
|
|
141
187
|
this.modifiedNestedFields.clear();
|
|
142
|
-
|
|
143
|
-
this.
|
|
188
|
+
this.modifiedProjectFields.clear();
|
|
189
|
+
this.modifiedProjectNestedFields.clear();
|
|
190
|
+
const projectLoad = SettingsManager.tryLoadFromStorage(this.storage, "project");
|
|
191
|
+
if (!projectLoad.error) {
|
|
192
|
+
this.projectSettings = projectLoad.settings;
|
|
193
|
+
this.projectSettingsLoadError = null;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
this.projectSettingsLoadError = projectLoad.error;
|
|
197
|
+
this.recordError("project", projectLoad.error);
|
|
198
|
+
}
|
|
199
|
+
this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);
|
|
144
200
|
}
|
|
145
201
|
/** Apply additional overrides on top of current settings */
|
|
146
202
|
applyOverrides(overrides) {
|
|
147
203
|
this.settings = deepMergeSettings(this.settings, overrides);
|
|
148
204
|
}
|
|
149
|
-
/** Mark a field as modified during this session */
|
|
205
|
+
/** Mark a global field as modified during this session */
|
|
150
206
|
markModified(field, nestedKey) {
|
|
151
207
|
this.modifiedFields.add(field);
|
|
152
208
|
if (nestedKey) {
|
|
@@ -156,74 +212,103 @@ export class SettingsManager {
|
|
|
156
212
|
this.modifiedNestedFields.get(field).add(nestedKey);
|
|
157
213
|
}
|
|
158
214
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
try {
|
|
169
|
-
const dir = dirname(this.settingsPath);
|
|
170
|
-
if (!existsSync(dir)) {
|
|
171
|
-
mkdirSync(dir, { recursive: true });
|
|
172
|
-
}
|
|
173
|
-
// Re-read current file to get latest external changes
|
|
174
|
-
const currentFileSettings = SettingsManager.loadFromFile(this.settingsPath);
|
|
175
|
-
// Start with file settings as base - preserves external edits
|
|
176
|
-
const mergedSettings = { ...currentFileSettings };
|
|
177
|
-
// Only override with in-memory values for fields that were explicitly modified during this session
|
|
178
|
-
for (const field of this.modifiedFields) {
|
|
179
|
-
const value = this.globalSettings[field];
|
|
180
|
-
// Handle nested objects specially - merge at nested level to preserve unmodified nested keys
|
|
181
|
-
if (this.modifiedNestedFields.has(field) && typeof value === "object" && value !== null) {
|
|
182
|
-
const nestedModified = this.modifiedNestedFields.get(field);
|
|
183
|
-
const baseNested = currentFileSettings[field] ?? {};
|
|
184
|
-
const inMemoryNested = value;
|
|
185
|
-
const mergedNested = { ...baseNested };
|
|
186
|
-
for (const nestedKey of nestedModified) {
|
|
187
|
-
mergedNested[nestedKey] = inMemoryNested[nestedKey];
|
|
188
|
-
}
|
|
189
|
-
mergedSettings[field] = mergedNested;
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
// For top-level primitives and arrays, use the modified value directly
|
|
193
|
-
mergedSettings[field] = value;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
this.globalSettings = mergedSettings;
|
|
197
|
-
writeFileSync(this.settingsPath, JSON.stringify(this.globalSettings, null, 2), "utf-8");
|
|
198
|
-
}
|
|
199
|
-
catch (error) {
|
|
200
|
-
// File may have been externally modified with invalid JSON - don't overwrite
|
|
201
|
-
console.error(`Warning: Could not save settings file: ${error}`);
|
|
215
|
+
/** Mark a project field as modified during this session */
|
|
216
|
+
markProjectModified(field, nestedKey) {
|
|
217
|
+
this.modifiedProjectFields.add(field);
|
|
218
|
+
if (nestedKey) {
|
|
219
|
+
if (!this.modifiedProjectNestedFields.has(field)) {
|
|
220
|
+
this.modifiedProjectNestedFields.set(field, new Set());
|
|
202
221
|
}
|
|
222
|
+
this.modifiedProjectNestedFields.get(field).add(nestedKey);
|
|
203
223
|
}
|
|
204
|
-
// Always re-merge to update active settings (needed for both file and inMemory modes)
|
|
205
|
-
const projectSettings = this.loadProjectSettings();
|
|
206
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
207
224
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
225
|
+
recordError(scope, error) {
|
|
226
|
+
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
227
|
+
this.errors.push({ scope, error: normalizedError });
|
|
228
|
+
}
|
|
229
|
+
clearModifiedScope(scope) {
|
|
230
|
+
if (scope === "global") {
|
|
231
|
+
this.modifiedFields.clear();
|
|
232
|
+
this.modifiedNestedFields.clear();
|
|
212
233
|
return;
|
|
213
234
|
}
|
|
214
|
-
|
|
215
|
-
|
|
235
|
+
this.modifiedProjectFields.clear();
|
|
236
|
+
this.modifiedProjectNestedFields.clear();
|
|
237
|
+
}
|
|
238
|
+
enqueueWrite(scope, task) {
|
|
239
|
+
this.writeQueue = this.writeQueue
|
|
240
|
+
.then(() => {
|
|
241
|
+
task();
|
|
242
|
+
this.clearModifiedScope(scope);
|
|
243
|
+
})
|
|
244
|
+
.catch((error) => {
|
|
245
|
+
this.recordError(scope, error);
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
cloneModifiedNestedFields(source) {
|
|
249
|
+
const snapshot = new Map();
|
|
250
|
+
for (const [key, value] of source.entries()) {
|
|
251
|
+
snapshot.set(key, new Set(value));
|
|
216
252
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
253
|
+
return snapshot;
|
|
254
|
+
}
|
|
255
|
+
persistScopedSettings(scope, snapshotSettings, modifiedFields, modifiedNestedFields) {
|
|
256
|
+
this.storage.withLock(scope, (current) => {
|
|
257
|
+
const currentFileSettings = current
|
|
258
|
+
? SettingsManager.migrateSettings(JSON.parse(current))
|
|
259
|
+
: {};
|
|
260
|
+
const mergedSettings = { ...currentFileSettings };
|
|
261
|
+
for (const field of modifiedFields) {
|
|
262
|
+
const value = snapshotSettings[field];
|
|
263
|
+
if (modifiedNestedFields.has(field) && typeof value === "object" && value !== null) {
|
|
264
|
+
const nestedModified = modifiedNestedFields.get(field);
|
|
265
|
+
const baseNested = currentFileSettings[field] ?? {};
|
|
266
|
+
const inMemoryNested = value;
|
|
267
|
+
const mergedNested = { ...baseNested };
|
|
268
|
+
for (const nestedKey of nestedModified) {
|
|
269
|
+
mergedNested[nestedKey] = inMemoryNested[nestedKey];
|
|
270
|
+
}
|
|
271
|
+
mergedSettings[field] = mergedNested;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
mergedSettings[field] = value;
|
|
275
|
+
}
|
|
221
276
|
}
|
|
222
|
-
|
|
277
|
+
return JSON.stringify(mergedSettings, null, 2);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
save() {
|
|
281
|
+
this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);
|
|
282
|
+
if (this.globalSettingsLoadError) {
|
|
283
|
+
return;
|
|
223
284
|
}
|
|
224
|
-
|
|
225
|
-
|
|
285
|
+
const snapshotGlobalSettings = structuredClone(this.globalSettings);
|
|
286
|
+
const modifiedFields = new Set(this.modifiedFields);
|
|
287
|
+
const modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedNestedFields);
|
|
288
|
+
this.enqueueWrite("global", () => {
|
|
289
|
+
this.persistScopedSettings("global", snapshotGlobalSettings, modifiedFields, modifiedNestedFields);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
saveProjectSettings(settings) {
|
|
293
|
+
this.projectSettings = structuredClone(settings);
|
|
294
|
+
this.settings = deepMergeSettings(this.globalSettings, this.projectSettings);
|
|
295
|
+
if (this.projectSettingsLoadError) {
|
|
296
|
+
return;
|
|
226
297
|
}
|
|
298
|
+
const snapshotProjectSettings = structuredClone(this.projectSettings);
|
|
299
|
+
const modifiedFields = new Set(this.modifiedProjectFields);
|
|
300
|
+
const modifiedNestedFields = this.cloneModifiedNestedFields(this.modifiedProjectNestedFields);
|
|
301
|
+
this.enqueueWrite("project", () => {
|
|
302
|
+
this.persistScopedSettings("project", snapshotProjectSettings, modifiedFields, modifiedNestedFields);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
async flush() {
|
|
306
|
+
await this.writeQueue;
|
|
307
|
+
}
|
|
308
|
+
drainErrors() {
|
|
309
|
+
const drained = [...this.errors];
|
|
310
|
+
this.errors = [];
|
|
311
|
+
return drained;
|
|
227
312
|
}
|
|
228
313
|
getLastChangelogVersion() {
|
|
229
314
|
return this.settings.lastChangelogVersion;
|
|
@@ -288,6 +373,14 @@ export class SettingsManager {
|
|
|
288
373
|
this.markModified("defaultThinkingLevel");
|
|
289
374
|
this.save();
|
|
290
375
|
}
|
|
376
|
+
getTransport() {
|
|
377
|
+
return this.settings.transport ?? "sse";
|
|
378
|
+
}
|
|
379
|
+
setTransport(transport) {
|
|
380
|
+
this.globalSettings.transport = transport;
|
|
381
|
+
this.markModified("transport");
|
|
382
|
+
this.save();
|
|
383
|
+
}
|
|
291
384
|
getCompactionEnabled() {
|
|
292
385
|
return this.settings.compaction?.enabled ?? true;
|
|
293
386
|
}
|
|
@@ -385,10 +478,10 @@ export class SettingsManager {
|
|
|
385
478
|
this.save();
|
|
386
479
|
}
|
|
387
480
|
setProjectPackages(packages) {
|
|
388
|
-
const projectSettings = this.
|
|
481
|
+
const projectSettings = structuredClone(this.projectSettings);
|
|
389
482
|
projectSettings.packages = packages;
|
|
483
|
+
this.markProjectModified("packages");
|
|
390
484
|
this.saveProjectSettings(projectSettings);
|
|
391
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
392
485
|
}
|
|
393
486
|
getExtensionPaths() {
|
|
394
487
|
return [...(this.settings.extensions ?? [])];
|
|
@@ -399,10 +492,10 @@ export class SettingsManager {
|
|
|
399
492
|
this.save();
|
|
400
493
|
}
|
|
401
494
|
setProjectExtensionPaths(paths) {
|
|
402
|
-
const projectSettings = this.
|
|
495
|
+
const projectSettings = structuredClone(this.projectSettings);
|
|
403
496
|
projectSettings.extensions = paths;
|
|
497
|
+
this.markProjectModified("extensions");
|
|
404
498
|
this.saveProjectSettings(projectSettings);
|
|
405
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
406
499
|
}
|
|
407
500
|
getSkillPaths() {
|
|
408
501
|
return [...(this.settings.skills ?? [])];
|
|
@@ -413,10 +506,10 @@ export class SettingsManager {
|
|
|
413
506
|
this.save();
|
|
414
507
|
}
|
|
415
508
|
setProjectSkillPaths(paths) {
|
|
416
|
-
const projectSettings = this.
|
|
509
|
+
const projectSettings = structuredClone(this.projectSettings);
|
|
417
510
|
projectSettings.skills = paths;
|
|
511
|
+
this.markProjectModified("skills");
|
|
418
512
|
this.saveProjectSettings(projectSettings);
|
|
419
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
420
513
|
}
|
|
421
514
|
getPromptTemplatePaths() {
|
|
422
515
|
return [...(this.settings.prompts ?? [])];
|
|
@@ -427,10 +520,10 @@ export class SettingsManager {
|
|
|
427
520
|
this.save();
|
|
428
521
|
}
|
|
429
522
|
setProjectPromptTemplatePaths(paths) {
|
|
430
|
-
const projectSettings = this.
|
|
523
|
+
const projectSettings = structuredClone(this.projectSettings);
|
|
431
524
|
projectSettings.prompts = paths;
|
|
525
|
+
this.markProjectModified("prompts");
|
|
432
526
|
this.saveProjectSettings(projectSettings);
|
|
433
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
434
527
|
}
|
|
435
528
|
getThemePaths() {
|
|
436
529
|
return [...(this.settings.themes ?? [])];
|
|
@@ -441,10 +534,10 @@ export class SettingsManager {
|
|
|
441
534
|
this.save();
|
|
442
535
|
}
|
|
443
536
|
setProjectThemePaths(paths) {
|
|
444
|
-
const projectSettings = this.
|
|
537
|
+
const projectSettings = structuredClone(this.projectSettings);
|
|
445
538
|
projectSettings.themes = paths;
|
|
539
|
+
this.markProjectModified("themes");
|
|
446
540
|
this.saveProjectSettings(projectSettings);
|
|
447
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
448
541
|
}
|
|
449
542
|
getEnableSkillCommands() {
|
|
450
543
|
return this.settings.enableSkillCommands ?? true;
|