@caupulican/pi-adaptative 0.81.26 → 0.81.29

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 (286) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/cli/args.d.ts.map +1 -1
  3. package/dist/cli/args.js +3 -2
  4. package/dist/cli/args.js.map +1 -1
  5. package/dist/core/agent-session-services.d.ts +4 -0
  6. package/dist/core/agent-session-services.d.ts.map +1 -1
  7. package/dist/core/agent-session-services.js +19 -2
  8. package/dist/core/agent-session-services.js.map +1 -1
  9. package/dist/core/agent-session.d.ts +30 -12
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +128 -36
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/auth-storage.d.ts +6 -0
  14. package/dist/core/auth-storage.d.ts.map +1 -1
  15. package/dist/core/auth-storage.js +35 -0
  16. package/dist/core/auth-storage.js.map +1 -1
  17. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
  18. package/dist/core/autonomy/bounded-completion.js +59 -19
  19. package/dist/core/autonomy/bounded-completion.js.map +1 -1
  20. package/dist/core/autonomy/contracts.d.ts +2 -0
  21. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  22. package/dist/core/autonomy/contracts.js.map +1 -1
  23. package/dist/core/autonomy/lane-tool-surface.d.ts +31 -0
  24. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -0
  25. package/dist/core/autonomy/lane-tool-surface.js +96 -0
  26. package/dist/core/autonomy/lane-tool-surface.js.map +1 -0
  27. package/dist/core/autonomy/lane-tracker.d.ts +5 -0
  28. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  29. package/dist/core/autonomy/lane-tracker.js +14 -3
  30. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  31. package/dist/core/background-lane-controller.d.ts +28 -4
  32. package/dist/core/background-lane-controller.d.ts.map +1 -1
  33. package/dist/core/background-lane-controller.js +237 -28
  34. package/dist/core/background-lane-controller.js.map +1 -1
  35. package/dist/core/billing-failover-controller.d.ts.map +1 -1
  36. package/dist/core/billing-failover-controller.js +1 -1
  37. package/dist/core/billing-failover-controller.js.map +1 -1
  38. package/dist/core/context/current-work-memory.d.ts +9 -0
  39. package/dist/core/context/current-work-memory.d.ts.map +1 -0
  40. package/dist/core/context/current-work-memory.js +61 -0
  41. package/dist/core/context/current-work-memory.js.map +1 -0
  42. package/dist/core/context/file-store-memory-provider.d.ts +9 -0
  43. package/dist/core/context/file-store-memory-provider.d.ts.map +1 -0
  44. package/dist/core/context/file-store-memory-provider.js +106 -0
  45. package/dist/core/context/file-store-memory-provider.js.map +1 -0
  46. package/dist/core/context/long-term-memory-trigger.d.ts +15 -0
  47. package/dist/core/context/long-term-memory-trigger.d.ts.map +1 -0
  48. package/dist/core/context/long-term-memory-trigger.js +39 -0
  49. package/dist/core/context/long-term-memory-trigger.js.map +1 -0
  50. package/dist/core/context/memory-prompt-block.d.ts +3 -1
  51. package/dist/core/context/memory-prompt-block.d.ts.map +1 -1
  52. package/dist/core/context/memory-prompt-block.js +20 -3
  53. package/dist/core/context/memory-prompt-block.js.map +1 -1
  54. package/dist/core/context/memory-prompt-budget.d.ts +17 -0
  55. package/dist/core/context/memory-prompt-budget.d.ts.map +1 -0
  56. package/dist/core/context/memory-prompt-budget.js +64 -0
  57. package/dist/core/context/memory-prompt-budget.js.map +1 -0
  58. package/dist/core/context/memory-provider-contract.d.ts.map +1 -1
  59. package/dist/core/context/memory-provider-contract.js +2 -5
  60. package/dist/core/context/memory-provider-contract.js.map +1 -1
  61. package/dist/core/context/memory-tier-composer.d.ts +27 -0
  62. package/dist/core/context/memory-tier-composer.d.ts.map +1 -0
  63. package/dist/core/context/memory-tier-composer.js +79 -0
  64. package/dist/core/context/memory-tier-composer.js.map +1 -0
  65. package/dist/core/context-gc.d.ts.map +1 -1
  66. package/dist/core/context-gc.js +2 -0
  67. package/dist/core/context-gc.js.map +1 -1
  68. package/dist/core/context-pipeline.d.ts +5 -3
  69. package/dist/core/context-pipeline.d.ts.map +1 -1
  70. package/dist/core/context-pipeline.js +15 -5
  71. package/dist/core/context-pipeline.js.map +1 -1
  72. package/dist/core/cost/cost-summary.d.ts +3 -1
  73. package/dist/core/cost/cost-summary.d.ts.map +1 -1
  74. package/dist/core/cost/cost-summary.js +3 -3
  75. package/dist/core/cost/cost-summary.js.map +1 -1
  76. package/dist/core/cost-guard.d.ts +17 -7
  77. package/dist/core/cost-guard.d.ts.map +1 -1
  78. package/dist/core/cost-guard.js +33 -10
  79. package/dist/core/cost-guard.js.map +1 -1
  80. package/dist/core/default-tool-surface.d.ts +9 -0
  81. package/dist/core/default-tool-surface.d.ts.map +1 -0
  82. package/dist/core/default-tool-surface.js +18 -0
  83. package/dist/core/default-tool-surface.js.map +1 -0
  84. package/dist/core/delegation/worker-result.d.ts.map +1 -1
  85. package/dist/core/delegation/worker-result.js +3 -0
  86. package/dist/core/delegation/worker-result.js.map +1 -1
  87. package/dist/core/delegation/worker-runner.d.ts +11 -5
  88. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  89. package/dist/core/delegation/worker-runner.js +77 -16
  90. package/dist/core/delegation/worker-runner.js.map +1 -1
  91. package/dist/core/extensions/loader.d.ts.map +1 -1
  92. package/dist/core/extensions/loader.js +15 -0
  93. package/dist/core/extensions/loader.js.map +1 -1
  94. package/dist/core/extensions/runner.d.ts +2 -0
  95. package/dist/core/extensions/runner.d.ts.map +1 -1
  96. package/dist/core/extensions/runner.js +7 -0
  97. package/dist/core/extensions/runner.js.map +1 -1
  98. package/dist/core/extensions/types.d.ts +9 -0
  99. package/dist/core/extensions/types.d.ts.map +1 -1
  100. package/dist/core/extensions/types.js.map +1 -1
  101. package/dist/core/failure-corpus.d.ts.map +1 -1
  102. package/dist/core/failure-corpus.js +2 -4
  103. package/dist/core/failure-corpus.js.map +1 -1
  104. package/dist/core/footer-data-provider.d.ts.map +1 -1
  105. package/dist/core/footer-data-provider.js +9 -1
  106. package/dist/core/footer-data-provider.js.map +1 -1
  107. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  108. package/dist/core/goals/goal-continuation-prompt.js +4 -3
  109. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  110. package/dist/core/http-dispatcher.d.ts +12 -0
  111. package/dist/core/http-dispatcher.d.ts.map +1 -1
  112. package/dist/core/http-dispatcher.js +42 -4
  113. package/dist/core/http-dispatcher.js.map +1 -1
  114. package/dist/core/local-runtime-controller.d.ts +16 -0
  115. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  116. package/dist/core/local-runtime-controller.js +107 -28
  117. package/dist/core/local-runtime-controller.js.map +1 -1
  118. package/dist/core/memory/memory-manager.d.ts +8 -3
  119. package/dist/core/memory/memory-manager.d.ts.map +1 -1
  120. package/dist/core/memory/memory-manager.js +27 -11
  121. package/dist/core/memory/memory-manager.js.map +1 -1
  122. package/dist/core/memory/memory-provider.d.ts +5 -1
  123. package/dist/core/memory/memory-provider.d.ts.map +1 -1
  124. package/dist/core/memory/memory-provider.js.map +1 -1
  125. package/dist/core/memory/providers/file-store.d.ts +3 -1
  126. package/dist/core/memory/providers/file-store.d.ts.map +1 -1
  127. package/dist/core/memory/providers/file-store.js +7 -2
  128. package/dist/core/memory/providers/file-store.js.map +1 -1
  129. package/dist/core/memory/providers/transcript-recall.d.ts +1 -0
  130. package/dist/core/memory/providers/transcript-recall.d.ts.map +1 -1
  131. package/dist/core/memory/providers/transcript-recall.js +4 -7
  132. package/dist/core/memory/providers/transcript-recall.js.map +1 -1
  133. package/dist/core/memory-controller.d.ts +36 -10
  134. package/dist/core/memory-controller.d.ts.map +1 -1
  135. package/dist/core/memory-controller.js +137 -21
  136. package/dist/core/memory-controller.js.map +1 -1
  137. package/dist/core/model-registry.d.ts +25 -0
  138. package/dist/core/model-registry.d.ts.map +1 -1
  139. package/dist/core/model-registry.js +91 -8
  140. package/dist/core/model-registry.js.map +1 -1
  141. package/dist/core/model-resolver.d.ts.map +1 -1
  142. package/dist/core/model-resolver.js +30 -11
  143. package/dist/core/model-resolver.js.map +1 -1
  144. package/dist/core/model-router-controller.d.ts.map +1 -1
  145. package/dist/core/model-router-controller.js +33 -29
  146. package/dist/core/model-router-controller.js.map +1 -1
  147. package/dist/core/model-selection-controller.d.ts +3 -0
  148. package/dist/core/model-selection-controller.d.ts.map +1 -1
  149. package/dist/core/model-selection-controller.js +8 -1
  150. package/dist/core/model-selection-controller.js.map +1 -1
  151. package/dist/core/models/local-runtime.d.ts +2 -0
  152. package/dist/core/models/local-runtime.d.ts.map +1 -1
  153. package/dist/core/models/local-runtime.js +10 -4
  154. package/dist/core/models/local-runtime.js.map +1 -1
  155. package/dist/core/models/perf-profile.d.ts.map +1 -1
  156. package/dist/core/models/perf-profile.js +95 -33
  157. package/dist/core/models/perf-profile.js.map +1 -1
  158. package/dist/core/models/runtime-arbiter.d.ts +11 -0
  159. package/dist/core/models/runtime-arbiter.d.ts.map +1 -1
  160. package/dist/core/models/runtime-arbiter.js +35 -13
  161. package/dist/core/models/runtime-arbiter.js.map +1 -1
  162. package/dist/core/profile-filter-controller.d.ts +11 -0
  163. package/dist/core/profile-filter-controller.d.ts.map +1 -1
  164. package/dist/core/profile-filter-controller.js +56 -11
  165. package/dist/core/profile-filter-controller.js.map +1 -1
  166. package/dist/core/profile-registry.d.ts +2 -2
  167. package/dist/core/profile-registry.d.ts.map +1 -1
  168. package/dist/core/profile-registry.js +58 -7
  169. package/dist/core/profile-registry.js.map +1 -1
  170. package/dist/core/reflection-controller.d.ts +9 -7
  171. package/dist/core/reflection-controller.d.ts.map +1 -1
  172. package/dist/core/reflection-controller.js +81 -12
  173. package/dist/core/reflection-controller.js.map +1 -1
  174. package/dist/core/research/research-runner.d.ts +2 -2
  175. package/dist/core/research/research-runner.d.ts.map +1 -1
  176. package/dist/core/research/research-runner.js +8 -6
  177. package/dist/core/research/research-runner.js.map +1 -1
  178. package/dist/core/resource-loader.d.ts +4 -2
  179. package/dist/core/resource-loader.d.ts.map +1 -1
  180. package/dist/core/resource-loader.js +11 -1
  181. package/dist/core/resource-loader.js.map +1 -1
  182. package/dist/core/runtime-builder.d.ts +30 -3
  183. package/dist/core/runtime-builder.d.ts.map +1 -1
  184. package/dist/core/runtime-builder.js +140 -40
  185. package/dist/core/runtime-builder.js.map +1 -1
  186. package/dist/core/sdk.d.ts +8 -7
  187. package/dist/core/sdk.d.ts.map +1 -1
  188. package/dist/core/sdk.js +38 -5
  189. package/dist/core/sdk.js.map +1 -1
  190. package/dist/core/security/secret-text.d.ts +3 -0
  191. package/dist/core/security/secret-text.d.ts.map +1 -0
  192. package/dist/core/security/secret-text.js +26 -0
  193. package/dist/core/security/secret-text.js.map +1 -0
  194. package/dist/core/settings-manager.d.ts +59 -17
  195. package/dist/core/settings-manager.d.ts.map +1 -1
  196. package/dist/core/settings-manager.js +300 -51
  197. package/dist/core/settings-manager.js.map +1 -1
  198. package/dist/core/skills.d.ts.map +1 -1
  199. package/dist/core/skills.js +1 -1
  200. package/dist/core/skills.js.map +1 -1
  201. package/dist/core/system-prompt-builder.d.ts +7 -0
  202. package/dist/core/system-prompt-builder.d.ts.map +1 -1
  203. package/dist/core/system-prompt-builder.js +23 -1
  204. package/dist/core/system-prompt-builder.js.map +1 -1
  205. package/dist/core/tool-gate-controller.d.ts +3 -0
  206. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  207. package/dist/core/tool-gate-controller.js +20 -15
  208. package/dist/core/tool-gate-controller.js.map +1 -1
  209. package/dist/core/tool-selection/expected-utility.d.ts +51 -0
  210. package/dist/core/tool-selection/expected-utility.d.ts.map +1 -0
  211. package/dist/core/tool-selection/expected-utility.js +85 -0
  212. package/dist/core/tool-selection/expected-utility.js.map +1 -0
  213. package/dist/core/tool-selection/tool-performance-store.d.ts +82 -0
  214. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -0
  215. package/dist/core/tool-selection/tool-performance-store.js +249 -0
  216. package/dist/core/tool-selection/tool-performance-store.js.map +1 -0
  217. package/dist/core/tool-selection/tool-selection-controller.d.ts +41 -0
  218. package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -0
  219. package/dist/core/tool-selection/tool-selection-controller.js +199 -0
  220. package/dist/core/tool-selection/tool-selection-controller.js.map +1 -0
  221. package/dist/core/tools/delegate-status.d.ts +9 -0
  222. package/dist/core/tools/delegate-status.d.ts.map +1 -0
  223. package/dist/core/tools/delegate-status.js +52 -0
  224. package/dist/core/tools/delegate-status.js.map +1 -0
  225. package/dist/core/tools/delegate.d.ts +10 -0
  226. package/dist/core/tools/delegate.d.ts.map +1 -1
  227. package/dist/core/tools/delegate.js +36 -13
  228. package/dist/core/tools/delegate.js.map +1 -1
  229. package/dist/core/tools/run-toolkit-script.d.ts +3 -0
  230. package/dist/core/tools/run-toolkit-script.d.ts.map +1 -1
  231. package/dist/core/tools/run-toolkit-script.js +17 -7
  232. package/dist/core/tools/run-toolkit-script.js.map +1 -1
  233. package/dist/main.d.ts.map +1 -1
  234. package/dist/main.js +2 -0
  235. package/dist/main.js.map +1 -1
  236. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  237. package/dist/modes/interactive/components/footer.js +8 -1
  238. package/dist/modes/interactive/components/footer.js.map +1 -1
  239. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  240. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  241. package/dist/modes/interactive/components/settings-selector.js +69 -29
  242. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  243. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  244. package/dist/modes/interactive/components/thinking-selector.js +2 -0
  245. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  246. package/dist/modes/interactive/config-backup.d.ts +7 -1
  247. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  248. package/dist/modes/interactive/config-backup.js +196 -32
  249. package/dist/modes/interactive/config-backup.js.map +1 -1
  250. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  251. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  252. package/dist/modes/interactive/interactive-mode.js +22 -28
  253. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  254. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
  255. package/dist/modes/interactive/local-model-commands.js +2 -0
  256. package/dist/modes/interactive/local-model-commands.js.map +1 -1
  257. package/dist/modes/interactive/profile-menu-controller.d.ts +6 -4
  258. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  259. package/dist/modes/interactive/profile-menu-controller.js +248 -65
  260. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  261. package/dist/modes/interactive/report-commands.d.ts.map +1 -1
  262. package/dist/modes/interactive/report-commands.js +8 -2
  263. package/dist/modes/interactive/report-commands.js.map +1 -1
  264. package/dist/modes/interactive/settings-selector-flow.d.ts.map +1 -1
  265. package/dist/modes/interactive/settings-selector-flow.js +8 -0
  266. package/dist/modes/interactive/settings-selector-flow.js.map +1 -1
  267. package/dist/modes/interactive/theme/theme-schema.json +1 -1
  268. package/dist/modes/interactive/theme/theme.d.ts +1 -1
  269. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  270. package/dist/modes/interactive/theme/theme.js +3 -1
  271. package/dist/modes/interactive/theme/theme.js.map +1 -1
  272. package/docs/extensions.md +32 -0
  273. package/docs/integration-sweep-builder-blueprint-2026-07-09.md +365 -0
  274. package/docs/integration-sweep-resume-2026-07-09.md +407 -0
  275. package/docs/resources.md +15 -7
  276. package/docs/settings.md +56 -5
  277. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  278. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  279. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  280. package/examples/extensions/preset.ts +2 -2
  281. package/examples/extensions/sandbox/package-lock.json +2 -2
  282. package/examples/extensions/sandbox/package.json +1 -1
  283. package/examples/extensions/with-deps/package-lock.json +2 -2
  284. package/examples/extensions/with-deps/package.json +1 -1
  285. package/npm-shrinkwrap.json +44 -35
  286. package/package.json +4 -4
@@ -9,7 +9,7 @@ import { normalizePath, resolvePath } from "../utils/paths.js";
9
9
  import { DEFAULT_GOAL_AUTO_CONTINUE, DEFAULT_GOAL_AUTO_CONTINUE_DELAY_MS, DEFAULT_GOAL_CONTINUE_MAX_STALL_TURNS, DEFAULT_GOAL_CONTINUE_MAX_TURNS, DEFAULT_GOAL_CONTINUE_MAX_WALL_CLOCK_MINUTES, MAX_GOAL_AUTO_CONTINUE_DELAY_MS, MAX_GOAL_CONTINUE_MAX_STALL_TURNS, MAX_GOAL_CONTINUE_MAX_TURNS, MAX_GOAL_CONTINUE_MAX_WALL_CLOCK_MINUTES, } from "./goals/goal-continuation-defaults.js";
10
10
  import { DEFAULT_HTTP_IDLE_TIMEOUT_MS, parseHttpIdleTimeoutMs } from "./http-dispatcher.js";
11
11
  import { ProfileRegistry } from "./profile-registry.js";
12
- import { mergeResourceProfileMap } from "./resource-profile-blocks.js";
12
+ import { mergeResourceProfileMap, mergeResourceProfileSettings } from "./resource-profile-blocks.js";
13
13
  import { validateSkillName } from "./skills.js";
14
14
  export const MEMORY_RETRIEVAL_MAX_RESULTS_MIN = 1;
15
15
  export const MEMORY_RETRIEVAL_MAX_RESULTS_MAX = 20;
@@ -35,7 +35,7 @@ export const MAX_RESEARCH_LANE_MAX_FINDINGS = 50;
35
35
  export const MAX_RESEARCH_LANE_MAX_WALL_CLOCK_MS = 3_600_000;
36
36
  export const MAX_RESEARCH_LANE_IDLE_DELAY_MS = 300_000;
37
37
  export const MAX_RESEARCH_LANE_MAX_RUNS_PER_SESSION = 100;
38
- export const DEFAULT_WORKER_DELEGATION_ENABLED = false;
38
+ export const DEFAULT_WORKER_DELEGATION_ENABLED = true;
39
39
  export const DEFAULT_WORKER_DELEGATION_MAX_USD = 0.5;
40
40
  export const DEFAULT_WORKER_DELEGATION_MAX_WALL_CLOCK_MS = 120_000;
41
41
  export const MAX_WORKER_DELEGATION_MAX_USD = 5;
@@ -144,9 +144,17 @@ function normalizeResourceProfileNames(value) {
144
144
  function hasExplicitActiveResourceProfileSelection(settings) {
145
145
  return Object.hasOwn(settings, "activeResourceProfiles") || Object.hasOwn(settings, "activeResourceProfile");
146
146
  }
147
+ function hasExplicitEmptyActiveResourceProfileSelection(settings) {
148
+ return (Object.hasOwn(settings, "activeResourceProfiles") &&
149
+ normalizeResourceProfileNames(settings.activeResourceProfiles).length === 0);
150
+ }
147
151
  function normalizeActiveResourceProfiles(settings) {
148
- const explicitProfiles = normalizeResourceProfileNames(settings.activeResourceProfiles);
149
- const values = explicitProfiles.length > 0 ? explicitProfiles : normalizeResourceProfileNames(settings.activeResourceProfile);
152
+ // The array form is canonical when present, including an explicit empty array. Falling through
153
+ // from `activeResourceProfiles: []` to the scalar alias would resurrect a lower-precedence or
154
+ // legacy selection and makes it impossible to persist a durable "none" choice.
155
+ const values = Object.hasOwn(settings, "activeResourceProfiles")
156
+ ? normalizeResourceProfileNames(settings.activeResourceProfiles)
157
+ : normalizeResourceProfileNames(settings.activeResourceProfile);
150
158
  if (values.length === 0 &&
151
159
  !hasExplicitActiveResourceProfileSelection(settings) &&
152
160
  settings.resourceProfiles?.default) {
@@ -205,7 +213,7 @@ function sanitizeNumberSetting(value, fallback, min, max) {
205
213
  return fallback;
206
214
  return value;
207
215
  }
208
- const VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
216
+ const VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
209
217
  function isThinkingLevel(value) {
210
218
  return typeof value === "string" && VALID_THINKING_LEVELS.includes(value);
211
219
  }
@@ -275,12 +283,12 @@ function normalizeModelRouterSettings(value) {
275
283
  }
276
284
  return Object.keys(settings).length > 0 ? settings : undefined;
277
285
  }
278
- function parseProfileFileDefinition(content) {
286
+ function parseProfileFileDefinition(content, fallbackName) {
279
287
  const parsed = JSON.parse(content);
280
288
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
281
289
  throw new Error("profile file must contain a JSON object");
282
290
  }
283
- const name = typeof parsed.name === "string" ? parsed.name.trim() : undefined;
291
+ const name = (typeof parsed.name === "string" ? parsed.name.trim() : undefined) || fallbackName;
284
292
  if (!name) {
285
293
  throw new Error("profile name is required");
286
294
  }
@@ -296,6 +304,7 @@ function parseProfileFileDefinition(content) {
296
304
  };
297
305
  }
298
306
  export class FileSettingsStorage {
307
+ profileResolutionBaseDir;
299
308
  globalSettingsPath;
300
309
  projectSettingsPath;
301
310
  directoryProfileInfo;
@@ -303,6 +312,7 @@ export class FileSettingsStorage {
303
312
  constructor(cwd, agentDir) {
304
313
  const resolvedCwd = resolvePath(cwd);
305
314
  const resolvedAgentDir = resolvePath(agentDir);
315
+ this.profileResolutionBaseDir = resolvedCwd;
306
316
  this.globalSettingsPath = join(resolvedAgentDir, "settings.json");
307
317
  this.projectSettingsPath = join(resolvedCwd, CONFIG_DIR_NAME, "settings.json");
308
318
  this.directoryProfileInfo = getDirectoryResourceProfileInfo(resolvedCwd, resolvedAgentDir);
@@ -314,6 +324,9 @@ export class FileSettingsStorage {
314
324
  getProfilesDir() {
315
325
  return this.profilesDir;
316
326
  }
327
+ getProfileResolutionBaseDir() {
328
+ return this.profileResolutionBaseDir;
329
+ }
317
330
  readDirectoryResourceProfile() {
318
331
  const path = this.directoryProfileInfo.path;
319
332
  return existsSync(path) ? readFileSync(path, "utf-8") : undefined;
@@ -454,9 +467,15 @@ export class SettingsManager {
454
467
  // Mirror getActiveResourceProfileNames()'s source precedence (runtime profiles from
455
468
  // --resource-profile take priority) so a bad runtime profile name still surfaces a
456
469
  // "profile not found" diagnostic instead of silently applying zero filtering.
457
- if (this.runtimeResourceProfiles && this.runtimeResourceProfiles.length > 0) {
470
+ if (this.runtimeResourceProfiles !== undefined) {
458
471
  return normalizeResourceProfileNames(this.runtimeResourceProfiles);
459
472
  }
473
+ // `/profiles none` is persisted globally as an explicit empty array. It is a durable
474
+ // user-level off switch and must dominate project/directory/default/external fallbacks until
475
+ // the user explicitly selects another profile.
476
+ if (hasExplicitEmptyActiveResourceProfileSelection(this.globalSettings)) {
477
+ return [];
478
+ }
460
479
  const explicitProfiles = this.settings.activeResourceProfiles && this.settings.activeResourceProfiles.length > 0
461
480
  ? this.settings.activeResourceProfiles
462
481
  : this.settings.activeResourceProfile
@@ -492,16 +511,24 @@ export class SettingsManager {
492
511
  this.reportProfileDiagnostic("global", `Profile diagnostic${path}: ${diagnostic.message}`);
493
512
  }
494
513
  for (const profileName of this.getActiveProfileNamesForDiagnostics()) {
495
- if (!this.profileRegistry.getProfile(profileName)) {
514
+ if (!this.resolveProfileFromRegistry(this.profileRegistry, profileName)) {
496
515
  this.reportProfileDiagnostic("global", `Active profile not found: ${profileName}`);
497
516
  }
498
517
  }
499
518
  }
519
+ resolveProfileFromRegistry(registry, profileRef) {
520
+ return profileRef.startsWith("./") || profileRef.startsWith("../")
521
+ ? registry.resolveProfileRef(profileRef, this.storage.getProfileResolutionBaseDir?.() ?? process.cwd())
522
+ : registry.getProfile(profileRef);
523
+ }
500
524
  mergeEffectiveSettings() {
501
525
  let merged = deepMergeSettings(this.globalSettings, this.projectSettings);
502
526
  merged = deepMergeSettings(merged, this.directoryProfileSettings);
503
- if (this.runtimeResourceProfiles) {
504
- merged = deepMergeSettings(merged, { activeResourceProfiles: this.runtimeResourceProfiles });
527
+ if (this.runtimeResourceProfiles !== undefined) {
528
+ merged = deepMergeSettings(merged, {
529
+ activeResourceProfile: this.runtimeResourceProfiles,
530
+ activeResourceProfiles: this.runtimeResourceProfiles,
531
+ });
505
532
  }
506
533
  return merged;
507
534
  }
@@ -643,16 +670,22 @@ export class SettingsManager {
643
670
  return this.profileRegistry;
644
671
  }
645
672
  getActiveResourceProfileNames() {
646
- if (this.runtimeResourceProfiles && this.runtimeResourceProfiles.length > 0) {
673
+ if (this.runtimeResourceProfiles !== undefined) {
647
674
  return [...this.runtimeResourceProfiles];
648
675
  }
676
+ if (hasExplicitEmptyActiveResourceProfileSelection(this.globalSettings)) {
677
+ return [];
678
+ }
649
679
  const names = normalizeActiveResourceProfiles(this.settings);
650
680
  return names.length > 0 || hasExplicitActiveResourceProfileSelection(this.settings)
651
681
  ? names
652
682
  : this.getExternalRootActiveResourceProfileNames();
653
683
  }
654
684
  hasExplicitActiveResourceProfileSelection() {
655
- return hasExplicitActiveResourceProfileSelection(this.settings);
685
+ // An explicit empty runtime/settings selection means "no profile", not an invalid profile
686
+ // whose authority should collapse to deny-all. Non-empty unresolved refs remain explicit and
687
+ // are diagnosed/strictly denied through the normal active-profile path.
688
+ return this.getActiveResourceProfileNames().length > 0;
656
689
  }
657
690
  /**
658
691
  * Aggregate ONLY the active profiles' contribution to a resource kind's filter — the user's own
@@ -673,7 +706,7 @@ export class SettingsManager {
673
706
  if (seenProfiles.has(profileName))
674
707
  continue;
675
708
  seenProfiles.add(profileName);
676
- const kindFilter = registry.getProfile(profileName)?.resources[kind];
709
+ const kindFilter = this.resolveProfileFromRegistry(registry, profileName)?.resources[kind];
677
710
  if (kindFilter && ((kindFilter.allow?.length ?? 0) > 0 || (kindFilter.block?.length ?? 0) > 0)) {
678
711
  kindMentionedByProfile = true;
679
712
  }
@@ -713,7 +746,7 @@ export class SettingsManager {
713
746
  const registry = this.getProfileRegistry();
714
747
  const conflicts = new Set();
715
748
  for (const profileName of this.getActiveResourceProfileNames()) {
716
- const filter = registry.getProfile(profileName)?.resources[kind];
749
+ const filter = this.resolveProfileFromRegistry(registry, profileName)?.resources[kind];
717
750
  for (const allowEntry of filter?.allow ?? []) {
718
751
  if (allowEntry === "*")
719
752
  continue;
@@ -763,7 +796,7 @@ export class SettingsManager {
763
796
  if (seen.has(profileName))
764
797
  continue;
765
798
  seen.add(profileName);
766
- const soul = registry.getProfile(profileName)?.soul?.trim();
799
+ const soul = this.resolveProfileFromRegistry(registry, profileName)?.soul?.trim();
767
800
  if (soul)
768
801
  return soul;
769
802
  }
@@ -827,18 +860,69 @@ export class SettingsManager {
827
860
  }
828
861
  this.recomputeSettings();
829
862
  }
863
+ /** Capture the complete in-memory settings generation before runtime reload mutates it. */
864
+ createReloadSnapshot() {
865
+ return {
866
+ globalSettings: structuredClone(this.globalSettings),
867
+ projectSettings: structuredClone(this.projectSettings),
868
+ directoryProfileSettings: structuredClone(this.directoryProfileSettings),
869
+ runtimeResourceProfiles: this.runtimeResourceProfiles === undefined ? undefined : [...this.runtimeResourceProfiles],
870
+ inlineResourceProfileDefinitions: structuredClone(this.inlineResourceProfileDefinitions),
871
+ discoveredResourceProfileDefinitions: structuredClone(this.discoveredResourceProfileDefinitions),
872
+ effectiveSettings: structuredClone(this.settings),
873
+ projectTrusted: this.projectTrusted,
874
+ modifiedFields: new Set(this.modifiedFields),
875
+ modifiedNestedFields: this.cloneModifiedNestedFields(this.modifiedNestedFields),
876
+ modifiedProjectFields: new Set(this.modifiedProjectFields),
877
+ modifiedProjectNestedFields: this.cloneModifiedNestedFields(this.modifiedProjectNestedFields),
878
+ globalSettingsLoadError: this.globalSettingsLoadError,
879
+ projectSettingsLoadError: this.projectSettingsLoadError,
880
+ directoryProfileInfo: this.directoryProfileInfo ? { ...this.directoryProfileInfo } : null,
881
+ errors: [...this.errors],
882
+ };
883
+ }
884
+ /** Restore a failed runtime reload without changing the on-disk settings generation. */
885
+ restoreReloadSnapshot(snapshot) {
886
+ this.globalSettings = structuredClone(snapshot.globalSettings);
887
+ this.projectSettings = structuredClone(snapshot.projectSettings);
888
+ this.directoryProfileSettings = structuredClone(snapshot.directoryProfileSettings);
889
+ this.runtimeResourceProfiles =
890
+ snapshot.runtimeResourceProfiles === undefined ? undefined : [...snapshot.runtimeResourceProfiles];
891
+ this.inlineResourceProfileDefinitions = structuredClone(snapshot.inlineResourceProfileDefinitions);
892
+ this.discoveredResourceProfileDefinitions = structuredClone(snapshot.discoveredResourceProfileDefinitions);
893
+ this.settings = structuredClone(snapshot.effectiveSettings);
894
+ this.projectTrusted = snapshot.projectTrusted;
895
+ this.modifiedFields = new Set(snapshot.modifiedFields);
896
+ this.modifiedNestedFields = this.cloneModifiedNestedFields(snapshot.modifiedNestedFields);
897
+ this.modifiedProjectFields = new Set(snapshot.modifiedProjectFields);
898
+ this.modifiedProjectNestedFields = this.cloneModifiedNestedFields(snapshot.modifiedProjectNestedFields);
899
+ this.globalSettingsLoadError = snapshot.globalSettingsLoadError;
900
+ this.projectSettingsLoadError = snapshot.projectSettingsLoadError;
901
+ this.directoryProfileInfo = snapshot.directoryProfileInfo ? { ...snapshot.directoryProfileInfo } : null;
902
+ this.errors = [...snapshot.errors];
903
+ this.refreshProfileRegistry();
904
+ }
830
905
  /** Apply additional overrides on top of current settings */
831
906
  applyOverrides(overrides) {
832
907
  this.settings = deepMergeSettings(this.settings, overrides);
833
908
  }
834
909
  /** Select runtime-only resource profiles, e.g. from CLI/subagent launch options. */
835
910
  setRuntimeResourceProfiles(profileNames) {
836
- this.runtimeResourceProfiles = profileNames.length > 0 ? [...profileNames] : undefined;
911
+ this.runtimeResourceProfiles = normalizeResourceProfileNames(profileNames);
837
912
  this.recomputeSettings();
838
913
  }
839
914
  /** Add one-shot profile definitions from CLI/SDK/ephemeral agent launch input. Never writes to disk. */
840
915
  addInlineResourceProfileDefinitions(profiles) {
841
- this.inlineResourceProfileDefinitions = mergeResourceProfileMap(this.inlineResourceProfileDefinitions, profiles);
916
+ const next = { ...this.inlineResourceProfileDefinitions };
917
+ for (const [name, input] of Object.entries(profiles)) {
918
+ const existing = next[name];
919
+ const definition = Object.hasOwn(input, "resources")
920
+ ? input
921
+ : { resources: input };
922
+ const resources = mergeResourceProfileSettings(existing?.resources, definition.resources);
923
+ next[name] = this.mergeProfileDefinition(name, definition, resources, existing);
924
+ }
925
+ this.inlineResourceProfileDefinitions = next;
842
926
  this.refreshProfileRegistry();
843
927
  }
844
928
  /** Replace profile definitions discovered inside loaded resource files. Never writes to disk. */
@@ -862,6 +946,13 @@ export class SettingsManager {
862
946
  }
863
947
  return trimmed;
864
948
  }
949
+ normalizeProfileSelection(profileName) {
950
+ const trimmed = profileName.trim();
951
+ if (trimmed.startsWith("./") || trimmed.startsWith("../")) {
952
+ return trimmed;
953
+ }
954
+ return this.normalizeProfileName(trimmed);
955
+ }
865
956
  sanitizeProfileResources(resources) {
866
957
  const result = {};
867
958
  for (const kind of ["extensions", "skills", "prompts", "themes", "agents", "tools"]) {
@@ -876,15 +967,94 @@ export class SettingsManager {
876
967
  }
877
968
  return result;
878
969
  }
970
+ decodeStoredProfileDefinition(name, stored) {
971
+ if (stored && Object.hasOwn(stored, "resources")) {
972
+ const definition = stored;
973
+ return { ...definition, name, resources: this.sanitizeProfileResources(definition.resources) };
974
+ }
975
+ return {
976
+ name,
977
+ resources: this.sanitizeProfileResources(stored ?? {}),
978
+ };
979
+ }
980
+ mergeProfileDefinition(name, definition, resources, existing) {
981
+ const previous = this.decodeStoredProfileDefinition(name, existing);
982
+ return {
983
+ ...previous,
984
+ name,
985
+ resources,
986
+ description: definition.description ?? previous.description,
987
+ model: definition.model ?? previous.model,
988
+ thinking: definition.thinking ?? previous.thinking,
989
+ modelRouter: definition.modelRouter ?? previous.modelRouter,
990
+ soul: definition.soul ?? previous.soul,
991
+ };
992
+ }
993
+ encodeStoredProfileDefinition(definition) {
994
+ const hasMetadata = Boolean(definition.description || definition.model || definition.thinking || definition.modelRouter || definition.soul);
995
+ if (hasMetadata)
996
+ return definition;
997
+ return Object.keys(definition.resources).length > 0 ? definition.resources : undefined;
998
+ }
879
999
  setActiveProfileInSettings(settings, profileName) {
880
1000
  if (profileName) {
881
1001
  settings.activeResourceProfile = profileName;
882
1002
  settings.activeResourceProfiles = [profileName];
883
1003
  return;
884
1004
  }
885
- delete settings.activeResourceProfiles;
1005
+ settings.activeResourceProfiles = [];
886
1006
  delete settings.activeResourceProfile;
887
1007
  }
1008
+ rewriteActiveProfileReference(settings, oldName, newName) {
1009
+ let changed = false;
1010
+ const rewrite = (values) => {
1011
+ const next = values.flatMap((value) => {
1012
+ if (value !== oldName)
1013
+ return [value];
1014
+ changed = true;
1015
+ return newName ? [newName] : [];
1016
+ });
1017
+ return [...new Set(next)];
1018
+ };
1019
+ if (settings.activeResourceProfiles !== undefined) {
1020
+ const next = rewrite(normalizeResourceProfileNames(settings.activeResourceProfiles));
1021
+ if (next.length > 0)
1022
+ settings.activeResourceProfiles = next;
1023
+ else
1024
+ delete settings.activeResourceProfiles;
1025
+ }
1026
+ if (settings.activeResourceProfile !== undefined) {
1027
+ const next = rewrite(normalizeResourceProfileNames(settings.activeResourceProfile));
1028
+ if (next.length === 0)
1029
+ delete settings.activeResourceProfile;
1030
+ else
1031
+ settings.activeResourceProfile =
1032
+ Array.isArray(settings.activeResourceProfile) || next.length > 1 ? next : next[0];
1033
+ }
1034
+ return changed;
1035
+ }
1036
+ rewriteReusableProfileSelections(oldName, newName) {
1037
+ if (this.runtimeResourceProfiles?.includes(oldName)) {
1038
+ this.runtimeResourceProfiles = [
1039
+ ...new Set(this.runtimeResourceProfiles.flatMap((profile) => profile === oldName ? (newName ? [newName] : []) : [profile])),
1040
+ ];
1041
+ }
1042
+ if (this.rewriteActiveProfileReference(this.globalSettings, oldName, newName)) {
1043
+ this.markModified("activeResourceProfile");
1044
+ this.markModified("activeResourceProfiles");
1045
+ this.save();
1046
+ }
1047
+ const projectSettings = structuredClone(this.projectSettings);
1048
+ if (this.rewriteActiveProfileReference(projectSettings, oldName, newName)) {
1049
+ this.markProjectModified("activeResourceProfile");
1050
+ this.markProjectModified("activeResourceProfiles");
1051
+ this.saveProjectSettings(projectSettings);
1052
+ }
1053
+ if (this.rewriteActiveProfileReference(this.directoryProfileSettings, oldName, newName)) {
1054
+ this.persistDirectoryProfiles(() => { });
1055
+ }
1056
+ this.recomputeSettings();
1057
+ }
888
1058
  persistDirectoryProfiles(update) {
889
1059
  const next = structuredClone(this.directoryProfileSettings);
890
1060
  update(next);
@@ -932,8 +1102,9 @@ export class SettingsManager {
932
1102
  const resources = this.sanitizeProfileResources(definition.resources);
933
1103
  if (scope === "session") {
934
1104
  const next = { ...this.inlineResourceProfileDefinitions };
935
- if (Object.keys(resources).length > 0) {
936
- next[name] = resources;
1105
+ const payload = this.mergeProfileDefinition(name, definition, resources, next[name]);
1106
+ if (this.encodeStoredProfileDefinition(payload)) {
1107
+ next[name] = payload;
937
1108
  }
938
1109
  else {
939
1110
  delete next[name];
@@ -945,8 +1116,9 @@ export class SettingsManager {
945
1116
  if (scope === "global") {
946
1117
  const next = structuredClone(this.globalSettings);
947
1118
  next.resourceProfiles = { ...(next.resourceProfiles ?? {}) };
948
- if (Object.keys(resources).length > 0) {
949
- next.resourceProfiles[name] = resources;
1119
+ const stored = this.encodeStoredProfileDefinition(this.mergeProfileDefinition(name, definition, resources, next.resourceProfiles[name]));
1120
+ if (stored) {
1121
+ next.resourceProfiles[name] = stored;
950
1122
  }
951
1123
  else {
952
1124
  delete next.resourceProfiles[name];
@@ -962,8 +1134,9 @@ export class SettingsManager {
962
1134
  if (scope === "project") {
963
1135
  this.updateProjectSettings("resourceProfiles", (settings) => {
964
1136
  const next = structuredClone(settings.resourceProfiles ?? {});
965
- if (Object.keys(resources).length > 0) {
966
- next[name] = resources;
1137
+ const stored = this.encodeStoredProfileDefinition(this.mergeProfileDefinition(name, definition, resources, next[name]));
1138
+ if (stored) {
1139
+ next[name] = stored;
967
1140
  }
968
1141
  else {
969
1142
  delete next[name];
@@ -980,8 +1153,9 @@ export class SettingsManager {
980
1153
  if (scope === "directory") {
981
1154
  this.persistDirectoryProfiles((current) => {
982
1155
  const next = { ...(current.resourceProfiles ?? {}) };
983
- if (Object.keys(resources).length > 0) {
984
- next[name] = resources;
1156
+ const stored = this.encodeStoredProfileDefinition(this.mergeProfileDefinition(name, definition, resources, next[name]));
1157
+ if (stored) {
1158
+ next[name] = stored;
985
1159
  }
986
1160
  else {
987
1161
  delete next[name];
@@ -997,17 +1171,9 @@ export class SettingsManager {
997
1171
  }
998
1172
  const path = this.getProfileFilePath(name);
999
1173
  const existing = existsSync(path)
1000
- ? parseProfileFileDefinition(readFileSync(path, "utf-8"))
1174
+ ? parseProfileFileDefinition(readFileSync(path, "utf-8"), name)
1001
1175
  : { name, resources: {} };
1002
- const payload = {
1003
- ...existing,
1004
- name,
1005
- resources,
1006
- description: definition.description ?? existing.description,
1007
- model: definition.model ?? existing.model,
1008
- thinking: definition.thinking ?? existing.thinking,
1009
- modelRouter: definition.modelRouter ?? existing.modelRouter,
1010
- };
1176
+ const payload = this.mergeProfileDefinition(name, definition, resources, existing);
1011
1177
  mkdirSync(dirname(path), { recursive: true });
1012
1178
  writeFileSync(path, JSON.stringify(payload, null, 2), "utf-8");
1013
1179
  }
@@ -1097,6 +1263,7 @@ export class SettingsManager {
1097
1263
  throw new Error(`Profile not found: ${name}`);
1098
1264
  }
1099
1265
  rmSync(profilePath, { force: true });
1266
+ this.rewriteReusableProfileSelections(name, undefined);
1100
1267
  }
1101
1268
  renameProfile(profileName, newProfileName, scope) {
1102
1269
  const oldName = this.normalizeProfileName(profileName);
@@ -1191,16 +1358,17 @@ export class SettingsManager {
1191
1358
  if (existsSync(newPath)) {
1192
1359
  throw new Error(`Profile already exists: ${newName}`);
1193
1360
  }
1194
- const parsed = parseProfileFileDefinition(readFileSync(oldPath, "utf-8"));
1361
+ const parsed = parseProfileFileDefinition(readFileSync(oldPath, "utf-8"), oldName);
1195
1362
  parsed.name = newName;
1196
1363
  writeFileSync(newPath, JSON.stringify(parsed, null, 2), "utf-8");
1197
1364
  rmSync(oldPath, { force: true });
1365
+ this.rewriteReusableProfileSelections(oldName, newName);
1198
1366
  }
1199
1367
  /**
1200
1368
  * Set active profile selection in the selected scope.
1201
1369
  */
1202
1370
  setActiveProfile(profileName, scope) {
1203
- const name = profileName ? this.normalizeProfileName(profileName) : undefined;
1371
+ const name = profileName ? this.normalizeProfileSelection(profileName) : undefined;
1204
1372
  if (scope === "session") {
1205
1373
  if (name) {
1206
1374
  this.setRuntimeResourceProfiles([name]);
@@ -1217,7 +1385,7 @@ export class SettingsManager {
1217
1385
  }
1218
1386
  else {
1219
1387
  delete this.globalSettings.activeResourceProfile;
1220
- delete this.globalSettings.activeResourceProfiles;
1388
+ this.globalSettings.activeResourceProfiles = [];
1221
1389
  }
1222
1390
  this.markModified("activeResourceProfile");
1223
1391
  this.markModified("activeResourceProfiles");
@@ -1234,6 +1402,67 @@ export class SettingsManager {
1234
1402
  this.setActiveProfileInSettings(current, name);
1235
1403
  });
1236
1404
  }
1405
+ /** Atomically replace the global profile/authority fields used by config restore and rollback. */
1406
+ replaceGlobalResourceProfileConfiguration(configuration) {
1407
+ const next = structuredClone(this.globalSettings);
1408
+ const replace = (key) => {
1409
+ const value = configuration[key];
1410
+ if (value === undefined) {
1411
+ delete next[key];
1412
+ }
1413
+ else {
1414
+ next[key] = structuredClone(value);
1415
+ }
1416
+ this.markModified(key);
1417
+ };
1418
+ replace("resourceProfiles");
1419
+ replace("activeResourceProfile");
1420
+ replace("activeResourceProfiles");
1421
+ replace("externalResourceRoots");
1422
+ replace("trustedResourceRoots");
1423
+ this.globalSettings = next;
1424
+ this.save();
1425
+ }
1426
+ /** Restore one profile definition's persistent owner after a post-doctor commit failure. */
1427
+ restoreProfileDefinitionFromReloadSnapshot(profileName, scope, snapshot) {
1428
+ const name = this.normalizeProfileName(profileName);
1429
+ if (scope === "session") {
1430
+ const previous = snapshot.inlineResourceProfileDefinitions[name];
1431
+ if (previous)
1432
+ this.inlineResourceProfileDefinitions[name] = structuredClone(previous);
1433
+ else
1434
+ delete this.inlineResourceProfileDefinitions[name];
1435
+ this.refreshProfileRegistry();
1436
+ return;
1437
+ }
1438
+ const restoreDefinition = (settings, previous) => {
1439
+ const definitions = structuredClone(settings.resourceProfiles ?? {});
1440
+ const oldDefinition = previous.resourceProfiles?.[name];
1441
+ if (oldDefinition)
1442
+ definitions[name] = structuredClone(oldDefinition);
1443
+ else
1444
+ delete definitions[name];
1445
+ if (Object.keys(definitions).length > 0)
1446
+ settings.resourceProfiles = definitions;
1447
+ else
1448
+ delete settings.resourceProfiles;
1449
+ };
1450
+ if (scope === "global") {
1451
+ restoreDefinition(this.globalSettings, snapshot.globalSettings);
1452
+ this.markModified("resourceProfiles");
1453
+ this.save();
1454
+ return;
1455
+ }
1456
+ if (scope === "project") {
1457
+ this.updateProjectSettings("resourceProfiles", (settings) => {
1458
+ restoreDefinition(settings, snapshot.projectSettings);
1459
+ });
1460
+ return;
1461
+ }
1462
+ this.persistDirectoryProfiles((settings) => {
1463
+ restoreDefinition(settings, snapshot.directoryProfileSettings);
1464
+ });
1465
+ }
1237
1466
  /** Mark a global field as modified during this session */
1238
1467
  markModified(field, nestedKey) {
1239
1468
  this.modifiedFields.add(field);
@@ -1479,7 +1708,7 @@ export class SettingsManager {
1479
1708
  }
1480
1709
  /**
1481
1710
  * Proactive per-turn cost guard (#34). Default ON in WARN-only mode with a high anomaly-catching
1482
- * ceiling so an unusually expensive turn surfaces a visible footer notice without ever silently
1711
+ * projection threshold so an unusually expensive turn surfaces a visible footer notice without silently
1483
1712
  * changing behavior. Set `maxTurnUsd: 0` to disable, or `action: "downgrade"` to also auto-reduce
1484
1713
  * reasoning effort over the ceiling.
1485
1714
  */
@@ -1496,14 +1725,19 @@ export class SettingsManager {
1496
1725
  const activeProfileNames = this.getActiveResourceProfileNames();
1497
1726
  if (activeProfileNames.length === 0)
1498
1727
  return undefined;
1728
+ const registry = this.getProfileRegistry();
1499
1729
  const merged = {};
1500
1730
  for (let index = activeProfileNames.length - 1; index >= 0; index--) {
1501
- const profile = this.profileRegistry.getProfile(activeProfileNames[index]);
1731
+ const profile = this.resolveProfileFromRegistry(registry, activeProfileNames[index]);
1502
1732
  const router = profile?.modelRouter;
1503
1733
  if (!router)
1504
1734
  continue;
1505
1735
  if (router.enabled !== undefined)
1506
1736
  merged.enabled = router.enabled;
1737
+ if (router.judgeEnabled !== undefined)
1738
+ merged.judgeEnabled = router.judgeEnabled;
1739
+ if (router.fitnessGate !== undefined)
1740
+ merged.fitnessGate = router.fitnessGate;
1507
1741
  if (router.cheapModel !== undefined)
1508
1742
  merged.cheapModel = router.cheapModel;
1509
1743
  if (router.mediumModel !== undefined)
@@ -1512,6 +1746,20 @@ export class SettingsManager {
1512
1746
  merged.expensiveModel = router.expensiveModel;
1513
1747
  if (router.learningModel !== undefined)
1514
1748
  merged.learningModel = router.learningModel;
1749
+ if (router.judgeModel !== undefined)
1750
+ merged.judgeModel = router.judgeModel;
1751
+ if (router.executorModel !== undefined)
1752
+ merged.executorModel = router.executorModel;
1753
+ if (router.cheapThinking !== undefined)
1754
+ merged.cheapThinking = router.cheapThinking;
1755
+ if (router.mediumThinking !== undefined)
1756
+ merged.mediumThinking = router.mediumThinking;
1757
+ if (router.expensiveThinking !== undefined)
1758
+ merged.expensiveThinking = router.expensiveThinking;
1759
+ if (router.executorThinking !== undefined)
1760
+ merged.executorThinking = router.executorThinking;
1761
+ if (router.judgeThinking !== undefined)
1762
+ merged.judgeThinking = router.judgeThinking;
1515
1763
  }
1516
1764
  return Object.keys(merged).length > 0 ? merged : undefined;
1517
1765
  }
@@ -1527,8 +1775,6 @@ export class SettingsManager {
1527
1775
  fitnessGate: this.settings.modelRouter?.fitnessGate ?? false,
1528
1776
  judgeModel: this.settings.modelRouter?.judgeModel?.trim() || undefined,
1529
1777
  executorModel: this.settings.modelRouter?.executorModel?.trim() || undefined,
1530
- // Not yet profile-overridable (same as judgeModel/executorModel above): validated here so a
1531
- // corrupt/hand-edited value on disk never reaches the routed-turn swap in agent-session.ts.
1532
1778
  cheapThinking: isThinkingLevel(this.settings.modelRouter?.cheapThinking)
1533
1779
  ? this.settings.modelRouter?.cheapThinking
1534
1780
  : undefined,
@@ -1555,11 +1801,11 @@ export class SettingsManager {
1555
1801
  fitnessGate: profileSettings?.fitnessGate ?? settings.fitnessGate,
1556
1802
  judgeModel: profileSettings?.judgeModel?.trim() || settings.judgeModel,
1557
1803
  executorModel: profileSettings?.executorModel?.trim() || settings.executorModel,
1558
- cheapThinking: settings.cheapThinking,
1559
- mediumThinking: settings.mediumThinking,
1560
- expensiveThinking: settings.expensiveThinking,
1561
- executorThinking: settings.executorThinking,
1562
- judgeThinking: settings.judgeThinking,
1804
+ cheapThinking: profileSettings?.cheapThinking ?? settings.cheapThinking,
1805
+ mediumThinking: profileSettings?.mediumThinking ?? settings.mediumThinking,
1806
+ expensiveThinking: profileSettings?.expensiveThinking ?? settings.expensiveThinking,
1807
+ executorThinking: profileSettings?.executorThinking ?? settings.executorThinking,
1808
+ judgeThinking: profileSettings?.judgeThinking ?? settings.judgeThinking,
1563
1809
  };
1564
1810
  }
1565
1811
  setModelRouterSettings(settings, scope = "global") {
@@ -1641,6 +1887,7 @@ export class SettingsManager {
1641
1887
  "automata_graph_pointer_pack",
1642
1888
  "learning_query_memory",
1643
1889
  "subagent",
1890
+ "delegate",
1644
1891
  "task_steps",
1645
1892
  "task_background",
1646
1893
  "task_goal",
@@ -1710,9 +1957,10 @@ export class SettingsManager {
1710
1957
  }
1711
1958
  getMemoryRetrievalSettings() {
1712
1959
  return {
1713
- enabled: this.settings.contextPolicy?.memory?.enabled ?? false,
1960
+ enabled: this.settings.contextPolicy?.memory?.enabled ?? true,
1714
1961
  maxResults: clampMemoryRetrievalMaxResults(this.settings.contextPolicy?.memory?.maxResults ?? MEMORY_RETRIEVAL_MAX_RESULTS_DEFAULT),
1715
- includeInPrompt: this.settings.contextPolicy?.memory?.includeInPrompt ?? false,
1962
+ includeInPrompt: this.settings.contextPolicy?.memory?.includeInPrompt ?? true,
1963
+ allowExternalEgress: this.settings.contextPolicy?.memory?.allowExternalEgress === true,
1716
1964
  };
1717
1965
  }
1718
1966
  setMemoryRetrievalSettings(settings, scope = "global") {
@@ -1720,6 +1968,7 @@ export class SettingsManager {
1720
1968
  enabled: settings.enabled,
1721
1969
  maxResults: settings.maxResults === undefined ? undefined : clampMemoryRetrievalMaxResults(settings.maxResults),
1722
1970
  includeInPrompt: settings.includeInPrompt,
1971
+ allowExternalEgress: settings.allowExternalEgress,
1723
1972
  };
1724
1973
  if (scope === "project") {
1725
1974
  const projectSettings = structuredClone(this.projectSettings);