@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.
- package/LICENSE +1 -1
- package/README.md +61 -48
- package/dist/bin/oracle-cli.js +455 -402
- 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 +275 -117
- package/dist/src/browser/actions/navigation.js +161 -137
- 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 +390 -295
- 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 +1 -1
- package/dist/src/browser/providers/chatgptDomProvider.js +9 -9
- package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +51 -42
- package/dist/src/browser/providers/index.js +2 -2
- 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 +62 -48
- 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 +2 -2
- 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 +3 -3
- 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 +7 -7
- package/dist/src/cli/markdownRenderer.js +15 -15
- package/dist/src/cli/notifier.js +77 -67
- package/dist/src/cli/options.js +127 -106
- 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 +32 -28
- package/dist/src/cli/sessionCommand.js +31 -21
- package/dist/src/cli/sessionDisplay.js +95 -81
- package/dist/src/cli/sessionLineage.js +6 -2
- package/dist/src/cli/sessionRunner.js +103 -93
- package/dist/src/cli/sessionTable.js +26 -23
- package/dist/src/cli/stdin.js +22 -0
- package/dist/src/cli/tagline.js +121 -124
- package/dist/src/cli/tui/index.js +139 -128
- package/dist/src/cli/writeOutputPath.js +5 -5
- package/dist/src/config.js +7 -7
- package/dist/src/gemini-web/browserSessionManager.js +19 -15
- package/dist/src/gemini-web/client.js +76 -70
- package/dist/src/gemini-web/executionMode.js +6 -8
- package/dist/src/gemini-web/executor.js +98 -93
- package/dist/src/gemini-web/index.js +1 -1
- package/dist/src/mcp/server.js +16 -12
- package/dist/src/mcp/tools/consult.js +51 -47
- 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 +50 -41
- package/dist/src/oracle/config.js +96 -66
- package/dist/src/oracle/errors.js +38 -38
- package/dist/src/oracle/files.js +55 -46
- package/dist/src/oracle/finishLine.js +10 -8
- package/dist/src/oracle/format.js +3 -3
- package/dist/src/oracle/gemini.js +37 -33
- 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 +16 -13
- package/dist/src/oracle/run.js +156 -134
- 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 +77 -75
- package/dist/src/sessionStore.js +3 -3
- package/dist/src/version.js +10 -10
- package/dist/vendor/oracle-notifier/README.md +2 -0
- package/package.json +66 -62
- 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/types.js +0 -1
- 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
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import chalk from
|
|
2
|
-
import kleur from
|
|
3
|
-
import { renderMarkdownAnsi } from
|
|
4
|
-
import { formatFinishLine } from
|
|
5
|
-
import { sessionStore, wait } from
|
|
6
|
-
import { formatTokenCount, formatTokenValue } from
|
|
7
|
-
import { resumeBrowserSession } from
|
|
8
|
-
import { estimateTokenCount } from
|
|
9
|
-
import { formatSessionTableHeader, formatSessionTableRow, resolveSessionCost } from
|
|
10
|
-
import { abbreviateResponseId, buildResponseOwnerIndex, resolveSessionLineage, } from
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import kleur from "kleur";
|
|
3
|
+
import { renderMarkdownAnsi } from "./markdownRenderer.js";
|
|
4
|
+
import { formatFinishLine } from "../oracle/finishLine.js";
|
|
5
|
+
import { sessionStore, wait } from "../sessionStore.js";
|
|
6
|
+
import { formatTokenCount, formatTokenValue } from "../oracle/runUtils.js";
|
|
7
|
+
import { resumeBrowserSession } from "../browser/reattach.js";
|
|
8
|
+
import { estimateTokenCount } from "../browser/utils.js";
|
|
9
|
+
import { formatSessionTableHeader, formatSessionTableRow, resolveSessionCost, } from "./sessionTable.js";
|
|
10
|
+
import { abbreviateResponseId, buildResponseOwnerIndex, resolveSessionLineage, } from "./sessionLineage.js";
|
|
11
11
|
const isTty = () => Boolean(process.stdout.isTTY);
|
|
12
12
|
const dim = (text) => (isTty() ? kleur.dim(text) : text);
|
|
13
13
|
export const MAX_RENDER_BYTES = 200_000;
|
|
@@ -20,10 +20,10 @@ function isProcessAlive(pid) {
|
|
|
20
20
|
}
|
|
21
21
|
catch (error) {
|
|
22
22
|
const code = error instanceof Error ? error.code : undefined;
|
|
23
|
-
if (code ===
|
|
23
|
+
if (code === "ESRCH" || code === "EINVAL") {
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
|
-
if (code ===
|
|
26
|
+
if (code === "EPERM") {
|
|
27
27
|
return true;
|
|
28
28
|
}
|
|
29
29
|
return true;
|
|
@@ -32,8 +32,14 @@ function isProcessAlive(pid) {
|
|
|
32
32
|
const CLEANUP_TIP = 'Tip: Run "oracle session --clear --hours 24" to prune cached runs (add --all to wipe everything).';
|
|
33
33
|
export async function showStatus({ hours, includeAll, limit, showExamples = false, modelFilter, }) {
|
|
34
34
|
const metas = await sessionStore.listSessions();
|
|
35
|
-
const { entries, truncated, total } = sessionStore.filterSessions(metas, {
|
|
36
|
-
|
|
35
|
+
const { entries, truncated, total } = sessionStore.filterSessions(metas, {
|
|
36
|
+
hours,
|
|
37
|
+
includeAll,
|
|
38
|
+
limit,
|
|
39
|
+
});
|
|
40
|
+
const filteredEntries = modelFilter
|
|
41
|
+
? entries.filter((entry) => matchesModel(entry, modelFilter))
|
|
42
|
+
: entries;
|
|
37
43
|
const richTty = process.stdout.isTTY && chalk.level > 0;
|
|
38
44
|
const responseOwners = buildResponseOwnerIndex(metas);
|
|
39
45
|
if (!filteredEntries.length) {
|
|
@@ -43,7 +49,7 @@ export async function showStatus({ hours, includeAll, limit, showExamples = fals
|
|
|
43
49
|
}
|
|
44
50
|
return;
|
|
45
51
|
}
|
|
46
|
-
console.log(chalk.bold(
|
|
52
|
+
console.log(chalk.bold("Recent Sessions"));
|
|
47
53
|
console.log(formatSessionTableHeader(richTty));
|
|
48
54
|
const treeRows = buildStatusTreeRows(filteredEntries, responseOwners);
|
|
49
55
|
for (const row of treeRows) {
|
|
@@ -52,7 +58,7 @@ export async function showStatus({ hours, includeAll, limit, showExamples = fals
|
|
|
52
58
|
? richTty
|
|
53
59
|
? chalk.gray(` <- ${row.detachedParentLabel}`)
|
|
54
60
|
: ` <- ${row.detachedParentLabel}`
|
|
55
|
-
:
|
|
61
|
+
: "";
|
|
56
62
|
console.log(`${line}${detachedParent}`);
|
|
57
63
|
}
|
|
58
64
|
if (truncated) {
|
|
@@ -70,7 +76,7 @@ export async function attachSession(sessionId, options) {
|
|
|
70
76
|
process.exitCode = 1;
|
|
71
77
|
return;
|
|
72
78
|
}
|
|
73
|
-
if (metadata.mode ===
|
|
79
|
+
if (metadata.mode === "browser" && metadata.status === "running" && !metadata.browser?.runtime) {
|
|
74
80
|
await wait(250);
|
|
75
81
|
const refreshed = await sessionStore.readSession(sessionId);
|
|
76
82
|
if (refreshed) {
|
|
@@ -92,16 +98,16 @@ export async function attachSession(sessionId, options) {
|
|
|
92
98
|
const isVerbose = Boolean(process.env.ORACLE_VERBOSE_RENDER);
|
|
93
99
|
const runtime = metadata.browser?.runtime;
|
|
94
100
|
const controllerAlive = isProcessAlive(runtime?.controllerPid);
|
|
95
|
-
const hasChromeDisconnect = metadata.response?.incompleteReason ===
|
|
96
|
-
const statusAllowsReattach = metadata.status ===
|
|
101
|
+
const hasChromeDisconnect = metadata.response?.incompleteReason === "chrome-disconnected";
|
|
102
|
+
const statusAllowsReattach = metadata.status === "running" || (metadata.status === "error" && hasChromeDisconnect);
|
|
97
103
|
const hasFallbackSessionInfo = Boolean(runtime?.chromePort || runtime?.tabUrl || runtime?.conversationId);
|
|
98
104
|
const canReattach = statusAllowsReattach &&
|
|
99
|
-
metadata.mode ===
|
|
105
|
+
metadata.mode === "browser" &&
|
|
100
106
|
hasFallbackSessionInfo &&
|
|
101
107
|
(hasChromeDisconnect || (runtime?.controllerPid && !controllerAlive));
|
|
102
108
|
if (canReattach) {
|
|
103
|
-
const portInfo = runtime?.chromePort ? `port ${runtime.chromePort}` :
|
|
104
|
-
const urlInfo = runtime?.tabUrl ? `url=${runtime.tabUrl}` :
|
|
109
|
+
const portInfo = runtime?.chromePort ? `port ${runtime.chromePort}` : "unknown port";
|
|
110
|
+
const urlInfo = runtime?.tabUrl ? `url=${runtime.tabUrl}` : "url=unknown";
|
|
105
111
|
console.log(chalk.yellow(`Attempting to reattach to the existing Chrome session (${portInfo}, ${urlInfo})...`));
|
|
106
112
|
try {
|
|
107
113
|
const result = await resumeBrowserSession(runtime, metadata.browser?.config, Object.assign(((message) => {
|
|
@@ -111,13 +117,13 @@ export async function attachSession(sessionId, options) {
|
|
|
111
117
|
}), { verbose: true }), { promptPreview: metadata.promptPreview });
|
|
112
118
|
const outputTokens = estimateTokenCount(result.answerMarkdown);
|
|
113
119
|
const logWriter = sessionStore.createLogWriter(sessionId);
|
|
114
|
-
logWriter.logLine(
|
|
115
|
-
logWriter.logLine(
|
|
120
|
+
logWriter.logLine("[reattach] captured assistant response from existing Chrome tab");
|
|
121
|
+
logWriter.logLine("Answer:");
|
|
116
122
|
logWriter.logLine(result.answerMarkdown || result.answerText);
|
|
117
123
|
logWriter.stream.end();
|
|
118
124
|
if (metadata.model) {
|
|
119
125
|
await sessionStore.updateModelRun(metadata.id, metadata.model, {
|
|
120
|
-
status:
|
|
126
|
+
status: "completed",
|
|
121
127
|
usage: {
|
|
122
128
|
inputTokens: 0,
|
|
123
129
|
outputTokens,
|
|
@@ -128,7 +134,7 @@ export async function attachSession(sessionId, options) {
|
|
|
128
134
|
});
|
|
129
135
|
}
|
|
130
136
|
await sessionStore.updateSession(sessionId, {
|
|
131
|
-
status:
|
|
137
|
+
status: "completed",
|
|
132
138
|
completedAt: new Date().toISOString(),
|
|
133
139
|
usage: {
|
|
134
140
|
inputTokens: 0,
|
|
@@ -140,11 +146,11 @@ export async function attachSession(sessionId, options) {
|
|
|
140
146
|
config: metadata.browser?.config,
|
|
141
147
|
runtime,
|
|
142
148
|
},
|
|
143
|
-
response: { status:
|
|
149
|
+
response: { status: "completed" },
|
|
144
150
|
error: undefined,
|
|
145
151
|
transport: undefined,
|
|
146
152
|
});
|
|
147
|
-
console.log(chalk.green(
|
|
153
|
+
console.log(chalk.green("Reattach succeeded; session marked completed."));
|
|
148
154
|
metadata = (await sessionStore.readSession(sessionId)) ?? metadata;
|
|
149
155
|
}
|
|
150
156
|
catch (error) {
|
|
@@ -164,11 +170,11 @@ export async function attachSession(sessionId, options) {
|
|
|
164
170
|
console.log(`Created: ${metadata.createdAt}`);
|
|
165
171
|
console.log(`Status: ${metadata.status}`);
|
|
166
172
|
if (metadata.models && metadata.models.length > 0) {
|
|
167
|
-
console.log(
|
|
173
|
+
console.log("Models:");
|
|
168
174
|
for (const run of metadata.models) {
|
|
169
175
|
const usage = run.usage
|
|
170
176
|
? ` tok=${formatTokenCount(run.usage.outputTokens ?? 0)}/${formatTokenCount(run.usage.totalTokens ?? 0)}`
|
|
171
|
-
:
|
|
177
|
+
: "";
|
|
172
178
|
console.log(`- ${chalk.cyan(run.model)} — ${run.status}${usage}`);
|
|
173
179
|
}
|
|
174
180
|
}
|
|
@@ -188,19 +194,19 @@ export async function attachSession(sessionId, options) {
|
|
|
188
194
|
console.log(dim(`User error: ${userErrorSummary}`));
|
|
189
195
|
}
|
|
190
196
|
}
|
|
191
|
-
const shouldTrimIntro = initialStatus ===
|
|
197
|
+
const shouldTrimIntro = initialStatus === "completed" || initialStatus === "error";
|
|
192
198
|
if (options?.renderPrompt !== false) {
|
|
193
199
|
const prompt = await readStoredPrompt(sessionId);
|
|
194
200
|
if (prompt) {
|
|
195
|
-
console.log(chalk.bold(
|
|
201
|
+
console.log(chalk.bold("Prompt:"));
|
|
196
202
|
console.log(renderMarkdownAnsi(prompt));
|
|
197
|
-
console.log(dim(
|
|
203
|
+
console.log(dim("---"));
|
|
198
204
|
}
|
|
199
205
|
}
|
|
200
206
|
if (shouldTrimIntro) {
|
|
201
207
|
const fullLog = await buildSessionLogForDisplay(sessionId, metadata, normalizedModelFilter);
|
|
202
208
|
const trimmed = trimBeforeFirstAnswer(fullLog);
|
|
203
|
-
const size = Buffer.byteLength(trimmed,
|
|
209
|
+
const size = Buffer.byteLength(trimmed, "utf8");
|
|
204
210
|
const canRender = wantsRender && isTty() && size <= MAX_RENDER_BYTES;
|
|
205
211
|
if (wantsRender && size > MAX_RENDER_BYTES) {
|
|
206
212
|
const msg = `Render skipped (log too large: ${size} bytes > ${MAX_RENDER_BYTES}). Showing raw text.`;
|
|
@@ -210,7 +216,7 @@ export async function attachSession(sessionId, options) {
|
|
|
210
216
|
}
|
|
211
217
|
}
|
|
212
218
|
else if (wantsRender && !isTty()) {
|
|
213
|
-
const msg =
|
|
219
|
+
const msg = "Render requested but stdout is not a TTY; showing raw text.";
|
|
214
220
|
console.log(dim(msg));
|
|
215
221
|
if (isVerbose) {
|
|
216
222
|
console.log(dim(`Verbose: renderMarkdown=true tty=${isTty()} size=${size}`));
|
|
@@ -232,13 +238,20 @@ export async function attachSession(sessionId, options) {
|
|
|
232
238
|
return;
|
|
233
239
|
}
|
|
234
240
|
if (wantsRender) {
|
|
235
|
-
console.log(dim(
|
|
241
|
+
console.log(dim("Render will apply after completion; streaming raw text meanwhile..."));
|
|
236
242
|
if (isVerbose) {
|
|
237
243
|
console.log(dim(`Verbose: streaming phase renderMarkdown=true tty=${isTty()}`));
|
|
238
244
|
}
|
|
239
245
|
}
|
|
240
246
|
const liveRenderState = wantsRender && isTty()
|
|
241
|
-
? {
|
|
247
|
+
? {
|
|
248
|
+
pending: "",
|
|
249
|
+
inFence: false,
|
|
250
|
+
inTable: false,
|
|
251
|
+
renderedBytes: 0,
|
|
252
|
+
fallback: false,
|
|
253
|
+
noticedFallback: false,
|
|
254
|
+
}
|
|
242
255
|
: null;
|
|
243
256
|
let lastLength = 0;
|
|
244
257
|
const renderLiveChunk = (chunk) => {
|
|
@@ -254,7 +267,7 @@ export async function attachSession(sessionId, options) {
|
|
|
254
267
|
const { chunks, remainder } = extractRenderableChunks(liveRenderState.pending, liveRenderState);
|
|
255
268
|
liveRenderState.pending = remainder;
|
|
256
269
|
for (const candidate of chunks) {
|
|
257
|
-
const projected = liveRenderState.renderedBytes + Buffer.byteLength(candidate,
|
|
270
|
+
const projected = liveRenderState.renderedBytes + Buffer.byteLength(candidate, "utf8");
|
|
258
271
|
if (projected > MAX_RENDER_BYTES) {
|
|
259
272
|
if (!liveRenderState.noticedFallback) {
|
|
260
273
|
console.log(dim(`Render skipped (log too large: > ${MAX_RENDER_BYTES} bytes). Showing raw text.`));
|
|
@@ -262,11 +275,11 @@ export async function attachSession(sessionId, options) {
|
|
|
262
275
|
}
|
|
263
276
|
liveRenderState.fallback = true;
|
|
264
277
|
process.stdout.write(candidate + liveRenderState.pending);
|
|
265
|
-
liveRenderState.pending =
|
|
278
|
+
liveRenderState.pending = "";
|
|
266
279
|
return;
|
|
267
280
|
}
|
|
268
281
|
process.stdout.write(renderMarkdownAnsi(candidate));
|
|
269
|
-
liveRenderState.renderedBytes += Buffer.byteLength(candidate,
|
|
282
|
+
liveRenderState.renderedBytes += Buffer.byteLength(candidate, "utf8");
|
|
270
283
|
}
|
|
271
284
|
};
|
|
272
285
|
const flushRemainder = () => {
|
|
@@ -277,8 +290,8 @@ export async function attachSession(sessionId, options) {
|
|
|
277
290
|
return;
|
|
278
291
|
}
|
|
279
292
|
const text = liveRenderState.pending;
|
|
280
|
-
liveRenderState.pending =
|
|
281
|
-
const projected = liveRenderState.renderedBytes + Buffer.byteLength(text,
|
|
293
|
+
liveRenderState.pending = "";
|
|
294
|
+
const projected = liveRenderState.renderedBytes + Buffer.byteLength(text, "utf8");
|
|
282
295
|
if (projected > MAX_RENDER_BYTES) {
|
|
283
296
|
if (!liveRenderState.noticedFallback) {
|
|
284
297
|
console.log(dim(`Render skipped (log too large: > ${MAX_RENDER_BYTES} bytes). Showing raw text.`));
|
|
@@ -304,15 +317,15 @@ export async function attachSession(sessionId, options) {
|
|
|
304
317
|
if (!latest) {
|
|
305
318
|
break;
|
|
306
319
|
}
|
|
307
|
-
if (latest.status ===
|
|
320
|
+
if (latest.status === "completed" || latest.status === "error") {
|
|
308
321
|
await printNew();
|
|
309
322
|
flushRemainder();
|
|
310
323
|
if (!options?.suppressMetadata) {
|
|
311
|
-
if (latest.status ===
|
|
312
|
-
console.log(
|
|
324
|
+
if (latest.status === "error" && latest.errorMessage) {
|
|
325
|
+
console.log("\nResult:");
|
|
313
326
|
console.log(`Session failed: ${latest.errorMessage}`);
|
|
314
327
|
}
|
|
315
|
-
if (latest.status ===
|
|
328
|
+
if (latest.status === "completed" && latest.usage) {
|
|
316
329
|
const summary = formatCompletionSummary(latest, { includeSlug: true });
|
|
317
330
|
if (summary) {
|
|
318
331
|
console.log(`\n${chalk.green.bold(summary)}`);
|
|
@@ -346,19 +359,19 @@ export function formatResponseMetadata(metadata) {
|
|
|
346
359
|
if (metadata.incompleteReason) {
|
|
347
360
|
parts.push(`incomplete=${metadata.incompleteReason}`);
|
|
348
361
|
}
|
|
349
|
-
return parts.length > 0 ? parts.join(
|
|
362
|
+
return parts.length > 0 ? parts.join(" | ") : null;
|
|
350
363
|
}
|
|
351
364
|
export function formatTransportMetadata(metadata) {
|
|
352
365
|
if (!metadata?.reason) {
|
|
353
366
|
return null;
|
|
354
367
|
}
|
|
355
368
|
const reasonLabels = {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
unknown:
|
|
369
|
+
"client-timeout": "client timeout (deadline exceeded)",
|
|
370
|
+
"connection-lost": "connection lost before completion",
|
|
371
|
+
"client-abort": "request aborted locally",
|
|
372
|
+
unknown: "unknown transport failure",
|
|
360
373
|
};
|
|
361
|
-
const label = reasonLabels[metadata.reason] ??
|
|
374
|
+
const label = reasonLabels[metadata.reason] ?? "transport error";
|
|
362
375
|
return `${metadata.reason} — ${label}`;
|
|
363
376
|
}
|
|
364
377
|
export function formatUserErrorMetadata(metadata) {
|
|
@@ -375,7 +388,7 @@ export function formatUserErrorMetadata(metadata) {
|
|
|
375
388
|
if (metadata.details && Object.keys(metadata.details).length > 0) {
|
|
376
389
|
parts.push(`details=${JSON.stringify(metadata.details)}`);
|
|
377
390
|
}
|
|
378
|
-
return parts.length > 0 ? parts.join(
|
|
391
|
+
return parts.length > 0 ? parts.join(" | ") : null;
|
|
379
392
|
}
|
|
380
393
|
export function buildReattachLine(metadata) {
|
|
381
394
|
if (!metadata.id) {
|
|
@@ -389,13 +402,13 @@ export function buildReattachLine(metadata) {
|
|
|
389
402
|
if (!elapsedLabel) {
|
|
390
403
|
return null;
|
|
391
404
|
}
|
|
392
|
-
if (metadata.status ===
|
|
405
|
+
if (metadata.status === "running") {
|
|
393
406
|
return `Session ${metadata.id} reattached, request started ${elapsedLabel} ago.`;
|
|
394
407
|
}
|
|
395
408
|
return null;
|
|
396
409
|
}
|
|
397
410
|
export function trimBeforeFirstAnswer(logText) {
|
|
398
|
-
const marker =
|
|
411
|
+
const marker = "Answer:";
|
|
399
412
|
const index = logText.indexOf(marker);
|
|
400
413
|
if (index === -1) {
|
|
401
414
|
return logText;
|
|
@@ -427,7 +440,7 @@ function formatRelativeDuration(referenceIso) {
|
|
|
427
440
|
if (remainingMinutes > 0) {
|
|
428
441
|
parts.push(`${remainingMinutes}m`);
|
|
429
442
|
}
|
|
430
|
-
return parts.join(
|
|
443
|
+
return parts.join(" ");
|
|
431
444
|
}
|
|
432
445
|
const days = Math.floor(hours / 24);
|
|
433
446
|
const remainingHours = hours % 24;
|
|
@@ -438,17 +451,17 @@ function formatRelativeDuration(referenceIso) {
|
|
|
438
451
|
if (remainingMinutes > 0 && days === 0) {
|
|
439
452
|
parts.push(`${remainingMinutes}m`);
|
|
440
453
|
}
|
|
441
|
-
return parts.join(
|
|
454
|
+
return parts.join(" ");
|
|
442
455
|
}
|
|
443
456
|
function printStatusExamples() {
|
|
444
|
-
console.log(
|
|
445
|
-
console.log(chalk.bold(
|
|
446
|
-
console.log(`${chalk.bold(
|
|
447
|
-
console.log(dim(
|
|
448
|
-
console.log(`${chalk.bold(
|
|
449
|
-
console.log(dim(
|
|
450
|
-
console.log(`${chalk.bold(
|
|
451
|
-
console.log(dim(
|
|
457
|
+
console.log("");
|
|
458
|
+
console.log(chalk.bold("Usage Examples"));
|
|
459
|
+
console.log(`${chalk.bold(" oracle status --hours 72 --limit 50")}`);
|
|
460
|
+
console.log(dim(" Show 72h of history capped at 50 entries."));
|
|
461
|
+
console.log(`${chalk.bold(" oracle status --clear --hours 168")}`);
|
|
462
|
+
console.log(dim(" Delete sessions older than 7 days (use --all to wipe everything)."));
|
|
463
|
+
console.log(`${chalk.bold(" oracle session <session-id>")}`);
|
|
464
|
+
console.log(dim(" Attach to a specific running/completed session to stream its output."));
|
|
452
465
|
console.log(dim(CLEANUP_TIP));
|
|
453
466
|
}
|
|
454
467
|
function matchesModel(entry, filter) {
|
|
@@ -456,7 +469,8 @@ function matchesModel(entry, filter) {
|
|
|
456
469
|
if (!normalized) {
|
|
457
470
|
return true;
|
|
458
471
|
}
|
|
459
|
-
const models = entry.models?.map((model) => model.model.toLowerCase()) ??
|
|
472
|
+
const models = entry.models?.map((model) => model.model.toLowerCase()) ??
|
|
473
|
+
(entry.model ? [entry.model.toLowerCase()] : []);
|
|
460
474
|
return models.includes(normalized);
|
|
461
475
|
}
|
|
462
476
|
function buildStatusTreeRows(entries, responseOwners) {
|
|
@@ -485,8 +499,8 @@ function buildStatusTreeRows(entries, responseOwners) {
|
|
|
485
499
|
}
|
|
486
500
|
visited.add(entry.id);
|
|
487
501
|
const children = childMap.get(entry.id) ?? [];
|
|
488
|
-
const nodeBranch = isLast ?
|
|
489
|
-
const prefix = `${ancestorHasMore.map((hasMore) => (hasMore ?
|
|
502
|
+
const nodeBranch = isLast ? "└─ " : "├─ ";
|
|
503
|
+
const prefix = `${ancestorHasMore.map((hasMore) => (hasMore ? "│ " : " ")).join("")}${nodeBranch}`;
|
|
490
504
|
rows.push({ entry, displaySlug: `${prefix}${entry.id}` });
|
|
491
505
|
children.forEach((child, index) => {
|
|
492
506
|
walkChild(child, [...ancestorHasMore, !isLast], index === children.length - 1);
|
|
@@ -549,12 +563,12 @@ async function buildSessionLogForDisplay(sessionId, fallbackMeta, modelFilter) {
|
|
|
549
563
|
? models.filter((model) => model.model.toLowerCase() === normalizedFilter)
|
|
550
564
|
: models;
|
|
551
565
|
if (candidates.length === 0) {
|
|
552
|
-
return
|
|
566
|
+
return "";
|
|
553
567
|
}
|
|
554
568
|
const sections = [];
|
|
555
569
|
let hasContent = false;
|
|
556
570
|
for (const model of candidates) {
|
|
557
|
-
const body = (await sessionStore.readModelLog(sessionId, model.model)) ??
|
|
571
|
+
const body = (await sessionStore.readModelLog(sessionId, model.model)) ?? "";
|
|
558
572
|
if (body.trim().length > 0) {
|
|
559
573
|
hasContent = true;
|
|
560
574
|
}
|
|
@@ -564,18 +578,18 @@ async function buildSessionLogForDisplay(sessionId, fallbackMeta, modelFilter) {
|
|
|
564
578
|
// Fallback for runs that recorded output only in the session log (e.g., browser runs without per-model logs).
|
|
565
579
|
return await sessionStore.readLog(sessionId);
|
|
566
580
|
}
|
|
567
|
-
return sections.join(
|
|
581
|
+
return sections.join("\n\n");
|
|
568
582
|
}
|
|
569
583
|
function extractRenderableChunks(text, state) {
|
|
570
584
|
const chunks = [];
|
|
571
|
-
let buffer =
|
|
585
|
+
let buffer = "";
|
|
572
586
|
const lines = text.split(/(\n)/);
|
|
573
587
|
for (let i = 0; i < lines.length; i += 1) {
|
|
574
588
|
const segment = lines[i];
|
|
575
|
-
if (segment ===
|
|
589
|
+
if (segment === "\n") {
|
|
576
590
|
buffer += segment;
|
|
577
591
|
// Detect code fences
|
|
578
|
-
const prev = lines[i - 1] ??
|
|
592
|
+
const prev = lines[i - 1] ?? "";
|
|
579
593
|
const fenceMatch = prev.match(/^(\s*)(`{3,}|~{3,})(.*)$/);
|
|
580
594
|
if (!state.inFence && fenceMatch) {
|
|
581
595
|
state.inFence = true;
|
|
@@ -587,17 +601,17 @@ function extractRenderableChunks(text, state) {
|
|
|
587
601
|
}
|
|
588
602
|
const trimmed = prev.trim();
|
|
589
603
|
if (!state.inFence) {
|
|
590
|
-
if (!state.inTable && trimmed.startsWith(
|
|
604
|
+
if (!state.inTable && trimmed.startsWith("|") && trimmed.includes("|")) {
|
|
591
605
|
state.inTable = true;
|
|
592
606
|
}
|
|
593
|
-
if (state.inTable && trimmed ===
|
|
607
|
+
if (state.inTable && trimmed === "") {
|
|
594
608
|
state.inTable = false;
|
|
595
609
|
}
|
|
596
610
|
}
|
|
597
|
-
const safeBreak = !state.inFence && !state.inTable && trimmed ===
|
|
611
|
+
const safeBreak = !state.inFence && !state.inTable && trimmed === "";
|
|
598
612
|
if (safeBreak) {
|
|
599
613
|
chunks.push(buffer);
|
|
600
|
-
buffer =
|
|
614
|
+
buffer = "";
|
|
601
615
|
}
|
|
602
616
|
continue;
|
|
603
617
|
}
|
|
@@ -609,7 +623,7 @@ export function formatCompletionSummary(metadata, options = {}) {
|
|
|
609
623
|
if (!metadata.usage || metadata.elapsedMs == null) {
|
|
610
624
|
return null;
|
|
611
625
|
}
|
|
612
|
-
const modeLabel = metadata.mode ===
|
|
626
|
+
const modeLabel = metadata.mode === "browser" ? `${metadata.model ?? "n/a"}[browser]` : (metadata.model ?? "n/a");
|
|
613
627
|
const usage = metadata.usage;
|
|
614
628
|
const cost = resolveSessionCost(metadata);
|
|
615
629
|
const tokensDisplay = [
|
|
@@ -624,9 +638,9 @@ export function formatCompletionSummary(metadata, options = {}) {
|
|
|
624
638
|
reasoning_tokens: usage.reasoningTokens,
|
|
625
639
|
total_tokens: usage.totalTokens,
|
|
626
640
|
}, index))
|
|
627
|
-
.join(
|
|
641
|
+
.join("/");
|
|
628
642
|
const tokensPart = (() => {
|
|
629
|
-
const parts = tokensDisplay.split(
|
|
643
|
+
const parts = tokensDisplay.split("/");
|
|
630
644
|
if (parts.length !== 4)
|
|
631
645
|
return tokensDisplay;
|
|
632
646
|
return `↑${parts[0]} ↓${parts[1]} ↻${parts[2]} Δ${parts[3]}`;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
function readResponseId(record) {
|
|
2
2
|
if (!record)
|
|
3
3
|
return null;
|
|
4
|
-
const candidate = typeof record.responseId ===
|
|
5
|
-
|
|
4
|
+
const candidate = typeof record.responseId === "string"
|
|
5
|
+
? record.responseId
|
|
6
|
+
: typeof record.id === "string"
|
|
7
|
+
? record.id
|
|
8
|
+
: null;
|
|
9
|
+
if (!candidate || !candidate.startsWith("resp_")) {
|
|
6
10
|
return null;
|
|
7
11
|
}
|
|
8
12
|
return candidate;
|