@oh-my-pi/pi-coding-agent 1.337.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/CHANGELOG.md +1228 -0
  2. package/README.md +1041 -0
  3. package/docs/compaction.md +403 -0
  4. package/docs/custom-tools.md +541 -0
  5. package/docs/extension-loading.md +1004 -0
  6. package/docs/hooks.md +867 -0
  7. package/docs/rpc.md +1040 -0
  8. package/docs/sdk.md +994 -0
  9. package/docs/session-tree-plan.md +441 -0
  10. package/docs/session.md +240 -0
  11. package/docs/skills.md +290 -0
  12. package/docs/theme.md +637 -0
  13. package/docs/tree.md +197 -0
  14. package/docs/tui.md +341 -0
  15. package/examples/README.md +21 -0
  16. package/examples/custom-tools/README.md +124 -0
  17. package/examples/custom-tools/hello/index.ts +20 -0
  18. package/examples/custom-tools/question/index.ts +84 -0
  19. package/examples/custom-tools/subagent/README.md +172 -0
  20. package/examples/custom-tools/subagent/agents/planner.md +37 -0
  21. package/examples/custom-tools/subagent/agents/reviewer.md +35 -0
  22. package/examples/custom-tools/subagent/agents/scout.md +50 -0
  23. package/examples/custom-tools/subagent/agents/worker.md +24 -0
  24. package/examples/custom-tools/subagent/agents.ts +156 -0
  25. package/examples/custom-tools/subagent/commands/implement-and-review.md +10 -0
  26. package/examples/custom-tools/subagent/commands/implement.md +10 -0
  27. package/examples/custom-tools/subagent/commands/scout-and-plan.md +9 -0
  28. package/examples/custom-tools/subagent/index.ts +1002 -0
  29. package/examples/custom-tools/todo/index.ts +212 -0
  30. package/examples/hooks/README.md +56 -0
  31. package/examples/hooks/auto-commit-on-exit.ts +49 -0
  32. package/examples/hooks/confirm-destructive.ts +59 -0
  33. package/examples/hooks/custom-compaction.ts +116 -0
  34. package/examples/hooks/dirty-repo-guard.ts +52 -0
  35. package/examples/hooks/file-trigger.ts +41 -0
  36. package/examples/hooks/git-checkpoint.ts +53 -0
  37. package/examples/hooks/handoff.ts +150 -0
  38. package/examples/hooks/permission-gate.ts +34 -0
  39. package/examples/hooks/protected-paths.ts +30 -0
  40. package/examples/hooks/qna.ts +119 -0
  41. package/examples/hooks/snake.ts +343 -0
  42. package/examples/hooks/status-line.ts +40 -0
  43. package/examples/sdk/01-minimal.ts +22 -0
  44. package/examples/sdk/02-custom-model.ts +49 -0
  45. package/examples/sdk/03-custom-prompt.ts +44 -0
  46. package/examples/sdk/04-skills.ts +44 -0
  47. package/examples/sdk/05-tools.ts +90 -0
  48. package/examples/sdk/06-hooks.ts +61 -0
  49. package/examples/sdk/07-context-files.ts +36 -0
  50. package/examples/sdk/08-slash-commands.ts +42 -0
  51. package/examples/sdk/09-api-keys-and-oauth.ts +55 -0
  52. package/examples/sdk/10-settings.ts +38 -0
  53. package/examples/sdk/11-sessions.ts +48 -0
  54. package/examples/sdk/12-full-control.ts +95 -0
  55. package/examples/sdk/README.md +154 -0
  56. package/package.json +81 -0
  57. package/src/cli/args.ts +246 -0
  58. package/src/cli/file-processor.ts +72 -0
  59. package/src/cli/list-models.ts +104 -0
  60. package/src/cli/plugin-cli.ts +650 -0
  61. package/src/cli/session-picker.ts +41 -0
  62. package/src/cli.ts +10 -0
  63. package/src/commands/init.md +20 -0
  64. package/src/config.ts +159 -0
  65. package/src/core/agent-session.ts +1900 -0
  66. package/src/core/auth-storage.ts +236 -0
  67. package/src/core/bash-executor.ts +196 -0
  68. package/src/core/compaction/branch-summarization.ts +343 -0
  69. package/src/core/compaction/compaction.ts +742 -0
  70. package/src/core/compaction/index.ts +7 -0
  71. package/src/core/compaction/utils.ts +154 -0
  72. package/src/core/custom-tools/index.ts +21 -0
  73. package/src/core/custom-tools/loader.ts +248 -0
  74. package/src/core/custom-tools/types.ts +169 -0
  75. package/src/core/custom-tools/wrapper.ts +28 -0
  76. package/src/core/exec.ts +129 -0
  77. package/src/core/export-html/index.ts +211 -0
  78. package/src/core/export-html/template.css +781 -0
  79. package/src/core/export-html/template.html +54 -0
  80. package/src/core/export-html/template.js +1185 -0
  81. package/src/core/export-html/vendor/highlight.min.js +1213 -0
  82. package/src/core/export-html/vendor/marked.min.js +6 -0
  83. package/src/core/hooks/index.ts +16 -0
  84. package/src/core/hooks/loader.ts +312 -0
  85. package/src/core/hooks/runner.ts +434 -0
  86. package/src/core/hooks/tool-wrapper.ts +99 -0
  87. package/src/core/hooks/types.ts +773 -0
  88. package/src/core/index.ts +52 -0
  89. package/src/core/mcp/client.ts +158 -0
  90. package/src/core/mcp/config.ts +154 -0
  91. package/src/core/mcp/index.ts +45 -0
  92. package/src/core/mcp/loader.ts +68 -0
  93. package/src/core/mcp/manager.ts +181 -0
  94. package/src/core/mcp/tool-bridge.ts +148 -0
  95. package/src/core/mcp/transports/http.ts +316 -0
  96. package/src/core/mcp/transports/index.ts +6 -0
  97. package/src/core/mcp/transports/stdio.ts +252 -0
  98. package/src/core/mcp/types.ts +220 -0
  99. package/src/core/messages.ts +189 -0
  100. package/src/core/model-registry.ts +317 -0
  101. package/src/core/model-resolver.ts +393 -0
  102. package/src/core/plugins/doctor.ts +59 -0
  103. package/src/core/plugins/index.ts +38 -0
  104. package/src/core/plugins/installer.ts +189 -0
  105. package/src/core/plugins/loader.ts +338 -0
  106. package/src/core/plugins/manager.ts +672 -0
  107. package/src/core/plugins/parser.ts +105 -0
  108. package/src/core/plugins/paths.ts +32 -0
  109. package/src/core/plugins/types.ts +190 -0
  110. package/src/core/sdk.ts +760 -0
  111. package/src/core/session-manager.ts +1128 -0
  112. package/src/core/settings-manager.ts +443 -0
  113. package/src/core/skills.ts +437 -0
  114. package/src/core/slash-commands.ts +248 -0
  115. package/src/core/system-prompt.ts +439 -0
  116. package/src/core/timings.ts +25 -0
  117. package/src/core/tools/ask.ts +211 -0
  118. package/src/core/tools/bash-interceptor.ts +120 -0
  119. package/src/core/tools/bash.ts +250 -0
  120. package/src/core/tools/context.ts +32 -0
  121. package/src/core/tools/edit-diff.ts +475 -0
  122. package/src/core/tools/edit.ts +208 -0
  123. package/src/core/tools/exa/company.ts +59 -0
  124. package/src/core/tools/exa/index.ts +64 -0
  125. package/src/core/tools/exa/linkedin.ts +59 -0
  126. package/src/core/tools/exa/logger.ts +56 -0
  127. package/src/core/tools/exa/mcp-client.ts +368 -0
  128. package/src/core/tools/exa/render.ts +196 -0
  129. package/src/core/tools/exa/researcher.ts +90 -0
  130. package/src/core/tools/exa/search.ts +337 -0
  131. package/src/core/tools/exa/types.ts +168 -0
  132. package/src/core/tools/exa/websets.ts +248 -0
  133. package/src/core/tools/find.ts +261 -0
  134. package/src/core/tools/grep.ts +555 -0
  135. package/src/core/tools/index.ts +202 -0
  136. package/src/core/tools/ls.ts +140 -0
  137. package/src/core/tools/lsp/client.ts +605 -0
  138. package/src/core/tools/lsp/config.ts +147 -0
  139. package/src/core/tools/lsp/edits.ts +101 -0
  140. package/src/core/tools/lsp/index.ts +804 -0
  141. package/src/core/tools/lsp/render.ts +447 -0
  142. package/src/core/tools/lsp/rust-analyzer.ts +145 -0
  143. package/src/core/tools/lsp/types.ts +463 -0
  144. package/src/core/tools/lsp/utils.ts +486 -0
  145. package/src/core/tools/notebook.ts +229 -0
  146. package/src/core/tools/path-utils.ts +61 -0
  147. package/src/core/tools/read.ts +240 -0
  148. package/src/core/tools/renderers.ts +540 -0
  149. package/src/core/tools/task/agents.ts +153 -0
  150. package/src/core/tools/task/artifacts.ts +114 -0
  151. package/src/core/tools/task/bundled-agents/browser.md +71 -0
  152. package/src/core/tools/task/bundled-agents/explore.md +82 -0
  153. package/src/core/tools/task/bundled-agents/plan.md +54 -0
  154. package/src/core/tools/task/bundled-agents/reviewer.md +59 -0
  155. package/src/core/tools/task/bundled-agents/task.md +53 -0
  156. package/src/core/tools/task/bundled-commands/architect-plan.md +10 -0
  157. package/src/core/tools/task/bundled-commands/implement-with-critic.md +11 -0
  158. package/src/core/tools/task/bundled-commands/implement.md +11 -0
  159. package/src/core/tools/task/commands.ts +213 -0
  160. package/src/core/tools/task/discovery.ts +208 -0
  161. package/src/core/tools/task/executor.ts +367 -0
  162. package/src/core/tools/task/index.ts +388 -0
  163. package/src/core/tools/task/model-resolver.ts +115 -0
  164. package/src/core/tools/task/parallel.ts +38 -0
  165. package/src/core/tools/task/render.ts +232 -0
  166. package/src/core/tools/task/types.ts +99 -0
  167. package/src/core/tools/truncate.ts +265 -0
  168. package/src/core/tools/web-fetch.ts +2370 -0
  169. package/src/core/tools/web-search/auth.ts +193 -0
  170. package/src/core/tools/web-search/index.ts +537 -0
  171. package/src/core/tools/web-search/providers/anthropic.ts +198 -0
  172. package/src/core/tools/web-search/providers/exa.ts +302 -0
  173. package/src/core/tools/web-search/providers/perplexity.ts +195 -0
  174. package/src/core/tools/web-search/render.ts +182 -0
  175. package/src/core/tools/web-search/types.ts +180 -0
  176. package/src/core/tools/write.ts +99 -0
  177. package/src/index.ts +176 -0
  178. package/src/main.ts +464 -0
  179. package/src/migrations.ts +135 -0
  180. package/src/modes/index.ts +43 -0
  181. package/src/modes/interactive/components/armin.ts +382 -0
  182. package/src/modes/interactive/components/assistant-message.ts +86 -0
  183. package/src/modes/interactive/components/bash-execution.ts +196 -0
  184. package/src/modes/interactive/components/bordered-loader.ts +41 -0
  185. package/src/modes/interactive/components/branch-summary-message.ts +42 -0
  186. package/src/modes/interactive/components/compaction-summary-message.ts +45 -0
  187. package/src/modes/interactive/components/custom-editor.ts +122 -0
  188. package/src/modes/interactive/components/diff.ts +147 -0
  189. package/src/modes/interactive/components/dynamic-border.ts +25 -0
  190. package/src/modes/interactive/components/footer.ts +381 -0
  191. package/src/modes/interactive/components/hook-editor.ts +117 -0
  192. package/src/modes/interactive/components/hook-input.ts +64 -0
  193. package/src/modes/interactive/components/hook-message.ts +96 -0
  194. package/src/modes/interactive/components/hook-selector.ts +91 -0
  195. package/src/modes/interactive/components/model-selector.ts +247 -0
  196. package/src/modes/interactive/components/oauth-selector.ts +120 -0
  197. package/src/modes/interactive/components/plugin-settings.ts +479 -0
  198. package/src/modes/interactive/components/queue-mode-selector.ts +56 -0
  199. package/src/modes/interactive/components/session-selector.ts +204 -0
  200. package/src/modes/interactive/components/settings-selector.ts +453 -0
  201. package/src/modes/interactive/components/show-images-selector.ts +45 -0
  202. package/src/modes/interactive/components/theme-selector.ts +62 -0
  203. package/src/modes/interactive/components/thinking-selector.ts +64 -0
  204. package/src/modes/interactive/components/tool-execution.ts +675 -0
  205. package/src/modes/interactive/components/tree-selector.ts +866 -0
  206. package/src/modes/interactive/components/user-message-selector.ts +159 -0
  207. package/src/modes/interactive/components/user-message.ts +18 -0
  208. package/src/modes/interactive/components/visual-truncate.ts +50 -0
  209. package/src/modes/interactive/components/welcome.ts +183 -0
  210. package/src/modes/interactive/interactive-mode.ts +2516 -0
  211. package/src/modes/interactive/theme/dark.json +101 -0
  212. package/src/modes/interactive/theme/light.json +98 -0
  213. package/src/modes/interactive/theme/theme-schema.json +308 -0
  214. package/src/modes/interactive/theme/theme.ts +998 -0
  215. package/src/modes/print-mode.ts +128 -0
  216. package/src/modes/rpc/rpc-client.ts +527 -0
  217. package/src/modes/rpc/rpc-mode.ts +483 -0
  218. package/src/modes/rpc/rpc-types.ts +203 -0
  219. package/src/utils/changelog.ts +99 -0
  220. package/src/utils/clipboard.ts +265 -0
  221. package/src/utils/fuzzy.ts +108 -0
  222. package/src/utils/mime.ts +30 -0
  223. package/src/utils/shell.ts +276 -0
  224. package/src/utils/tools-manager.ts +274 -0
@@ -0,0 +1,443 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2
+ import { dirname, join } from "path";
3
+ import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
4
+
5
+ export interface CompactionSettings {
6
+ enabled?: boolean; // default: true
7
+ reserveTokens?: number; // default: 16384
8
+ keepRecentTokens?: number; // default: 20000
9
+ }
10
+
11
+ export interface BranchSummarySettings {
12
+ reserveTokens?: number; // default: 16384 (tokens reserved for prompt + LLM response)
13
+ }
14
+
15
+ export interface RetrySettings {
16
+ enabled?: boolean; // default: true
17
+ maxRetries?: number; // default: 3
18
+ baseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)
19
+ }
20
+
21
+ export interface SkillsSettings {
22
+ enabled?: boolean; // default: true
23
+ enableCodexUser?: boolean; // default: true
24
+ enableClaudeUser?: boolean; // default: true
25
+ enableClaudeProject?: boolean; // default: true
26
+ enablePiUser?: boolean; // default: true
27
+ enablePiProject?: boolean; // default: true
28
+ customDirectories?: string[]; // default: []
29
+ ignoredSkills?: string[]; // default: [] (glob patterns to exclude; takes precedence over includeSkills)
30
+ includeSkills?: string[]; // default: [] (empty = include all; glob patterns to filter)
31
+ }
32
+
33
+ export interface TerminalSettings {
34
+ showImages?: boolean; // default: true (only relevant if terminal supports images)
35
+ }
36
+
37
+ export interface ExaSettings {
38
+ enabled?: boolean; // default: true (master toggle for all Exa tools)
39
+ enableSearch?: boolean; // default: true (search, deep, code, crawl)
40
+ enableLinkedin?: boolean; // default: false
41
+ enableCompany?: boolean; // default: false
42
+ enableResearcher?: boolean; // default: false
43
+ enableWebsets?: boolean; // default: false
44
+ }
45
+
46
+ export interface Settings {
47
+ lastChangelogVersion?: string;
48
+ defaultProvider?: string;
49
+ defaultModel?: string;
50
+ defaultThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
51
+ queueMode?: "all" | "one-at-a-time";
52
+ theme?: string;
53
+ compaction?: CompactionSettings;
54
+ branchSummary?: BranchSummarySettings;
55
+ retry?: RetrySettings;
56
+ hideThinkingBlock?: boolean;
57
+ shellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows)
58
+ collapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)
59
+ hooks?: string[]; // Array of hook file paths
60
+ customTools?: string[]; // Array of custom tool file paths
61
+ skills?: SkillsSettings;
62
+ terminal?: TerminalSettings;
63
+ enabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)
64
+ exa?: ExaSettings;
65
+ }
66
+
67
+ /** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
68
+ function deepMergeSettings(base: Settings, overrides: Settings): Settings {
69
+ const result: Settings = { ...base };
70
+
71
+ for (const key of Object.keys(overrides) as (keyof Settings)[]) {
72
+ const overrideValue = overrides[key];
73
+ const baseValue = base[key];
74
+
75
+ if (overrideValue === undefined) {
76
+ continue;
77
+ }
78
+
79
+ // For nested objects, merge recursively
80
+ if (
81
+ typeof overrideValue === "object" &&
82
+ overrideValue !== null &&
83
+ !Array.isArray(overrideValue) &&
84
+ typeof baseValue === "object" &&
85
+ baseValue !== null &&
86
+ !Array.isArray(baseValue)
87
+ ) {
88
+ (result as Record<string, unknown>)[key] = { ...baseValue, ...overrideValue };
89
+ } else {
90
+ // For primitives and arrays, override value wins
91
+ (result as Record<string, unknown>)[key] = overrideValue;
92
+ }
93
+ }
94
+
95
+ return result;
96
+ }
97
+
98
+ export class SettingsManager {
99
+ private settingsPath: string | null;
100
+ private projectSettingsPath: string | null;
101
+ private globalSettings: Settings;
102
+ private settings: Settings;
103
+ private persist: boolean;
104
+
105
+ private constructor(
106
+ settingsPath: string | null,
107
+ projectSettingsPath: string | null,
108
+ initialSettings: Settings,
109
+ persist: boolean,
110
+ ) {
111
+ this.settingsPath = settingsPath;
112
+ this.projectSettingsPath = projectSettingsPath;
113
+ this.persist = persist;
114
+ this.globalSettings = initialSettings;
115
+ const projectSettings = this.loadProjectSettings();
116
+ this.settings = deepMergeSettings(this.globalSettings, projectSettings);
117
+ }
118
+
119
+ /** Create a SettingsManager that loads from files */
120
+ static create(cwd: string = process.cwd(), agentDir: string = getAgentDir()): SettingsManager {
121
+ const settingsPath = join(agentDir, "settings.json");
122
+ const projectSettingsPath = join(cwd, CONFIG_DIR_NAME, "settings.json");
123
+ const globalSettings = SettingsManager.loadFromFile(settingsPath);
124
+ return new SettingsManager(settingsPath, projectSettingsPath, globalSettings, true);
125
+ }
126
+
127
+ /** Create an in-memory SettingsManager (no file I/O) */
128
+ static inMemory(settings: Partial<Settings> = {}): SettingsManager {
129
+ return new SettingsManager(null, null, settings, false);
130
+ }
131
+
132
+ private static loadFromFile(path: string): Settings {
133
+ if (!existsSync(path)) {
134
+ return {};
135
+ }
136
+ try {
137
+ const content = readFileSync(path, "utf-8");
138
+ return JSON.parse(content);
139
+ } catch (error) {
140
+ console.error(`Warning: Could not read settings file ${path}: ${error}`);
141
+ return {};
142
+ }
143
+ }
144
+
145
+ private loadProjectSettings(): Settings {
146
+ if (!this.projectSettingsPath || !existsSync(this.projectSettingsPath)) {
147
+ return {};
148
+ }
149
+
150
+ try {
151
+ const content = readFileSync(this.projectSettingsPath, "utf-8");
152
+ return JSON.parse(content);
153
+ } catch (error) {
154
+ console.error(`Warning: Could not read project settings file: ${error}`);
155
+ return {};
156
+ }
157
+ }
158
+
159
+ /** Apply additional overrides on top of current settings */
160
+ applyOverrides(overrides: Partial<Settings>): void {
161
+ this.settings = deepMergeSettings(this.settings, overrides);
162
+ }
163
+
164
+ private save(): void {
165
+ if (!this.persist || !this.settingsPath) return;
166
+
167
+ try {
168
+ const dir = dirname(this.settingsPath);
169
+ if (!existsSync(dir)) {
170
+ mkdirSync(dir, { recursive: true });
171
+ }
172
+
173
+ // Save only global settings (project settings are read-only)
174
+ writeFileSync(this.settingsPath, JSON.stringify(this.globalSettings, null, 2), "utf-8");
175
+
176
+ // Re-merge project settings into active settings
177
+ const projectSettings = this.loadProjectSettings();
178
+ this.settings = deepMergeSettings(this.globalSettings, projectSettings);
179
+ } catch (error) {
180
+ console.error(`Warning: Could not save settings file: ${error}`);
181
+ }
182
+ }
183
+
184
+ getLastChangelogVersion(): string | undefined {
185
+ return this.settings.lastChangelogVersion;
186
+ }
187
+
188
+ setLastChangelogVersion(version: string): void {
189
+ this.globalSettings.lastChangelogVersion = version;
190
+ this.save();
191
+ }
192
+
193
+ getDefaultProvider(): string | undefined {
194
+ return this.settings.defaultProvider;
195
+ }
196
+
197
+ getDefaultModel(): string | undefined {
198
+ return this.settings.defaultModel;
199
+ }
200
+
201
+ setDefaultProvider(provider: string): void {
202
+ this.globalSettings.defaultProvider = provider;
203
+ this.save();
204
+ }
205
+
206
+ setDefaultModel(modelId: string): void {
207
+ this.globalSettings.defaultModel = modelId;
208
+ this.save();
209
+ }
210
+
211
+ setDefaultModelAndProvider(provider: string, modelId: string): void {
212
+ this.globalSettings.defaultProvider = provider;
213
+ this.globalSettings.defaultModel = modelId;
214
+ this.save();
215
+ }
216
+
217
+ getQueueMode(): "all" | "one-at-a-time" {
218
+ return this.settings.queueMode || "one-at-a-time";
219
+ }
220
+
221
+ setQueueMode(mode: "all" | "one-at-a-time"): void {
222
+ this.globalSettings.queueMode = mode;
223
+ this.save();
224
+ }
225
+
226
+ getTheme(): string | undefined {
227
+ return this.settings.theme;
228
+ }
229
+
230
+ setTheme(theme: string): void {
231
+ this.globalSettings.theme = theme;
232
+ this.save();
233
+ }
234
+
235
+ getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined {
236
+ return this.settings.defaultThinkingLevel;
237
+ }
238
+
239
+ setDefaultThinkingLevel(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"): void {
240
+ this.globalSettings.defaultThinkingLevel = level;
241
+ this.save();
242
+ }
243
+
244
+ getCompactionEnabled(): boolean {
245
+ return this.settings.compaction?.enabled ?? true;
246
+ }
247
+
248
+ setCompactionEnabled(enabled: boolean): void {
249
+ if (!this.globalSettings.compaction) {
250
+ this.globalSettings.compaction = {};
251
+ }
252
+ this.globalSettings.compaction.enabled = enabled;
253
+ this.save();
254
+ }
255
+
256
+ getCompactionReserveTokens(): number {
257
+ return this.settings.compaction?.reserveTokens ?? 16384;
258
+ }
259
+
260
+ getCompactionKeepRecentTokens(): number {
261
+ return this.settings.compaction?.keepRecentTokens ?? 20000;
262
+ }
263
+
264
+ getCompactionSettings(): { enabled: boolean; reserveTokens: number; keepRecentTokens: number } {
265
+ return {
266
+ enabled: this.getCompactionEnabled(),
267
+ reserveTokens: this.getCompactionReserveTokens(),
268
+ keepRecentTokens: this.getCompactionKeepRecentTokens(),
269
+ };
270
+ }
271
+
272
+ getBranchSummarySettings(): { reserveTokens: number } {
273
+ return {
274
+ reserveTokens: this.settings.branchSummary?.reserveTokens ?? 16384,
275
+ };
276
+ }
277
+
278
+ getRetryEnabled(): boolean {
279
+ return this.settings.retry?.enabled ?? true;
280
+ }
281
+
282
+ setRetryEnabled(enabled: boolean): void {
283
+ if (!this.globalSettings.retry) {
284
+ this.globalSettings.retry = {};
285
+ }
286
+ this.globalSettings.retry.enabled = enabled;
287
+ this.save();
288
+ }
289
+
290
+ getRetrySettings(): { enabled: boolean; maxRetries: number; baseDelayMs: number } {
291
+ return {
292
+ enabled: this.getRetryEnabled(),
293
+ maxRetries: this.settings.retry?.maxRetries ?? 3,
294
+ baseDelayMs: this.settings.retry?.baseDelayMs ?? 2000,
295
+ };
296
+ }
297
+
298
+ getHideThinkingBlock(): boolean {
299
+ return this.settings.hideThinkingBlock ?? false;
300
+ }
301
+
302
+ setHideThinkingBlock(hide: boolean): void {
303
+ this.globalSettings.hideThinkingBlock = hide;
304
+ this.save();
305
+ }
306
+
307
+ getShellPath(): string | undefined {
308
+ return this.settings.shellPath;
309
+ }
310
+
311
+ setShellPath(path: string | undefined): void {
312
+ this.globalSettings.shellPath = path;
313
+ this.save();
314
+ }
315
+
316
+ getCollapseChangelog(): boolean {
317
+ return this.settings.collapseChangelog ?? false;
318
+ }
319
+
320
+ setCollapseChangelog(collapse: boolean): void {
321
+ this.globalSettings.collapseChangelog = collapse;
322
+ this.save();
323
+ }
324
+
325
+ getHookPaths(): string[] {
326
+ return [...(this.settings.hooks ?? [])];
327
+ }
328
+
329
+ setHookPaths(paths: string[]): void {
330
+ this.globalSettings.hooks = paths;
331
+ this.save();
332
+ }
333
+
334
+ getCustomToolPaths(): string[] {
335
+ return [...(this.settings.customTools ?? [])];
336
+ }
337
+
338
+ setCustomToolPaths(paths: string[]): void {
339
+ this.globalSettings.customTools = paths;
340
+ this.save();
341
+ }
342
+
343
+ getSkillsEnabled(): boolean {
344
+ return this.settings.skills?.enabled ?? true;
345
+ }
346
+
347
+ setSkillsEnabled(enabled: boolean): void {
348
+ if (!this.globalSettings.skills) {
349
+ this.globalSettings.skills = {};
350
+ }
351
+ this.globalSettings.skills.enabled = enabled;
352
+ this.save();
353
+ }
354
+
355
+ getSkillsSettings(): Required<SkillsSettings> {
356
+ return {
357
+ enabled: this.settings.skills?.enabled ?? true,
358
+ enableCodexUser: this.settings.skills?.enableCodexUser ?? true,
359
+ enableClaudeUser: this.settings.skills?.enableClaudeUser ?? true,
360
+ enableClaudeProject: this.settings.skills?.enableClaudeProject ?? true,
361
+ enablePiUser: this.settings.skills?.enablePiUser ?? true,
362
+ enablePiProject: this.settings.skills?.enablePiProject ?? true,
363
+ customDirectories: [...(this.settings.skills?.customDirectories ?? [])],
364
+ ignoredSkills: [...(this.settings.skills?.ignoredSkills ?? [])],
365
+ includeSkills: [...(this.settings.skills?.includeSkills ?? [])],
366
+ };
367
+ }
368
+
369
+ getShowImages(): boolean {
370
+ return this.settings.terminal?.showImages ?? true;
371
+ }
372
+
373
+ setShowImages(show: boolean): void {
374
+ if (!this.globalSettings.terminal) {
375
+ this.globalSettings.terminal = {};
376
+ }
377
+ this.globalSettings.terminal.showImages = show;
378
+ this.save();
379
+ }
380
+
381
+ getEnabledModels(): string[] | undefined {
382
+ return this.settings.enabledModels;
383
+ }
384
+
385
+ getExaSettings(): Required<ExaSettings> {
386
+ return {
387
+ enabled: this.settings.exa?.enabled ?? true,
388
+ enableSearch: this.settings.exa?.enableSearch ?? true,
389
+ enableLinkedin: this.settings.exa?.enableLinkedin ?? false,
390
+ enableCompany: this.settings.exa?.enableCompany ?? false,
391
+ enableResearcher: this.settings.exa?.enableResearcher ?? false,
392
+ enableWebsets: this.settings.exa?.enableWebsets ?? false,
393
+ };
394
+ }
395
+
396
+ setExaEnabled(enabled: boolean): void {
397
+ if (!this.globalSettings.exa) {
398
+ this.globalSettings.exa = {};
399
+ }
400
+ this.globalSettings.exa.enabled = enabled;
401
+ this.save();
402
+ }
403
+
404
+ setExaSearchEnabled(enabled: boolean): void {
405
+ if (!this.globalSettings.exa) {
406
+ this.globalSettings.exa = {};
407
+ }
408
+ this.globalSettings.exa.enableSearch = enabled;
409
+ this.save();
410
+ }
411
+
412
+ setExaLinkedinEnabled(enabled: boolean): void {
413
+ if (!this.globalSettings.exa) {
414
+ this.globalSettings.exa = {};
415
+ }
416
+ this.globalSettings.exa.enableLinkedin = enabled;
417
+ this.save();
418
+ }
419
+
420
+ setExaCompanyEnabled(enabled: boolean): void {
421
+ if (!this.globalSettings.exa) {
422
+ this.globalSettings.exa = {};
423
+ }
424
+ this.globalSettings.exa.enableCompany = enabled;
425
+ this.save();
426
+ }
427
+
428
+ setExaResearcherEnabled(enabled: boolean): void {
429
+ if (!this.globalSettings.exa) {
430
+ this.globalSettings.exa = {};
431
+ }
432
+ this.globalSettings.exa.enableResearcher = enabled;
433
+ this.save();
434
+ }
435
+
436
+ setExaWebsetsEnabled(enabled: boolean): void {
437
+ if (!this.globalSettings.exa) {
438
+ this.globalSettings.exa = {};
439
+ }
440
+ this.globalSettings.exa.enableWebsets = enabled;
441
+ this.save();
442
+ }
443
+ }