@caupulican/pi-adaptative 0.80.40 → 0.80.44

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.
Files changed (105) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/bundled-resources/prompts/extensionify.md +20 -0
  3. package/dist/bundled-resources/prompts/learn.md +27 -0
  4. package/dist/bundled-resources/prompts/skillify.md +21 -0
  5. package/dist/bundled-resources/skills/pi-harness-learning/SKILL.md +217 -0
  6. package/dist/bundled-resources/skills/skill-architect/SKILL.md +162 -0
  7. package/dist/config.d.ts +17 -0
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +30 -0
  10. package/dist/config.js.map +1 -1
  11. package/dist/core/agent-session.d.ts +37 -2
  12. package/dist/core/agent-session.d.ts.map +1 -1
  13. package/dist/core/agent-session.js +217 -11
  14. package/dist/core/agent-session.js.map +1 -1
  15. package/dist/core/compaction/compaction.d.ts +1 -1
  16. package/dist/core/compaction/compaction.d.ts.map +1 -1
  17. package/dist/core/compaction/compaction.js +4 -2
  18. package/dist/core/compaction/compaction.js.map +1 -1
  19. package/dist/core/context-gc.d.ts.map +1 -1
  20. package/dist/core/context-gc.js +27 -5
  21. package/dist/core/context-gc.js.map +1 -1
  22. package/dist/core/extensions/loader.d.ts +10 -3
  23. package/dist/core/extensions/loader.d.ts.map +1 -1
  24. package/dist/core/extensions/loader.js +38 -7
  25. package/dist/core/extensions/loader.js.map +1 -1
  26. package/dist/core/extensions/runner.d.ts +6 -0
  27. package/dist/core/extensions/runner.d.ts.map +1 -1
  28. package/dist/core/extensions/runner.js +53 -6
  29. package/dist/core/extensions/runner.js.map +1 -1
  30. package/dist/core/extensions/types.d.ts +16 -2
  31. package/dist/core/extensions/types.d.ts.map +1 -1
  32. package/dist/core/extensions/types.js.map +1 -1
  33. package/dist/core/profile-registry.d.ts +39 -0
  34. package/dist/core/profile-registry.d.ts.map +1 -0
  35. package/dist/core/profile-registry.js +230 -0
  36. package/dist/core/profile-registry.js.map +1 -0
  37. package/dist/core/profile-resource-selection.d.ts +19 -0
  38. package/dist/core/profile-resource-selection.d.ts.map +1 -0
  39. package/dist/core/profile-resource-selection.js +84 -0
  40. package/dist/core/profile-resource-selection.js.map +1 -0
  41. package/dist/core/resource-loader.d.ts +33 -3
  42. package/dist/core/resource-loader.d.ts.map +1 -1
  43. package/dist/core/resource-loader.js +68 -11
  44. package/dist/core/resource-loader.js.map +1 -1
  45. package/dist/core/settings-manager.d.ts +44 -2
  46. package/dist/core/settings-manager.d.ts.map +1 -1
  47. package/dist/core/settings-manager.js +557 -27
  48. package/dist/core/settings-manager.js.map +1 -1
  49. package/dist/core/skills.d.ts +5 -0
  50. package/dist/core/skills.d.ts.map +1 -1
  51. package/dist/core/skills.js +2 -2
  52. package/dist/core/skills.js.map +1 -1
  53. package/dist/core/slash-commands.d.ts.map +1 -1
  54. package/dist/core/slash-commands.js +1 -0
  55. package/dist/core/slash-commands.js.map +1 -1
  56. package/dist/core/system-prompt.d.ts.map +1 -1
  57. package/dist/core/system-prompt.js +5 -17
  58. package/dist/core/system-prompt.js.map +1 -1
  59. package/dist/core/tools/extensionify.d.ts +33 -0
  60. package/dist/core/tools/extensionify.d.ts.map +1 -0
  61. package/dist/core/tools/extensionify.js +146 -0
  62. package/dist/core/tools/extensionify.js.map +1 -0
  63. package/dist/core/tools/index.d.ts +10 -1
  64. package/dist/core/tools/index.d.ts.map +1 -1
  65. package/dist/core/tools/index.js +36 -1
  66. package/dist/core/tools/index.js.map +1 -1
  67. package/dist/core/tools/skill-audit.d.ts +63 -0
  68. package/dist/core/tools/skill-audit.d.ts.map +1 -0
  69. package/dist/core/tools/skill-audit.js +175 -0
  70. package/dist/core/tools/skill-audit.js.map +1 -0
  71. package/dist/core/tools/skillify.d.ts +30 -0
  72. package/dist/core/tools/skillify.d.ts.map +1 -0
  73. package/dist/core/tools/skillify.js +91 -0
  74. package/dist/core/tools/skillify.js.map +1 -0
  75. package/dist/index.d.ts +1 -0
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +4 -0
  78. package/dist/index.js.map +1 -1
  79. package/dist/modes/interactive/components/profile-resource-editor.d.ts +50 -0
  80. package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -0
  81. package/dist/modes/interactive/components/profile-resource-editor.js +232 -0
  82. package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -0
  83. package/dist/modes/interactive/components/profile-selector.d.ts +8 -0
  84. package/dist/modes/interactive/components/profile-selector.d.ts.map +1 -0
  85. package/dist/modes/interactive/components/profile-selector.js +77 -0
  86. package/dist/modes/interactive/components/profile-selector.js.map +1 -0
  87. package/dist/modes/interactive/components/settings-selector.d.ts +7 -0
  88. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  89. package/dist/modes/interactive/components/settings-selector.js +62 -0
  90. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  91. package/dist/modes/interactive/interactive-mode.d.ts +12 -0
  92. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  93. package/dist/modes/interactive/interactive-mode.js +362 -24
  94. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  95. package/docs/settings.md +20 -1
  96. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  97. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  98. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  99. package/examples/extensions/sandbox/package-lock.json +2 -2
  100. package/examples/extensions/sandbox/package.json +1 -1
  101. package/examples/extensions/with-deps/package-lock.json +2 -2
  102. package/examples/extensions/with-deps/package.json +1 -1
  103. package/examples/sdk/12-full-control.ts +4 -0
  104. package/npm-shrinkwrap.json +12 -12
  105. 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" ? this.globalSettingsPath : this.projectSettingsPath;
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 !== undefined) {
225
- if (scope === "global") {
226
- this.global = next;
227
- }
228
- else {
229
- this.project = next;
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 activeProfiles = this.getActiveResourceProfileNames();
414
- const profileFilter = mergeResourceProfileFilters(collectNamedResourceProfileFilters(this.globalSettings, kind, activeProfiles), collectNamedResourceProfileFilters(this.projectSettings, kind, activeProfiles), collectNamedResourceProfileFilters(this.directoryProfileSettings, kind, activeProfiles), collectNamedResourceProfileFilters({ resourceProfiles: this.inlineResourceProfileDefinitions }, kind, activeProfiles), collectNamedResourceProfileFilters({ resourceProfiles: this.discoveredResourceProfileDefinitions }, kind, activeProfiles));
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 ?? 12,
737
- minToolResultChars: this.settings.contextGc?.minToolResultChars ?? 2500,
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 ?? 2,
749
- minChars: this.settings.contextGc?.semanticMemory?.minChars ?? 1200,
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 = { ...settings };
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 = { ...settings };
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
- return { ...(this.settings.autoLearn ?? {}) };
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") {