@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
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import path from
|
|
2
|
-
import fs from
|
|
3
|
-
import { createWriteStream } from
|
|
4
|
-
import net from
|
|
5
|
-
import { DEFAULT_MODEL, formatElapsed } from
|
|
6
|
-
import { safeModelSlug } from
|
|
7
|
-
import { getOracleHomeDir } from
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import { createWriteStream } from "node:fs";
|
|
4
|
+
import net from "node:net";
|
|
5
|
+
import { DEFAULT_MODEL, formatElapsed } from "./oracle.js";
|
|
6
|
+
import { safeModelSlug } from "./oracle/modelResolver.js";
|
|
7
|
+
import { getOracleHomeDir } from "./oracleHome.js";
|
|
8
8
|
export function getSessionsDir() {
|
|
9
|
-
return path.join(getOracleHomeDir(),
|
|
10
|
-
}
|
|
11
|
-
const METADATA_FILENAME =
|
|
12
|
-
const LEGACY_SESSION_FILENAME =
|
|
13
|
-
const LEGACY_REQUEST_FILENAME =
|
|
14
|
-
const MODELS_DIRNAME =
|
|
15
|
-
const MODEL_JSON_EXTENSION =
|
|
16
|
-
const MODEL_LOG_EXTENSION =
|
|
9
|
+
return path.join(getOracleHomeDir(), "sessions");
|
|
10
|
+
}
|
|
11
|
+
const METADATA_FILENAME = "meta.json";
|
|
12
|
+
const LEGACY_SESSION_FILENAME = "session.json";
|
|
13
|
+
const LEGACY_REQUEST_FILENAME = "request.json";
|
|
14
|
+
const MODELS_DIRNAME = "models";
|
|
15
|
+
const MODEL_JSON_EXTENSION = ".json";
|
|
16
|
+
const MODEL_LOG_EXTENSION = ".log";
|
|
17
17
|
const MAX_STATUS_LIMIT = 1000;
|
|
18
18
|
const ZOMBIE_MAX_AGE_MS = 60 * 60 * 1000; // 60 minutes
|
|
19
19
|
const CHROME_RUNTIME_TIMEOUT_MS = 250;
|
|
20
|
-
const DEFAULT_SLUG =
|
|
20
|
+
const DEFAULT_SLUG = "session";
|
|
21
21
|
const MAX_SLUG_WORDS = 5;
|
|
22
22
|
const MIN_CUSTOM_SLUG_WORDS = 3;
|
|
23
23
|
const MAX_SLUG_WORD_LENGTH = 10;
|
|
@@ -28,15 +28,13 @@ export async function ensureSessionStorage() {
|
|
|
28
28
|
await ensureDir(getSessionsDir());
|
|
29
29
|
}
|
|
30
30
|
function slugify(text, maxWords = MAX_SLUG_WORDS) {
|
|
31
|
-
const normalized = text?.toLowerCase() ??
|
|
31
|
+
const normalized = text?.toLowerCase() ?? "";
|
|
32
32
|
const words = normalized.match(/[a-z0-9]+/g) ?? [];
|
|
33
|
-
const trimmed = words
|
|
34
|
-
|
|
35
|
-
.map((word) => word.slice(0, MAX_SLUG_WORD_LENGTH));
|
|
36
|
-
return trimmed.length > 0 ? trimmed.join('-') : DEFAULT_SLUG;
|
|
33
|
+
const trimmed = words.slice(0, maxWords).map((word) => word.slice(0, MAX_SLUG_WORD_LENGTH));
|
|
34
|
+
return trimmed.length > 0 ? trimmed.join("-") : DEFAULT_SLUG;
|
|
37
35
|
}
|
|
38
36
|
function countSlugWords(slug) {
|
|
39
|
-
return slug.split(
|
|
37
|
+
return slug.split("-").filter(Boolean).length;
|
|
40
38
|
}
|
|
41
39
|
function normalizeCustomSlug(candidate) {
|
|
42
40
|
const slug = slugify(candidate, MAX_SLUG_WORDS);
|
|
@@ -65,7 +63,7 @@ function legacySessionPath(id) {
|
|
|
65
63
|
return path.join(sessionDir(id), LEGACY_SESSION_FILENAME);
|
|
66
64
|
}
|
|
67
65
|
function logPath(id) {
|
|
68
|
-
return path.join(sessionDir(id),
|
|
66
|
+
return path.join(sessionDir(id), "output.log");
|
|
69
67
|
}
|
|
70
68
|
function modelsDir(id) {
|
|
71
69
|
return path.join(sessionDir(id), MODELS_DIRNAME);
|
|
@@ -106,7 +104,7 @@ async function listModelRunFiles(sessionId) {
|
|
|
106
104
|
}
|
|
107
105
|
const jsonPath = path.join(dir, entry);
|
|
108
106
|
try {
|
|
109
|
-
const raw = await fs.readFile(jsonPath,
|
|
107
|
+
const raw = await fs.readFile(jsonPath, "utf8");
|
|
110
108
|
const parsed = JSON.parse(raw);
|
|
111
109
|
const normalized = ensureModelLogReference(sessionId, parsed);
|
|
112
110
|
result.push(normalized);
|
|
@@ -126,7 +124,7 @@ function ensureModelLogReference(sessionId, record) {
|
|
|
126
124
|
}
|
|
127
125
|
async function readModelRunFile(sessionId, model) {
|
|
128
126
|
try {
|
|
129
|
-
const raw = await fs.readFile(modelJsonPath(sessionId, model),
|
|
127
|
+
const raw = await fs.readFile(modelJsonPath(sessionId, model), "utf8");
|
|
130
128
|
const parsed = JSON.parse(raw);
|
|
131
129
|
return ensureModelLogReference(sessionId, parsed);
|
|
132
130
|
}
|
|
@@ -138,14 +136,14 @@ export async function updateModelRunMetadata(sessionId, model, updates) {
|
|
|
138
136
|
await ensureDir(modelsDir(sessionId));
|
|
139
137
|
const existing = (await readModelRunFile(sessionId, model)) ?? {
|
|
140
138
|
model,
|
|
141
|
-
status:
|
|
139
|
+
status: "pending",
|
|
142
140
|
};
|
|
143
141
|
const next = ensureModelLogReference(sessionId, {
|
|
144
142
|
...existing,
|
|
145
143
|
...updates,
|
|
146
144
|
model,
|
|
147
145
|
});
|
|
148
|
-
await fs.writeFile(modelJsonPath(sessionId, model), JSON.stringify(next, null, 2),
|
|
146
|
+
await fs.writeFile(modelJsonPath(sessionId, model), JSON.stringify(next, null, 2), "utf8");
|
|
149
147
|
return next;
|
|
150
148
|
}
|
|
151
149
|
export async function readModelRunMetadata(sessionId, model) {
|
|
@@ -157,7 +155,7 @@ export async function initializeSession(options, cwd, notifications, baseSlugOve
|
|
|
157
155
|
const sessionId = await ensureUniqueSessionId(baseSlug);
|
|
158
156
|
const dir = sessionDir(sessionId);
|
|
159
157
|
await ensureDir(dir);
|
|
160
|
-
const mode = options.mode ??
|
|
158
|
+
const mode = options.mode ?? "api";
|
|
161
159
|
const browserConfig = options.browserConfig;
|
|
162
160
|
const modelList = Array.isArray(options.models) && options.models.length > 0
|
|
163
161
|
? options.models
|
|
@@ -167,12 +165,12 @@ export async function initializeSession(options, cwd, notifications, baseSlugOve
|
|
|
167
165
|
const metadata = {
|
|
168
166
|
id: sessionId,
|
|
169
167
|
createdAt: new Date().toISOString(),
|
|
170
|
-
status:
|
|
171
|
-
promptPreview: (options.prompt ||
|
|
168
|
+
status: "pending",
|
|
169
|
+
promptPreview: (options.prompt || "").slice(0, 160),
|
|
172
170
|
model: modelList[0] ?? options.model,
|
|
173
171
|
models: modelList.map((modelName) => ({
|
|
174
172
|
model: modelName,
|
|
175
|
-
status:
|
|
173
|
+
status: "pending",
|
|
176
174
|
})),
|
|
177
175
|
cwd,
|
|
178
176
|
mode,
|
|
@@ -181,8 +179,12 @@ export async function initializeSession(options, cwd, notifications, baseSlugOve
|
|
|
181
179
|
options: {
|
|
182
180
|
prompt: options.prompt,
|
|
183
181
|
file: options.file ?? [],
|
|
182
|
+
maxFileSizeBytes: options.maxFileSizeBytes,
|
|
184
183
|
model: options.model,
|
|
185
184
|
models: modelList,
|
|
185
|
+
previousResponseId: options.previousResponseId,
|
|
186
|
+
followupSessionId: options.followupSessionId,
|
|
187
|
+
followupModel: options.followupModel,
|
|
186
188
|
effectiveModelId: options.effectiveModelId,
|
|
187
189
|
maxInput: options.maxInput,
|
|
188
190
|
system: options.system,
|
|
@@ -216,19 +218,19 @@ export async function initializeSession(options, cwd, notifications, baseSlugOve
|
|
|
216
218
|
},
|
|
217
219
|
};
|
|
218
220
|
await ensureDir(modelsDir(sessionId));
|
|
219
|
-
await fs.writeFile(metaPath(sessionId), JSON.stringify(metadata, null, 2),
|
|
221
|
+
await fs.writeFile(metaPath(sessionId), JSON.stringify(metadata, null, 2), "utf8");
|
|
220
222
|
await Promise.all((modelList.length > 0 ? modelList : [metadata.model ?? DEFAULT_MODEL]).map(async (modelName) => {
|
|
221
223
|
const jsonPath = modelJsonPath(sessionId, modelName);
|
|
222
224
|
const logFilePath = modelLogPath(sessionId, modelName);
|
|
223
225
|
const modelRecord = {
|
|
224
226
|
model: modelName,
|
|
225
|
-
status:
|
|
227
|
+
status: "pending",
|
|
226
228
|
log: { path: path.relative(sessionDir(sessionId), logFilePath) },
|
|
227
229
|
};
|
|
228
|
-
await fs.writeFile(jsonPath, JSON.stringify(modelRecord, null, 2),
|
|
229
|
-
await fs.writeFile(logFilePath,
|
|
230
|
+
await fs.writeFile(jsonPath, JSON.stringify(modelRecord, null, 2), "utf8");
|
|
231
|
+
await fs.writeFile(logFilePath, "", "utf8");
|
|
230
232
|
}));
|
|
231
|
-
await fs.writeFile(logPath(sessionId),
|
|
233
|
+
await fs.writeFile(logPath(sessionId), "", "utf8");
|
|
232
234
|
return metadata;
|
|
233
235
|
}
|
|
234
236
|
export async function readSessionMetadata(sessionId) {
|
|
@@ -247,12 +249,12 @@ export async function updateSessionMetadata(sessionId, updates) {
|
|
|
247
249
|
(await readLegacySessionMetadata(sessionId)) ??
|
|
248
250
|
{ id: sessionId };
|
|
249
251
|
const next = { ...existing, ...updates };
|
|
250
|
-
await fs.writeFile(metaPath(sessionId), JSON.stringify(next, null, 2),
|
|
252
|
+
await fs.writeFile(metaPath(sessionId), JSON.stringify(next, null, 2), "utf8");
|
|
251
253
|
return next;
|
|
252
254
|
}
|
|
253
255
|
async function readModernSessionMetadata(sessionId) {
|
|
254
256
|
try {
|
|
255
|
-
const raw = await fs.readFile(metaPath(sessionId),
|
|
257
|
+
const raw = await fs.readFile(metaPath(sessionId), "utf8");
|
|
256
258
|
const parsed = JSON.parse(raw);
|
|
257
259
|
if (!isSessionMetadataRecord(parsed)) {
|
|
258
260
|
return null;
|
|
@@ -267,7 +269,7 @@ async function readModernSessionMetadata(sessionId) {
|
|
|
267
269
|
}
|
|
268
270
|
async function readLegacySessionMetadata(sessionId) {
|
|
269
271
|
try {
|
|
270
|
-
const raw = await fs.readFile(legacySessionPath(sessionId),
|
|
272
|
+
const raw = await fs.readFile(legacySessionPath(sessionId), "utf8");
|
|
271
273
|
const parsed = JSON.parse(raw);
|
|
272
274
|
const enriched = await attachModelRuns(parsed, sessionId);
|
|
273
275
|
const runtimeChecked = await markDeadBrowser(enriched, { persist: false });
|
|
@@ -278,7 +280,7 @@ async function readLegacySessionMetadata(sessionId) {
|
|
|
278
280
|
}
|
|
279
281
|
}
|
|
280
282
|
function isSessionMetadataRecord(value) {
|
|
281
|
-
return Boolean(value && typeof value.id ===
|
|
283
|
+
return Boolean(value && typeof value.id === "string" && value.status);
|
|
282
284
|
}
|
|
283
285
|
async function attachModelRuns(meta, sessionId) {
|
|
284
286
|
const runs = await listModelRunFiles(sessionId);
|
|
@@ -292,8 +294,8 @@ export function createSessionLogWriter(sessionId, model) {
|
|
|
292
294
|
if (model) {
|
|
293
295
|
void ensureDir(modelsDir(sessionId));
|
|
294
296
|
}
|
|
295
|
-
const stream = createWriteStream(targetPath, { flags:
|
|
296
|
-
const logLine = (line =
|
|
297
|
+
const stream = createWriteStream(targetPath, { flags: "a" });
|
|
298
|
+
const logLine = (line = "") => {
|
|
297
299
|
stream.write(`${line}\n`);
|
|
298
300
|
};
|
|
299
301
|
const writeChunk = (chunk) => {
|
|
@@ -316,7 +318,7 @@ export async function listSessionsMetadata() {
|
|
|
316
318
|
}
|
|
317
319
|
return metas.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
318
320
|
}
|
|
319
|
-
export function filterSessionsByRange(metas, { hours = 24, includeAll = false, limit = 100 }) {
|
|
321
|
+
export function filterSessionsByRange(metas, { hours = 24, includeAll = false, limit = 100, }) {
|
|
320
322
|
const maxLimit = Math.min(limit, MAX_STATUS_LIMIT);
|
|
321
323
|
let filtered = metas;
|
|
322
324
|
if (!includeAll) {
|
|
@@ -331,29 +333,31 @@ export async function readSessionLog(sessionId) {
|
|
|
331
333
|
const runs = await listModelRunFiles(sessionId);
|
|
332
334
|
if (runs.length === 0) {
|
|
333
335
|
try {
|
|
334
|
-
return await fs.readFile(logPath(sessionId),
|
|
336
|
+
return await fs.readFile(logPath(sessionId), "utf8");
|
|
335
337
|
}
|
|
336
338
|
catch {
|
|
337
|
-
return
|
|
339
|
+
return "";
|
|
338
340
|
}
|
|
339
341
|
}
|
|
340
342
|
const sections = [];
|
|
341
343
|
let hasContent = false;
|
|
342
344
|
const ordered = runs
|
|
343
345
|
.slice()
|
|
344
|
-
.sort((a, b) =>
|
|
346
|
+
.sort((a, b) => a.startedAt && b.startedAt
|
|
347
|
+
? a.startedAt.localeCompare(b.startedAt)
|
|
348
|
+
: a.model.localeCompare(b.model));
|
|
345
349
|
for (const run of ordered) {
|
|
346
350
|
const logFile = run.log?.path
|
|
347
351
|
? path.isAbsolute(run.log.path)
|
|
348
352
|
? run.log.path
|
|
349
353
|
: path.join(sessionDir(sessionId), run.log.path)
|
|
350
354
|
: modelLogPath(sessionId, run.model);
|
|
351
|
-
let body =
|
|
355
|
+
let body = "";
|
|
352
356
|
try {
|
|
353
|
-
body = await fs.readFile(logFile,
|
|
357
|
+
body = await fs.readFile(logFile, "utf8");
|
|
354
358
|
}
|
|
355
359
|
catch {
|
|
356
|
-
body =
|
|
360
|
+
body = "";
|
|
357
361
|
}
|
|
358
362
|
if (body.length > 0) {
|
|
359
363
|
hasContent = true;
|
|
@@ -362,20 +366,20 @@ export async function readSessionLog(sessionId) {
|
|
|
362
366
|
}
|
|
363
367
|
if (!hasContent) {
|
|
364
368
|
try {
|
|
365
|
-
return await fs.readFile(logPath(sessionId),
|
|
369
|
+
return await fs.readFile(logPath(sessionId), "utf8");
|
|
366
370
|
}
|
|
367
371
|
catch {
|
|
368
372
|
// ignore and return structured header-only log
|
|
369
373
|
}
|
|
370
374
|
}
|
|
371
|
-
return sections.join(
|
|
375
|
+
return sections.join("\n\n");
|
|
372
376
|
}
|
|
373
377
|
export async function readModelLog(sessionId, model) {
|
|
374
378
|
try {
|
|
375
|
-
return await fs.readFile(modelLogPath(sessionId, model),
|
|
379
|
+
return await fs.readFile(modelLogPath(sessionId, model), "utf8");
|
|
376
380
|
}
|
|
377
381
|
catch {
|
|
378
|
-
return
|
|
382
|
+
return "";
|
|
379
383
|
}
|
|
380
384
|
}
|
|
381
385
|
export async function readSessionRequest(sessionId) {
|
|
@@ -384,7 +388,7 @@ export async function readSessionRequest(sessionId) {
|
|
|
384
388
|
return modern.options;
|
|
385
389
|
}
|
|
386
390
|
try {
|
|
387
|
-
const raw = await fs.readFile(requestPath(sessionId),
|
|
391
|
+
const raw = await fs.readFile(requestPath(sessionId), "utf8");
|
|
388
392
|
const parsed = JSON.parse(raw);
|
|
389
393
|
if (isSessionMetadataRecord(parsed)) {
|
|
390
394
|
return parsed.options ?? null;
|
|
@@ -448,7 +452,7 @@ export async function getSessionPaths(sessionId) {
|
|
|
448
452
|
}
|
|
449
453
|
}
|
|
450
454
|
if (missing.length > 0) {
|
|
451
|
-
throw new Error(`Session "${sessionId}" is missing: ${missing.join(
|
|
455
|
+
throw new Error(`Session "${sessionId}" is missing: ${missing.join(", ")}`);
|
|
452
456
|
}
|
|
453
457
|
return { dir, metadata, log, request };
|
|
454
458
|
}
|
|
@@ -456,7 +460,7 @@ async function markZombie(meta, { persist }) {
|
|
|
456
460
|
if (!(await isZombie(meta))) {
|
|
457
461
|
return meta;
|
|
458
462
|
}
|
|
459
|
-
if (meta.mode ===
|
|
463
|
+
if (meta.mode === "browser") {
|
|
460
464
|
const runtime = meta.browser?.runtime;
|
|
461
465
|
if (runtime) {
|
|
462
466
|
const signals = [];
|
|
@@ -464,7 +468,7 @@ async function markZombie(meta, { persist }) {
|
|
|
464
468
|
signals.push(isProcessAlive(runtime.chromePid));
|
|
465
469
|
}
|
|
466
470
|
if (runtime.chromePort) {
|
|
467
|
-
const host = runtime.chromeHost ??
|
|
471
|
+
const host = runtime.chromeHost ?? "127.0.0.1";
|
|
468
472
|
signals.push(await isPortOpen(host, runtime.chromePort));
|
|
469
473
|
}
|
|
470
474
|
if (signals.some(Boolean)) {
|
|
@@ -475,17 +479,17 @@ async function markZombie(meta, { persist }) {
|
|
|
475
479
|
const maxAgeMs = resolveZombieMaxAgeMs(meta);
|
|
476
480
|
const updated = {
|
|
477
481
|
...meta,
|
|
478
|
-
status:
|
|
482
|
+
status: "error",
|
|
479
483
|
errorMessage: `Session marked as zombie (> ${formatElapsed(maxAgeMs)} stale)`,
|
|
480
484
|
completedAt: new Date().toISOString(),
|
|
481
485
|
};
|
|
482
486
|
if (persist) {
|
|
483
|
-
await fs.writeFile(metaPath(meta.id), JSON.stringify(updated, null, 2),
|
|
487
|
+
await fs.writeFile(metaPath(meta.id), JSON.stringify(updated, null, 2), "utf8");
|
|
484
488
|
}
|
|
485
489
|
return updated;
|
|
486
490
|
}
|
|
487
491
|
async function markDeadBrowser(meta, { persist }) {
|
|
488
|
-
if (meta.status !==
|
|
492
|
+
if (meta.status !== "running" || meta.mode !== "browser") {
|
|
489
493
|
return meta;
|
|
490
494
|
}
|
|
491
495
|
const runtime = meta.browser?.runtime;
|
|
@@ -497,7 +501,7 @@ async function markDeadBrowser(meta, { persist }) {
|
|
|
497
501
|
signals.push(isProcessAlive(runtime.chromePid));
|
|
498
502
|
}
|
|
499
503
|
if (runtime.chromePort) {
|
|
500
|
-
const host = runtime.chromeHost ??
|
|
504
|
+
const host = runtime.chromeHost ?? "127.0.0.1";
|
|
501
505
|
signals.push(await isPortOpen(host, runtime.chromePort));
|
|
502
506
|
}
|
|
503
507
|
if (signals.length === 0 || signals.some(Boolean)) {
|
|
@@ -506,24 +510,24 @@ async function markDeadBrowser(meta, { persist }) {
|
|
|
506
510
|
const response = meta.response
|
|
507
511
|
? {
|
|
508
512
|
...meta.response,
|
|
509
|
-
status:
|
|
510
|
-
incompleteReason: meta.response.incompleteReason ??
|
|
513
|
+
status: "error",
|
|
514
|
+
incompleteReason: meta.response.incompleteReason ?? "chrome-disconnected",
|
|
511
515
|
}
|
|
512
|
-
: { status:
|
|
516
|
+
: { status: "error", incompleteReason: "chrome-disconnected" };
|
|
513
517
|
const updated = {
|
|
514
518
|
...meta,
|
|
515
|
-
status:
|
|
516
|
-
errorMessage:
|
|
519
|
+
status: "error",
|
|
520
|
+
errorMessage: "Browser session ended (Chrome is no longer reachable)",
|
|
517
521
|
completedAt: new Date().toISOString(),
|
|
518
522
|
response,
|
|
519
523
|
};
|
|
520
524
|
if (persist) {
|
|
521
|
-
await fs.writeFile(metaPath(meta.id), JSON.stringify(updated, null, 2),
|
|
525
|
+
await fs.writeFile(metaPath(meta.id), JSON.stringify(updated, null, 2), "utf8");
|
|
522
526
|
}
|
|
523
527
|
return updated;
|
|
524
528
|
}
|
|
525
529
|
async function isZombie(meta) {
|
|
526
|
-
if (meta.status !==
|
|
530
|
+
if (meta.status !== "running") {
|
|
527
531
|
return false;
|
|
528
532
|
}
|
|
529
533
|
const reference = meta.startedAt ?? meta.createdAt;
|
|
@@ -542,11 +546,13 @@ async function isZombie(meta) {
|
|
|
542
546
|
}
|
|
543
547
|
function resolveZombieMaxAgeMs(meta) {
|
|
544
548
|
const explicit = meta.options?.zombieTimeoutMs;
|
|
545
|
-
const hasExplicit = typeof explicit ===
|
|
549
|
+
const hasExplicit = typeof explicit === "number" && Number.isFinite(explicit) && explicit > 0;
|
|
546
550
|
let maxAgeMs = hasExplicit ? explicit : ZOMBIE_MAX_AGE_MS;
|
|
547
551
|
if (!hasExplicit) {
|
|
548
552
|
const timeoutSeconds = meta.options?.timeoutSeconds;
|
|
549
|
-
if (typeof timeoutSeconds ===
|
|
553
|
+
if (typeof timeoutSeconds === "number" &&
|
|
554
|
+
Number.isFinite(timeoutSeconds) &&
|
|
555
|
+
timeoutSeconds > 0) {
|
|
550
556
|
const timeoutMs = timeoutSeconds * 1000;
|
|
551
557
|
if (timeoutMs > maxAgeMs) {
|
|
552
558
|
maxAgeMs = timeoutMs;
|
|
@@ -559,7 +565,7 @@ async function getLastActivityMs(meta) {
|
|
|
559
565
|
const candidates = new Set();
|
|
560
566
|
candidates.add(logPath(meta.id));
|
|
561
567
|
const modelNames = new Set();
|
|
562
|
-
if (typeof meta.model ===
|
|
568
|
+
if (typeof meta.model === "string" && meta.model.length > 0) {
|
|
563
569
|
modelNames.add(meta.model);
|
|
564
570
|
}
|
|
565
571
|
if (Array.isArray(meta.models)) {
|
|
@@ -598,10 +604,10 @@ function isProcessAlive(pid) {
|
|
|
598
604
|
}
|
|
599
605
|
catch (error) {
|
|
600
606
|
const code = error instanceof Error ? error.code : undefined;
|
|
601
|
-
if (code ===
|
|
607
|
+
if (code === "ESRCH" || code === "EINVAL") {
|
|
602
608
|
return false;
|
|
603
609
|
}
|
|
604
|
-
if (code ===
|
|
610
|
+
if (code === "EPERM") {
|
|
605
611
|
return true;
|
|
606
612
|
}
|
|
607
613
|
return true;
|
|
@@ -625,11 +631,11 @@ async function isPortOpen(host, port) {
|
|
|
625
631
|
resolve(result);
|
|
626
632
|
};
|
|
627
633
|
const timer = setTimeout(() => cleanup(false), CHROME_RUNTIME_TIMEOUT_MS);
|
|
628
|
-
socket.once(
|
|
634
|
+
socket.once("connect", () => {
|
|
629
635
|
clearTimeout(timer);
|
|
630
636
|
cleanup(true);
|
|
631
637
|
});
|
|
632
|
-
socket.once(
|
|
638
|
+
socket.once("error", () => {
|
|
633
639
|
clearTimeout(timer);
|
|
634
640
|
cleanup(false);
|
|
635
641
|
});
|
package/dist/src/sessionStore.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ensureSessionStorage, initializeSession, readSessionMetadata, updateSessionMetadata, createSessionLogWriter, readSessionLog, readModelLog, readSessionRequest, listSessionsMetadata, filterSessionsByRange, deleteSessionsOlderThan, updateModelRunMetadata, getSessionPaths, getSessionsDir, } from
|
|
1
|
+
import { ensureSessionStorage, initializeSession, readSessionMetadata, updateSessionMetadata, createSessionLogWriter, readSessionLog, readModelLog, readSessionRequest, listSessionsMetadata, filterSessionsByRange, deleteSessionsOlderThan, updateModelRunMetadata, getSessionPaths, getSessionsDir, } from "./sessionManager.js";
|
|
2
2
|
class FileSessionStore {
|
|
3
3
|
ensureStorage() {
|
|
4
4
|
return ensureSessionStorage();
|
|
@@ -44,9 +44,9 @@ class FileSessionStore {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
export const sessionStore = new FileSessionStore();
|
|
47
|
-
export { wait } from
|
|
47
|
+
export { wait } from "./sessionManager.js";
|
|
48
48
|
export async function pruneOldSessions(hours, log) {
|
|
49
|
-
if (typeof hours !==
|
|
49
|
+
if (typeof hours !== "number" || Number.isNaN(hours) || hours <= 0) {
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
const result = await sessionStore.deleteOlderThan({ hours });
|
package/dist/src/version.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readFileSync } from
|
|
2
|
-
import path from
|
|
3
|
-
import { fileURLToPath } from
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
4
|
let cachedVersion = null;
|
|
5
5
|
export function getCliVersion() {
|
|
6
6
|
if (cachedVersion) {
|
|
@@ -15,18 +15,18 @@ function readVersionFromPackage() {
|
|
|
15
15
|
const filesystemRoot = path.parse(currentDir).root;
|
|
16
16
|
// biome-ignore lint/nursery/noUnnecessaryConditions: deliberate sentinel loop to walk up directories
|
|
17
17
|
while (true) {
|
|
18
|
-
const candidate = path.join(currentDir,
|
|
18
|
+
const candidate = path.join(currentDir, "package.json");
|
|
19
19
|
try {
|
|
20
|
-
const raw = readFileSync(candidate,
|
|
20
|
+
const raw = readFileSync(candidate, "utf8");
|
|
21
21
|
const parsed = JSON.parse(raw);
|
|
22
|
-
const version = typeof parsed.version ===
|
|
22
|
+
const version = typeof parsed.version === "string" && parsed.version.trim().length > 0
|
|
23
23
|
? parsed.version.trim()
|
|
24
|
-
:
|
|
24
|
+
: "0.0.0";
|
|
25
25
|
return version;
|
|
26
26
|
}
|
|
27
27
|
catch (error) {
|
|
28
|
-
const code = error instanceof Error &&
|
|
29
|
-
if (code && code !==
|
|
28
|
+
const code = error instanceof Error && "code" in error ? error.code : undefined;
|
|
29
|
+
if (code && code !== "ENOENT") {
|
|
30
30
|
break;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -35,5 +35,5 @@ function readVersionFromPackage() {
|
|
|
35
35
|
}
|
|
36
36
|
currentDir = path.dirname(currentDir);
|
|
37
37
|
}
|
|
38
|
-
return
|
|
38
|
+
return "0.0.0";
|
|
39
39
|
}
|
|
Binary file
|
|
Binary file
|
|
@@ -18,7 +18,9 @@ export APP_STORE_CONNECT_ISSUER_ID=YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY
|
|
|
18
18
|
- Output: `OracleNotifier.app` (arm64 only), bundled with `OracleIcon.icns`.
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
21
|
+
|
|
21
22
|
The CLI prefers this helper on macOS; if it fails or is missing, it falls back to toasted-notifier/terminal-notifier.
|
|
22
23
|
|
|
23
24
|
## Permissions
|
|
25
|
+
|
|
24
26
|
After first run, allow notifications for “Oracle Notifier” in System Settings → Notifications.
|