@mariozechner/pi-coding-agent 0.52.12 → 0.53.1
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 +30 -0
- package/README.md +1 -1
- 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 +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +40 -7
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +214 -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/docs/sdk.md +12 -5
- 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
|
|
@@ -104,54 +167,42 @@ export class SettingsManager {
|
|
|
104
167
|
}
|
|
105
168
|
return settings;
|
|
106
169
|
}
|
|
107
|
-
loadProjectSettings() {
|
|
108
|
-
// In-memory mode: return stored in-memory project settings
|
|
109
|
-
if (!this.persist) {
|
|
110
|
-
return structuredClone(this.inMemoryProjectSettings);
|
|
111
|
-
}
|
|
112
|
-
if (!this.projectSettingsPath || !existsSync(this.projectSettingsPath)) {
|
|
113
|
-
return {};
|
|
114
|
-
}
|
|
115
|
-
try {
|
|
116
|
-
const content = readFileSync(this.projectSettingsPath, "utf-8");
|
|
117
|
-
const settings = JSON.parse(content);
|
|
118
|
-
return SettingsManager.migrateSettings(settings);
|
|
119
|
-
}
|
|
120
|
-
catch (error) {
|
|
121
|
-
console.error(`Warning: Could not read project settings file: ${error}`);
|
|
122
|
-
return {};
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
170
|
getGlobalSettings() {
|
|
126
171
|
return structuredClone(this.globalSettings);
|
|
127
172
|
}
|
|
128
173
|
getProjectSettings() {
|
|
129
|
-
return this.
|
|
174
|
+
return structuredClone(this.projectSettings);
|
|
130
175
|
}
|
|
131
176
|
reload() {
|
|
132
|
-
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
this.globalSettingsLoadError = null;
|
|
137
|
-
}
|
|
138
|
-
catch (error) {
|
|
139
|
-
this.globalSettingsLoadError = error;
|
|
140
|
-
}
|
|
177
|
+
const globalLoad = SettingsManager.tryLoadFromStorage(this.storage, "global");
|
|
178
|
+
if (!globalLoad.error) {
|
|
179
|
+
this.globalSettings = globalLoad.settings;
|
|
180
|
+
this.globalSettingsLoadError = null;
|
|
141
181
|
}
|
|
142
|
-
|
|
143
|
-
this.
|
|
182
|
+
else {
|
|
183
|
+
this.globalSettingsLoadError = globalLoad.error;
|
|
184
|
+
this.recordError("global", globalLoad.error);
|
|
144
185
|
}
|
|
145
186
|
this.modifiedFields.clear();
|
|
146
187
|
this.modifiedNestedFields.clear();
|
|
147
|
-
|
|
148
|
-
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);
|
|
149
200
|
}
|
|
150
201
|
/** Apply additional overrides on top of current settings */
|
|
151
202
|
applyOverrides(overrides) {
|
|
152
203
|
this.settings = deepMergeSettings(this.settings, overrides);
|
|
153
204
|
}
|
|
154
|
-
/** Mark a field as modified during this session */
|
|
205
|
+
/** Mark a global field as modified during this session */
|
|
155
206
|
markModified(field, nestedKey) {
|
|
156
207
|
this.modifiedFields.add(field);
|
|
157
208
|
if (nestedKey) {
|
|
@@ -161,74 +212,103 @@ export class SettingsManager {
|
|
|
161
212
|
this.modifiedNestedFields.get(field).add(nestedKey);
|
|
162
213
|
}
|
|
163
214
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
try {
|
|
174
|
-
const dir = dirname(this.settingsPath);
|
|
175
|
-
if (!existsSync(dir)) {
|
|
176
|
-
mkdirSync(dir, { recursive: true });
|
|
177
|
-
}
|
|
178
|
-
// Re-read current file to get latest external changes
|
|
179
|
-
const currentFileSettings = SettingsManager.loadFromFile(this.settingsPath);
|
|
180
|
-
// Start with file settings as base - preserves external edits
|
|
181
|
-
const mergedSettings = { ...currentFileSettings };
|
|
182
|
-
// Only override with in-memory values for fields that were explicitly modified during this session
|
|
183
|
-
for (const field of this.modifiedFields) {
|
|
184
|
-
const value = this.globalSettings[field];
|
|
185
|
-
// Handle nested objects specially - merge at nested level to preserve unmodified nested keys
|
|
186
|
-
if (this.modifiedNestedFields.has(field) && typeof value === "object" && value !== null) {
|
|
187
|
-
const nestedModified = this.modifiedNestedFields.get(field);
|
|
188
|
-
const baseNested = currentFileSettings[field] ?? {};
|
|
189
|
-
const inMemoryNested = value;
|
|
190
|
-
const mergedNested = { ...baseNested };
|
|
191
|
-
for (const nestedKey of nestedModified) {
|
|
192
|
-
mergedNested[nestedKey] = inMemoryNested[nestedKey];
|
|
193
|
-
}
|
|
194
|
-
mergedSettings[field] = mergedNested;
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
// For top-level primitives and arrays, use the modified value directly
|
|
198
|
-
mergedSettings[field] = value;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
this.globalSettings = mergedSettings;
|
|
202
|
-
writeFileSync(this.settingsPath, JSON.stringify(this.globalSettings, null, 2), "utf-8");
|
|
203
|
-
}
|
|
204
|
-
catch (error) {
|
|
205
|
-
// File may have been externally modified with invalid JSON - don't overwrite
|
|
206
|
-
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());
|
|
207
221
|
}
|
|
222
|
+
this.modifiedProjectNestedFields.get(field).add(nestedKey);
|
|
208
223
|
}
|
|
209
|
-
// Always re-merge to update active settings (needed for both file and inMemory modes)
|
|
210
|
-
const projectSettings = this.loadProjectSettings();
|
|
211
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
212
224
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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();
|
|
217
233
|
return;
|
|
218
234
|
}
|
|
219
|
-
|
|
220
|
-
|
|
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));
|
|
221
252
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
+
}
|
|
226
276
|
}
|
|
227
|
-
|
|
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;
|
|
228
284
|
}
|
|
229
|
-
|
|
230
|
-
|
|
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;
|
|
231
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;
|
|
232
312
|
}
|
|
233
313
|
getLastChangelogVersion() {
|
|
234
314
|
return this.settings.lastChangelogVersion;
|
|
@@ -398,10 +478,10 @@ export class SettingsManager {
|
|
|
398
478
|
this.save();
|
|
399
479
|
}
|
|
400
480
|
setProjectPackages(packages) {
|
|
401
|
-
const projectSettings = this.
|
|
481
|
+
const projectSettings = structuredClone(this.projectSettings);
|
|
402
482
|
projectSettings.packages = packages;
|
|
483
|
+
this.markProjectModified("packages");
|
|
403
484
|
this.saveProjectSettings(projectSettings);
|
|
404
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
405
485
|
}
|
|
406
486
|
getExtensionPaths() {
|
|
407
487
|
return [...(this.settings.extensions ?? [])];
|
|
@@ -412,10 +492,10 @@ export class SettingsManager {
|
|
|
412
492
|
this.save();
|
|
413
493
|
}
|
|
414
494
|
setProjectExtensionPaths(paths) {
|
|
415
|
-
const projectSettings = this.
|
|
495
|
+
const projectSettings = structuredClone(this.projectSettings);
|
|
416
496
|
projectSettings.extensions = paths;
|
|
497
|
+
this.markProjectModified("extensions");
|
|
417
498
|
this.saveProjectSettings(projectSettings);
|
|
418
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
419
499
|
}
|
|
420
500
|
getSkillPaths() {
|
|
421
501
|
return [...(this.settings.skills ?? [])];
|
|
@@ -426,10 +506,10 @@ export class SettingsManager {
|
|
|
426
506
|
this.save();
|
|
427
507
|
}
|
|
428
508
|
setProjectSkillPaths(paths) {
|
|
429
|
-
const projectSettings = this.
|
|
509
|
+
const projectSettings = structuredClone(this.projectSettings);
|
|
430
510
|
projectSettings.skills = paths;
|
|
511
|
+
this.markProjectModified("skills");
|
|
431
512
|
this.saveProjectSettings(projectSettings);
|
|
432
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
433
513
|
}
|
|
434
514
|
getPromptTemplatePaths() {
|
|
435
515
|
return [...(this.settings.prompts ?? [])];
|
|
@@ -440,10 +520,10 @@ export class SettingsManager {
|
|
|
440
520
|
this.save();
|
|
441
521
|
}
|
|
442
522
|
setProjectPromptTemplatePaths(paths) {
|
|
443
|
-
const projectSettings = this.
|
|
523
|
+
const projectSettings = structuredClone(this.projectSettings);
|
|
444
524
|
projectSettings.prompts = paths;
|
|
525
|
+
this.markProjectModified("prompts");
|
|
445
526
|
this.saveProjectSettings(projectSettings);
|
|
446
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
447
527
|
}
|
|
448
528
|
getThemePaths() {
|
|
449
529
|
return [...(this.settings.themes ?? [])];
|
|
@@ -454,10 +534,10 @@ export class SettingsManager {
|
|
|
454
534
|
this.save();
|
|
455
535
|
}
|
|
456
536
|
setProjectThemePaths(paths) {
|
|
457
|
-
const projectSettings = this.
|
|
537
|
+
const projectSettings = structuredClone(this.projectSettings);
|
|
458
538
|
projectSettings.themes = paths;
|
|
539
|
+
this.markProjectModified("themes");
|
|
459
540
|
this.saveProjectSettings(projectSettings);
|
|
460
|
-
this.settings = deepMergeSettings(this.globalSettings, projectSettings);
|
|
461
541
|
}
|
|
462
542
|
getEnableSkillCommands() {
|
|
463
543
|
return this.settings.enableSkillCommands ?? true;
|