@oar-sh/oar 0.9.19 → 0.9.21
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/.github/extensions/web-relay/polling/polling-loop.mjs +2 -26
- package/.github/extensions/web-relay/skills/question-routing-hooks.mjs +2 -26
- package/CHANGELOG.md +529 -0
- package/README.md +14 -14
- package/bin/oar.js +392 -98
- package/package.json +4 -2
- package/server/claude-cloud-worker/claude-cloud-event-normalizer.mjs +60 -0
- package/server/claude-cloud-worker/claude-cloud-session-process.mjs +258 -1
- package/server/claude-cloud-worker/claude-cloud-session-worker.mjs +22 -1
- package/server/claude-cloud-worker/claude-cloud-worker-steering.mjs +34 -0
- package/server/claude-worker/claude-remote-relay-tool.mjs +1 -0
- package/server/claude-worker/claude-session-process.mjs +10 -0
- package/server/claude-worker/claude-session-worker-main.mjs +8 -1
- package/server/claude-worker/claude-turn-publisher.mjs +163 -8
- package/server/claude-worker/claude-usage-totals.mjs +58 -0
- package/server/copilot-worker/copilot-plan-board.mjs +4 -7
- package/server/copilot-worker/copilot-sdk-event-normalizer.mjs +86 -3
- package/server/copilot-worker/copilot-sdk-session-process.mjs +131 -5
- package/server/copilot-worker/copilot-sdk-session-worker.mjs +8 -1
- package/server/cursor-worker/cursor-session-worker.mjs +12 -1
- package/server/cursor-worker/cursor-turn-runner.mjs +42 -6
- package/server/cursor-worker/cursor-worker-steering.mjs +20 -0
- package/server/db-schema.mjs +18 -0
- package/server/deepseek-worker/deepseek-claude-backend.mjs +14 -0
- package/server/grok-worker/grok-background-tasks.mjs +9 -0
- package/server/grok-worker/grok-session-worker.mjs +12 -1
- package/server/grok-worker/grok-turn-runner.mjs +47 -6
- package/server/grok-worker/grok-worker-steering.mjs +23 -0
- package/server/migrations/0001-add-structured-answer.mjs +5 -7
- package/server/migrations/0002-recent-workspace-roots-path-key.mjs +5 -7
- package/server/migrations/0003-push-subscriptions.mjs +5 -7
- package/server/migrations/0004-steer-settle-markers.mjs +5 -7
- package/server/migrations/0005-remote-relays.mjs +5 -7
- package/server/migrations/0006-workspace-root-settings.mjs +5 -7
- package/server/migrations/0007-claude-cloud.mjs +5 -7
- package/server/migrations/0008-message-pins.mjs +5 -7
- package/server/migrations/0009-subagent-timeline.mjs +5 -7
- package/server/migrations/0010-subagent-timeline-pruning.mjs +5 -7
- package/server/migrations/0011-relay-event-subscriptions.mjs +5 -7
- package/server/migrations/0012-cross-relay-event-subscriptions.mjs +5 -7
- package/server/migrations/0013-previews.mjs +5 -7
- package/server/migrations/0014-conversation-groups.mjs +5 -7
- package/server/migrations/0015-conversation-group-position.mjs +5 -7
- package/server/migrations/0016-share-access-log.mjs +5 -7
- package/server/migrations/0017-conversation-history-indexes.mjs +5 -7
- package/server/migrations/0018-background-task-rows.mjs +5 -7
- package/server/migrations/0019-relay-event-subscription-options.mjs +5 -7
- package/server/migrations/0020-conversation-may-create-sessions.mjs +5 -7
- package/server/migrations/0021-conversation-group-agent-marks.mjs +5 -7
- package/server/migrations/0022-relay-schedules.mjs +5 -7
- package/server/migrations/0023-relay-asks.mjs +5 -7
- package/server/migrations/0024-deepseek-usage-totals.mjs +5 -7
- package/server/migrations/0025-deepseek-usage-requests-daily.mjs +5 -7
- package/server/migrations/0026-deepseek-usage-served-models.mjs +5 -7
- package/server/migrations/0027-deepseek-usage-checkpoint-runs.mjs +5 -7
- package/server/migrations/0028-deepseek-usage-checkpoint-request-runs.mjs +5 -7
- package/server/migrations/0029-deepseek-balance-rises.mjs +5 -7
- package/server/migrations/0030-deepseek-usage-actuals.mjs +5 -7
- package/server/migrations/0031-queue-provider.mjs +5 -7
- package/server/migrations/0032-runtime-session-billing-switch.mjs +5 -7
- package/server/migrations/0033-claude-api-usage-checkpoints.mjs +5 -7
- package/server/migrations/0034-claude-api-usage-totals.mjs +5 -7
- package/server/migrations/0035-conversation-plan-only.mjs +87 -0
- package/server/migrations/0036-token-usage.mjs +267 -0
- package/server/public/app/about-ui.js +1 -1
- package/server/public/app/about-view.mjs +106 -3
- package/server/public/app/action-confirmations.js +1 -1
- package/server/public/app/api-client.js +6 -3
- package/server/public/app/ask-user-view.js +20 -6
- package/server/public/app/attachments-view.js +1 -1
- package/server/public/app/back-guard.mjs +31 -5
- package/server/public/app/bootstrap.js +611 -70
- package/server/public/app/chat-actions-menu-state.mjs +139 -4
- package/server/public/app/chat-header-meta.mjs +27 -0
- package/server/public/app/claude-billing-toggle-ui.js +2 -1
- package/server/public/app/claude-cloud-conversation-ui.js +2 -2
- package/server/public/app/composer-control-state.mjs +12 -2
- package/server/public/app/composer-settings-label.mjs +90 -0
- package/server/public/app/composer-settings-ui.js +442 -0
- package/server/public/app/context-menu.mjs +36 -5
- package/server/public/app/context-usage-view.mjs +16 -0
- package/server/public/app/conversation-deep-link.mjs +15 -11
- package/server/public/app/conversation-group-drag.mjs +12 -2
- package/server/public/app/conversation-group-order.mjs +9 -2
- package/server/public/app/conversation-group-state.mjs +47 -10
- package/server/public/app/conversation-origin-ui.js +17 -1
- package/server/public/app/conversation-view.js +20 -2
- package/server/public/app/cwd-menu-placement.mjs +18 -6
- package/server/public/app/cwd-picker.js +36 -6
- package/server/public/app/emoji-view.js +1 -1
- package/server/public/app/font-scaling.js +26 -0
- package/server/public/app/header-priority-actions.mjs +234 -0
- package/server/public/app/hidden-messages-view.mjs +4 -0
- package/server/public/app/inbox-ui.js +50 -2
- package/server/public/app/inbox-view.mjs +141 -5
- package/server/public/app/journal-view.js +311 -58
- package/server/public/app/phone-landscape-ui.js +225 -0
- package/server/public/app/phone-landscape.mjs +99 -0
- package/server/public/app/phone-typing-state.mjs +104 -0
- package/server/public/app/pinned-messages-view.mjs +5 -0
- package/server/public/app/plan-board-shared.mjs +49 -0
- package/server/public/app/plan-usage-view.mjs +1 -1
- package/server/public/app/push-settings.js +2 -2
- package/server/public/app/pwa-install.js +24 -3
- package/server/public/app/relay-board-inline.mjs +4 -1
- package/server/public/app/relay-board-view.js +38 -10
- package/server/public/app/relay-event-subscriptions-ui.js +71 -22
- package/server/public/app/relay-event-view.mjs +42 -0
- package/server/public/app/relay-restart-ui.js +2 -2
- package/server/public/app/relay-schedule-view.mjs +32 -6
- package/server/public/app/relay-schedules-ui.js +69 -20
- package/server/public/app/remote-relay-origin-view.mjs +41 -23
- package/server/public/app/session-history-ui.js +250 -0
- package/server/public/app/session-history.mjs +599 -0
- package/server/public/app/settings-modal.js +61 -6
- package/server/public/app/settings-tabs.js +12 -0
- package/server/public/app/share-state.js +1 -1
- package/server/public/app/shared-conversations-settings.js +2 -2
- package/server/public/app/socket-handlers.js +15 -4
- package/server/public/app/status-view.mjs +18 -2
- package/server/public/app/store.js +87 -16
- package/server/public/app/subagent-viewer.mjs +27 -2
- package/server/public/app/tab-strip-fade.mjs +101 -0
- package/server/public/app/tap-actions.js +66 -0
- package/server/public/app/usage-limit-ui.js +63 -2
- package/server/public/app/viewer-history.mjs +13 -2
- package/server/public/index.html +2258 -1585
- package/server/public/sw.js +8 -0
- package/server/relay-heap-guard.mjs +14 -1
- package/server/relay-self-restart.mjs +83 -2
- package/server/relay-tools.md +5 -3
- package/server/repositories/message-repository.mjs +54 -1
- package/server/repositories/remote-relay-repository.mjs +10 -0
- package/server/repositories/session-repository.mjs +25 -1
- package/server/routes/claude-cloud-routes.mjs +19 -0
- package/server/routes/messages-routes.mjs +144 -1
- package/server/routes/relay-ask-routes.mjs +138 -8
- package/server/routes/relay-board-routes.mjs +55 -40
- package/server/routes/sessions-routes.mjs +144 -14
- package/server/server-runtime.mjs +322 -51
- package/server/services/about-service.mjs +81 -53
- package/server/services/cache-rebuild-service.mjs +7 -0
- package/server/services/claude-billing-swap-service.mjs +7 -20
- package/server/services/claude-cloud-session-service.mjs +47 -5
- package/server/services/conversation-preferences-service.mjs +31 -0
- package/server/services/database-file.mjs +413 -0
- package/server/services/db-backup-service.mjs +809 -0
- package/server/services/deepseek-usage-import.mjs +6 -9
- package/server/services/delete-archive-service.mjs +3 -0
- package/server/services/earlier-database-service.mjs +69 -126
- package/server/services/oar-cli-helpers.mjs +214 -12
- package/server/services/oar-cli-menu.mjs +1 -0
- package/server/services/oar-state-migration-service.mjs +33 -13
- package/server/services/package-data-rescue.mjs +4 -2
- package/server/services/plan-usage-claude-api.mjs +14 -15
- package/server/services/plan-usage-contract.mjs +6 -2
- package/server/services/plan-usage-deepseek.mjs +1 -1
- package/server/services/plan-usage-tokens.mjs +248 -0
- package/server/services/push-dispatch-service.mjs +134 -9
- package/server/services/relay-cli-launcher-service.mjs +3 -0
- package/server/services/relay-event-service.mjs +30 -0
- package/server/services/relay-question-context.mjs +11 -0
- package/server/services/relay-restart-picture.mjs +67 -22
- package/server/services/remote-inbox-watch-service.mjs +204 -0
- package/server/services/remote-relay-caller-context.mjs +80 -7
- package/server/services/remote-relay-dispatcher.mjs +101 -19
- package/server/services/restart-resume-service.mjs +5 -2
- package/server/services/session-activity-tracker.mjs +1 -1
- package/server/services/session-launch-mutex-service.mjs +23 -0
- package/server/services/session-worker-launch-service.mjs +12 -3
- package/server/services/session-worker-registry-service.mjs +36 -0
- package/server/services/session-worker-stop-service.mjs +27 -6
- package/server/services/session-worker-websocket-service.mjs +40 -16
- package/server/services/token-usage-service.mjs +430 -0
- package/server/services/update-install-service.mjs +13 -0
- package/server/services/usage-limit-pause-service.mjs +8 -1
- package/server/services/worker-recycle-service.mjs +772 -0
- package/server/services/worker-replacement.mjs +197 -0
- package/server/services/worker-scope.mjs +77 -0
- package/shared/build-id.mjs +128 -0
- package/shared/plan-board-actions.mjs +130 -0
- package/shared/plan-only.mjs +43 -0
- package/shared/relay-asks.mjs +3 -0
- package/shared/relay-events.mjs +38 -4
- package/shared/remote-relay-contract.mjs +66 -11
- package/shared/turn-token-usage.mjs +144 -0
- package/shared/worker-runtime/heartbeat.mjs +5 -0
- package/shared/worker-runtime/simple-steering-state.mjs +38 -0
- package/shared/worker-runtime/worker-websocket-link.mjs +23 -0
- package/shared/worker-runtime/working-directory.mjs +1 -1
|
@@ -29,6 +29,8 @@ let currentConversationId = '';
|
|
|
29
29
|
let currentProviderType = '';
|
|
30
30
|
let actionInFlight = false;
|
|
31
31
|
let wakeTimer = null;
|
|
32
|
+
// The report whose one-line warning was tapped open (its dismissedKey).
|
|
33
|
+
let expandedKey = '';
|
|
32
34
|
|
|
33
35
|
function notifyBilling(conversationId) {
|
|
34
36
|
const id = String(conversationId || '').trim();
|
|
@@ -88,6 +90,30 @@ export function usageLimitAccountText(state, nowMs = Date.now()) {
|
|
|
88
90
|
return `Claude usage at ${Math.round(utilization * 100)} % of the ${label} — resets ${resets}`;
|
|
89
91
|
}
|
|
90
92
|
|
|
93
|
+
/** "04:00" today, "Tue 04:00" on another day: the one-line banner's time. */
|
|
94
|
+
export function formatUsageLimitShortTime(iso, nowMs = Date.now()) {
|
|
95
|
+
const at = new Date(String(iso || ''));
|
|
96
|
+
if (Number.isNaN(at.getTime())) return '';
|
|
97
|
+
const clock = at.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
98
|
+
if (new Date(nowMs).toDateString() === at.toDateString()) return clock;
|
|
99
|
+
return `${at.toLocaleDateString([], { weekday: 'short' })} ${clock}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The account's line in one short line, for the compact banner:
|
|
104
|
+
* "⚠ Claude 94 % weekly · resets Tue 04:00", or at the limit
|
|
105
|
+
* "⚠ Claude weekly limit reached · resets Tue 04:00". '' when
|
|
106
|
+
* usageLimitAccountText says nothing.
|
|
107
|
+
*/
|
|
108
|
+
export function usageLimitAccountShortText(state, nowMs = Date.now()) {
|
|
109
|
+
if (!usageLimitAccountText(state, nowMs)) return '';
|
|
110
|
+
const label = String(state.label || 'usage limit');
|
|
111
|
+
const resets = formatUsageLimitShortTime(state.resetsAt, nowMs);
|
|
112
|
+
if (state.status === 'rejected') return `⚠ Claude ${label} reached · resets ${resets}`;
|
|
113
|
+
const limitWindow = label.replace(/\s*limit$/i, '').trim() || label;
|
|
114
|
+
return `⚠ Claude ${Math.round(Number(state.utilization) * 100)} % ${limitWindow} · resets ${resets}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
91
117
|
/**
|
|
92
118
|
* Whether the usage-limit note offers to move the chat to the API key: a
|
|
93
119
|
* subscription chat (never a cloud one) whose relay says the switch is
|
|
@@ -201,6 +227,8 @@ export function renderUsageLimitBanner(nowMs = Date.now()) {
|
|
|
201
227
|
const banner = document.getElementById(BANNER_ID);
|
|
202
228
|
if (!banner) return;
|
|
203
229
|
const children = [];
|
|
230
|
+
let compact = false;
|
|
231
|
+
let expanded = false;
|
|
204
232
|
const pause = activeUsageLimitPause(currentConversationId, nowMs);
|
|
205
233
|
if (pause) {
|
|
206
234
|
const text = document.createElement('span');
|
|
@@ -225,14 +253,46 @@ export function renderUsageLimitBanner(nowMs = Date.now()) {
|
|
|
225
253
|
? usageLimitAccountText(account, nowMs)
|
|
226
254
|
: '';
|
|
227
255
|
if (line) {
|
|
256
|
+
// One line with the full sentence in the title; a tap on it opens the
|
|
257
|
+
// full sentence until the report changes.
|
|
258
|
+
if (expandedKey && expandedKey !== dismissedKey(account)) expandedKey = '';
|
|
259
|
+
expanded = expandedKey !== '' && expandedKey === dismissedKey(account);
|
|
228
260
|
const text = document.createElement('span');
|
|
229
261
|
text.className = 'usage-limit-text';
|
|
230
|
-
text.textContent = line;
|
|
231
|
-
|
|
262
|
+
text.textContent = expanded ? line : (usageLimitAccountShortText(account, nowMs) || line);
|
|
263
|
+
text.title = line;
|
|
264
|
+
text.setAttribute('role', 'button');
|
|
265
|
+
text.tabIndex = 0;
|
|
266
|
+
text.setAttribute('aria-expanded', expanded ? 'true' : 'false');
|
|
267
|
+
const toggle = (event) => {
|
|
268
|
+
event.preventDefault();
|
|
269
|
+
expandedKey = expanded ? '' : dismissedKey(account);
|
|
270
|
+
renderUsageLimitBanner();
|
|
271
|
+
};
|
|
272
|
+
text.addEventListener('click', toggle);
|
|
273
|
+
text.addEventListener('keydown', (event) => {
|
|
274
|
+
if (event.key === 'Enter' || event.key === ' ') toggle(event);
|
|
275
|
+
});
|
|
276
|
+
const hide = button('✕', 'usage-limit-dismiss', async () => dismissWarning());
|
|
277
|
+
hide.title = 'Hide';
|
|
278
|
+
hide.setAttribute('aria-label', 'Hide');
|
|
279
|
+
children.push(text, hide);
|
|
232
280
|
banner.dataset.state = account.status === 'rejected' ? 'reached' : 'warning';
|
|
281
|
+
compact = true;
|
|
233
282
|
}
|
|
234
283
|
}
|
|
284
|
+
banner.classList.toggle('usage-limit-compact', compact);
|
|
285
|
+
banner.classList.toggle('usage-limit-expanded', compact && expanded);
|
|
286
|
+
// The banner is drawn anew: the control that had the focus (the line's
|
|
287
|
+
// toggle, a button) gets it back in its new node, found by its class.
|
|
288
|
+
const focused = typeof document.activeElement?.className === 'string' && banner.contains(document.activeElement)
|
|
289
|
+
? document.activeElement.className
|
|
290
|
+
: '';
|
|
235
291
|
banner.replaceChildren(...children);
|
|
292
|
+
if (focused) {
|
|
293
|
+
const again = children.find((child) => child.className === focused);
|
|
294
|
+
try { again?.focus({ preventScroll: true }); } catch {}
|
|
295
|
+
}
|
|
236
296
|
banner.classList.toggle('visible', children.length > 0);
|
|
237
297
|
banner.hidden = children.length === 0;
|
|
238
298
|
if (!children.length) delete banner.dataset.state;
|
|
@@ -350,6 +410,7 @@ export function __resetUsageLimitUiForTests() {
|
|
|
350
410
|
currentConversationId = '';
|
|
351
411
|
currentProviderType = '';
|
|
352
412
|
actionInFlight = false;
|
|
413
|
+
expandedKey = '';
|
|
353
414
|
if (wakeTimer) { clearTimeout(wakeTimer); wakeTimer = null; }
|
|
354
415
|
try { localStorage.removeItem(DISMISSED_KEY); } catch {}
|
|
355
416
|
renderUsageLimitBanner();
|
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
// and the pop closes the viewer. Closing by any other means (the × button,
|
|
5
5
|
// Escape, a swipe down) pops that entry itself so history is left as it
|
|
6
6
|
// was, and the pop that follows is recognised as our own and ignored. The
|
|
7
|
-
// address never changes: the entry carries only its state
|
|
7
|
+
// address never changes: the entry carries only its state, its place in the
|
|
8
|
+
// stack and the visit's marks of the entry below (session-history.mjs, the
|
|
9
|
+
// back guard).
|
|
10
|
+
|
|
11
|
+
import { HISTORY_POSITION, inheritedVisitMarks } from './back-guard.mjs';
|
|
8
12
|
|
|
9
13
|
export const VIEWER_HISTORY_MARK = 'oarFileViewer';
|
|
10
14
|
const OWN_POP_WINDOW_MS = 1500;
|
|
@@ -18,7 +22,11 @@ export function createViewerHistory({ history, onBack, now = () => Date.now(), m
|
|
|
18
22
|
/** The viewer came up: one entry, however many files it then shows. */
|
|
19
23
|
opened() {
|
|
20
24
|
if (state.pushed) return;
|
|
21
|
-
|
|
25
|
+
const below = history.state;
|
|
26
|
+
const entry = { ...inheritedVisitMarks(below), [mark]: true };
|
|
27
|
+
const position = below?.[HISTORY_POSITION];
|
|
28
|
+
if (Number.isFinite(position)) entry[HISTORY_POSITION] = position + 1;
|
|
29
|
+
history.pushState(entry, '');
|
|
22
30
|
state.pushed = true;
|
|
23
31
|
},
|
|
24
32
|
/** The viewer went away by itself: take its entry back out of history. */
|
|
@@ -38,6 +46,9 @@ export function createViewerHistory({ history, onBack, now = () => Date.now(), m
|
|
|
38
46
|
}
|
|
39
47
|
state.ownPopAt = 0;
|
|
40
48
|
if (!state.pushed) return;
|
|
49
|
+
// Our entry is still the current one: what was popped lay above it
|
|
50
|
+
// (a dialog opened over the viewer), the viewer stays.
|
|
51
|
+
if (history.state?.[mark]) return;
|
|
41
52
|
state.pushed = false;
|
|
42
53
|
onBack?.();
|
|
43
54
|
},
|