@steipete/oracle 0.9.0 → 0.10.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 (177) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +61 -48
  3. package/dist/bin/oracle-cli.js +455 -402
  4. package/dist/bin/oracle-mcp.js +2 -2
  5. package/dist/bin/oracle.js +165 -279
  6. package/dist/scripts/agent-send.js +31 -31
  7. package/dist/scripts/check.js +6 -6
  8. package/dist/scripts/debug/extract-chatgpt-response.js +10 -10
  9. package/dist/scripts/docs-list.js +30 -30
  10. package/dist/scripts/git-policy.js +25 -23
  11. package/dist/scripts/run-cli.js +8 -8
  12. package/dist/scripts/runner.js +203 -195
  13. package/dist/scripts/test-browser.js +21 -18
  14. package/dist/scripts/test-remote-chrome.js +20 -20
  15. package/dist/src/bridge/connection.js +18 -18
  16. package/dist/src/bridge/userConfigFile.js +7 -7
  17. package/dist/src/browser/actions/assistantResponse.js +149 -101
  18. package/dist/src/browser/actions/attachmentDataTransfer.js +49 -47
  19. package/dist/src/browser/actions/attachments.js +246 -150
  20. package/dist/src/browser/actions/domEvents.js +2 -2
  21. package/dist/src/browser/actions/modelSelection.js +275 -117
  22. package/dist/src/browser/actions/navigation.js +161 -137
  23. package/dist/src/browser/actions/promptComposer.js +100 -64
  24. package/dist/src/browser/actions/remoteFileTransfer.js +10 -10
  25. package/dist/src/browser/actions/thinkingTime.js +207 -110
  26. package/dist/src/browser/chromeLifecycle.js +62 -60
  27. package/dist/src/browser/config.js +34 -15
  28. package/dist/src/browser/constants.js +17 -12
  29. package/dist/src/browser/cookies.js +19 -19
  30. package/dist/src/browser/detect.js +62 -62
  31. package/dist/src/browser/domDebug.js +1 -1
  32. package/dist/src/browser/index.js +390 -295
  33. package/dist/src/browser/modelStrategy.js +1 -1
  34. package/dist/src/browser/pageActions.js +5 -5
  35. package/dist/src/browser/policies.js +16 -13
  36. package/dist/src/browser/profileState.js +44 -39
  37. package/dist/src/browser/prompt.js +72 -42
  38. package/dist/src/browser/promptSummary.js +5 -5
  39. package/dist/src/browser/providerDomFlow.js +1 -1
  40. package/dist/src/browser/providers/chatgptDomProvider.js +9 -9
  41. package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +51 -42
  42. package/dist/src/browser/providers/index.js +2 -2
  43. package/dist/src/browser/reattach.js +67 -34
  44. package/dist/src/browser/reattachHelpers.js +31 -26
  45. package/dist/src/browser/sessionRunner.js +37 -25
  46. package/dist/src/browser/utils.js +9 -9
  47. package/dist/src/browserMode.js +1 -1
  48. package/dist/src/cli/bridge/claudeConfig.js +16 -16
  49. package/dist/src/cli/bridge/client.js +28 -20
  50. package/dist/src/cli/bridge/codexConfig.js +16 -16
  51. package/dist/src/cli/bridge/doctor.js +47 -39
  52. package/dist/src/cli/bridge/host.js +58 -56
  53. package/dist/src/cli/browserConfig.js +62 -48
  54. package/dist/src/cli/browserDefaults.js +27 -26
  55. package/dist/src/cli/bundleWarnings.js +1 -1
  56. package/dist/src/cli/clipboard.js +11 -2
  57. package/dist/src/cli/detach.js +2 -2
  58. package/dist/src/cli/dryRun.js +29 -25
  59. package/dist/src/cli/duplicatePromptGuard.js +3 -3
  60. package/dist/src/cli/engine.js +9 -9
  61. package/dist/src/cli/errorUtils.js +1 -1
  62. package/dist/src/cli/fileSize.js +3 -3
  63. package/dist/src/cli/format.js +2 -2
  64. package/dist/src/cli/help.js +28 -28
  65. package/dist/src/cli/hiddenAliases.js +3 -3
  66. package/dist/src/cli/markdownBundle.js +7 -7
  67. package/dist/src/cli/markdownRenderer.js +15 -15
  68. package/dist/src/cli/notifier.js +77 -67
  69. package/dist/src/cli/options.js +127 -106
  70. package/dist/src/cli/oscUtils.js +1 -1
  71. package/dist/src/cli/promptRequirement.js +2 -2
  72. package/dist/src/cli/renderOutput.js +1 -1
  73. package/dist/src/cli/rootAlias.js +1 -1
  74. package/dist/src/cli/runOptions.js +32 -28
  75. package/dist/src/cli/sessionCommand.js +31 -21
  76. package/dist/src/cli/sessionDisplay.js +95 -81
  77. package/dist/src/cli/sessionLineage.js +6 -2
  78. package/dist/src/cli/sessionRunner.js +103 -93
  79. package/dist/src/cli/sessionTable.js +26 -23
  80. package/dist/src/cli/stdin.js +22 -0
  81. package/dist/src/cli/tagline.js +121 -124
  82. package/dist/src/cli/tui/index.js +139 -128
  83. package/dist/src/cli/writeOutputPath.js +5 -5
  84. package/dist/src/config.js +7 -7
  85. package/dist/src/gemini-web/browserSessionManager.js +19 -15
  86. package/dist/src/gemini-web/client.js +76 -70
  87. package/dist/src/gemini-web/executionMode.js +6 -8
  88. package/dist/src/gemini-web/executor.js +98 -93
  89. package/dist/src/gemini-web/index.js +1 -1
  90. package/dist/src/mcp/server.js +16 -12
  91. package/dist/src/mcp/tools/consult.js +51 -47
  92. package/dist/src/mcp/tools/sessionResources.js +12 -12
  93. package/dist/src/mcp/tools/sessions.js +26 -17
  94. package/dist/src/mcp/types.js +5 -5
  95. package/dist/src/mcp/utils.js +15 -7
  96. package/dist/src/oracle/background.js +15 -15
  97. package/dist/src/oracle/claude.js +53 -25
  98. package/dist/src/oracle/client.js +50 -41
  99. package/dist/src/oracle/config.js +96 -66
  100. package/dist/src/oracle/errors.js +38 -38
  101. package/dist/src/oracle/files.js +55 -46
  102. package/dist/src/oracle/finishLine.js +10 -8
  103. package/dist/src/oracle/format.js +3 -3
  104. package/dist/src/oracle/gemini.js +37 -33
  105. package/dist/src/oracle/logging.js +7 -7
  106. package/dist/src/oracle/markdown.js +28 -28
  107. package/dist/src/oracle/modelResolver.js +16 -16
  108. package/dist/src/oracle/multiModelRunner.js +12 -12
  109. package/dist/src/oracle/oscProgress.js +8 -8
  110. package/dist/src/oracle/promptAssembly.js +6 -3
  111. package/dist/src/oracle/request.js +16 -13
  112. package/dist/src/oracle/run.js +156 -134
  113. package/dist/src/oracle/runUtils.js +8 -5
  114. package/dist/src/oracle/tokenEstimate.js +6 -6
  115. package/dist/src/oracle/tokenStats.js +5 -5
  116. package/dist/src/oracle/tokenStringifier.js +5 -5
  117. package/dist/src/oracle.js +12 -12
  118. package/dist/src/oracleHome.js +3 -3
  119. package/dist/src/remote/client.js +25 -25
  120. package/dist/src/remote/health.js +20 -20
  121. package/dist/src/remote/remoteServiceConfig.js +9 -9
  122. package/dist/src/remote/server.js +129 -118
  123. package/dist/src/sessionManager.js +77 -75
  124. package/dist/src/sessionStore.js +3 -3
  125. package/dist/src/version.js +10 -10
  126. package/dist/vendor/oracle-notifier/README.md +2 -0
  127. package/package.json +66 -62
  128. package/vendor/oracle-notifier/README.md +2 -0
  129. package/dist/markdansi/types/index.js +0 -4
  130. package/dist/oracle/bin/oracle-cli.js +0 -472
  131. package/dist/oracle/src/browser/actions/assistantResponse.js +0 -471
  132. package/dist/oracle/src/browser/actions/attachments.js +0 -82
  133. package/dist/oracle/src/browser/actions/modelSelection.js +0 -190
  134. package/dist/oracle/src/browser/actions/navigation.js +0 -75
  135. package/dist/oracle/src/browser/actions/promptComposer.js +0 -167
  136. package/dist/oracle/src/browser/chromeLifecycle.js +0 -104
  137. package/dist/oracle/src/browser/config.js +0 -33
  138. package/dist/oracle/src/browser/constants.js +0 -40
  139. package/dist/oracle/src/browser/cookies.js +0 -210
  140. package/dist/oracle/src/browser/domDebug.js +0 -36
  141. package/dist/oracle/src/browser/index.js +0 -331
  142. package/dist/oracle/src/browser/pageActions.js +0 -5
  143. package/dist/oracle/src/browser/prompt.js +0 -88
  144. package/dist/oracle/src/browser/promptSummary.js +0 -20
  145. package/dist/oracle/src/browser/sessionRunner.js +0 -80
  146. package/dist/oracle/src/browser/types.js +0 -1
  147. package/dist/oracle/src/browser/utils.js +0 -62
  148. package/dist/oracle/src/browserMode.js +0 -1
  149. package/dist/oracle/src/cli/browserConfig.js +0 -44
  150. package/dist/oracle/src/cli/dryRun.js +0 -59
  151. package/dist/oracle/src/cli/engine.js +0 -17
  152. package/dist/oracle/src/cli/errorUtils.js +0 -9
  153. package/dist/oracle/src/cli/help.js +0 -70
  154. package/dist/oracle/src/cli/markdownRenderer.js +0 -15
  155. package/dist/oracle/src/cli/options.js +0 -103
  156. package/dist/oracle/src/cli/promptRequirement.js +0 -14
  157. package/dist/oracle/src/cli/rootAlias.js +0 -30
  158. package/dist/oracle/src/cli/sessionCommand.js +0 -77
  159. package/dist/oracle/src/cli/sessionDisplay.js +0 -270
  160. package/dist/oracle/src/cli/sessionRunner.js +0 -94
  161. package/dist/oracle/src/heartbeat.js +0 -43
  162. package/dist/oracle/src/oracle/client.js +0 -48
  163. package/dist/oracle/src/oracle/config.js +0 -29
  164. package/dist/oracle/src/oracle/errors.js +0 -101
  165. package/dist/oracle/src/oracle/files.js +0 -220
  166. package/dist/oracle/src/oracle/format.js +0 -33
  167. package/dist/oracle/src/oracle/fsAdapter.js +0 -7
  168. package/dist/oracle/src/oracle/oscProgress.js +0 -60
  169. package/dist/oracle/src/oracle/request.js +0 -48
  170. package/dist/oracle/src/oracle/run.js +0 -444
  171. package/dist/oracle/src/oracle/tokenStats.js +0 -39
  172. package/dist/oracle/src/oracle/types.js +0 -1
  173. package/dist/oracle/src/oracle.js +0 -9
  174. package/dist/oracle/src/sessionManager.js +0 -205
  175. package/dist/oracle/src/version.js +0 -39
  176. package/dist/scripts/chrome/browser-tools.js +0 -295
  177. package/dist/src/browser/profileSync.js +0 -141
@@ -1,14 +1,17 @@
1
- import { InvalidArgumentError } from 'commander';
2
- import { parseDuration } from '../browserMode.js';
3
- import path from 'node:path';
4
- import fg from 'fast-glob';
5
- import { DEFAULT_MODEL, MODEL_CONFIGS } from '../oracle.js';
1
+ import { InvalidArgumentError } from "commander";
2
+ import { parseDuration } from "../browserMode.js";
3
+ import path from "node:path";
4
+ import fg from "fast-glob";
5
+ import { DEFAULT_MODEL, MODEL_CONFIGS } from "../oracle.js";
6
6
  export function collectPaths(value, previous = []) {
7
7
  if (!value) {
8
8
  return previous;
9
9
  }
10
10
  const nextValues = Array.isArray(value) ? value : [value];
11
- return previous.concat(nextValues.flatMap((entry) => entry.split(',')).map((entry) => entry.trim()).filter(Boolean));
11
+ return previous.concat(nextValues
12
+ .flatMap((entry) => entry.split(","))
13
+ .map((entry) => entry.trim())
14
+ .filter(Boolean));
12
15
  }
13
16
  /**
14
17
  * Merge all path-like CLI inputs (file/include aliases) into a single list, preserving order.
@@ -29,7 +32,7 @@ export function dedupePathInputs(inputs, { cwd = process.cwd() } = {}) {
29
32
  if (!raw)
30
33
  continue;
31
34
  let key = raw;
32
- if (!raw.startsWith('!') && !fg.isDynamicPattern(raw)) {
35
+ if (!raw.startsWith("!") && !fg.isDynamicPattern(raw)) {
33
36
  const absolute = path.isAbsolute(raw) ? raw : path.resolve(cwd, raw);
34
37
  key = `path:${path.normalize(absolute)}`;
35
38
  }
@@ -50,7 +53,7 @@ export function collectModelList(value, previous = []) {
50
53
  return previous;
51
54
  }
52
55
  const entries = value
53
- .split(',')
56
+ .split(",")
54
57
  .map((entry) => entry.trim())
55
58
  .filter((entry) => entry.length > 0);
56
59
  return previous.concat(entries);
@@ -58,7 +61,7 @@ export function collectModelList(value, previous = []) {
58
61
  export function parseFloatOption(value) {
59
62
  const parsed = Number.parseFloat(value);
60
63
  if (Number.isNaN(parsed)) {
61
- throw new InvalidArgumentError('Value must be a number.');
64
+ throw new InvalidArgumentError("Value must be a number.");
62
65
  }
63
66
  return parsed;
64
67
  }
@@ -68,7 +71,7 @@ export function parseIntOption(value) {
68
71
  }
69
72
  const parsed = Number.parseInt(value, 10);
70
73
  if (Number.isNaN(parsed)) {
71
- throw new InvalidArgumentError('Value must be an integer.');
74
+ throw new InvalidArgumentError("Value must be an integer.");
72
75
  }
73
76
  return parsed;
74
77
  }
@@ -76,9 +79,9 @@ export function parseHeartbeatOption(value) {
76
79
  if (value == null) {
77
80
  return 30;
78
81
  }
79
- if (typeof value === 'number') {
82
+ if (typeof value === "number") {
80
83
  if (Number.isNaN(value) || value < 0) {
81
- throw new InvalidArgumentError('Heartbeat interval must be zero or a positive number.');
84
+ throw new InvalidArgumentError("Heartbeat interval must be zero or a positive number.");
82
85
  }
83
86
  return value;
84
87
  }
@@ -86,42 +89,42 @@ export function parseHeartbeatOption(value) {
86
89
  if (normalized.length === 0) {
87
90
  return 30;
88
91
  }
89
- if (normalized === 'false' || normalized === 'off') {
92
+ if (normalized === "false" || normalized === "off") {
90
93
  return 0;
91
94
  }
92
95
  const parsed = Number.parseFloat(normalized);
93
96
  if (Number.isNaN(parsed) || parsed < 0) {
94
- throw new InvalidArgumentError('Heartbeat interval must be zero or a positive number.');
97
+ throw new InvalidArgumentError("Heartbeat interval must be zero or a positive number.");
95
98
  }
96
99
  return parsed;
97
100
  }
98
101
  export function usesDefaultStatusFilters(cmd) {
99
- const hoursSource = cmd.getOptionValueSource?.('hours') ?? 'default';
100
- const limitSource = cmd.getOptionValueSource?.('limit') ?? 'default';
101
- const allSource = cmd.getOptionValueSource?.('all') ?? 'default';
102
- return hoursSource === 'default' && limitSource === 'default' && allSource === 'default';
102
+ const hoursSource = cmd.getOptionValueSource?.("hours") ?? "default";
103
+ const limitSource = cmd.getOptionValueSource?.("limit") ?? "default";
104
+ const allSource = cmd.getOptionValueSource?.("all") ?? "default";
105
+ return hoursSource === "default" && limitSource === "default" && allSource === "default";
103
106
  }
104
107
  export function resolvePreviewMode(value) {
105
- if (typeof value === 'string' && value.length > 0) {
108
+ if (typeof value === "string" && value.length > 0) {
106
109
  return value;
107
110
  }
108
111
  if (value === true) {
109
- return 'summary';
112
+ return "summary";
110
113
  }
111
114
  return undefined;
112
115
  }
113
116
  export function parseSearchOption(value) {
114
117
  const normalized = value.trim().toLowerCase();
115
- if (['on', 'true', '1', 'yes'].includes(normalized)) {
118
+ if (["on", "true", "1", "yes"].includes(normalized)) {
116
119
  return true;
117
120
  }
118
- if (['off', 'false', '0', 'no'].includes(normalized)) {
121
+ if (["off", "false", "0", "no"].includes(normalized)) {
119
122
  return false;
120
123
  }
121
124
  throw new InvalidArgumentError('Search mode must be "on" or "off".');
122
125
  }
123
126
  export function normalizeModelOption(value) {
124
- return (value ?? '').trim();
127
+ return (value ?? "").trim();
125
128
  }
126
129
  export function normalizeBaseUrl(value) {
127
130
  const trimmed = value?.trim();
@@ -131,8 +134,8 @@ export function parseTimeoutOption(value) {
131
134
  if (value == null)
132
135
  return undefined;
133
136
  const normalized = value.trim().toLowerCase();
134
- if (normalized === 'auto')
135
- return 'auto';
137
+ if (normalized === "auto")
138
+ return "auto";
136
139
  const parsed = Number.parseFloat(normalized);
137
140
  if (Number.isNaN(parsed) || parsed <= 0) {
138
141
  throw new InvalidArgumentError('Timeout must be a positive number of seconds or "auto".');
@@ -153,68 +156,74 @@ export function parseDurationOption(value, label) {
153
156
  return parsed;
154
157
  }
155
158
  function isGeminiDeepThinkAlias(normalized) {
156
- return ((normalized.includes('gemini') && normalized.includes('deep')) ||
157
- normalized.includes('deep-think') ||
158
- normalized.includes('deep_think') ||
159
- normalized.includes('deepthink'));
159
+ return ((normalized.includes("gemini") && normalized.includes("deep")) ||
160
+ normalized.includes("deep-think") ||
161
+ normalized.includes("deep_think") ||
162
+ normalized.includes("deepthink"));
160
163
  }
161
164
  export function resolveApiModel(modelValue) {
162
165
  const normalized = normalizeModelOption(modelValue).toLowerCase();
163
166
  if (normalized in MODEL_CONFIGS) {
164
167
  return normalized;
165
168
  }
166
- if (normalized.includes('/')) {
169
+ if (normalized.includes("/")) {
167
170
  return normalized;
168
171
  }
169
- if (normalized.includes('grok')) {
170
- return 'grok-4.1';
172
+ if (normalized.includes("grok")) {
173
+ return "grok-4.1";
174
+ }
175
+ if (normalized.includes("claude") && normalized.includes("sonnet")) {
176
+ return "claude-4.6-sonnet";
177
+ }
178
+ if (normalized.includes("claude") && normalized.includes("opus")) {
179
+ return "claude-4.1-opus";
171
180
  }
172
- if (normalized.includes('claude') && normalized.includes('sonnet')) {
173
- return 'claude-4.5-sonnet';
181
+ if (normalized.includes("5.5") && normalized.includes("pro")) {
182
+ return "gpt-5.5-pro";
174
183
  }
175
- if (normalized.includes('claude') && normalized.includes('opus')) {
176
- return 'claude-4.1-opus';
184
+ if (normalized.includes("5.5")) {
185
+ return "gpt-5.5";
177
186
  }
178
- if (normalized.includes('5.4') && normalized.includes('pro')) {
179
- return 'gpt-5.4-pro';
187
+ if (normalized.includes("5.4") && normalized.includes("pro")) {
188
+ return "gpt-5.4-pro";
180
189
  }
181
- if (normalized.includes('5.4')) {
182
- return 'gpt-5.4';
190
+ if (normalized.includes("5.4")) {
191
+ return "gpt-5.4";
183
192
  }
184
- if (normalized === 'claude' || normalized === 'sonnet' || /(^|\b)sonnet(\b|$)/.test(normalized)) {
185
- return 'claude-4.5-sonnet';
193
+ if (normalized === "claude" || normalized === "sonnet" || /(^|\b)sonnet(\b|$)/.test(normalized)) {
194
+ return "claude-4.6-sonnet";
186
195
  }
187
- if (normalized === 'opus' || normalized === 'claude-4.1') {
188
- return 'claude-4.1-opus';
196
+ if (normalized === "opus" || normalized === "claude-4.1") {
197
+ return "claude-4.1-opus";
189
198
  }
190
- if (normalized.includes('5.0') || normalized === 'gpt-5-pro' || normalized === 'gpt-5') {
191
- return 'gpt-5-pro';
199
+ if (normalized.includes("5.0") || normalized === "gpt-5-pro" || normalized === "gpt-5") {
200
+ return "gpt-5-pro";
192
201
  }
193
- if (normalized.includes('5-pro') && !normalized.includes('5.1')) {
194
- return 'gpt-5-pro';
202
+ if (normalized.includes("5-pro") && !normalized.includes("5.1")) {
203
+ return "gpt-5-pro";
195
204
  }
196
- if (normalized.includes('5.2') && normalized.includes('pro')) {
197
- return 'gpt-5.2-pro';
205
+ if (normalized.includes("5.2") && normalized.includes("pro")) {
206
+ return "gpt-5.2-pro";
198
207
  }
199
- if (normalized.includes('5.1') && normalized.includes('pro')) {
200
- return 'gpt-5.1-pro';
208
+ if (normalized.includes("5.1") && normalized.includes("pro")) {
209
+ return "gpt-5.1-pro";
201
210
  }
202
- if (normalized.includes('codex')) {
203
- if (normalized.includes('max')) {
204
- throw new InvalidArgumentError('gpt-5.1-codex-max is not available yet. OpenAI has not released the API.');
211
+ if (normalized.includes("codex")) {
212
+ if (normalized.includes("max")) {
213
+ throw new InvalidArgumentError("gpt-5.1-codex-max is not available yet. OpenAI has not released the API.");
205
214
  }
206
- return 'gpt-5.1-codex';
215
+ return "gpt-5.1-codex";
207
216
  }
208
217
  if (isGeminiDeepThinkAlias(normalized)) {
209
- throw new InvalidArgumentError('Gemini Deep Think is browser-only today. Use --engine browser --model gemini-3-deep-think.');
218
+ throw new InvalidArgumentError("Gemini Deep Think is browser-only today. Use --engine browser --model gemini-3-deep-think.");
210
219
  }
211
- if (normalized.includes('gemini')) {
212
- if (normalized.includes('3.1') || normalized.includes('3_1')) {
213
- return 'gemini-3.1-pro';
220
+ if (normalized.includes("gemini")) {
221
+ if (normalized.includes("3.1") || normalized.includes("3_1")) {
222
+ return "gemini-3.1-pro";
214
223
  }
215
- return 'gemini-3-pro';
224
+ return "gemini-3-pro";
216
225
  }
217
- if (normalized.includes('pro')) {
226
+ if (normalized.includes("pro")) {
218
227
  return DEFAULT_MODEL;
219
228
  }
220
229
  // Passthrough for custom/OpenRouter model IDs.
@@ -228,73 +237,85 @@ export function inferModelFromLabel(modelValue) {
228
237
  if (normalized in MODEL_CONFIGS) {
229
238
  return normalized;
230
239
  }
231
- if (normalized.includes('/')) {
240
+ if (normalized.includes("/")) {
232
241
  return normalized;
233
242
  }
234
- if (normalized.includes('grok')) {
235
- return 'grok-4.1';
243
+ if (normalized.includes("grok")) {
244
+ return "grok-4.1";
236
245
  }
237
- if (normalized.includes('claude') && normalized.includes('sonnet')) {
238
- return 'claude-4.5-sonnet';
246
+ if (normalized.includes("claude") && normalized.includes("sonnet")) {
247
+ return "claude-4.6-sonnet";
239
248
  }
240
- if (normalized.includes('claude') && normalized.includes('opus')) {
241
- return 'claude-4.1-opus';
249
+ if (normalized.includes("claude") && normalized.includes("opus")) {
250
+ return "claude-4.1-opus";
242
251
  }
243
- if (normalized.includes('codex')) {
244
- return 'gpt-5.1-codex';
252
+ if (normalized.includes("codex")) {
253
+ return "gpt-5.1-codex";
245
254
  }
246
255
  if (isGeminiDeepThinkAlias(normalized)) {
247
- return 'gemini-3-pro-deep-think';
256
+ return "gemini-3-pro-deep-think";
248
257
  }
249
- if (normalized.includes('gemini')) {
250
- if (normalized.includes('3.1') || normalized.includes('3_1')) {
251
- return 'gemini-3.1-pro';
258
+ if (normalized.includes("gemini")) {
259
+ if (normalized.includes("3.1") || normalized.includes("3_1")) {
260
+ return "gemini-3.1-pro";
252
261
  }
253
- return 'gemini-3-pro';
262
+ return "gemini-3-pro";
263
+ }
264
+ if (normalized.includes("classic")) {
265
+ return "gpt-5-pro";
266
+ }
267
+ if (normalized.includes("thinking") && normalized.includes("heavy")) {
268
+ return "gpt-5.5";
269
+ }
270
+ if ((normalized.includes("5.5") || normalized.includes("5_5")) && normalized.includes("pro")) {
271
+ return "gpt-5.5-pro";
254
272
  }
255
- if (normalized.includes('classic')) {
256
- return 'gpt-5-pro';
273
+ if (normalized.includes("5.5") || normalized.includes("5_5")) {
274
+ return "gpt-5.5";
257
275
  }
258
- if ((normalized.includes('5.4') || normalized.includes('5_4')) && normalized.includes('pro')) {
259
- return 'gpt-5.4-pro';
276
+ if ((normalized.includes("5.4") || normalized.includes("5_4")) && normalized.includes("pro")) {
277
+ return "gpt-5.4-pro";
260
278
  }
261
- if (normalized.includes('5.4') || normalized.includes('5_4')) {
262
- return 'gpt-5.4';
279
+ if (normalized.includes("5.4") || normalized.includes("5_4")) {
280
+ return "gpt-5.4";
263
281
  }
264
- if ((normalized.includes('5.2') || normalized.includes('5_2')) && normalized.includes('pro')) {
265
- return 'gpt-5.2-pro';
282
+ if ((normalized.includes("5.2") || normalized.includes("5_2")) && normalized.includes("pro")) {
283
+ return "gpt-5.2-pro";
266
284
  }
267
285
  // Browser-only: pass through 5.2 thinking/instant variants for browser label mapping
268
- if ((normalized.includes('5.2') || normalized.includes('5_2')) && normalized.includes('thinking')) {
269
- return 'gpt-5.2-thinking';
286
+ if ((normalized.includes("5.2") || normalized.includes("5_2")) &&
287
+ normalized.includes("thinking")) {
288
+ return "gpt-5.2-thinking";
270
289
  }
271
- if ((normalized.includes('5.2') || normalized.includes('5_2')) && normalized.includes('instant')) {
272
- return 'gpt-5.2-instant';
290
+ if ((normalized.includes("5.2") || normalized.includes("5_2")) &&
291
+ normalized.includes("instant")) {
292
+ return "gpt-5.2-instant";
273
293
  }
274
- if (normalized.includes('5.0') || normalized.includes('5-pro')) {
275
- return 'gpt-5-pro';
294
+ if (normalized.includes("5.0") || normalized.includes("5-pro")) {
295
+ return "gpt-5-pro";
276
296
  }
277
- if (normalized.includes('gpt-5') &&
278
- normalized.includes('pro') &&
279
- !normalized.includes('5.1') &&
280
- !normalized.includes('5.2') &&
281
- !normalized.includes('5.4')) {
282
- return 'gpt-5-pro';
297
+ if (normalized.includes("gpt-5") &&
298
+ normalized.includes("pro") &&
299
+ !normalized.includes("5.1") &&
300
+ !normalized.includes("5.2") &&
301
+ !normalized.includes("5.5") &&
302
+ !normalized.includes("5.4")) {
303
+ return "gpt-5-pro";
283
304
  }
284
- if ((normalized.includes('5.1') || normalized.includes('5_1')) && normalized.includes('pro')) {
285
- return 'gpt-5.1-pro';
305
+ if ((normalized.includes("5.1") || normalized.includes("5_1")) && normalized.includes("pro")) {
306
+ return "gpt-5.1-pro";
286
307
  }
287
- if (normalized.includes('pro')) {
308
+ if (normalized.includes("pro")) {
288
309
  return DEFAULT_MODEL;
289
310
  }
290
- if (normalized.includes('5.1') || normalized.includes('5_1')) {
291
- return 'gpt-5.1';
311
+ if (normalized.includes("5.1") || normalized.includes("5_1")) {
312
+ return "gpt-5.1";
292
313
  }
293
- if (normalized.includes('thinking')) {
294
- return 'gpt-5.2-thinking';
314
+ if (normalized.includes("thinking")) {
315
+ return "gpt-5.2-thinking";
295
316
  }
296
- if (normalized.includes('instant') || normalized.includes('fast')) {
297
- return 'gpt-5.2-instant';
317
+ if (normalized.includes("instant") || normalized.includes("fast")) {
318
+ return "gpt-5.2-instant";
298
319
  }
299
- return 'gpt-5.2';
320
+ return "gpt-5.2";
300
321
  }
@@ -1,2 +1,2 @@
1
1
  // Utilities for handling OSC progress codes embedded in stored logs.
2
- export { sanitizeOscProgress } from 'osc-progress';
2
+ export { sanitizeOscProgress } from "osc-progress";
@@ -10,8 +10,8 @@ export function shouldRequirePrompt(rawArgs, options) {
10
10
  options.execSession ||
11
11
  options.status ||
12
12
  options.debugHelp ||
13
- firstArg === 'status' ||
14
- firstArg === 'session');
13
+ firstArg === "status" ||
14
+ firstArg === "session");
15
15
  const requiresPrompt = options.renderMarkdown || Boolean(options.preview) || Boolean(options.dryRun) || !bypassPrompt;
16
16
  return requiresPrompt && !options.prompt;
17
17
  }
@@ -1,4 +1,4 @@
1
- import { ensureShikiReady, renderMarkdownAnsi } from './markdownRenderer.js';
1
+ import { ensureShikiReady, renderMarkdownAnsi } from "./markdownRenderer.js";
2
2
  export function shouldRenderRich(options = {}) {
3
3
  return options.richTty ?? Boolean(process.stdout.isTTY);
4
4
  }
@@ -1,4 +1,4 @@
1
- import { attachSession, showStatus } from './sessionDisplay.js';
1
+ import { attachSession, showStatus } from "./sessionDisplay.js";
2
2
  const defaultDeps = {
3
3
  attachSession,
4
4
  showStatus,
@@ -1,51 +1,55 @@
1
- import { DEFAULT_MODEL, MODEL_CONFIGS } from '../oracle.js';
2
- import { resolveEngine } from './engine.js';
3
- import { normalizeModelOption, inferModelFromLabel, resolveApiModel, normalizeBaseUrl } from './options.js';
4
- import { resolveGeminiModelId } from '../oracle/gemini.js';
5
- import { PromptValidationError } from '../oracle/errors.js';
6
- import { normalizeChatGptModelForBrowser } from './browserConfig.js';
7
- import { resolveConfiguredMaxFileSizeBytes } from './fileSize.js';
1
+ import { DEFAULT_MODEL, MODEL_CONFIGS } from "../oracle.js";
2
+ import { resolveEngine } from "./engine.js";
3
+ import { normalizeModelOption, inferModelFromLabel, resolveApiModel, normalizeBaseUrl, } from "./options.js";
4
+ import { resolveGeminiModelId } from "../oracle/gemini.js";
5
+ import { PromptValidationError } from "../oracle/errors.js";
6
+ import { normalizeChatGptModelForBrowser } from "./browserConfig.js";
7
+ import { resolveConfiguredMaxFileSizeBytes } from "./fileSize.js";
8
8
  export function resolveRunOptionsFromConfig({ prompt, files = [], model, models, engine, userConfig, env = process.env, }) {
9
9
  const resolvedEngine = resolveEngineWithConfig({ engine, configEngine: userConfig?.engine, env });
10
- const browserRequested = engine === 'browser';
11
- const browserConfigured = userConfig?.engine === 'browser';
10
+ const browserRequested = engine === "browser";
11
+ const browserConfigured = userConfig?.engine === "browser";
12
12
  const requestedModelList = Array.isArray(models) ? models : [];
13
- const normalizedRequestedModels = requestedModelList.map((entry) => normalizeModelOption(entry)).filter(Boolean);
13
+ const normalizedRequestedModels = requestedModelList
14
+ .map((entry) => normalizeModelOption(entry))
15
+ .filter(Boolean);
14
16
  const cliModelArg = normalizeModelOption(model ?? userConfig?.model) || DEFAULT_MODEL;
15
- const inferredModel = resolvedEngine === 'browser' && normalizedRequestedModels.length === 0
17
+ const inferredModel = resolvedEngine === "browser" && normalizedRequestedModels.length === 0
16
18
  ? inferModelFromLabel(cliModelArg)
17
19
  : resolveApiModel(cliModelArg);
18
- // Browser engine maps Pro/legacy aliases to the latest ChatGPT picker targets (GPT-5.4 / GPT-5.4 Pro).
19
- const resolvedModel = resolvedEngine === 'browser' ? normalizeChatGptModelForBrowser(inferredModel) : inferredModel;
20
- const isCodex = resolvedModel.startsWith('gpt-5.1-codex');
21
- const isClaude = resolvedModel.startsWith('claude');
22
- const isGrok = resolvedModel.startsWith('grok');
23
- const isGeminiApiOnly = resolvedModel === 'gemini-3.1-pro';
24
- const engineWasBrowser = resolvedEngine === 'browser';
20
+ // Browser engine maps Pro/legacy aliases to the latest ChatGPT picker targets.
21
+ const resolvedModel = resolvedEngine === "browser" ? normalizeChatGptModelForBrowser(inferredModel) : inferredModel;
22
+ const isCodex = resolvedModel.startsWith("gpt-5.1-codex");
23
+ const isClaude = resolvedModel.startsWith("claude");
24
+ const isGrok = resolvedModel.startsWith("grok");
25
+ const isGeminiApiOnly = resolvedModel === "gemini-3.1-pro";
26
+ const engineWasBrowser = resolvedEngine === "browser";
25
27
  const allModels = normalizedRequestedModels.length > 0
26
28
  ? Array.from(new Set(normalizedRequestedModels.map((entry) => resolveApiModel(entry))))
27
29
  : [resolvedModel];
28
- const includesGeminiApiOnly = allModels.some((m) => m === 'gemini-3.1-pro');
30
+ const includesGeminiApiOnly = allModels.some((m) => m === "gemini-3.1-pro");
29
31
  if ((browserRequested || browserConfigured) && includesGeminiApiOnly) {
30
- throw new PromptValidationError('gemini-3.1-pro is API-only today. Use --engine api or switch to gemini-3-pro for Gemini web.', { engine: 'browser', models: allModels });
32
+ throw new PromptValidationError("gemini-3.1-pro is API-only today. Use --engine api or switch to gemini-3-pro for Gemini web.", { engine: "browser", models: allModels });
31
33
  }
32
- const isBrowserCompatible = (m) => m.startsWith('gpt-') || m.startsWith('gemini');
34
+ const isBrowserCompatible = (m) => m.startsWith("gpt-") || m.startsWith("gemini");
33
35
  const hasNonBrowserCompatibleTarget = (browserRequested || browserConfigured) && allModels.some((m) => !isBrowserCompatible(m));
34
36
  if (hasNonBrowserCompatibleTarget) {
35
- throw new PromptValidationError('Browser engine only supports GPT and Gemini models. Re-run with --engine api for Grok, Claude, or other models.', { engine: 'browser', models: allModels });
37
+ throw new PromptValidationError("Browser engine only supports GPT and Gemini models. Re-run with --engine api for Grok, Claude, or other models.", { engine: "browser", models: allModels });
36
38
  }
37
39
  const engineCoercedToApi = engineWasBrowser && (isCodex || isClaude || isGrok || isGeminiApiOnly);
38
- const fixedEngine = isCodex || isClaude || isGrok || isGeminiApiOnly || normalizedRequestedModels.length > 0 ? 'api' : resolvedEngine;
40
+ const fixedEngine = isCodex || isClaude || isGrok || isGeminiApiOnly || normalizedRequestedModels.length > 0
41
+ ? "api"
42
+ : resolvedEngine;
39
43
  const promptWithSuffix = userConfig?.promptSuffix && userConfig.promptSuffix.trim().length > 0
40
44
  ? `${prompt.trim()}\n${userConfig.promptSuffix}`
41
45
  : prompt;
42
- const search = userConfig?.search !== 'off';
46
+ const search = userConfig?.search !== "off";
43
47
  const heartbeatIntervalMs = userConfig?.heartbeatSeconds !== undefined ? userConfig.heartbeatSeconds * 1000 : 30_000;
44
48
  const maxFileSizeBytes = resolveConfiguredMaxFileSizeBytes(userConfig, env);
45
49
  const baseUrl = normalizeBaseUrl(userConfig?.apiBaseUrl ??
46
50
  (isClaude ? env.ANTHROPIC_BASE_URL : isGrok ? env.XAI_BASE_URL : env.OPENAI_BASE_URL));
47
51
  const uniqueMultiModels = normalizedRequestedModels.length > 0 ? allModels : [];
48
- const includesCodexMultiModel = uniqueMultiModels.some((entry) => entry.startsWith('gpt-5.1-codex'));
52
+ const includesCodexMultiModel = uniqueMultiModels.some((entry) => entry.startsWith("gpt-5.1-codex"));
49
53
  if (includesCodexMultiModel && browserRequested) {
50
54
  // Silent coerce; multi-model still forces API.
51
55
  }
@@ -69,8 +73,8 @@ export function resolveRunOptionsFromConfig({ prompt, files = [], model, models,
69
73
  function resolveEngineWithConfig({ engine, configEngine, env, }) {
70
74
  if (engine)
71
75
  return engine;
72
- const envOverride = (env.ORACLE_ENGINE ?? '').trim().toLowerCase();
73
- if (envOverride === 'api' || envOverride === 'browser') {
76
+ const envOverride = (env.ORACLE_ENGINE ?? "").trim().toLowerCase();
77
+ if (envOverride === "api" || envOverride === "browser") {
74
78
  return envOverride;
75
79
  }
76
80
  if (configEngine)
@@ -78,7 +82,7 @@ function resolveEngineWithConfig({ engine, configEngine, env, }) {
78
82
  return resolveEngine({ engine: undefined, env });
79
83
  }
80
84
  function resolveEffectiveModelId(model) {
81
- if (typeof model === 'string' && model.startsWith('gemini')) {
85
+ if (typeof model === "string" && model.startsWith("gemini")) {
82
86
  return resolveGeminiModelId(model);
83
87
  }
84
88
  const config = MODEL_CONFIGS[model];
@@ -1,7 +1,7 @@
1
- import chalk from 'chalk';
2
- import { usesDefaultStatusFilters } from './options.js';
3
- import { attachSession, showStatus } from './sessionDisplay.js';
4
- import { sessionStore } from '../sessionStore.js';
1
+ import chalk from "chalk";
2
+ import { usesDefaultStatusFilters } from "./options.js";
3
+ import { attachSession, showStatus, } from "./sessionDisplay.js";
4
+ import { sessionStore } from "../sessionStore.js";
5
5
  const defaultDependencies = {
6
6
  showStatus,
7
7
  attachSession,
@@ -9,39 +9,49 @@ const defaultDependencies = {
9
9
  deleteSessionsOlderThan: (options) => sessionStore.deleteOlderThan(options),
10
10
  getSessionPaths: (sessionId) => sessionStore.getPaths(sessionId),
11
11
  };
12
- const SESSION_OPTION_KEYS = new Set(['hours', 'limit', 'all', 'clear', 'clean', 'render', 'renderMarkdown', 'path', 'model']);
12
+ const SESSION_OPTION_KEYS = new Set([
13
+ "hours",
14
+ "limit",
15
+ "all",
16
+ "clear",
17
+ "clean",
18
+ "render",
19
+ "renderMarkdown",
20
+ "path",
21
+ "model",
22
+ ]);
13
23
  export async function handleSessionCommand(sessionId, command, deps = defaultDependencies) {
14
24
  const sessionOptions = command.opts();
15
25
  if (sessionOptions.verboseRender) {
16
- process.env.ORACLE_VERBOSE_RENDER = '1';
26
+ process.env.ORACLE_VERBOSE_RENDER = "1";
17
27
  }
18
- const renderSource = command.getOptionValueSource?.('render');
19
- const renderMarkdownSource = command.getOptionValueSource?.('renderMarkdown');
20
- const renderExplicit = renderSource === 'cli' || renderMarkdownSource === 'cli';
28
+ const renderSource = command.getOptionValueSource?.("render");
29
+ const renderMarkdownSource = command.getOptionValueSource?.("renderMarkdown");
30
+ const renderExplicit = renderSource === "cli" || renderMarkdownSource === "cli";
21
31
  const autoRender = !renderExplicit && process.stdout.isTTY;
22
32
  const pathRequested = Boolean(sessionOptions.path);
23
33
  const clearRequested = Boolean(sessionOptions.clear || sessionOptions.clean);
24
34
  if (clearRequested) {
25
35
  if (sessionId) {
26
- console.error('Cannot combine a session ID with --clear. Remove the ID to delete cached sessions.');
36
+ console.error("Cannot combine a session ID with --clear. Remove the ID to delete cached sessions.");
27
37
  process.exitCode = 1;
28
38
  return;
29
39
  }
30
40
  const hours = sessionOptions.hours;
31
41
  const includeAll = sessionOptions.all;
32
42
  const result = await deps.deleteSessionsOlderThan({ hours, includeAll });
33
- const scope = includeAll ? 'all stored sessions' : `sessions older than ${hours}h`;
43
+ const scope = includeAll ? "all stored sessions" : `sessions older than ${hours}h`;
34
44
  console.log(formatSessionCleanupMessage(result, scope));
35
45
  return;
36
46
  }
37
- if (sessionId === 'clear' || sessionId === 'clean') {
47
+ if (sessionId === "clear" || sessionId === "clean") {
38
48
  console.error('Session cleanup now uses --clear. Run "oracle session --clear --hours <n>" instead.');
39
49
  process.exitCode = 1;
40
50
  return;
41
51
  }
42
52
  if (pathRequested) {
43
53
  if (!sessionId) {
44
- console.error('The --path flag requires a session ID.');
54
+ console.error("The --path flag requires a session ID.");
45
55
  process.exitCode = 1;
46
56
  return;
47
57
  }
@@ -50,10 +60,10 @@ export async function handleSessionCommand(sessionId, command, deps = defaultDep
50
60
  const richTty = Boolean(process.stdout.isTTY && chalk.level > 0);
51
61
  const label = (text) => (richTty ? chalk.cyan(text) : text);
52
62
  const value = (text) => (richTty ? chalk.dim(text) : text);
53
- console.log(`${label('Session dir:')} ${value(paths.dir)}`);
54
- console.log(`${label('Metadata:')} ${value(paths.metadata)}`);
55
- console.log(`${label('Request:')} ${value(paths.request)}`);
56
- console.log(`${label('Log:')} ${value(paths.log)}`);
63
+ console.log(`${label("Session dir:")} ${value(paths.dir)}`);
64
+ console.log(`${label("Metadata:")} ${value(paths.metadata)}`);
65
+ console.log(`${label("Request:")} ${value(paths.request)}`);
66
+ console.log(`${label("Log:")} ${value(paths.log)}`);
57
67
  }
58
68
  catch (error) {
59
69
  console.error(error instanceof Error ? error.message : String(error));
@@ -75,7 +85,7 @@ export async function handleSessionCommand(sessionId, command, deps = defaultDep
75
85
  // Surface any root-level flags that were provided but are ignored when attaching to a session.
76
86
  const ignoredFlags = listIgnoredFlags(command);
77
87
  if (ignoredFlags.length > 0) {
78
- console.log(`Ignoring flags on session attach: ${ignoredFlags.join(', ')}`);
88
+ console.log(`Ignoring flags on session attach: ${ignoredFlags.join(", ")}`);
79
89
  }
80
90
  const renderMarkdown = Boolean(sessionOptions.render || sessionOptions.renderMarkdown || autoRender);
81
91
  await deps.attachSession(sessionId, {
@@ -85,8 +95,8 @@ export async function handleSessionCommand(sessionId, command, deps = defaultDep
85
95
  });
86
96
  }
87
97
  export function formatSessionCleanupMessage(result, scope) {
88
- const deletedLabel = `${result.deleted} ${result.deleted === 1 ? 'session' : 'sessions'}`;
89
- const remainingLabel = `${result.remaining} ${result.remaining === 1 ? 'session' : 'sessions'} remain`;
98
+ const deletedLabel = `${result.deleted} ${result.deleted === 1 ? "session" : "sessions"}`;
99
+ const remainingLabel = `${result.remaining} ${result.remaining === 1 ? "session" : "sessions"} remain`;
90
100
  const hint = 'Run "oracle session --clear --all" to delete everything.';
91
101
  return `Deleted ${deletedLabel} (${scope}). ${remainingLabel}.\n${hint}`;
92
102
  }
@@ -98,7 +108,7 @@ function listIgnoredFlags(command) {
98
108
  continue;
99
109
  }
100
110
  const source = command.getOptionValueSource?.(key);
101
- if (source !== 'cli' && source !== 'env') {
111
+ if (source !== "cli" && source !== "env") {
102
112
  continue;
103
113
  }
104
114
  const value = opts[key];