@steipete/oracle 0.8.6 → 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.
- package/LICENSE +1 -1
- package/README.md +130 -45
- package/dist/bin/oracle-cli.js +613 -379
- package/dist/bin/oracle-mcp.js +2 -2
- package/dist/bin/oracle.js +165 -279
- package/dist/scripts/agent-send.js +31 -31
- package/dist/scripts/check.js +6 -6
- package/dist/scripts/debug/extract-chatgpt-response.js +10 -10
- package/dist/scripts/docs-list.js +30 -30
- package/dist/scripts/git-policy.js +25 -23
- package/dist/scripts/run-cli.js +8 -8
- package/dist/scripts/runner.js +203 -195
- package/dist/scripts/test-browser.js +21 -18
- package/dist/scripts/test-remote-chrome.js +20 -20
- package/dist/src/bridge/connection.js +18 -18
- package/dist/src/bridge/userConfigFile.js +7 -7
- package/dist/src/browser/actions/assistantResponse.js +149 -101
- package/dist/src/browser/actions/attachmentDataTransfer.js +49 -47
- package/dist/src/browser/actions/attachments.js +246 -150
- package/dist/src/browser/actions/domEvents.js +2 -2
- package/dist/src/browser/actions/modelSelection.js +314 -104
- package/dist/src/browser/actions/navigation.js +161 -136
- package/dist/src/browser/actions/promptComposer.js +100 -64
- package/dist/src/browser/actions/remoteFileTransfer.js +10 -10
- package/dist/src/browser/actions/thinkingTime.js +207 -110
- package/dist/src/browser/chromeLifecycle.js +62 -60
- package/dist/src/browser/config.js +34 -15
- package/dist/src/browser/constants.js +17 -12
- package/dist/src/browser/cookies.js +19 -19
- package/dist/src/browser/detect.js +62 -62
- package/dist/src/browser/domDebug.js +1 -1
- package/dist/src/browser/index.js +452 -303
- package/dist/src/browser/modelStrategy.js +1 -1
- package/dist/src/browser/pageActions.js +5 -5
- package/dist/src/browser/policies.js +16 -13
- package/dist/src/browser/profileState.js +44 -39
- package/dist/src/browser/prompt.js +72 -42
- package/dist/src/browser/promptSummary.js +5 -5
- package/dist/src/browser/providerDomFlow.js +17 -0
- package/dist/src/browser/providers/chatgptDomProvider.js +49 -0
- package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +254 -0
- package/dist/src/browser/providers/index.js +2 -0
- package/dist/src/browser/reattach.js +67 -34
- package/dist/src/browser/reattachHelpers.js +31 -26
- package/dist/src/browser/sessionRunner.js +37 -25
- package/dist/src/browser/utils.js +9 -9
- package/dist/src/browserMode.js +1 -1
- package/dist/src/cli/bridge/claudeConfig.js +16 -16
- package/dist/src/cli/bridge/client.js +28 -20
- package/dist/src/cli/bridge/codexConfig.js +16 -16
- package/dist/src/cli/bridge/doctor.js +47 -39
- package/dist/src/cli/bridge/host.js +58 -56
- package/dist/src/cli/browserConfig.js +65 -45
- package/dist/src/cli/browserDefaults.js +27 -26
- package/dist/src/cli/bundleWarnings.js +1 -1
- package/dist/src/cli/clipboard.js +11 -2
- package/dist/src/cli/detach.js +7 -4
- package/dist/src/cli/dryRun.js +29 -25
- package/dist/src/cli/duplicatePromptGuard.js +3 -3
- package/dist/src/cli/engine.js +9 -9
- package/dist/src/cli/errorUtils.js +1 -1
- package/dist/src/cli/fileSize.js +11 -0
- package/dist/src/cli/format.js +2 -2
- package/dist/src/cli/help.js +28 -28
- package/dist/src/cli/hiddenAliases.js +3 -3
- package/dist/src/cli/markdownBundle.js +12 -8
- package/dist/src/cli/markdownRenderer.js +15 -15
- package/dist/src/cli/notifier.js +77 -67
- package/dist/src/cli/options.js +145 -87
- package/dist/src/cli/oscUtils.js +1 -1
- package/dist/src/cli/promptRequirement.js +2 -2
- package/dist/src/cli/renderOutput.js +1 -1
- package/dist/src/cli/rootAlias.js +1 -1
- package/dist/src/cli/runOptions.js +37 -25
- package/dist/src/cli/sessionCommand.js +31 -21
- package/dist/src/cli/sessionDisplay.js +182 -79
- package/dist/src/cli/sessionLineage.js +60 -0
- package/dist/src/cli/sessionRunner.js +118 -90
- package/dist/src/cli/sessionTable.js +28 -24
- package/dist/src/cli/stdin.js +22 -0
- package/dist/src/cli/tagline.js +121 -124
- package/dist/src/cli/tui/index.js +140 -127
- package/dist/src/cli/writeOutputPath.js +5 -5
- package/dist/src/config.js +7 -7
- package/dist/src/gemini-web/browserSessionManager.js +80 -0
- package/dist/src/gemini-web/client.js +81 -64
- package/dist/src/gemini-web/executionMode.js +16 -0
- package/dist/src/gemini-web/executor.js +327 -169
- package/dist/src/gemini-web/index.js +1 -1
- package/dist/src/mcp/server.js +16 -12
- package/dist/src/mcp/tools/consult.js +81 -64
- package/dist/src/mcp/tools/sessionResources.js +12 -12
- package/dist/src/mcp/tools/sessions.js +26 -17
- package/dist/src/mcp/types.js +5 -5
- package/dist/src/mcp/utils.js +15 -7
- package/dist/src/oracle/background.js +15 -15
- package/dist/src/oracle/claude.js +53 -25
- package/dist/src/oracle/client.js +84 -46
- package/dist/src/oracle/config.js +124 -58
- package/dist/src/oracle/errors.js +38 -38
- package/dist/src/oracle/files.js +69 -45
- package/dist/src/oracle/finishLine.js +10 -8
- package/dist/src/oracle/format.js +3 -3
- package/dist/src/oracle/gemini.js +37 -30
- package/dist/src/oracle/logging.js +7 -7
- package/dist/src/oracle/markdown.js +28 -28
- package/dist/src/oracle/modelResolver.js +16 -16
- package/dist/src/oracle/multiModelRunner.js +12 -12
- package/dist/src/oracle/oscProgress.js +8 -8
- package/dist/src/oracle/promptAssembly.js +6 -3
- package/dist/src/oracle/request.js +23 -15
- package/dist/src/oracle/run.js +172 -140
- package/dist/src/oracle/runUtils.js +8 -5
- package/dist/src/oracle/tokenEstimate.js +6 -6
- package/dist/src/oracle/tokenStats.js +5 -5
- package/dist/src/oracle/tokenStringifier.js +5 -5
- package/dist/src/oracle.js +12 -12
- package/dist/src/oracleHome.js +3 -3
- package/dist/src/remote/client.js +25 -25
- package/dist/src/remote/health.js +20 -20
- package/dist/src/remote/remoteServiceConfig.js +9 -9
- package/dist/src/remote/server.js +129 -118
- package/dist/src/sessionManager.js +81 -75
- package/dist/src/sessionStore.js +3 -3
- package/dist/src/version.js +10 -10
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/dist/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/dist/vendor/oracle-notifier/README.md +2 -0
- package/package.json +69 -65
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/CodeResources +0 -0
- package/vendor/oracle-notifier/OracleNotifier.app/Contents/MacOS/OracleNotifier +0 -0
- package/vendor/oracle-notifier/README.md +2 -0
- package/dist/markdansi/types/index.js +0 -4
- package/dist/oracle/bin/oracle-cli.js +0 -472
- package/dist/oracle/src/browser/actions/assistantResponse.js +0 -471
- package/dist/oracle/src/browser/actions/attachments.js +0 -82
- package/dist/oracle/src/browser/actions/modelSelection.js +0 -190
- package/dist/oracle/src/browser/actions/navigation.js +0 -75
- package/dist/oracle/src/browser/actions/promptComposer.js +0 -167
- package/dist/oracle/src/browser/chromeLifecycle.js +0 -104
- package/dist/oracle/src/browser/config.js +0 -33
- package/dist/oracle/src/browser/constants.js +0 -40
- package/dist/oracle/src/browser/cookies.js +0 -210
- package/dist/oracle/src/browser/domDebug.js +0 -36
- package/dist/oracle/src/browser/index.js +0 -331
- package/dist/oracle/src/browser/pageActions.js +0 -5
- package/dist/oracle/src/browser/prompt.js +0 -88
- package/dist/oracle/src/browser/promptSummary.js +0 -20
- package/dist/oracle/src/browser/sessionRunner.js +0 -80
- package/dist/oracle/src/browser/utils.js +0 -62
- package/dist/oracle/src/browserMode.js +0 -1
- package/dist/oracle/src/cli/browserConfig.js +0 -44
- package/dist/oracle/src/cli/dryRun.js +0 -59
- package/dist/oracle/src/cli/engine.js +0 -17
- package/dist/oracle/src/cli/errorUtils.js +0 -9
- package/dist/oracle/src/cli/help.js +0 -70
- package/dist/oracle/src/cli/markdownRenderer.js +0 -15
- package/dist/oracle/src/cli/options.js +0 -103
- package/dist/oracle/src/cli/promptRequirement.js +0 -14
- package/dist/oracle/src/cli/rootAlias.js +0 -30
- package/dist/oracle/src/cli/sessionCommand.js +0 -77
- package/dist/oracle/src/cli/sessionDisplay.js +0 -270
- package/dist/oracle/src/cli/sessionRunner.js +0 -94
- package/dist/oracle/src/heartbeat.js +0 -43
- package/dist/oracle/src/oracle/client.js +0 -48
- package/dist/oracle/src/oracle/config.js +0 -29
- package/dist/oracle/src/oracle/errors.js +0 -101
- package/dist/oracle/src/oracle/files.js +0 -220
- package/dist/oracle/src/oracle/format.js +0 -33
- package/dist/oracle/src/oracle/fsAdapter.js +0 -7
- package/dist/oracle/src/oracle/oscProgress.js +0 -60
- package/dist/oracle/src/oracle/request.js +0 -48
- package/dist/oracle/src/oracle/run.js +0 -444
- package/dist/oracle/src/oracle/tokenStats.js +0 -39
- package/dist/oracle/src/oracle/types.js +0 -1
- package/dist/oracle/src/oracle.js +0 -9
- package/dist/oracle/src/sessionManager.js +0 -205
- package/dist/oracle/src/version.js +0 -39
- package/dist/scripts/chrome/browser-tools.js +0 -295
- package/dist/src/browser/profileSync.js +0 -141
- /package/dist/{oracle/src/browser/types.js → src/gemini-web/executionClients.js} +0 -0
package/dist/bin/oracle-mcp.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { startMcpServer } from
|
|
2
|
+
import { startMcpServer } from "../src/mcp/server.js";
|
|
3
3
|
startMcpServer().catch((error) => {
|
|
4
|
-
console.error(
|
|
4
|
+
console.error("oracle-mcp exited with an error:", error);
|
|
5
5
|
process.exitCode = 1;
|
|
6
6
|
});
|
package/dist/bin/oracle.js
CHANGED
|
@@ -4,70 +4,107 @@ import { Command, InvalidArgumentError, Option } from 'commander';
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import kleur from 'kleur';
|
|
6
6
|
import { ensureSessionStorage, initializeSession, updateSessionMetadata, readSessionMetadata, listSessionsMetadata, filterSessionsByRange, createSessionLogWriter, readSessionLog, wait, SESSIONS_DIR, deleteSessionsOlderThan, } from '../src/sessionManager.js';
|
|
7
|
-
import { runOracle, MODEL_CONFIGS, parseIntOption, renderPromptMarkdown, readFiles
|
|
8
|
-
import { runBrowserMode, CHATGPT_URL, DEFAULT_MODEL_TARGET, parseDuration } from '../src/browserMode.js';
|
|
7
|
+
import { runOracle, MODEL_CONFIGS, parseIntOption, renderPromptMarkdown, readFiles } from '../src/oracle.js';
|
|
9
8
|
const VERSION = '1.0.0';
|
|
10
9
|
const rawCliArgs = process.argv.slice(2);
|
|
11
10
|
const isTty = process.stdout.isTTY;
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
muted:
|
|
23
|
-
|
|
11
|
+
const HELP_THEME_NAMES = ['aurora', 'ember', 'slate'];
|
|
12
|
+
const passthrough = (text) => text;
|
|
13
|
+
const wrapForTty = (styler) => (text) => (isTty ? styler(text) : text);
|
|
14
|
+
const createTheme = (name, config) => ({
|
|
15
|
+
name,
|
|
16
|
+
banner: wrapForTty(config.banner),
|
|
17
|
+
subtitle: wrapForTty(config.subtitle),
|
|
18
|
+
heading: wrapForTty(config.heading),
|
|
19
|
+
bullet: wrapForTty(config.bullet),
|
|
20
|
+
body: wrapForTty(config.body),
|
|
21
|
+
muted: wrapForTty(config.muted),
|
|
22
|
+
command: wrapForTty(config.command),
|
|
23
|
+
accent: wrapForTty(config.accent),
|
|
24
|
+
});
|
|
25
|
+
const HELP_THEMES = {
|
|
26
|
+
aurora: createTheme('aurora', {
|
|
27
|
+
banner: (text) => kleur.bold().cyan(text),
|
|
28
|
+
subtitle: (text) => kleur.dim(text),
|
|
29
|
+
heading: (text) => kleur.bold().magenta(text),
|
|
30
|
+
bullet: (text) => kleur.cyan(text),
|
|
31
|
+
body: passthrough,
|
|
32
|
+
muted: (text) => kleur.gray(text),
|
|
33
|
+
command: (text) => kleur.bold().white(text),
|
|
34
|
+
accent: (text) => kleur.magenta(text),
|
|
35
|
+
}),
|
|
36
|
+
ember: createTheme('ember', {
|
|
37
|
+
banner: (text) => kleur.bold().yellow(text),
|
|
38
|
+
subtitle: (text) => kleur.dim(text),
|
|
39
|
+
heading: (text) => kleur.bold().red(text),
|
|
40
|
+
bullet: (text) => kleur.yellow(text),
|
|
41
|
+
body: passthrough,
|
|
42
|
+
muted: (text) => kleur.dim(text),
|
|
43
|
+
command: (text) => kleur.bold().yellow(text),
|
|
44
|
+
accent: (text) => kleur.red(text),
|
|
45
|
+
}),
|
|
46
|
+
slate: createTheme('slate', {
|
|
47
|
+
banner: (text) => kleur.bold().blue(text),
|
|
48
|
+
subtitle: (text) => kleur.dim(text),
|
|
49
|
+
heading: (text) => kleur.bold().white(text),
|
|
50
|
+
bullet: (text) => kleur.blue(text),
|
|
51
|
+
body: passthrough,
|
|
52
|
+
muted: (text) => kleur.gray(text),
|
|
53
|
+
command: (text) => kleur.bold().blue(text),
|
|
54
|
+
accent: (text) => kleur.cyan(text),
|
|
55
|
+
}),
|
|
24
56
|
};
|
|
57
|
+
const helpThemeName = resolveHelpThemeName(rawCliArgs, process.env.ORACLE_HELP_THEME);
|
|
58
|
+
const helpTheme = HELP_THEMES[helpThemeName];
|
|
59
|
+
function resolveHelpThemeName(args, envValue) {
|
|
60
|
+
const fromArgs = extractHelpThemeFromArgs(args);
|
|
61
|
+
if (isHelpThemeName(fromArgs)) {
|
|
62
|
+
return fromArgs;
|
|
63
|
+
}
|
|
64
|
+
const fromEnv = envValue?.toLowerCase();
|
|
65
|
+
if (isHelpThemeName(fromEnv)) {
|
|
66
|
+
return fromEnv;
|
|
67
|
+
}
|
|
68
|
+
return 'aurora';
|
|
69
|
+
}
|
|
70
|
+
function extractHelpThemeFromArgs(args) {
|
|
71
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
72
|
+
const current = args[index];
|
|
73
|
+
if (current === '--help-theme') {
|
|
74
|
+
const maybeTheme = args[index + 1];
|
|
75
|
+
if (maybeTheme) {
|
|
76
|
+
return maybeTheme.toLowerCase();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (current.startsWith('--help-theme=')) {
|
|
80
|
+
return current.split('=')[1]?.toLowerCase();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
function isHelpThemeName(value) {
|
|
86
|
+
if (!value) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
return HELP_THEME_NAMES.includes(value);
|
|
90
|
+
}
|
|
25
91
|
const program = new Command();
|
|
26
|
-
program.configureHelp({
|
|
27
|
-
styleTitle(title) {
|
|
28
|
-
return helpColors.section(title);
|
|
29
|
-
},
|
|
30
|
-
styleDescriptionText(text) {
|
|
31
|
-
return helpColors.description(text);
|
|
32
|
-
},
|
|
33
|
-
styleCommandText(text) {
|
|
34
|
-
return helpColors.command(text);
|
|
35
|
-
},
|
|
36
|
-
styleSubcommandText(text) {
|
|
37
|
-
return helpColors.command(text);
|
|
38
|
-
},
|
|
39
|
-
styleOptionText(text) {
|
|
40
|
-
return helpColors.option(text);
|
|
41
|
-
},
|
|
42
|
-
styleArgumentText(text) {
|
|
43
|
-
return helpColors.argument(text);
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
92
|
program
|
|
47
93
|
.name('oracle')
|
|
48
94
|
.description('One-shot GPT-5 Pro / GPT-5.1 tool for hard questions that benefit from large file context and server-side search.')
|
|
49
95
|
.version(VERSION)
|
|
50
96
|
.option('-p, --prompt <text>', 'User prompt to send to the model.')
|
|
51
97
|
.option('-f, --file <paths...>', 'Paths to files or directories to append to the prompt; repeat, comma-separate, or supply a space-separated list.', collectPaths, [])
|
|
52
|
-
.option('-s, --slug <words>', 'Custom session slug (3-5 words).')
|
|
53
98
|
.option('-m, --model <model>', 'Model to target (gpt-5-pro | gpt-5.1).', validateModel, 'gpt-5-pro')
|
|
54
99
|
.option('--files-report', 'Show token usage per attached file (also prints automatically when files exceed the token budget).', false)
|
|
55
|
-
.option('-v, --verbose', 'Enable verbose logging for all operations.', false)
|
|
56
100
|
.addOption(new Option('--preview [mode]', 'Preview the request without calling the API (summary | json | full).')
|
|
57
101
|
.choices(['summary', 'json', 'full'])
|
|
58
102
|
.preset('summary'))
|
|
103
|
+
.addOption(new Option('--help-theme <theme>', 'Choose a color palette for --help output.')
|
|
104
|
+
.choices(Array.from(HELP_THEME_NAMES))
|
|
105
|
+
.env('ORACLE_HELP_THEME'))
|
|
59
106
|
.addOption(new Option('--exec-session <id>').hideHelp())
|
|
60
107
|
.option('--render-markdown', 'Emit the assembled markdown bundle for prompt + files and exit.', false)
|
|
61
|
-
.option('--browser', 'Run the prompt via the ChatGPT web UI (Chrome automation).', false)
|
|
62
|
-
.option('--browser-chrome-profile <name>', 'Chrome profile name/path for cookie reuse.')
|
|
63
|
-
.option('--browser-chrome-path <path>', 'Explicit Chrome or Chromium executable path.')
|
|
64
|
-
.option('--browser-url <url>', `Override the ChatGPT URL (default ${CHATGPT_URL}).`)
|
|
65
|
-
.option('--browser-timeout <ms|s|m>', 'Maximum time to wait for an answer (default 900s).')
|
|
66
|
-
.option('--browser-input-timeout <ms|s|m>', 'Maximum time to wait for the prompt textarea (default 30s).')
|
|
67
|
-
.option('--browser-no-cookie-sync', 'Skip copying cookies from Chrome.', false)
|
|
68
|
-
.option('--browser-headless', 'Launch Chrome in headless mode.', false)
|
|
69
|
-
.option('--browser-hide-window', 'Hide the Chrome window after launch (macOS headful only).', false)
|
|
70
|
-
.option('--browser-keep-browser', 'Keep Chrome running after completion.', false)
|
|
71
108
|
.showHelpAfterError('(use --help for usage)');
|
|
72
109
|
program
|
|
73
110
|
.command('session [id]')
|
|
@@ -75,10 +112,10 @@ program
|
|
|
75
112
|
.option('--hours <hours>', 'Look back this many hours when listing sessions (default 24).', parseFloatOption, 24)
|
|
76
113
|
.option('--limit <count>', 'Maximum sessions to show when listing (max 1000).', parseIntOption, 100)
|
|
77
114
|
.option('--all', 'Include all stored sessions regardless of age.', false)
|
|
78
|
-
.action(async (sessionId
|
|
79
|
-
const sessionOptions =
|
|
115
|
+
.action(async function (sessionId) {
|
|
116
|
+
const sessionOptions = this.opts();
|
|
80
117
|
if (!sessionId) {
|
|
81
|
-
const showExamples = usesDefaultStatusFilters(
|
|
118
|
+
const showExamples = usesDefaultStatusFilters(this);
|
|
82
119
|
await showStatus({
|
|
83
120
|
hours: sessionOptions.all ? Infinity : sessionOptions.hours,
|
|
84
121
|
includeAll: sessionOptions.all,
|
|
@@ -95,9 +132,9 @@ const statusCommand = program
|
|
|
95
132
|
.option('--hours <hours>', 'Look back this many hours (default 24).', parseFloatOption, 24)
|
|
96
133
|
.option('--limit <count>', 'Maximum sessions to show (max 1000).', parseIntOption, 100)
|
|
97
134
|
.option('--all', 'Include all stored sessions regardless of age.', false)
|
|
98
|
-
.action(async (
|
|
99
|
-
const statusOptions =
|
|
100
|
-
const showExamples = usesDefaultStatusFilters(
|
|
135
|
+
.action(async function () {
|
|
136
|
+
const statusOptions = this.opts();
|
|
137
|
+
const showExamples = usesDefaultStatusFilters(this);
|
|
101
138
|
await showStatus({
|
|
102
139
|
hours: statusOptions.all ? Infinity : statusOptions.hours,
|
|
103
140
|
includeAll: statusOptions.all,
|
|
@@ -110,42 +147,63 @@ statusCommand
|
|
|
110
147
|
.description('Delete stored sessions older than the provided window (24h default).')
|
|
111
148
|
.option('--hours <hours>', 'Delete sessions older than this many hours (default 24).', parseFloatOption, 24)
|
|
112
149
|
.option('--all', 'Delete all stored sessions.', false)
|
|
113
|
-
.action(async (
|
|
114
|
-
const clearOptions =
|
|
150
|
+
.action(async function () {
|
|
151
|
+
const clearOptions = this.opts();
|
|
115
152
|
const result = await deleteSessionsOlderThan({ hours: clearOptions.hours, includeAll: clearOptions.all });
|
|
116
153
|
const scope = clearOptions.all ? 'all stored sessions' : `sessions older than ${clearOptions.hours}h`;
|
|
117
154
|
console.log(`Deleted ${result.deleted} ${result.deleted === 1 ? 'session' : 'sessions'} (${scope}).`);
|
|
118
155
|
});
|
|
119
156
|
const bold = (text) => (isTty ? kleur.bold(text) : text);
|
|
120
157
|
const dim = (text) => (isTty ? kleur.dim(text) : text);
|
|
121
|
-
program.addHelpText('beforeAll', renderHelpBanner);
|
|
122
|
-
program.addHelpText('after', renderHelpFooter);
|
|
123
|
-
function renderHelpBanner() {
|
|
158
|
+
program.addHelpText('beforeAll', () => renderHelpBanner(helpTheme));
|
|
159
|
+
program.addHelpText('after', () => renderHelpFooter(helpTheme));
|
|
160
|
+
function renderHelpBanner(theme) {
|
|
124
161
|
const subtitle = 'GPT-5 Pro/GPT-5.1 for tough questions with code/file context.';
|
|
125
|
-
return `${
|
|
162
|
+
return `${theme.banner(`Oracle CLI v${VERSION}`)} ${theme.subtitle(`— ${subtitle}`)}\n`;
|
|
126
163
|
}
|
|
127
|
-
function renderHelpFooter() {
|
|
128
|
-
const
|
|
129
|
-
`${
|
|
130
|
-
`${
|
|
131
|
-
`${
|
|
132
|
-
`${
|
|
133
|
-
|
|
164
|
+
function renderHelpFooter(theme) {
|
|
165
|
+
const tipLines = [
|
|
166
|
+
`${theme.bullet(' •')} Attach source files for best results, but keep total input under ~196k tokens.`,
|
|
167
|
+
`${theme.bullet(' •')} The model has no built-in knowledge of your project—open with the architecture, key components, and why you’re asking.`,
|
|
168
|
+
`${theme.bullet(' •')} Run ${theme.accent('--files-report')} to see per-file token impact before spending money.`,
|
|
169
|
+
`${theme.bullet(' •')} Non-preview runs spawn detached sessions so requests keep running even if your terminal closes.`,
|
|
170
|
+
].join('\n');
|
|
171
|
+
const exampleEntries = [
|
|
172
|
+
{
|
|
173
|
+
command: `${program.name()} --prompt "Summarize risks" --file docs/risk.md --files-report --preview`,
|
|
174
|
+
description: 'Inspect tokens + files without calling the API.',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
command: `${program.name()} --prompt "Explain bug" --file src/,docs/crash.log --files-report`,
|
|
178
|
+
description: 'Attach src/ plus docs/crash.log, launch a background session, and capture the Session ID.',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
command: `${program.name()} status --hours 72 --limit 50`,
|
|
182
|
+
description: 'Show sessions from the last 72h (capped at 50 entries).',
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
command: `${program.name()} session <sessionId>`,
|
|
186
|
+
description: 'Attach to a running/completed session and stream the saved transcript.',
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
const exampleLines = exampleEntries
|
|
190
|
+
.map((entry) => `${theme.command(` ${entry.command}`)}\n${theme.muted(` ${entry.description}`)}`)
|
|
191
|
+
.join('\n\n');
|
|
192
|
+
const paletteList = HELP_THEME_NAMES.map((name) => name === theme.name ? theme.command(name) : theme.accent(name)).join(theme.muted(', '));
|
|
193
|
+
const themeLines = [
|
|
194
|
+
`${theme.bullet(' •')} Current: ${theme.command(theme.name)}`,
|
|
195
|
+
`${theme.bullet(' •')} Try: ${paletteList}`,
|
|
196
|
+
`${theme.bullet(' •')} Switch via ${theme.accent('--help-theme <name>')} or ${theme.accent('ORACLE_HELP_THEME=<name>')}.`,
|
|
134
197
|
].join('\n');
|
|
135
|
-
const formatExample = (command, description) => `${helpColors.command(` ${command}`)}\n${helpColors.muted(` ${description}`)}`;
|
|
136
|
-
const examples = [
|
|
137
|
-
formatExample(`${program.name()} --prompt "Summarize risks" --file docs/risk.md --files-report --preview`, 'Inspect tokens + files without calling the API.'),
|
|
138
|
-
formatExample(`${program.name()} --prompt "Explain bug" --file src/,docs/crash.log --files-report`, 'Attach src/ plus docs/crash.log, launch a background session, and capture the Session ID.'),
|
|
139
|
-
formatExample(`${program.name()} status --hours 72 --limit 50`, 'Show sessions from the last 72h (capped at 50 entries).'),
|
|
140
|
-
formatExample(`${program.name()} session <sessionId>`, 'Attach to a running/completed session and stream the saved transcript.'),
|
|
141
|
-
formatExample(`${program.name()} --prompt "Ship review" --slug "release-readiness-audit"`, 'Encourage the model to hand you a 3–5 word slug and pass it along with --slug.'),
|
|
142
|
-
].join('\n\n');
|
|
143
198
|
return `
|
|
144
|
-
${
|
|
145
|
-
${
|
|
199
|
+
${theme.heading('Tips')}
|
|
200
|
+
${tipLines}
|
|
201
|
+
|
|
202
|
+
${theme.heading('Examples')}
|
|
203
|
+
${exampleLines}
|
|
146
204
|
|
|
147
|
-
${
|
|
148
|
-
${
|
|
205
|
+
${theme.heading('Color Themes')}
|
|
206
|
+
${themeLines}
|
|
149
207
|
`;
|
|
150
208
|
}
|
|
151
209
|
function collectPaths(value, previous = []) {
|
|
@@ -162,32 +220,6 @@ function parseFloatOption(value) {
|
|
|
162
220
|
}
|
|
163
221
|
return parsed;
|
|
164
222
|
}
|
|
165
|
-
const DEFAULT_BROWSER_TIMEOUT_MS = 900_000;
|
|
166
|
-
const DEFAULT_BROWSER_INPUT_TIMEOUT_MS = 30_000;
|
|
167
|
-
const BROWSER_MODEL_LABELS = {
|
|
168
|
-
'gpt-5-pro': 'GPT-5 Pro',
|
|
169
|
-
'gpt-5.1': 'ChatGPT 5.1',
|
|
170
|
-
};
|
|
171
|
-
function buildBrowserConfig(options) {
|
|
172
|
-
return {
|
|
173
|
-
chromeProfile: options.browserChromeProfile ?? null,
|
|
174
|
-
chromePath: options.browserChromePath ?? null,
|
|
175
|
-
url: options.browserUrl,
|
|
176
|
-
timeoutMs: options.browserTimeout ? parseDuration(options.browserTimeout, DEFAULT_BROWSER_TIMEOUT_MS) : undefined,
|
|
177
|
-
inputTimeoutMs: options.browserInputTimeout
|
|
178
|
-
? parseDuration(options.browserInputTimeout, DEFAULT_BROWSER_INPUT_TIMEOUT_MS)
|
|
179
|
-
: undefined,
|
|
180
|
-
cookieSync: options.browserNoCookieSync ? false : undefined,
|
|
181
|
-
headless: options.browserHeadless ? true : undefined,
|
|
182
|
-
keepBrowser: options.browserKeepBrowser ? true : undefined,
|
|
183
|
-
hideWindow: options.browserHideWindow ? true : undefined,
|
|
184
|
-
desiredModel: mapModelToBrowserLabel(options.model),
|
|
185
|
-
debug: options.verbose ? true : undefined,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
function mapModelToBrowserLabel(model) {
|
|
189
|
-
return BROWSER_MODEL_LABELS[model] ?? DEFAULT_MODEL_TARGET;
|
|
190
|
-
}
|
|
191
223
|
function validateModel(value) {
|
|
192
224
|
if (!(value in MODEL_CONFIGS)) {
|
|
193
225
|
throw new InvalidArgumentError(`Unsupported model "${value}". Choose one of: ${Object.keys(MODEL_CONFIGS).join(', ')}`);
|
|
@@ -217,7 +249,6 @@ function buildRunOptions(options, overrides = {}) {
|
|
|
217
249
|
prompt: options.prompt,
|
|
218
250
|
model: options.model,
|
|
219
251
|
file: overrides.file ?? options.file ?? [],
|
|
220
|
-
slug: overrides.slug ?? options.slug,
|
|
221
252
|
filesReport: overrides.filesReport ?? options.filesReport,
|
|
222
253
|
maxInput: overrides.maxInput ?? options.maxInput,
|
|
223
254
|
maxOutput: overrides.maxOutput ?? options.maxOutput,
|
|
@@ -228,7 +259,6 @@ function buildRunOptions(options, overrides = {}) {
|
|
|
228
259
|
previewMode: overrides.previewMode ?? options.previewMode,
|
|
229
260
|
apiKey: overrides.apiKey ?? options.apiKey,
|
|
230
261
|
sessionId: overrides.sessionId ?? options.sessionId,
|
|
231
|
-
verbose: overrides.verbose ?? options.verbose,
|
|
232
262
|
};
|
|
233
263
|
}
|
|
234
264
|
function buildRunOptionsFromMetadata(metadata) {
|
|
@@ -237,7 +267,6 @@ function buildRunOptionsFromMetadata(metadata) {
|
|
|
237
267
|
prompt: stored.prompt ?? '',
|
|
238
268
|
model: stored.model ?? 'gpt-5-pro',
|
|
239
269
|
file: stored.file ?? [],
|
|
240
|
-
slug: stored.slug,
|
|
241
270
|
filesReport: stored.filesReport,
|
|
242
271
|
maxInput: stored.maxInput,
|
|
243
272
|
maxOutput: stored.maxOutput,
|
|
@@ -248,15 +277,8 @@ function buildRunOptionsFromMetadata(metadata) {
|
|
|
248
277
|
previewMode: undefined,
|
|
249
278
|
apiKey: undefined,
|
|
250
279
|
sessionId: metadata.id,
|
|
251
|
-
verbose: stored.verbose,
|
|
252
280
|
};
|
|
253
281
|
}
|
|
254
|
-
function getSessionMode(metadata) {
|
|
255
|
-
return metadata.mode ?? metadata.options?.mode ?? 'api';
|
|
256
|
-
}
|
|
257
|
-
function getBrowserConfigFromMetadata(metadata) {
|
|
258
|
-
return metadata.options?.browserConfig ?? metadata.browser?.config;
|
|
259
|
-
}
|
|
260
282
|
async function runRootCommand(options) {
|
|
261
283
|
const helpRequested = rawCliArgs.some((arg) => arg === '--help' || arg === '-h');
|
|
262
284
|
if (helpRequested) {
|
|
@@ -286,9 +308,6 @@ async function runRootCommand(options) {
|
|
|
286
308
|
return;
|
|
287
309
|
}
|
|
288
310
|
if (previewMode) {
|
|
289
|
-
if (options.browser) {
|
|
290
|
-
throw new Error('--browser cannot be combined with --preview.');
|
|
291
|
-
}
|
|
292
311
|
if (!options.prompt) {
|
|
293
312
|
throw new Error('Prompt is required when using --preview.');
|
|
294
313
|
}
|
|
@@ -302,20 +321,14 @@ async function runRootCommand(options) {
|
|
|
302
321
|
if (options.file && options.file.length > 0) {
|
|
303
322
|
await readFiles(options.file, { cwd: process.cwd() });
|
|
304
323
|
}
|
|
305
|
-
const sessionMode = options.browser ? 'browser' : 'api';
|
|
306
|
-
const browserConfig = sessionMode === 'browser' ? buildBrowserConfig(options) : undefined;
|
|
307
324
|
await ensureSessionStorage();
|
|
308
325
|
const baseRunOptions = buildRunOptions(options, { preview: false, previewMode: undefined });
|
|
309
|
-
const sessionMeta = await initializeSession(
|
|
310
|
-
...baseRunOptions,
|
|
311
|
-
mode: sessionMode,
|
|
312
|
-
browserConfig,
|
|
313
|
-
}, process.cwd());
|
|
326
|
+
const sessionMeta = await initializeSession(baseRunOptions, process.cwd());
|
|
314
327
|
const liveRunOptions = { ...baseRunOptions, sessionId: sessionMeta.id };
|
|
315
|
-
await runInteractiveSession(sessionMeta, liveRunOptions
|
|
328
|
+
await runInteractiveSession(sessionMeta, liveRunOptions);
|
|
316
329
|
console.log(chalk.bold(`Session ${sessionMeta.id} completed`));
|
|
317
330
|
}
|
|
318
|
-
async function runInteractiveSession(sessionMeta, runOptions
|
|
331
|
+
async function runInteractiveSession(sessionMeta, runOptions) {
|
|
319
332
|
const { logLine, writeChunk, stream } = createSessionLogWriter(sessionMeta.id);
|
|
320
333
|
let headerAugmented = false;
|
|
321
334
|
const combinedLog = (message = '') => {
|
|
@@ -333,17 +346,29 @@ async function runInteractiveSession(sessionMeta, runOptions, mode, browserConfi
|
|
|
333
346
|
return process.stdout.write(chunk);
|
|
334
347
|
};
|
|
335
348
|
try {
|
|
336
|
-
await
|
|
337
|
-
|
|
338
|
-
runOptions,
|
|
339
|
-
mode,
|
|
340
|
-
browserConfig,
|
|
341
|
-
cwd: process.cwd(),
|
|
349
|
+
await updateSessionMetadata(sessionMeta.id, { status: 'running', startedAt: new Date().toISOString() });
|
|
350
|
+
const result = await runOracle(runOptions, {
|
|
342
351
|
log: combinedLog,
|
|
343
352
|
write: combinedWrite,
|
|
344
353
|
});
|
|
354
|
+
if (result.mode !== 'live') {
|
|
355
|
+
throw new Error('Unexpected preview result while running an interactive session.');
|
|
356
|
+
}
|
|
357
|
+
await updateSessionMetadata(sessionMeta.id, {
|
|
358
|
+
status: 'completed',
|
|
359
|
+
completedAt: new Date().toISOString(),
|
|
360
|
+
usage: result.usage,
|
|
361
|
+
elapsedMs: result.elapsedMs,
|
|
362
|
+
});
|
|
345
363
|
}
|
|
346
364
|
catch (error) {
|
|
365
|
+
const message = formatError(error);
|
|
366
|
+
combinedLog(`ERROR: ${message}`);
|
|
367
|
+
await updateSessionMetadata(sessionMeta.id, {
|
|
368
|
+
status: 'error',
|
|
369
|
+
completedAt: new Date().toISOString(),
|
|
370
|
+
errorMessage: message,
|
|
371
|
+
});
|
|
347
372
|
throw error;
|
|
348
373
|
}
|
|
349
374
|
finally {
|
|
@@ -358,152 +383,36 @@ async function executeSession(sessionId) {
|
|
|
358
383
|
return;
|
|
359
384
|
}
|
|
360
385
|
const runOptions = buildRunOptionsFromMetadata(metadata);
|
|
361
|
-
const sessionMode = getSessionMode(metadata);
|
|
362
|
-
const browserConfig = getBrowserConfigFromMetadata(metadata);
|
|
363
386
|
const { logLine, writeChunk, stream } = createSessionLogWriter(sessionId);
|
|
364
387
|
try {
|
|
365
|
-
await
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
mode: sessionMode,
|
|
369
|
-
browserConfig,
|
|
370
|
-
cwd: metadata.cwd ?? process.cwd(),
|
|
388
|
+
await updateSessionMetadata(sessionId, { status: 'running', startedAt: new Date().toISOString() });
|
|
389
|
+
const result = await runOracle(runOptions, {
|
|
390
|
+
cwd: metadata.cwd,
|
|
371
391
|
log: logLine,
|
|
372
392
|
write: writeChunk,
|
|
373
393
|
});
|
|
374
|
-
}
|
|
375
|
-
catch {
|
|
376
|
-
// Errors are already logged to the session log; keep quiet to mirror stored-session behavior.
|
|
377
|
-
}
|
|
378
|
-
finally {
|
|
379
|
-
stream.end();
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
async function performSessionRun({ sessionMeta, runOptions, mode, browserConfig, cwd, log, write, }) {
|
|
383
|
-
await updateSessionMetadata(sessionMeta.id, {
|
|
384
|
-
status: 'running',
|
|
385
|
-
startedAt: new Date().toISOString(),
|
|
386
|
-
mode,
|
|
387
|
-
...(browserConfig ? { browser: { config: browserConfig } } : {}),
|
|
388
|
-
});
|
|
389
|
-
try {
|
|
390
|
-
if (mode === 'browser') {
|
|
391
|
-
if (!browserConfig) {
|
|
392
|
-
throw new Error('Missing browser configuration for session.');
|
|
393
|
-
}
|
|
394
|
-
const result = await runBrowserSessionExecution({
|
|
395
|
-
runOptions,
|
|
396
|
-
browserConfig,
|
|
397
|
-
cwd,
|
|
398
|
-
log,
|
|
399
|
-
});
|
|
400
|
-
await updateSessionMetadata(sessionMeta.id, {
|
|
401
|
-
status: 'completed',
|
|
402
|
-
completedAt: new Date().toISOString(),
|
|
403
|
-
usage: result.usage,
|
|
404
|
-
elapsedMs: result.elapsedMs,
|
|
405
|
-
browser: {
|
|
406
|
-
config: browserConfig,
|
|
407
|
-
runtime: result.runtime,
|
|
408
|
-
},
|
|
409
|
-
response: undefined,
|
|
410
|
-
});
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
const result = await runOracle(runOptions, {
|
|
414
|
-
cwd,
|
|
415
|
-
log,
|
|
416
|
-
write,
|
|
417
|
-
});
|
|
418
394
|
if (result.mode !== 'live') {
|
|
419
|
-
throw new Error('Unexpected preview result while
|
|
395
|
+
throw new Error('Unexpected preview result while executing a stored session.');
|
|
420
396
|
}
|
|
421
|
-
await updateSessionMetadata(
|
|
397
|
+
await updateSessionMetadata(sessionId, {
|
|
422
398
|
status: 'completed',
|
|
423
399
|
completedAt: new Date().toISOString(),
|
|
424
400
|
usage: result.usage,
|
|
425
401
|
elapsedMs: result.elapsedMs,
|
|
426
|
-
response: extractResponseMetadata(result.response),
|
|
427
402
|
});
|
|
428
403
|
}
|
|
429
404
|
catch (error) {
|
|
430
405
|
const message = formatError(error);
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
const metadataLine = formatResponseMetadata(responseMetadata);
|
|
434
|
-
if (metadataLine) {
|
|
435
|
-
log(dim(`Response metadata: ${metadataLine}`));
|
|
436
|
-
}
|
|
437
|
-
await updateSessionMetadata(sessionMeta.id, {
|
|
406
|
+
logLine(`ERROR: ${message}`);
|
|
407
|
+
await updateSessionMetadata(sessionId, {
|
|
438
408
|
status: 'error',
|
|
439
409
|
completedAt: new Date().toISOString(),
|
|
440
410
|
errorMessage: message,
|
|
441
|
-
mode,
|
|
442
|
-
browser: browserConfig ? { config: browserConfig } : undefined,
|
|
443
|
-
response: responseMetadata,
|
|
444
411
|
});
|
|
445
|
-
throw error;
|
|
446
412
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
const promptArtifacts = await assembleBrowserPrompt(runOptions, cwd);
|
|
450
|
-
if (runOptions.verbose) {
|
|
451
|
-
log(dim(`[verbose] Browser config: ${JSON.stringify({
|
|
452
|
-
...browserConfig,
|
|
453
|
-
})}`));
|
|
454
|
-
log(dim(`[verbose] Browser prompt length: ${promptArtifacts.markdown.length} chars`));
|
|
455
|
-
}
|
|
456
|
-
const headerLine = `Oracle (${VERSION}) launching browser mode (${runOptions.model}) with ~${promptArtifacts.estimatedInputTokens.toLocaleString()} tokens`;
|
|
457
|
-
log(headerLine);
|
|
458
|
-
log(dim('Chrome automation does not stream output; this may take a minute...'));
|
|
459
|
-
const browserResult = await runBrowserMode({
|
|
460
|
-
prompt: promptArtifacts.markdown,
|
|
461
|
-
config: browserConfig,
|
|
462
|
-
log,
|
|
463
|
-
});
|
|
464
|
-
if (!runOptions.silent) {
|
|
465
|
-
log(chalk.bold('Answer:'));
|
|
466
|
-
log(browserResult.answerMarkdown || browserResult.answerText || chalk.dim('(no text output)'));
|
|
467
|
-
log('');
|
|
468
|
-
}
|
|
469
|
-
const usage = {
|
|
470
|
-
inputTokens: promptArtifacts.estimatedInputTokens,
|
|
471
|
-
outputTokens: browserResult.answerTokens,
|
|
472
|
-
reasoningTokens: 0,
|
|
473
|
-
totalTokens: promptArtifacts.estimatedInputTokens + browserResult.answerTokens,
|
|
474
|
-
};
|
|
475
|
-
const tokensDisplay = `${usage.inputTokens}/${usage.outputTokens}/${usage.reasoningTokens}/${usage.totalTokens}`;
|
|
476
|
-
const statsParts = [`${runOptions.model}[browser]`, `tok(i/o/r/t)=${tokensDisplay}`];
|
|
477
|
-
if (runOptions.file && runOptions.file.length > 0) {
|
|
478
|
-
statsParts.push(`files=${runOptions.file.length}`);
|
|
413
|
+
finally {
|
|
414
|
+
stream.end();
|
|
479
415
|
}
|
|
480
|
-
log(chalk.blue(`Finished in ${formatElapsed(browserResult.tookMs)} (${statsParts.join(' | ')})`));
|
|
481
|
-
return {
|
|
482
|
-
usage,
|
|
483
|
-
elapsedMs: browserResult.tookMs,
|
|
484
|
-
runtime: {
|
|
485
|
-
chromePid: browserResult.chromePid,
|
|
486
|
-
chromePort: browserResult.chromePort,
|
|
487
|
-
userDataDir: browserResult.userDataDir,
|
|
488
|
-
},
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
async function assembleBrowserPrompt(runOptions, cwd) {
|
|
492
|
-
const files = await readFiles(runOptions.file ?? [], { cwd });
|
|
493
|
-
const userPrompt = buildPrompt(runOptions.prompt, files, cwd);
|
|
494
|
-
const systemPrompt = runOptions.system?.trim() || DEFAULT_SYSTEM_PROMPT;
|
|
495
|
-
const sections = createFileSections(files, cwd);
|
|
496
|
-
const lines = ['[SYSTEM]', systemPrompt, '', '[USER]', userPrompt, ''];
|
|
497
|
-
sections.forEach((section) => {
|
|
498
|
-
lines.push(`[FILE: ${section.displayPath}]`, section.content.trimEnd(), '');
|
|
499
|
-
});
|
|
500
|
-
const markdown = lines.join('\n').trimEnd();
|
|
501
|
-
const tokenizer = MODEL_CONFIGS[runOptions.model].tokenizer;
|
|
502
|
-
const estimatedInputTokens = tokenizer([
|
|
503
|
-
{ role: 'system', content: systemPrompt },
|
|
504
|
-
{ role: 'user', content: userPrompt },
|
|
505
|
-
], TOKENIZER_OPTIONS);
|
|
506
|
-
return { markdown, estimatedInputTokens };
|
|
507
416
|
}
|
|
508
417
|
async function showStatus({ hours, includeAll, limit, showExamples = false }) {
|
|
509
418
|
const metas = await listSessionsMetadata();
|
|
@@ -556,10 +465,6 @@ async function attachSession(sessionId) {
|
|
|
556
465
|
console.log(`Created: ${metadata.createdAt}`);
|
|
557
466
|
console.log(`Status: ${metadata.status}`);
|
|
558
467
|
console.log(`Model: ${metadata.model}`);
|
|
559
|
-
const responseSummary = formatResponseMetadata(metadata.response);
|
|
560
|
-
if (responseSummary) {
|
|
561
|
-
console.log(dim(`Response: ${responseSummary}`));
|
|
562
|
-
}
|
|
563
468
|
let lastLength = 0;
|
|
564
469
|
const printNew = async () => {
|
|
565
470
|
const text = await readSessionLog(sessionId);
|
|
@@ -594,25 +499,6 @@ async function attachSession(sessionId) {
|
|
|
594
499
|
function formatError(error) {
|
|
595
500
|
return error instanceof Error ? error.message : String(error);
|
|
596
501
|
}
|
|
597
|
-
function formatResponseMetadata(metadata) {
|
|
598
|
-
if (!metadata) {
|
|
599
|
-
return null;
|
|
600
|
-
}
|
|
601
|
-
const parts = [];
|
|
602
|
-
if (metadata.responseId) {
|
|
603
|
-
parts.push(`response=${metadata.responseId}`);
|
|
604
|
-
}
|
|
605
|
-
if (metadata.requestId) {
|
|
606
|
-
parts.push(`request=${metadata.requestId}`);
|
|
607
|
-
}
|
|
608
|
-
if (metadata.status) {
|
|
609
|
-
parts.push(`status=${metadata.status}`);
|
|
610
|
-
}
|
|
611
|
-
if (metadata.incompleteReason) {
|
|
612
|
-
parts.push(`incomplete=${metadata.incompleteReason}`);
|
|
613
|
-
}
|
|
614
|
-
return parts.length > 0 ? parts.join(' | ') : null;
|
|
615
|
-
}
|
|
616
502
|
function buildReattachLine(metadata) {
|
|
617
503
|
if (!metadata.id) {
|
|
618
504
|
return null;
|