@caupulican/pi-adaptative 0.80.42 → 0.80.45
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 +24 -0
- package/dist/bundled-resources/prompts/extensionify.md +20 -0
- package/dist/bundled-resources/prompts/learn.md +27 -0
- package/dist/bundled-resources/prompts/skillify.md +21 -0
- package/dist/bundled-resources/skills/pi-harness-learning/SKILL.md +217 -0
- package/dist/bundled-resources/skills/skill-architect/SKILL.md +162 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +30 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +37 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +215 -9
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +27 -5
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +10 -3
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +38 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +6 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +53 -6
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +16 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/profile-registry.d.ts +39 -0
- package/dist/core/profile-registry.d.ts.map +1 -0
- package/dist/core/profile-registry.js +230 -0
- package/dist/core/profile-registry.js.map +1 -0
- package/dist/core/profile-resource-selection.d.ts +19 -0
- package/dist/core/profile-resource-selection.d.ts.map +1 -0
- package/dist/core/profile-resource-selection.js +84 -0
- package/dist/core/profile-resource-selection.js.map +1 -0
- package/dist/core/resource-loader.d.ts +33 -3
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +68 -11
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +44 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +557 -27
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +5 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +2 -2
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +5 -17
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/extensionify.d.ts +33 -0
- package/dist/core/tools/extensionify.d.ts.map +1 -0
- package/dist/core/tools/extensionify.js +146 -0
- package/dist/core/tools/extensionify.js.map +1 -0
- package/dist/core/tools/index.d.ts +10 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +36 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/skill-audit.d.ts +63 -0
- package/dist/core/tools/skill-audit.d.ts.map +1 -0
- package/dist/core/tools/skill-audit.js +175 -0
- package/dist/core/tools/skill-audit.js.map +1 -0
- package/dist/core/tools/skillify.d.ts +30 -0
- package/dist/core/tools/skillify.d.ts.map +1 -0
- package/dist/core/tools/skillify.js +91 -0
- package/dist/core/tools/skillify.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.d.ts +50 -0
- package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/profile-resource-editor.js +232 -0
- package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -0
- package/dist/modes/interactive/components/profile-selector.d.ts +8 -0
- package/dist/modes/interactive/components/profile-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/profile-selector.js +77 -0
- package/dist/modes/interactive/components/profile-selector.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +8 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +75 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +14 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +434 -24
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/settings.md +20 -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/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/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/12-full-control.ts +4 -0
- package/npm-shrinkwrap.json +12 -12
- package/package.json +6 -6
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { createHash } from "crypto";
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
|
|
3
3
|
import { minimatch } from "minimatch";
|
|
4
4
|
import { basename, dirname, join, relative, resolve, sep } from "path";
|
|
5
5
|
import lockfile from "proper-lockfile";
|
|
6
|
-
import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
|
|
6
|
+
import { CONFIG_DIR_NAME, getAgentDir, getProfilesDir } from "../config.js";
|
|
7
7
|
import { normalizePath, resolvePath } from "../utils/paths.js";
|
|
8
8
|
import { DEFAULT_HTTP_IDLE_TIMEOUT_MS, parseHttpIdleTimeoutMs } from "./http-dispatcher.js";
|
|
9
|
+
import { ProfileRegistry } from "./profile-registry.js";
|
|
9
10
|
import { mergeResourceProfileMap } from "./resource-profile-blocks.js";
|
|
11
|
+
import { validateSkillName } from "./skills.js";
|
|
10
12
|
/** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
|
|
11
13
|
function deepMergeSettings(base, overrides) {
|
|
12
14
|
const result = { ...base };
|
|
@@ -120,13 +122,6 @@ function collectLegacyDisabledFilterFromSettings(settings, kind) {
|
|
|
120
122
|
const legacyDisabled = settings.disabledResources?.[kind];
|
|
121
123
|
return Array.isArray(legacyDisabled) ? { block: legacyDisabled } : {};
|
|
122
124
|
}
|
|
123
|
-
function collectNamedResourceProfileFilters(settings, kind, profileNames) {
|
|
124
|
-
const result = {};
|
|
125
|
-
for (const profileName of profileNames) {
|
|
126
|
-
appendFilter(result, settings.resourceProfiles?.[profileName]?.[kind]);
|
|
127
|
-
}
|
|
128
|
-
return result;
|
|
129
|
-
}
|
|
130
125
|
function mergeResourceProfileFilters(...filters) {
|
|
131
126
|
const result = {};
|
|
132
127
|
for (const filter of filters)
|
|
@@ -143,20 +138,76 @@ function parseTimeoutSetting(value, settingName) {
|
|
|
143
138
|
}
|
|
144
139
|
return undefined;
|
|
145
140
|
}
|
|
141
|
+
const VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
142
|
+
function isThinkingLevel(value) {
|
|
143
|
+
return typeof value === "string" && VALID_THINKING_LEVELS.includes(value);
|
|
144
|
+
}
|
|
145
|
+
function asStringArrayWithPattern(value) {
|
|
146
|
+
if (!Array.isArray(value))
|
|
147
|
+
return undefined;
|
|
148
|
+
const values = value.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
149
|
+
return values.length > 0 ? values : undefined;
|
|
150
|
+
}
|
|
151
|
+
function normalizeProfileFilterResource(value) {
|
|
152
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
153
|
+
throw new Error("resource profile filter must be an object");
|
|
154
|
+
}
|
|
155
|
+
const filter = value;
|
|
156
|
+
return {
|
|
157
|
+
allow: asStringArrayWithPattern(filter.allow),
|
|
158
|
+
block: asStringArrayWithPattern(filter.block),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function normalizeProfileResources(value) {
|
|
162
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
163
|
+
throw new Error("resources must be an object");
|
|
164
|
+
}
|
|
165
|
+
const input = value;
|
|
166
|
+
const result = {};
|
|
167
|
+
for (const kind of ["extensions", "skills", "prompts", "themes", "agents", "tools"]) {
|
|
168
|
+
if (input[kind] === undefined)
|
|
169
|
+
continue;
|
|
170
|
+
result[kind] = normalizeProfileFilterResource(input[kind]);
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
function parseProfileFileDefinition(content) {
|
|
175
|
+
const parsed = JSON.parse(content);
|
|
176
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
177
|
+
throw new Error("profile file must contain a JSON object");
|
|
178
|
+
}
|
|
179
|
+
const name = typeof parsed.name === "string" ? parsed.name.trim() : undefined;
|
|
180
|
+
if (!name) {
|
|
181
|
+
throw new Error("profile name is required");
|
|
182
|
+
}
|
|
183
|
+
const resourceSection = parsed.resources ?? {};
|
|
184
|
+
return {
|
|
185
|
+
name,
|
|
186
|
+
description: typeof parsed.description === "string" ? parsed.description.trim() || undefined : undefined,
|
|
187
|
+
model: typeof parsed.model === "string" ? parsed.model.trim() || undefined : undefined,
|
|
188
|
+
thinking: isThinkingLevel(parsed.thinking) ? parsed.thinking : undefined,
|
|
189
|
+
resources: normalizeProfileResources(resourceSection),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
146
192
|
export class FileSettingsStorage {
|
|
147
193
|
globalSettingsPath;
|
|
148
194
|
projectSettingsPath;
|
|
149
195
|
directoryProfileInfo;
|
|
196
|
+
profilesDir;
|
|
150
197
|
constructor(cwd, agentDir) {
|
|
151
198
|
const resolvedCwd = resolvePath(cwd);
|
|
152
199
|
const resolvedAgentDir = resolvePath(agentDir);
|
|
153
200
|
this.globalSettingsPath = join(resolvedAgentDir, "settings.json");
|
|
154
201
|
this.projectSettingsPath = join(resolvedCwd, CONFIG_DIR_NAME, "settings.json");
|
|
155
202
|
this.directoryProfileInfo = getDirectoryResourceProfileInfo(resolvedCwd, resolvedAgentDir);
|
|
203
|
+
this.profilesDir = getProfilesDir(resolvedAgentDir);
|
|
156
204
|
}
|
|
157
205
|
getDirectoryResourceProfileInfo() {
|
|
158
206
|
return { ...this.directoryProfileInfo };
|
|
159
207
|
}
|
|
208
|
+
getProfilesDir() {
|
|
209
|
+
return this.profilesDir;
|
|
210
|
+
}
|
|
160
211
|
readDirectoryResourceProfile() {
|
|
161
212
|
const path = this.directoryProfileInfo.path;
|
|
162
213
|
return existsSync(path) ? readFileSync(path, "utf-8") : undefined;
|
|
@@ -186,7 +237,11 @@ export class FileSettingsStorage {
|
|
|
186
237
|
throw lastError ?? new Error("Failed to acquire settings lock");
|
|
187
238
|
}
|
|
188
239
|
withLock(scope, fn) {
|
|
189
|
-
const path = scope === "global"
|
|
240
|
+
const path = scope === "global"
|
|
241
|
+
? this.globalSettingsPath
|
|
242
|
+
: scope === "project"
|
|
243
|
+
? this.projectSettingsPath
|
|
244
|
+
: this.directoryProfileInfo.path;
|
|
190
245
|
const dir = dirname(path);
|
|
191
246
|
let release;
|
|
192
247
|
try {
|
|
@@ -218,17 +273,22 @@ export class FileSettingsStorage {
|
|
|
218
273
|
export class InMemorySettingsStorage {
|
|
219
274
|
global;
|
|
220
275
|
project;
|
|
276
|
+
directoryProfile;
|
|
221
277
|
withLock(scope, fn) {
|
|
222
|
-
const current = scope === "global" ? this.global : this.project;
|
|
278
|
+
const current = scope === "global" ? this.global : scope === "project" ? this.project : this.directoryProfile;
|
|
223
279
|
const next = fn(current);
|
|
224
|
-
if (next
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
280
|
+
if (next === undefined) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (scope === "global") {
|
|
284
|
+
this.global = next;
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (scope === "project") {
|
|
288
|
+
this.project = next;
|
|
289
|
+
return;
|
|
231
290
|
}
|
|
291
|
+
this.directoryProfile = next;
|
|
232
292
|
}
|
|
233
293
|
}
|
|
234
294
|
export class SettingsManager {
|
|
@@ -248,6 +308,7 @@ export class SettingsManager {
|
|
|
248
308
|
globalSettingsLoadError = null; // Track if global settings file had parse errors
|
|
249
309
|
projectSettingsLoadError = null; // Track if project settings file had parse errors
|
|
250
310
|
directoryProfileInfo = null;
|
|
311
|
+
profileRegistry;
|
|
251
312
|
writeQueue = Promise.resolve();
|
|
252
313
|
errors;
|
|
253
314
|
constructor(storage, initialGlobal, initialProject, initialDirectoryProfile = {}, globalLoadError = null, projectLoadError = null, initialErrors = [], projectTrusted = true, directoryProfileInfo = null) {
|
|
@@ -261,6 +322,48 @@ export class SettingsManager {
|
|
|
261
322
|
this.directoryProfileInfo = directoryProfileInfo;
|
|
262
323
|
this.errors = [...initialErrors];
|
|
263
324
|
this.settings = this.mergeEffectiveSettings();
|
|
325
|
+
this.refreshProfileRegistry();
|
|
326
|
+
}
|
|
327
|
+
createProfileRegistry() {
|
|
328
|
+
return new ProfileRegistry({
|
|
329
|
+
globalSettings: this.globalSettings,
|
|
330
|
+
projectSettings: this.projectSettings,
|
|
331
|
+
directoryProfileSettings: this.directoryProfileSettings,
|
|
332
|
+
inlineResourceProfileDefinitions: this.inlineResourceProfileDefinitions,
|
|
333
|
+
discoveredResourceProfileDefinitions: this.discoveredResourceProfileDefinitions,
|
|
334
|
+
profilesDir: this.storage.getProfilesDir?.(),
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
profileDiagnosticKeys = new Set();
|
|
338
|
+
reportProfileDiagnostic(scope, message) {
|
|
339
|
+
const key = `${scope}:${message}`;
|
|
340
|
+
if (this.profileDiagnosticKeys.has(key)) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
this.profileDiagnosticKeys.add(key);
|
|
344
|
+
this.errors.push({ scope, error: new Error(message) });
|
|
345
|
+
}
|
|
346
|
+
getActiveProfileNamesForDiagnostics() {
|
|
347
|
+
const explicitProfiles = this.settings.activeResourceProfiles && this.settings.activeResourceProfiles.length > 0
|
|
348
|
+
? this.settings.activeResourceProfiles
|
|
349
|
+
: this.settings.activeResourceProfile
|
|
350
|
+
? [this.settings.activeResourceProfile]
|
|
351
|
+
: [];
|
|
352
|
+
return normalizeResourceProfileNames(explicitProfiles);
|
|
353
|
+
}
|
|
354
|
+
refreshProfileRegistry() {
|
|
355
|
+
this.profileDiagnosticKeys.clear();
|
|
356
|
+
this.profileRegistry = this.createProfileRegistry();
|
|
357
|
+
const registryDiagnostics = this.profileRegistry.listDiagnostics();
|
|
358
|
+
for (const diagnostic of registryDiagnostics) {
|
|
359
|
+
const path = diagnostic.path ? ` (${diagnostic.path})` : "";
|
|
360
|
+
this.reportProfileDiagnostic("global", `Profile diagnostic${path}: ${diagnostic.message}`);
|
|
361
|
+
}
|
|
362
|
+
for (const profileName of this.getActiveProfileNamesForDiagnostics()) {
|
|
363
|
+
if (!this.profileRegistry.getProfile(profileName)) {
|
|
364
|
+
this.reportProfileDiagnostic("global", `Active profile not found: ${profileName}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
264
367
|
}
|
|
265
368
|
mergeEffectiveSettings() {
|
|
266
369
|
let merged = deepMergeSettings(this.globalSettings, this.projectSettings);
|
|
@@ -272,6 +375,7 @@ export class SettingsManager {
|
|
|
272
375
|
}
|
|
273
376
|
recomputeSettings() {
|
|
274
377
|
this.settings = this.mergeEffectiveSettings();
|
|
378
|
+
this.refreshProfileRegistry();
|
|
275
379
|
}
|
|
276
380
|
/** Create a SettingsManager that loads from files */
|
|
277
381
|
static create(cwd, agentDir = getAgentDir(), options = {}) {
|
|
@@ -402,6 +506,10 @@ export class SettingsManager {
|
|
|
402
506
|
getDirectoryResourceProfileInfo() {
|
|
403
507
|
return this.directoryProfileInfo ? { ...this.directoryProfileInfo } : null;
|
|
404
508
|
}
|
|
509
|
+
getProfileRegistry() {
|
|
510
|
+
this.refreshProfileRegistry();
|
|
511
|
+
return this.profileRegistry;
|
|
512
|
+
}
|
|
405
513
|
getActiveResourceProfileNames() {
|
|
406
514
|
if (this.runtimeResourceProfiles && this.runtimeResourceProfiles.length > 0) {
|
|
407
515
|
return [...this.runtimeResourceProfiles];
|
|
@@ -410,8 +518,15 @@ export class SettingsManager {
|
|
|
410
518
|
}
|
|
411
519
|
getResourceProfileFilter(kind) {
|
|
412
520
|
const legacyFilter = mergeResourceProfileFilters(collectLegacyDisabledFilterFromSettings(this.globalSettings, kind), collectLegacyDisabledFilterFromSettings(this.projectSettings, kind), collectLegacyDisabledFilterFromSettings(this.directoryProfileSettings, kind));
|
|
413
|
-
const
|
|
414
|
-
const
|
|
521
|
+
const profileFilter = {};
|
|
522
|
+
const seenProfiles = new Set();
|
|
523
|
+
const registry = this.getProfileRegistry();
|
|
524
|
+
for (const profileName of this.getActiveResourceProfileNames()) {
|
|
525
|
+
if (seenProfiles.has(profileName))
|
|
526
|
+
continue;
|
|
527
|
+
seenProfiles.add(profileName);
|
|
528
|
+
appendFilter(profileFilter, registry.getProfile(profileName)?.resources[kind]);
|
|
529
|
+
}
|
|
415
530
|
const filter = mergeResourceProfileFilters(legacyFilter, profileFilter);
|
|
416
531
|
return {
|
|
417
532
|
allow: [...new Set(filter.allow ?? [])],
|
|
@@ -498,14 +613,399 @@ export class SettingsManager {
|
|
|
498
613
|
/** Add one-shot profile definitions from CLI/SDK/ephemeral agent launch input. Never writes to disk. */
|
|
499
614
|
addInlineResourceProfileDefinitions(profiles) {
|
|
500
615
|
this.inlineResourceProfileDefinitions = mergeResourceProfileMap(this.inlineResourceProfileDefinitions, profiles);
|
|
616
|
+
this.refreshProfileRegistry();
|
|
501
617
|
}
|
|
502
618
|
/** Replace profile definitions discovered inside loaded resource files. Never writes to disk. */
|
|
503
619
|
replaceDiscoveredResourceProfileDefinitions(profiles) {
|
|
504
620
|
this.discoveredResourceProfileDefinitions = { ...profiles };
|
|
621
|
+
this.refreshProfileRegistry();
|
|
505
622
|
}
|
|
506
623
|
/** Add profile definitions discovered after resource resolution, e.g. context agent files. Never writes to disk. */
|
|
507
624
|
addDiscoveredResourceProfileDefinitions(profiles) {
|
|
508
625
|
this.discoveredResourceProfileDefinitions = mergeResourceProfileMap(this.discoveredResourceProfileDefinitions, profiles);
|
|
626
|
+
this.refreshProfileRegistry();
|
|
627
|
+
}
|
|
628
|
+
normalizeProfileName(profileName) {
|
|
629
|
+
const trimmed = profileName.trim();
|
|
630
|
+
if (!trimmed) {
|
|
631
|
+
throw new Error("Profile name is required");
|
|
632
|
+
}
|
|
633
|
+
const errors = validateSkillName(trimmed);
|
|
634
|
+
if (errors.length > 0) {
|
|
635
|
+
throw new Error(`Invalid profile name "${trimmed}": ${errors.join(", ")}`);
|
|
636
|
+
}
|
|
637
|
+
return trimmed;
|
|
638
|
+
}
|
|
639
|
+
sanitizeProfileResources(resources) {
|
|
640
|
+
const result = {};
|
|
641
|
+
for (const kind of ["extensions", "skills", "prompts", "themes", "agents", "tools"]) {
|
|
642
|
+
const filter = resources[kind];
|
|
643
|
+
if (!filter) {
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
result[kind] = {
|
|
647
|
+
allow: filter.allow ? [...filter.allow] : undefined,
|
|
648
|
+
block: filter.block ? [...filter.block] : undefined,
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
return result;
|
|
652
|
+
}
|
|
653
|
+
setActiveProfileInSettings(settings, profileName) {
|
|
654
|
+
if (profileName) {
|
|
655
|
+
settings.activeResourceProfile = profileName;
|
|
656
|
+
settings.activeResourceProfiles = [profileName];
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
delete settings.activeResourceProfiles;
|
|
660
|
+
delete settings.activeResourceProfile;
|
|
661
|
+
}
|
|
662
|
+
persistDirectoryProfiles(update) {
|
|
663
|
+
const next = structuredClone(this.directoryProfileSettings);
|
|
664
|
+
update(next);
|
|
665
|
+
this.directoryProfileSettings = next;
|
|
666
|
+
this.recomputeSettings();
|
|
667
|
+
if (!this.directoryProfileInfo) {
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
this.enqueueWrite("directoryProfile", () => {
|
|
671
|
+
this.storage.withLock("directoryProfile", (current) => {
|
|
672
|
+
const currentSettings = current
|
|
673
|
+
? SettingsManager.migrateSettings(JSON.parse(current))
|
|
674
|
+
: {};
|
|
675
|
+
const merged = {
|
|
676
|
+
...currentSettings,
|
|
677
|
+
...next,
|
|
678
|
+
resourceProfiles: next.resourceProfiles,
|
|
679
|
+
activeResourceProfiles: next.activeResourceProfiles,
|
|
680
|
+
activeResourceProfile: next.activeResourceProfile,
|
|
681
|
+
};
|
|
682
|
+
if (!next.resourceProfiles) {
|
|
683
|
+
delete merged.resourceProfiles;
|
|
684
|
+
}
|
|
685
|
+
if (!next.activeResourceProfiles && next.activeResourceProfile === undefined) {
|
|
686
|
+
delete merged.activeResourceProfiles;
|
|
687
|
+
delete merged.activeResourceProfile;
|
|
688
|
+
}
|
|
689
|
+
return JSON.stringify(merged, null, 2);
|
|
690
|
+
});
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
getProfileFilePath(profileName) {
|
|
694
|
+
const normalized = this.normalizeProfileName(profileName);
|
|
695
|
+
const profilesDir = this.storage.getProfilesDir?.();
|
|
696
|
+
if (!profilesDir) {
|
|
697
|
+
throw new Error("Profiles directory is not configured");
|
|
698
|
+
}
|
|
699
|
+
return join(resolve(profilesDir), `${normalized}.json`);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Create or update a profile definition in the selected persistence scope.
|
|
703
|
+
*/
|
|
704
|
+
setProfileDefinition(profileName, definition, scope) {
|
|
705
|
+
const name = this.normalizeProfileName(profileName);
|
|
706
|
+
const resources = this.sanitizeProfileResources(definition.resources);
|
|
707
|
+
if (scope === "session") {
|
|
708
|
+
const next = { ...this.inlineResourceProfileDefinitions };
|
|
709
|
+
if (Object.keys(resources).length > 0) {
|
|
710
|
+
next[name] = resources;
|
|
711
|
+
}
|
|
712
|
+
else {
|
|
713
|
+
delete next[name];
|
|
714
|
+
}
|
|
715
|
+
this.inlineResourceProfileDefinitions = next;
|
|
716
|
+
this.refreshProfileRegistry();
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
if (scope === "global") {
|
|
720
|
+
const next = structuredClone(this.globalSettings);
|
|
721
|
+
next.resourceProfiles = { ...(next.resourceProfiles ?? {}) };
|
|
722
|
+
if (Object.keys(resources).length > 0) {
|
|
723
|
+
next.resourceProfiles[name] = resources;
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
delete next.resourceProfiles[name];
|
|
727
|
+
}
|
|
728
|
+
if (Object.keys(next.resourceProfiles).length === 0) {
|
|
729
|
+
delete next.resourceProfiles;
|
|
730
|
+
}
|
|
731
|
+
this.globalSettings = next;
|
|
732
|
+
this.markModified("resourceProfiles");
|
|
733
|
+
this.save();
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
if (scope === "project") {
|
|
737
|
+
this.updateProjectSettings("resourceProfiles", (settings) => {
|
|
738
|
+
const next = structuredClone(settings.resourceProfiles ?? {});
|
|
739
|
+
if (Object.keys(resources).length > 0) {
|
|
740
|
+
next[name] = resources;
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
delete next[name];
|
|
744
|
+
}
|
|
745
|
+
if (Object.keys(next).length > 0) {
|
|
746
|
+
settings.resourceProfiles = next;
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
delete settings.resourceProfiles;
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
if (scope === "directory") {
|
|
755
|
+
this.persistDirectoryProfiles((current) => {
|
|
756
|
+
const next = { ...(current.resourceProfiles ?? {}) };
|
|
757
|
+
if (Object.keys(resources).length > 0) {
|
|
758
|
+
next[name] = resources;
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
delete next[name];
|
|
762
|
+
}
|
|
763
|
+
if (Object.keys(next).length > 0) {
|
|
764
|
+
current.resourceProfiles = next;
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
delete current.resourceProfiles;
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
const path = this.getProfileFilePath(name);
|
|
773
|
+
const existing = existsSync(path)
|
|
774
|
+
? parseProfileFileDefinition(readFileSync(path, "utf-8"))
|
|
775
|
+
: { name, resources: {} };
|
|
776
|
+
const payload = {
|
|
777
|
+
...existing,
|
|
778
|
+
name,
|
|
779
|
+
resources,
|
|
780
|
+
description: definition.description ?? existing.description,
|
|
781
|
+
model: definition.model ?? existing.model,
|
|
782
|
+
thinking: definition.thinking ?? existing.thinking,
|
|
783
|
+
};
|
|
784
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
785
|
+
writeFileSync(path, JSON.stringify(payload, null, 2), "utf-8");
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Delete a profile from the selected scope.
|
|
789
|
+
*/
|
|
790
|
+
deleteProfile(profileName, scope) {
|
|
791
|
+
const name = this.normalizeProfileName(profileName);
|
|
792
|
+
if (scope === "session") {
|
|
793
|
+
const next = { ...this.inlineResourceProfileDefinitions };
|
|
794
|
+
delete next[name];
|
|
795
|
+
this.inlineResourceProfileDefinitions = next;
|
|
796
|
+
this.refreshProfileRegistry();
|
|
797
|
+
if (this.runtimeResourceProfiles) {
|
|
798
|
+
this.setRuntimeResourceProfiles(this.runtimeResourceProfiles.filter((profile) => profile !== name));
|
|
799
|
+
}
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
if (scope === "global") {
|
|
803
|
+
const next = { ...(this.globalSettings.resourceProfiles ?? {}) };
|
|
804
|
+
delete next[name];
|
|
805
|
+
if (Object.keys(next).length > 0) {
|
|
806
|
+
this.globalSettings.resourceProfiles = next;
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
delete this.globalSettings.resourceProfiles;
|
|
810
|
+
}
|
|
811
|
+
if (this.globalSettings.activeResourceProfile === name) {
|
|
812
|
+
delete this.globalSettings.activeResourceProfile;
|
|
813
|
+
}
|
|
814
|
+
if (this.globalSettings.activeResourceProfiles) {
|
|
815
|
+
this.globalSettings.activeResourceProfiles = this.globalSettings.activeResourceProfiles.filter((profile) => profile !== name);
|
|
816
|
+
if (this.globalSettings.activeResourceProfiles.length === 0) {
|
|
817
|
+
delete this.globalSettings.activeResourceProfiles;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
this.markModified("resourceProfiles");
|
|
821
|
+
this.save();
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
if (scope === "project") {
|
|
825
|
+
this.updateProjectSettings("resourceProfiles", (settings) => {
|
|
826
|
+
const next = { ...(settings.resourceProfiles ?? {}) };
|
|
827
|
+
delete next[name];
|
|
828
|
+
if (Object.keys(next).length > 0) {
|
|
829
|
+
settings.resourceProfiles = next;
|
|
830
|
+
}
|
|
831
|
+
else {
|
|
832
|
+
delete settings.resourceProfiles;
|
|
833
|
+
}
|
|
834
|
+
if (settings.activeResourceProfile === name) {
|
|
835
|
+
delete settings.activeResourceProfile;
|
|
836
|
+
}
|
|
837
|
+
if (settings.activeResourceProfiles) {
|
|
838
|
+
settings.activeResourceProfiles = settings.activeResourceProfiles.filter((profile) => profile !== name);
|
|
839
|
+
if (settings.activeResourceProfiles.length === 0) {
|
|
840
|
+
delete settings.activeResourceProfiles;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
if (scope === "directory") {
|
|
847
|
+
this.persistDirectoryProfiles((current) => {
|
|
848
|
+
const next = { ...(current.resourceProfiles ?? {}) };
|
|
849
|
+
delete next[name];
|
|
850
|
+
if (Object.keys(next).length > 0) {
|
|
851
|
+
current.resourceProfiles = next;
|
|
852
|
+
}
|
|
853
|
+
else {
|
|
854
|
+
delete current.resourceProfiles;
|
|
855
|
+
}
|
|
856
|
+
if (current.activeResourceProfile === name) {
|
|
857
|
+
delete current.activeResourceProfile;
|
|
858
|
+
}
|
|
859
|
+
if (current.activeResourceProfiles) {
|
|
860
|
+
current.activeResourceProfiles = current.activeResourceProfiles.filter((profile) => profile !== name);
|
|
861
|
+
if (current.activeResourceProfiles.length === 0) {
|
|
862
|
+
delete current.activeResourceProfiles;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
const profilePath = this.getProfileFilePath(name);
|
|
869
|
+
if (!existsSync(profilePath)) {
|
|
870
|
+
throw new Error(`Profile not found: ${name}`);
|
|
871
|
+
}
|
|
872
|
+
rmSync(profilePath, { force: true });
|
|
873
|
+
}
|
|
874
|
+
renameProfile(profileName, newProfileName, scope) {
|
|
875
|
+
const oldName = this.normalizeProfileName(profileName);
|
|
876
|
+
const newName = this.normalizeProfileName(newProfileName);
|
|
877
|
+
if (oldName === newName) {
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if (scope === "session") {
|
|
881
|
+
const profile = this.inlineResourceProfileDefinitions[oldName];
|
|
882
|
+
if (!profile) {
|
|
883
|
+
throw new Error(`Profile not found: ${oldName}`);
|
|
884
|
+
}
|
|
885
|
+
delete this.inlineResourceProfileDefinitions[oldName];
|
|
886
|
+
this.inlineResourceProfileDefinitions[newName] = profile;
|
|
887
|
+
if (this.runtimeResourceProfiles) {
|
|
888
|
+
this.runtimeResourceProfiles = this.runtimeResourceProfiles.map((name) => name === oldName ? newName : name);
|
|
889
|
+
this.setRuntimeResourceProfiles(this.runtimeResourceProfiles);
|
|
890
|
+
}
|
|
891
|
+
this.refreshProfileRegistry();
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
if (scope === "global") {
|
|
895
|
+
const next = structuredClone(this.globalSettings);
|
|
896
|
+
if (!next.resourceProfiles?.[oldName]) {
|
|
897
|
+
throw new Error(`Profile not found: ${oldName}`);
|
|
898
|
+
}
|
|
899
|
+
if (next.resourceProfiles[newName]) {
|
|
900
|
+
throw new Error(`Profile already exists: ${newName}`);
|
|
901
|
+
}
|
|
902
|
+
next.resourceProfiles[newName] = next.resourceProfiles[oldName];
|
|
903
|
+
delete next.resourceProfiles[oldName];
|
|
904
|
+
if (next.activeResourceProfile === oldName) {
|
|
905
|
+
next.activeResourceProfile = newName;
|
|
906
|
+
}
|
|
907
|
+
if (next.activeResourceProfiles) {
|
|
908
|
+
next.activeResourceProfiles = next.activeResourceProfiles.map((name) => name === oldName ? newName : name);
|
|
909
|
+
}
|
|
910
|
+
this.globalSettings = next;
|
|
911
|
+
this.markModified("resourceProfiles");
|
|
912
|
+
this.markModified("activeResourceProfile");
|
|
913
|
+
this.markModified("activeResourceProfiles");
|
|
914
|
+
this.save();
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
if (scope === "project") {
|
|
918
|
+
this.updateProjectSettings("resourceProfiles", (settings) => {
|
|
919
|
+
const next = structuredClone(settings.resourceProfiles ?? {});
|
|
920
|
+
if (!next[oldName]) {
|
|
921
|
+
throw new Error(`Profile not found: ${oldName}`);
|
|
922
|
+
}
|
|
923
|
+
if (next[newName]) {
|
|
924
|
+
throw new Error(`Profile already exists: ${newName}`);
|
|
925
|
+
}
|
|
926
|
+
next[newName] = next[oldName];
|
|
927
|
+
delete next[oldName];
|
|
928
|
+
settings.resourceProfiles = next;
|
|
929
|
+
if (settings.activeResourceProfile === oldName) {
|
|
930
|
+
settings.activeResourceProfile = newName;
|
|
931
|
+
}
|
|
932
|
+
if (settings.activeResourceProfiles) {
|
|
933
|
+
settings.activeResourceProfiles = settings.activeResourceProfiles.map((name) => name === oldName ? newName : name);
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
if (scope === "directory") {
|
|
939
|
+
const next = structuredClone(this.directoryProfileSettings.resourceProfiles ?? {});
|
|
940
|
+
if (!next[oldName]) {
|
|
941
|
+
throw new Error(`Profile not found: ${oldName}`);
|
|
942
|
+
}
|
|
943
|
+
if (next[newName]) {
|
|
944
|
+
throw new Error(`Profile already exists: ${newName}`);
|
|
945
|
+
}
|
|
946
|
+
next[newName] = next[oldName];
|
|
947
|
+
delete next[oldName];
|
|
948
|
+
this.persistDirectoryProfiles((current) => {
|
|
949
|
+
current.resourceProfiles = next;
|
|
950
|
+
if (current.activeResourceProfile === oldName) {
|
|
951
|
+
current.activeResourceProfile = newName;
|
|
952
|
+
}
|
|
953
|
+
if (current.activeResourceProfiles) {
|
|
954
|
+
current.activeResourceProfiles = current.activeResourceProfiles.map((name) => name === oldName ? newName : name);
|
|
955
|
+
}
|
|
956
|
+
});
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
const oldPath = this.getProfileFilePath(oldName);
|
|
960
|
+
const newPath = this.getProfileFilePath(newName);
|
|
961
|
+
if (!existsSync(oldPath)) {
|
|
962
|
+
throw new Error(`Profile not found: ${oldName}`);
|
|
963
|
+
}
|
|
964
|
+
if (existsSync(newPath)) {
|
|
965
|
+
throw new Error(`Profile already exists: ${newName}`);
|
|
966
|
+
}
|
|
967
|
+
const parsed = parseProfileFileDefinition(readFileSync(oldPath, "utf-8"));
|
|
968
|
+
parsed.name = newName;
|
|
969
|
+
writeFileSync(newPath, JSON.stringify(parsed, null, 2), "utf-8");
|
|
970
|
+
rmSync(oldPath, { force: true });
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Set active profile selection in the selected scope.
|
|
974
|
+
*/
|
|
975
|
+
setActiveProfile(profileName, scope) {
|
|
976
|
+
const name = profileName ? this.normalizeProfileName(profileName) : undefined;
|
|
977
|
+
if (scope === "session") {
|
|
978
|
+
if (name) {
|
|
979
|
+
this.setRuntimeResourceProfiles([name]);
|
|
980
|
+
}
|
|
981
|
+
else {
|
|
982
|
+
this.setRuntimeResourceProfiles([]);
|
|
983
|
+
}
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
if (scope === "global") {
|
|
987
|
+
if (name) {
|
|
988
|
+
this.globalSettings.activeResourceProfile = name;
|
|
989
|
+
this.globalSettings.activeResourceProfiles = [name];
|
|
990
|
+
}
|
|
991
|
+
else {
|
|
992
|
+
delete this.globalSettings.activeResourceProfile;
|
|
993
|
+
delete this.globalSettings.activeResourceProfiles;
|
|
994
|
+
}
|
|
995
|
+
this.markModified("activeResourceProfile");
|
|
996
|
+
this.markModified("activeResourceProfiles");
|
|
997
|
+
this.save();
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
if (scope === "project") {
|
|
1001
|
+
this.updateProjectSettings("activeResourceProfile", (settings) => {
|
|
1002
|
+
this.setActiveProfileInSettings(settings, name);
|
|
1003
|
+
});
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
this.persistDirectoryProfiles((current) => {
|
|
1007
|
+
this.setActiveProfileInSettings(current, name);
|
|
1008
|
+
});
|
|
509
1009
|
}
|
|
510
1010
|
/** Mark a global field as modified during this session */
|
|
511
1011
|
markModified(field, nestedKey) {
|
|
@@ -733,20 +1233,35 @@ export class SettingsManager {
|
|
|
733
1233
|
getContextGcSettings() {
|
|
734
1234
|
return {
|
|
735
1235
|
enabled: this.settings.contextGc?.enabled ?? true,
|
|
736
|
-
preserveRecentMessages: this.settings.contextGc?.preserveRecentMessages ??
|
|
737
|
-
minToolResultChars: this.settings.contextGc?.minToolResultChars ??
|
|
1236
|
+
preserveRecentMessages: this.settings.contextGc?.preserveRecentMessages ?? 8,
|
|
1237
|
+
minToolResultChars: this.settings.contextGc?.minToolResultChars ?? 1200,
|
|
738
1238
|
tools: this.settings.contextGc?.tools ?? [
|
|
739
1239
|
"read",
|
|
740
1240
|
"bash",
|
|
741
1241
|
"rg",
|
|
742
1242
|
"grep",
|
|
1243
|
+
"find",
|
|
1244
|
+
"ls",
|
|
1245
|
+
"skill_open",
|
|
1246
|
+
"automata_graph_status",
|
|
1247
|
+
"automata_graph_search",
|
|
1248
|
+
"automata_graph_query",
|
|
1249
|
+
"automata_graph_neighbors",
|
|
1250
|
+
"automata_graph_path",
|
|
1251
|
+
"automata_graph_pointer_pack",
|
|
1252
|
+
"learning_query_memory",
|
|
1253
|
+
"subagent",
|
|
1254
|
+
"task_steps",
|
|
1255
|
+
"task_background",
|
|
1256
|
+
"task_goal",
|
|
1257
|
+
"run_ledger",
|
|
743
1258
|
"context_headroom_retrieve",
|
|
744
1259
|
"headroom_retrieve",
|
|
745
1260
|
],
|
|
746
1261
|
semanticMemory: {
|
|
747
1262
|
enabled: this.settings.contextGc?.semanticMemory?.enabled ?? true,
|
|
748
|
-
preserveRecentPages: this.settings.contextGc?.semanticMemory?.preserveRecentPages ??
|
|
749
|
-
minChars: this.settings.contextGc?.semanticMemory?.minChars ??
|
|
1263
|
+
preserveRecentPages: this.settings.contextGc?.semanticMemory?.preserveRecentPages ?? 1,
|
|
1264
|
+
minChars: this.settings.contextGc?.semanticMemory?.minChars ?? 900,
|
|
750
1265
|
markers: this.settings.contextGc?.semanticMemory?.markers ?? [
|
|
751
1266
|
"<automata_context",
|
|
752
1267
|
"<automata_response",
|
|
@@ -1086,12 +1601,22 @@ export class SettingsManager {
|
|
|
1086
1601
|
setSelfModificationSettings(settings, scope = "global") {
|
|
1087
1602
|
if (scope === "project") {
|
|
1088
1603
|
const projectSettings = structuredClone(this.projectSettings);
|
|
1089
|
-
projectSettings.selfModification
|
|
1604
|
+
const existing = projectSettings.selfModification;
|
|
1605
|
+
projectSettings.selfModification = {
|
|
1606
|
+
...existing,
|
|
1607
|
+
...settings,
|
|
1608
|
+
sourcePaths: settings.sourcePaths ?? existing?.sourcePaths,
|
|
1609
|
+
};
|
|
1090
1610
|
this.markProjectModified("selfModification");
|
|
1091
1611
|
this.saveProjectSettings(projectSettings);
|
|
1092
1612
|
return;
|
|
1093
1613
|
}
|
|
1094
|
-
this.globalSettings.selfModification
|
|
1614
|
+
const existing = this.globalSettings.selfModification;
|
|
1615
|
+
this.globalSettings.selfModification = {
|
|
1616
|
+
...existing,
|
|
1617
|
+
...settings,
|
|
1618
|
+
sourcePaths: settings.sourcePaths ?? existing?.sourcePaths,
|
|
1619
|
+
};
|
|
1095
1620
|
this.markModified("selfModification");
|
|
1096
1621
|
this.save();
|
|
1097
1622
|
}
|
|
@@ -1112,7 +1637,12 @@ export class SettingsManager {
|
|
|
1112
1637
|
this.save();
|
|
1113
1638
|
}
|
|
1114
1639
|
getAutoLearnSettings() {
|
|
1115
|
-
|
|
1640
|
+
const settings = this.settings.autoLearn ?? {};
|
|
1641
|
+
return {
|
|
1642
|
+
...settings,
|
|
1643
|
+
thinkingLevel: settings.thinkingLevel ?? "low",
|
|
1644
|
+
complexTaskToolCalls: settings.complexTaskToolCalls ?? 12,
|
|
1645
|
+
};
|
|
1116
1646
|
}
|
|
1117
1647
|
setAutoLearnSettings(settings, scope = "global") {
|
|
1118
1648
|
if (scope === "project") {
|