@beeuni/sdk 0.2.0 → 0.3.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/README.md +19 -10
- package/dist/beeuni.esm.min.js +37 -35
- package/dist/beeuni.global.js +37 -35
- package/dist/browser/cache/idb-sync-cache.js +15 -5
- package/dist/browser/session-sync/server-transcript-mirror.d.ts +7 -1
- package/dist/browser/session-sync/server-transcript-mirror.js +30 -24
- package/dist/browser/session-sync/session-sync-registry.d.ts +3 -1
- package/dist/browser/session-sync/session-sync-registry.js +48 -3
- package/dist/browser/stores/sync-store/keep-unchanged.d.ts +4 -0
- package/dist/browser/stores/sync-store/keep-unchanged.js +34 -0
- package/dist/browser/stores/sync-store.d.ts +1 -0
- package/dist/browser/stores/sync-store.js +72 -16
- package/dist/core/attachments/prompt-attachments.d.ts +4 -0
- package/dist/core/attachments/prompt-attachments.js +34 -0
- package/dist/core/capture/rules.d.ts +17 -0
- package/dist/core/capture/rules.js +27 -0
- package/dist/core/client/beeuni.d.ts +92 -5
- package/dist/core/client/beeuni.js +2 -0
- package/dist/core/client/capture.d.ts +105 -0
- package/dist/core/client/capture.js +48 -0
- package/dist/core/client/facade-identity.d.ts +1 -0
- package/dist/core/client/facade-identity.js +1 -0
- package/dist/core/client/project-access-resources.d.ts +3 -1
- package/dist/core/client/project-access-resources.js +1 -1
- package/dist/core/client/project-operations-admin.d.ts +4 -4
- package/dist/core/client/project-operations-review.d.ts +2 -3
- package/dist/core/client/project-operations-review.js +1 -0
- package/dist/core/client/project-operations-workspace.d.ts +4 -4
- package/dist/core/client/project-operations-workspace.js +1 -1
- package/dist/core/client/project-operations.d.ts +5 -4
- package/dist/core/client/session-context.d.ts +2 -0
- package/dist/core/client/session-handle.d.ts +13 -0
- package/dist/core/client/session-lifecycle-resources.d.ts +11 -0
- package/dist/core/client/session-lifecycle-resources.js +4 -0
- package/dist/core/client/session-lifecycle-security.d.ts +2 -0
- package/dist/core/client/session-lifecycle-security.js +1 -0
- package/dist/core/client/session-readiness.d.ts +2 -0
- package/dist/core/client/session-readiness.js +20 -1
- package/dist/core/http/api-client.d.ts +1 -0
- package/dist/core/http/api-client.js +1 -0
- package/dist/core/http/config.d.ts +2 -0
- package/dist/core/http/response-error.js +26 -11
- package/dist/core/http/transport.js +6 -1
- package/dist/core/models/composer-model.d.ts +14 -0
- package/dist/core/models/composer-model.js +21 -1
- package/dist/core/rest/platform-client/capture.d.ts +363 -0
- package/dist/core/rest/platform-client/capture.js +116 -0
- package/dist/core/rest/platform-client/index.d.ts +1 -0
- package/dist/core/rest/platform-client/index.js +1 -0
- package/dist/core/rest/platform-client/lifecycle.js +18 -12
- package/dist/core/rest/platform-client/shared.d.ts +5 -0
- package/dist/core/rest/platform-client/shared.js +18 -0
- package/dist/core/rest/projects-client/account-secret-resources.d.ts +2 -1
- package/dist/core/rest/projects-client/accounts.d.ts +34 -0
- package/dist/core/rest/projects-client/accounts.js +10 -0
- package/dist/core/rest/projects-client/admin-providers.d.ts +0 -61
- package/dist/core/rest/projects-client/admin-providers.js +0 -6
- package/dist/core/rest/projects-client/agent-config.d.ts +3 -0
- package/dist/core/rest/projects-client/apps-fleet.d.ts +5 -1
- package/dist/core/rest/projects-client/apps-fleet.js +2 -2
- package/dist/core/rest/projects-client/apps.d.ts +3 -0
- package/dist/core/rest/projects-client/change-requests.d.ts +2 -0
- package/dist/core/rest/projects-client/change-requests.js +2 -0
- package/dist/core/rest/projects-client/connectors.d.ts +7 -0
- package/dist/core/rest/projects-client/connectors.js +3 -0
- package/dist/core/rest/projects-client/files.d.ts +3 -0
- package/dist/core/rest/projects-client/files.js +4 -0
- package/dist/core/rest/projects-client/gateway.d.ts +5 -0
- package/dist/core/rest/projects-client/iam-actions.d.ts +76 -0
- package/dist/core/rest/projects-client/iam-actions.js +101 -0
- package/dist/core/rest/projects-client/iam.d.ts +1 -0
- package/dist/core/rest/projects-client/iam.js +1 -0
- package/dist/core/rest/projects-client/notifications.d.ts +1 -1
- package/dist/core/rest/projects-client/notifications.js +4 -0
- package/dist/core/rest/projects-client/projects.d.ts +3 -2
- package/dist/core/rest/projects-client/projects.js +2 -3
- package/dist/core/rest/projects-client/review-items.d.ts +2 -0
- package/dist/core/rest/projects-client/review-items.js +4 -0
- package/dist/core/rest/projects-client/review.d.ts +17 -3
- package/dist/core/rest/projects-client/review.js +11 -0
- package/dist/core/rest/projects-client/secrets.d.ts +3 -0
- package/dist/core/rest/projects-client/session-attachments.js +14 -1
- package/dist/core/rest/projects-client/sessions.d.ts +29 -2
- package/dist/core/rest/projects-client/sessions.js +34 -4
- package/dist/core/runtime/runtime-rest-client.js +1 -1
- package/dist/core/runtime/runtime-types.d.ts +1 -0
- package/dist/core/session/open-bundle.d.ts +4 -4
- package/dist/core/session/open-bundle.js +29 -46
- package/dist/core/session/turn-end-watch.d.ts +47 -0
- package/dist/core/session/turn-end-watch.js +141 -0
- package/dist/core/session-log/index.d.ts +4 -0
- package/dist/core/session-log/index.js +3 -0
- package/dist/core/session-log/tool-call.d.ts +7 -2
- package/dist/core/session-log/tool-call.js +25 -6
- package/dist/core/session-log/turns/blocks.d.ts +60 -0
- package/dist/core/session-log/turns/blocks.js +124 -0
- package/dist/core/session-log/turns/history.d.ts +32 -0
- package/dist/core/session-log/turns/history.js +99 -0
- package/dist/core/session-log/turns/index.d.ts +4 -0
- package/dist/core/session-log/turns/index.js +4 -0
- package/dist/core/session-log/turns/metrics.d.ts +21 -0
- package/dist/core/session-log/turns/metrics.js +29 -0
- package/dist/core/session-log/turns/turn.d.ts +55 -0
- package/dist/core/session-log/turns/turn.js +279 -0
- package/dist/core/session-log/turns/v1-parts.d.ts +8 -0
- package/dist/core/session-log/turns/v1-parts.js +43 -0
- package/dist/core/session-log/v1-view.d.ts +5 -2
- package/dist/core/session-log/v1-view.js +86 -22
- package/dist/core/session-log/v1.js +10 -3
- package/dist/core/session-sync/saved-transcript.d.ts +15 -1
- package/dist/core/session-sync/saved-transcript.js +55 -0
- package/dist/core/session-sync/session-sync-controller.js +3 -0
- package/dist/core/stream/event-stream.js +3 -3
- package/dist/core/turns/classify.js +4 -2
- package/dist/core/turns/edit-blocks.d.ts +1 -0
- package/dist/core/turns/edit-blocks.js +15 -0
- package/dist/core/turns/segments/burst-summary.d.ts +1 -0
- package/dist/core/turns/segments/burst-summary.js +24 -0
- package/dist/core/turns/segments/group-steps.d.ts +4 -3
- package/dist/core/turns/segments/group-steps.js +9 -6
- package/dist/core/turns/segments/narration.d.ts +5 -4
- package/dist/core/turns/segments/narration.js +12 -3
- package/dist/core/turns/segments/session-activity-groups.d.ts +2 -1
- package/dist/core/turns/segments/session-activity-groups.js +3 -1
- package/dist/core/turns/segments/step-label.d.ts +2 -1
- package/dist/core/turns/segments/step-label.js +3 -1
- package/dist/core/turns/segments/working-turn.d.ts +4 -2
- package/dist/core/turns/segments/working-turn.js +9 -8
- package/dist/core/turns/tool-kind.d.ts +1 -1
- package/dist/core/turns/tool-kind.js +3 -2
- package/dist/core/turns/tool-registry.js +1 -0
- package/dist/core/turns/tools/tool-meta.d.ts +1 -1
- package/dist/core/turns/tools/tool-meta.js +3 -2
- package/dist/core/turns/view-model.js +1 -13
- package/dist/genui/catalog.d.ts +28 -0
- package/dist/genui/catalog.js +396 -0
- package/dist/genui/expansion.d.ts +3 -0
- package/dist/genui/expansion.js +295 -0
- package/dist/genui/fence-entry.d.ts +2 -0
- package/dist/genui/fence-entry.js +1 -0
- package/dist/genui/fence.d.ts +21 -0
- package/dist/genui/fence.js +138 -0
- package/dist/genui/index.d.ts +6 -0
- package/dist/genui/index.js +6 -0
- package/dist/genui/markdown.d.ts +12 -0
- package/dist/genui/markdown.js +104 -0
- package/dist/genui/parse.d.ts +6 -0
- package/dist/genui/parse.js +75 -0
- package/dist/genui/prompt.d.ts +2 -0
- package/dist/genui/prompt.js +206 -0
- package/dist/genui/react/default-components.d.ts +2 -0
- package/dist/genui/react/default-components.js +72 -0
- package/dist/genui/react/default-components.test.d.ts +1 -0
- package/dist/genui/react/default-components.test.js +94 -0
- package/dist/genui/react/genui-block-disabled.test.d.ts +1 -0
- package/dist/genui/react/genui-block-disabled.test.js +50 -0
- package/dist/genui/react/genui-block.d.ts +28 -0
- package/dist/genui/react/genui-block.js +91 -0
- package/dist/genui/react/genui-block.test.d.ts +1 -0
- package/dist/genui/react/genui-block.test.js +205 -0
- package/dist/genui/react/index.d.ts +2 -0
- package/dist/genui/react/index.js +2 -0
- package/dist/genui/share.d.ts +5 -0
- package/dist/genui/share.js +30 -0
- package/dist/genui/test-fixtures.d.ts +2 -0
- package/dist/genui/test-fixtures.js +16 -0
- package/dist/genui/types.d.ts +29 -0
- package/dist/genui/types.js +1 -0
- package/dist/genui/urls.d.ts +1 -0
- package/dist/genui/urls.js +18 -0
- package/dist/genui/validate.d.ts +9 -0
- package/dist/genui/validate.js +116 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/internal/connector-catalog.d.ts +1 -0
- package/dist/platform/ui.d.ts +8 -2
- package/dist/platform/ui.js +19 -4
- package/dist/react/chat/use-chat-turns.d.ts +1 -1
- package/dist/react/human-presence.d.ts +9 -0
- package/dist/react/human-presence.js +12 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.js +4 -0
- package/dist/react/opencode.d.ts +1 -1
- package/dist/react/opencode.js +1 -1
- package/dist/react/query-contracts.d.ts +6 -0
- package/dist/react/query-contracts.js +6 -0
- package/dist/react/query-keys.d.ts +17 -1
- package/dist/react/query-keys.js +24 -1
- package/dist/react/reset-identity-state.js +2 -0
- package/dist/react/session-cache-write.d.ts +1 -0
- package/dist/react/session-cache-write.js +20 -0
- package/dist/react/session-transcript-subscription.js +1 -1
- package/dist/react/sign-in-with-beeuni.d.ts +5 -5
- package/dist/react/turn-end-handoff.d.ts +13 -0
- package/dist/react/turn-end-handoff.js +101 -0
- package/dist/react/use-admin-providers.d.ts +0 -3
- package/dist/react/use-admin-providers.js +1 -11
- package/dist/react/use-capture.d.ts +47 -0
- package/dist/react/use-capture.js +173 -0
- package/dist/react/use-feature-flag.js +1 -0
- package/dist/react/use-opencode-events/handle-interaction-event.js +8 -3
- package/dist/react/use-opencode-events/handle-session-event.js +13 -8
- package/dist/react/use-opencode-events/handler-context.d.ts +1 -0
- package/dist/react/use-opencode-events/helpers.d.ts +1 -0
- package/dist/react/use-opencode-events/helpers.js +11 -1
- package/dist/react/use-opencode-local.d.ts +5 -1
- package/dist/react/use-opencode-local.js +15 -2
- package/dist/react/use-opencode-sessions/commands.d.ts +11 -1
- package/dist/react/use-opencode-sessions/commands.js +21 -1
- package/dist/react/use-opencode-sessions/permissions.js +28 -1
- package/dist/react/use-project-sessions.d.ts +1 -1
- package/dist/react/use-project-sessions.js +6 -5
- package/dist/react/use-prompt-attachments.js +1 -0
- package/dist/react/use-review-summary.d.ts +13 -0
- package/dist/react/use-review-summary.js +32 -0
- package/dist/react/use-runtime-reconnect.js +2 -2
- package/dist/react/use-session-list-state.d.ts +6 -0
- package/dist/react/use-session-list-state.js +33 -0
- package/dist/react/use-session-log.d.ts +3 -2
- package/dist/react/use-session-log.js +26 -17
- package/dist/react/use-session-messages.d.ts +2 -1
- package/dist/react/use-session-messages.js +15 -14
- package/dist/react/use-session-stream.js +12 -1
- package/dist/react/use-session-sync.d.ts +2 -2
- package/dist/react/use-session-sync.js +10 -8
- package/dist/react/use-session-transcript-history.js +2 -12
- package/dist/react/use-session-working.d.ts +2 -0
- package/dist/react/use-session-working.js +10 -0
- package/dist/react/use-session.d.ts +6 -0
- package/dist/react/use-session.js +87 -7
- package/package.json +49 -3
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
import { getClient } from '../../core/runtime/client.js';
|
|
2
2
|
import { unwrap } from './shared.js';
|
|
3
|
-
|
|
3
|
+
const repliesInFlight = new Map();
|
|
4
|
+
function permissionAlreadyAnswered(result) {
|
|
5
|
+
if (result.response?.status !== 404)
|
|
6
|
+
return false;
|
|
7
|
+
const err = result.error;
|
|
8
|
+
if (typeof err === 'string') {
|
|
9
|
+
return err.toLowerCase().includes('permission request not found');
|
|
10
|
+
}
|
|
11
|
+
if (!err || typeof err !== 'object')
|
|
12
|
+
return false;
|
|
13
|
+
const rec = err;
|
|
14
|
+
const data = rec.data && typeof rec.data === 'object' ? rec.data : undefined;
|
|
15
|
+
const message = data?.message ?? rec.message ?? rec.error ?? '';
|
|
16
|
+
return String(message).toLowerCase().includes('permission request not found');
|
|
17
|
+
}
|
|
18
|
+
async function sendPermissionReply(requestId, reply, message) {
|
|
4
19
|
const client = getClient();
|
|
5
20
|
const result = await client.permission.reply({ requestID: requestId, reply, message });
|
|
21
|
+
if (permissionAlreadyAnswered(result))
|
|
22
|
+
return;
|
|
6
23
|
unwrap(result);
|
|
7
24
|
}
|
|
25
|
+
export async function replyToPermission(requestId, reply, message) {
|
|
26
|
+
const inFlight = repliesInFlight.get(requestId);
|
|
27
|
+
if (inFlight)
|
|
28
|
+
return inFlight;
|
|
29
|
+
const send = sendPermissionReply(requestId, reply, message).finally(() => {
|
|
30
|
+
repliesInFlight.delete(requestId);
|
|
31
|
+
});
|
|
32
|
+
repliesInFlight.set(requestId, send);
|
|
33
|
+
return send;
|
|
34
|
+
}
|
|
8
35
|
const KNOWN_PERMISSION_TYPES = [
|
|
9
36
|
'bash',
|
|
10
37
|
'edit',
|
|
@@ -9,7 +9,7 @@ export declare function shouldScanPastEmptySessionPages(data: {
|
|
|
9
9
|
pages: ProjectSessionPage[];
|
|
10
10
|
pageParams: unknown[];
|
|
11
11
|
} | undefined, hasNextPage: boolean): boolean;
|
|
12
|
-
export interface UseProjectSessionsOptions extends Pick<ListProjectSessionsOptions, 'scope' | 'limit' | 'parent' | 'startedBy' | 'q' | 'labels'> {
|
|
12
|
+
export interface UseProjectSessionsOptions extends Pick<ListProjectSessionsOptions, 'scope' | 'limit' | 'parent' | 'startedBy' | 'q' | 'labels' | 'view'> {
|
|
13
13
|
enabled?: boolean;
|
|
14
14
|
refetchInterval?: number | false | ((sessions: ProjectSession[]) => number | false);
|
|
15
15
|
refetchOnWindowFocus?: boolean;
|
|
@@ -31,9 +31,9 @@ export function shouldScanPastEmptySessionPages(data, hasNextPage) {
|
|
|
31
31
|
}
|
|
32
32
|
export function useProjectSessions(projectId, options) {
|
|
33
33
|
const scope = options?.scope ?? 'visible';
|
|
34
|
-
const { parent, startedBy, q, labels } = options ?? {};
|
|
34
|
+
const { parent, startedBy, q, labels, view } = options ?? {};
|
|
35
35
|
const query = useInfiniteQuery({
|
|
36
|
-
queryKey: qk.project.sessionsPaged(projectId, scope, { parent, startedBy, q, labels }),
|
|
36
|
+
queryKey: qk.project.sessionsPaged(projectId, scope, { parent, startedBy, q, labels, view }),
|
|
37
37
|
initialPageParam: null,
|
|
38
38
|
queryFn: ({ pageParam }) => listProjectSessionsPage(projectId, {
|
|
39
39
|
scope,
|
|
@@ -43,6 +43,7 @@ export function useProjectSessions(projectId, options) {
|
|
|
43
43
|
startedBy,
|
|
44
44
|
q,
|
|
45
45
|
labels,
|
|
46
|
+
view,
|
|
46
47
|
}),
|
|
47
48
|
getNextPageParam: projectSessionsPageParam,
|
|
48
49
|
enabled: options?.enabled ?? true,
|
|
@@ -55,12 +56,12 @@ export function useProjectSessions(projectId, options) {
|
|
|
55
56
|
return interval(flattenProjectSessionPages(query.state.data));
|
|
56
57
|
},
|
|
57
58
|
});
|
|
58
|
-
const isScanning = shouldScanPastEmptySessionPages(query.data, query.hasNextPage);
|
|
59
|
-
const { isFetching, fetchNextPage } = query;
|
|
59
|
+
const isScanning = shouldScanPastEmptySessionPages(query.data, query.hasNextPage) && !query.isError;
|
|
60
|
+
const { isFetching, data, dataUpdatedAt, fetchNextPage } = query;
|
|
60
61
|
useEffect(() => {
|
|
61
62
|
if (isScanning && !isFetching)
|
|
62
63
|
void fetchNextPage();
|
|
63
|
-
}, [isScanning, isFetching, fetchNextPage]);
|
|
64
|
+
}, [isScanning, isFetching, data, dataUpdatedAt, fetchNextPage]);
|
|
64
65
|
return {
|
|
65
66
|
...query,
|
|
66
67
|
isScanning,
|
|
@@ -22,6 +22,7 @@ export function usePromptAttachments(projectId, options = {}) {
|
|
|
22
22
|
return useMemo(() => ({
|
|
23
23
|
add: controller.add,
|
|
24
24
|
addMany: controller.addMany,
|
|
25
|
+
restore: controller.restore,
|
|
25
26
|
retry: controller.retry,
|
|
26
27
|
remove: controller.remove,
|
|
27
28
|
abort: controller.abort,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ApiReviewItem, type ReviewItemsPage, type ReviewItemsQuery } from '../core/rest/projects-client/index.js';
|
|
2
|
+
export declare function useReviewSummary(projectId: string, options?: {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
refetchInterval?: number | false;
|
|
5
|
+
}): import("@tanstack/react-query").UseQueryResult<import("../index.js").ReviewSummary, Error>;
|
|
6
|
+
export declare function nextReviewItemsCursor(page: ReviewItemsPage): string | undefined;
|
|
7
|
+
export declare function reviewItemsOf(data: {
|
|
8
|
+
pages: ReadonlyArray<Pick<ReviewItemsPage, 'review_items'>>;
|
|
9
|
+
} | undefined): ApiReviewItem[];
|
|
10
|
+
export declare function useReviewItemPages(projectId: string, query?: ReviewItemsQuery, options?: {
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
refetchInterval?: number | false;
|
|
13
|
+
}): import("@tanstack/react-query").UseInfiniteQueryResult<import("@tanstack/react-query").InfiniteData<ReviewItemsPage, unknown>, Error>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
|
|
3
|
+
import { getReviewSummary, listReviewItems, } from '../core/rest/projects-client/index.js';
|
|
4
|
+
import { qk } from './query-keys.js';
|
|
5
|
+
export function useReviewSummary(projectId, options) {
|
|
6
|
+
const enabled = Boolean(projectId) && options?.enabled !== false;
|
|
7
|
+
return useQuery({
|
|
8
|
+
queryKey: qk.project.reviewSummary(projectId),
|
|
9
|
+
queryFn: () => getReviewSummary(projectId),
|
|
10
|
+
enabled,
|
|
11
|
+
staleTime: 5_000,
|
|
12
|
+
refetchInterval: enabled ? (options?.refetchInterval ?? 60_000) : false,
|
|
13
|
+
refetchOnWindowFocus: false,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function nextReviewItemsCursor(page) {
|
|
17
|
+
return page.next_cursor ?? undefined;
|
|
18
|
+
}
|
|
19
|
+
export function reviewItemsOf(data) {
|
|
20
|
+
return data?.pages.flatMap((page) => page.review_items) ?? [];
|
|
21
|
+
}
|
|
22
|
+
export function useReviewItemPages(projectId, query = {}, options) {
|
|
23
|
+
return useInfiniteQuery({
|
|
24
|
+
queryKey: qk.project.reviewItemPages(projectId, query),
|
|
25
|
+
queryFn: ({ pageParam }) => listReviewItems(projectId, { ...query, cursor: pageParam }),
|
|
26
|
+
initialPageParam: undefined,
|
|
27
|
+
getNextPageParam: nextReviewItemsCursor,
|
|
28
|
+
enabled: Boolean(projectId) && options?.enabled !== false,
|
|
29
|
+
staleTime: 5_000,
|
|
30
|
+
refetchInterval: options?.refetchInterval ?? false,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useEffect, useRef } from 'react';
|
|
3
|
-
import { getAuthToken } from '../core/http/auth.js';
|
|
3
|
+
import { getAuthToken as getSupabaseAccessToken } from '../core/http/auth.js';
|
|
4
4
|
import { CONNECTION_FAULT_GRACE_MS, getSessionHealth, isRuntimeReady, } from '../core/session/index.js';
|
|
5
5
|
import { incrementSandboxFail, markInitialCheckDone, resetForServerSwitch, resetSandboxFail, setRuntimeHealth, setRuntimeCapabilities, setSandboxStatus, useSandboxConnectionStore, } from '../browser/stores/sandbox-connection-store.js';
|
|
6
6
|
import { useServerStore } from '../browser/stores/server-store.js';
|
|
@@ -109,7 +109,7 @@ export function useRuntimeReconnect() {
|
|
|
109
109
|
scheduleNext();
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
|
-
token = await
|
|
112
|
+
token = await getSupabaseAccessToken();
|
|
113
113
|
if (!token) {
|
|
114
114
|
scheduleNext();
|
|
115
115
|
return;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type SessionListState } from '../core/rest/projects-client/sessions.js';
|
|
2
|
+
export declare function useSessionListState(projectId: string): {
|
|
3
|
+
isPending: boolean;
|
|
4
|
+
setPinned: (sessionId: string, pinned: boolean) => Promise<SessionListState>;
|
|
5
|
+
setArchived: (sessionId: string, archived: boolean) => Promise<SessionListState>;
|
|
6
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { setSessionArchived, setSessionPinned, } from '../core/rest/projects-client/sessions.js';
|
|
5
|
+
import { qk } from './query-keys.js';
|
|
6
|
+
import { updateCachedProjectSessions } from './session-cache-write.js';
|
|
7
|
+
function changedState(session, change, now) {
|
|
8
|
+
if ('pinned' in change) {
|
|
9
|
+
return { pinned_at: change.pinned ? (session.pinned_at ?? now) : null, archived_at: change.pinned ? null : (session.archived_at ?? null) };
|
|
10
|
+
}
|
|
11
|
+
return { archived_at: change.archived ? (session.archived_at ?? now) : null, pinned_at: change.archived ? null : (session.pinned_at ?? null) };
|
|
12
|
+
}
|
|
13
|
+
export function useSessionListState(projectId) {
|
|
14
|
+
const client = useQueryClient();
|
|
15
|
+
const write = (sessionId, state) => updateCachedProjectSessions(client, projectId, (sessions) => sessions.map((session) => (session.session_id === sessionId ? { ...session, ...state(session) } : session)));
|
|
16
|
+
const mutation = useMutation({
|
|
17
|
+
mutationFn: ({ sessionId, change }) => 'pinned' in change
|
|
18
|
+
? setSessionPinned(projectId, sessionId, change.pinned)
|
|
19
|
+
: setSessionArchived(projectId, sessionId, change.archived),
|
|
20
|
+
onMutate: ({ sessionId, change }) => {
|
|
21
|
+
const now = new Date().toISOString();
|
|
22
|
+
write(sessionId, (session) => changedState(session, change, now));
|
|
23
|
+
},
|
|
24
|
+
onSuccess: (state, { sessionId }) => write(sessionId, () => state),
|
|
25
|
+
onSettled: () => client.invalidateQueries({ queryKey: [...qk.project.sessionsScope(projectId), 'list-paged'] }),
|
|
26
|
+
});
|
|
27
|
+
const { mutateAsync, isPending } = mutation;
|
|
28
|
+
const actions = useMemo(() => ({
|
|
29
|
+
setPinned: (sessionId, pinned) => mutateAsync({ sessionId, change: { pinned } }),
|
|
30
|
+
setArchived: (sessionId, archived) => mutateAsync({ sessionId, change: { archived } }),
|
|
31
|
+
}), [mutateAsync]);
|
|
32
|
+
return { ...actions, isPending };
|
|
33
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { type SessionControlStreamOptions } from '../core/session/control-stream.js';
|
|
2
2
|
import { type LoadSessionLogPage, type SessionLogDialect } from '../core/session-log/source.js';
|
|
3
3
|
import type { SessionLog, SessionLogThread } from '../core/session-log/types.js';
|
|
4
|
-
import { type SessionMessagesSource } from './use-session-messages.js';
|
|
4
|
+
import { type SessionMessagesOptions, type SessionMessagesSource } from './use-session-messages.js';
|
|
5
5
|
export declare function useSessionLog(session: SessionMessagesSource): (SessionLog & {
|
|
6
6
|
source: 'v1' | 'v2';
|
|
7
7
|
}) | null;
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function useSessionLogRecord(session: Pick<SessionMessagesSource, 'sessionId'>): Partial<Omit<SessionLog, 'threads'>> | null;
|
|
9
|
+
export declare function useSessionLogThread(session: SessionMessagesSource, threadId?: string | null, options?: SessionMessagesOptions): SessionLogThread | null;
|
|
9
10
|
export declare function useSessionLogSync(projectId: string, sessionId: string, options: {
|
|
10
11
|
enabled: boolean;
|
|
11
12
|
loader?: LoadSessionLogPage | null;
|
|
@@ -4,12 +4,14 @@ import { useSandboxConnectionStore } from '../browser/stores/sandbox-connection-
|
|
|
4
4
|
import { useSyncStore } from '../browser/stores/sync-store.js';
|
|
5
5
|
import { openSessionStream } from '../core/session/control-stream.js';
|
|
6
6
|
import { savedSessionLogCopies } from '../core/session-log/saved-log.js';
|
|
7
|
-
import {
|
|
7
|
+
import { sessionLogOfV1Rows, sessionLogThreadWithV1Rows } from '../core/session-log/v1-view.js';
|
|
8
8
|
import { fetchFirstSessionLogPage, loadSessionLogPage, negotiateSessionLog, } from '../core/session-log/source.js';
|
|
9
9
|
import { currentSavedCopyStore } from '../core/session-sync/saved-copy-store.js';
|
|
10
10
|
import { selectSessionLog, selectSessionLogThread } from '../core/session-log/store.js';
|
|
11
11
|
import { useFeatureFlag } from './use-feature-flag.js';
|
|
12
|
-
import {
|
|
12
|
+
import { selectSessionRows } from './session-transcript-subscription.js';
|
|
13
|
+
import { usePacedStoreValue, useSessionMessages } from './use-session-messages.js';
|
|
14
|
+
const PACED = Symbol('paced');
|
|
13
15
|
const sourced = new WeakMap();
|
|
14
16
|
const withSource = (log, source) => {
|
|
15
17
|
let out = sourced.get(log);
|
|
@@ -17,9 +19,9 @@ const withSource = (log, source) => {
|
|
|
17
19
|
sourced.set(log, (out = { ...log, source }));
|
|
18
20
|
return out;
|
|
19
21
|
};
|
|
20
|
-
function useV1SessionLog(session, threadId) {
|
|
21
|
-
const native = threadId || session.runtimeSessionId || session.opencodeSessionId || null;
|
|
22
|
-
const rows = useSessionMessages({ ...session, runtimeSessionId: native });
|
|
22
|
+
function useV1SessionLog(session, threadId, enabled, options) {
|
|
23
|
+
const native = enabled ? threadId || session.runtimeSessionId || session.opencodeSessionId || null : null;
|
|
24
|
+
const rows = useSessionMessages({ ...session, runtimeSessionId: native, opencodeSessionId: null }, options);
|
|
23
25
|
return useMemo(() => (native && rows.length ? sessionLogOfV1Rows(session.sessionId, native, rows) : null), [session.sessionId, native, rows]);
|
|
24
26
|
}
|
|
25
27
|
export function useSessionLog(session) {
|
|
@@ -27,18 +29,27 @@ export function useSessionLog(session) {
|
|
|
27
29
|
const log = state.sessionLogs[session.sessionId];
|
|
28
30
|
return log ? selectSessionLog(log) : null;
|
|
29
31
|
});
|
|
30
|
-
const v1 = useV1SessionLog(session);
|
|
32
|
+
const v1 = useV1SessionLog(session, undefined, !v2);
|
|
31
33
|
return v2 ? withSource(v2, 'v2') : v1 ? withSource(v1, 'v1') : null;
|
|
32
34
|
}
|
|
33
|
-
export function
|
|
34
|
-
|
|
35
|
+
export function useSessionLogRecord(session) {
|
|
36
|
+
return useSyncStore((state) => state.sessionLogs[session.sessionId]?.session ?? null);
|
|
37
|
+
}
|
|
38
|
+
export function useSessionLogThread(session, threadId, options) {
|
|
39
|
+
const throttleMs = options?.throttleMs && options.throttleMs > 0 ? options.throttleMs : 0;
|
|
40
|
+
const select = (state) => {
|
|
35
41
|
const log = state.sessionLogs[session.sessionId];
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
if (!log)
|
|
43
|
+
return undefined;
|
|
44
|
+
const thread = selectSessionLogThread(log, threadId);
|
|
45
|
+
return thread && sessionLogThreadWithV1Rows(log, thread, selectSessionRows(state, thread.thread_id), (id) => state.optimisticEchoOf(thread.thread_id, id));
|
|
46
|
+
};
|
|
47
|
+
const live = useSyncStore((state) => (throttleMs ? PACED : select(state)));
|
|
48
|
+
const paced = usePacedStoreValue(select, `${session.sessionId}/${threadId ?? ''}`, throttleMs);
|
|
49
|
+
const v2 = live === PACED ? paced : live;
|
|
50
|
+
const v1 = useV1SessionLog(session, threadId, v2 === undefined, options);
|
|
39
51
|
return v2 !== undefined ? v2 : (v1?.threads[0] ?? null);
|
|
40
52
|
}
|
|
41
|
-
const pageThreadIsV1 = (page) => isV1Thread(page.threads.find((t) => t.thread_id === page.thread_id));
|
|
42
53
|
export function useSessionLogSync(projectId, sessionId, options) {
|
|
43
54
|
const loader = options.loader === undefined ? loadSessionLogPage : options.loader;
|
|
44
55
|
const joinStream = options.joinStream ?? openSessionStream;
|
|
@@ -71,7 +82,7 @@ export function useSessionLogSync(projectId, sessionId, options) {
|
|
|
71
82
|
const page = await fetchFirstSessionLogPage(loader, projectId, sessionId, controller.signal);
|
|
72
83
|
if (stopped)
|
|
73
84
|
return null;
|
|
74
|
-
if (page
|
|
85
|
+
if (page) {
|
|
75
86
|
store().applySessionLogPage(sessionId, page);
|
|
76
87
|
void copies?.write(projectId, sessionId, page);
|
|
77
88
|
}
|
|
@@ -93,15 +104,13 @@ export function useSessionLogSync(projectId, sessionId, options) {
|
|
|
93
104
|
busy = false;
|
|
94
105
|
if (stopped)
|
|
95
106
|
return;
|
|
96
|
-
if (page
|
|
107
|
+
if (page) {
|
|
97
108
|
setRefusedKey(null);
|
|
98
109
|
join({ schema: 'v2', onConnectionChange: onReconnect(() => void load()), onRuntimeResync: () => void load() });
|
|
99
110
|
return;
|
|
100
111
|
}
|
|
101
112
|
store().dropSessionLog(sessionId);
|
|
102
113
|
setRefusedKey(`${projectId}/${sessionId}`);
|
|
103
|
-
if (page)
|
|
104
|
-
return;
|
|
105
114
|
join({
|
|
106
115
|
onControl: (frame) => {
|
|
107
116
|
if (frame.type !== 'beeuni.control.turn')
|
|
@@ -119,7 +128,7 @@ export function useSessionLogSync(projectId, sessionId, options) {
|
|
|
119
128
|
const saved = await Promise.resolve(copies?.read(projectId, sessionId) ?? null).catch(() => null);
|
|
120
129
|
if (stopped)
|
|
121
130
|
return;
|
|
122
|
-
if (saved &&
|
|
131
|
+
if (saved && !store().sessionLogs[sessionId])
|
|
123
132
|
store().applySessionLogPage(sessionId, saved);
|
|
124
133
|
await attempt();
|
|
125
134
|
})();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type MessageWithParts } from '../browser/stores/sync-store.js';
|
|
1
|
+
import { useSyncStore, type MessageWithParts } from '../browser/stores/sync-store.js';
|
|
2
2
|
export interface SessionMessagesSource {
|
|
3
3
|
projectId: string;
|
|
4
4
|
sessionId: string;
|
|
@@ -9,3 +9,4 @@ export interface SessionMessagesOptions {
|
|
|
9
9
|
throttleMs?: number;
|
|
10
10
|
}
|
|
11
11
|
export declare function useSessionMessages(session: SessionMessagesSource, options?: SessionMessagesOptions): MessageWithParts[];
|
|
12
|
+
export declare function usePacedStoreValue<T>(read: (state: ReturnType<typeof useSyncStore.getState>) => T, key: string, throttleMs: number): T;
|
|
@@ -16,31 +16,32 @@ export function useSessionMessages(session, options = {}) {
|
|
|
16
16
|
return useMemo(() => messagesBeforeRewind(rows, rewind), [rows, rewind]);
|
|
17
17
|
}
|
|
18
18
|
function usePacedRows(readableSessionId, throttleMs) {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
return usePacedStoreValue((state) => (readableSessionId ? selectSessionRows(state, readableSessionId) : EMPTY_ROWS), readableSessionId, throttleMs);
|
|
20
|
+
}
|
|
21
|
+
export function usePacedStoreValue(read, key, throttleMs) {
|
|
22
|
+
const current = () => read(useSyncStore.getState());
|
|
23
|
+
const [state, setState] = useState(() => ({ key, value: current() }));
|
|
21
24
|
useEffect(() => {
|
|
22
25
|
if (!throttleMs)
|
|
23
26
|
return;
|
|
24
27
|
let lastShownAt = -Infinity;
|
|
25
28
|
let timer = null;
|
|
26
|
-
let shown
|
|
29
|
+
let shown;
|
|
27
30
|
const now = () => (typeof performance !== 'undefined' ? performance.now() : Date.now());
|
|
28
31
|
const flush = () => {
|
|
29
32
|
timer = null;
|
|
30
|
-
const
|
|
31
|
-
if (
|
|
33
|
+
const value = current();
|
|
34
|
+
if (value === shown)
|
|
32
35
|
return;
|
|
33
|
-
shown =
|
|
36
|
+
shown = value;
|
|
34
37
|
lastShownAt = now();
|
|
35
|
-
setState({
|
|
38
|
+
setState({ key, value });
|
|
36
39
|
};
|
|
37
|
-
const initial =
|
|
40
|
+
const initial = current();
|
|
38
41
|
shown = initial;
|
|
39
|
-
setState((prev) => prev.
|
|
40
|
-
? prev
|
|
41
|
-
: { id: readableSessionId, rows: initial });
|
|
42
|
+
setState((prev) => (prev.key === key && prev.value === initial ? prev : { key, value: initial }));
|
|
42
43
|
const unsubscribe = useSyncStore.subscribe(() => {
|
|
43
|
-
if (
|
|
44
|
+
if (current() === shown)
|
|
44
45
|
return;
|
|
45
46
|
const wait = throttleMs - (now() - lastShownAt);
|
|
46
47
|
if (wait <= 0) {
|
|
@@ -57,6 +58,6 @@ function usePacedRows(readableSessionId, throttleMs) {
|
|
|
57
58
|
if (timer !== null)
|
|
58
59
|
clearTimeout(timer);
|
|
59
60
|
};
|
|
60
|
-
}, [
|
|
61
|
-
return state.
|
|
61
|
+
}, [key, throttleMs]);
|
|
62
|
+
return state.key === key ? state.value : current();
|
|
62
63
|
}
|
|
@@ -10,19 +10,30 @@ import { qk } from './query-keys.js';
|
|
|
10
10
|
export function useSessionStreamConnected(projectId, sessionId) {
|
|
11
11
|
return useSyncExternalStore(subscribeSessionStreamConnections, () => !!projectId && !!sessionId && sessionStreamConnected(projectId, sessionId), () => false);
|
|
12
12
|
}
|
|
13
|
+
function openTurnsKey(turns) {
|
|
14
|
+
return (turns ?? []).map((turn) => turn.turn_token).sort().join(',');
|
|
15
|
+
}
|
|
13
16
|
export function applySessionControlFrame(queryClient, projectId, sessionId, frame, memory, nowMs = Date.now()) {
|
|
14
17
|
if (frame.type === 'beeuni.control.turn') {
|
|
15
18
|
const payload = frame.payload;
|
|
16
19
|
if (!payload?.known || !Array.isArray(payload.turns))
|
|
17
20
|
return;
|
|
21
|
+
const key = qk.project.sessionTurn(projectId, sessionId);
|
|
22
|
+
const previous = queryClient.getQueryData(key);
|
|
23
|
+
const canStop = typeof payload.can_stop === 'boolean'
|
|
24
|
+
? payload.can_stop
|
|
25
|
+
: previous && openTurnsKey(previous.turns) === openTurnsKey(payload.turns)
|
|
26
|
+
? previous.can_stop
|
|
27
|
+
: undefined;
|
|
18
28
|
const observation = {
|
|
19
29
|
turns: payload.turns,
|
|
20
30
|
...(payload.last_ended ? { last_ended: payload.last_ended } : {}),
|
|
21
31
|
...(payload.recent_failures ? { recent_failures: payload.recent_failures } : {}),
|
|
32
|
+
...(canStop !== undefined ? { can_stop: canStop } : {}),
|
|
22
33
|
...(payload.working ? { working: payload.working } : {}),
|
|
23
34
|
atMs: nowMs,
|
|
24
35
|
};
|
|
25
|
-
queryClient.setQueryData(
|
|
36
|
+
queryClient.setQueryData(key, observation);
|
|
26
37
|
return;
|
|
27
38
|
}
|
|
28
39
|
if (frame.type === 'beeuni.control.session') {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SessionTranscriptSyncEnvelope } from '../core/rest/projects-client/sessions.js';
|
|
2
|
-
import { loadSessionRuntimeStatus, loadSessionTranscriptMessages } from '../browser/session-sync/session-sync-registry.js';
|
|
3
|
-
export { loadSessionRuntimeStatus, loadSessionTranscriptMessages };
|
|
2
|
+
import { loadSessionExportMessages, loadSessionRuntimeStatus, loadSessionTranscriptMessages } from '../browser/session-sync/session-sync-registry.js';
|
|
3
|
+
export { loadSessionExportMessages, loadSessionRuntimeStatus, loadSessionTranscriptMessages };
|
|
4
4
|
type FileDiff = Omit<import('../core/runtime/runtime-types.js').SnapshotFileDiff, 'patch'> & {
|
|
5
5
|
patch?: string;
|
|
6
6
|
before?: string;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
3
3
|
import { claimSessionCacheOwnership, getSessionCacheOwnership, resolveSessionCacheOwnerScope, sessionCacheOwnerScopesConflict, } from '../browser/session-sync/session-cache-ownership.js';
|
|
4
|
-
import { getSessionSyncController, loadSessionRuntimeStatus, loadSessionTranscriptMessages, resetSessionSyncControllersForSession, retainSessionSyncController, } from '../browser/session-sync/session-sync-registry.js';
|
|
4
|
+
import { getSessionSyncController, loadSessionExportMessages, loadSessionRuntimeStatus, loadSessionTranscriptMessages, resetSessionSyncControllersForSession, retainSessionSyncController, } from '../browser/session-sync/session-sync-registry.js';
|
|
5
5
|
import { loadOlderSessionTranscriptMirror, loadSessionTranscriptMirror, mirrorMessagesForHydrate, parseBeeuniSessionScope, refreshSavedCopy, SAVED_COPY_REFRESH_DELAY_MS, shouldHydrateFromMirror, } from '../browser/session-sync/server-transcript-mirror.js';
|
|
6
6
|
import { currentSavedCopyStore } from '../core/session-sync/saved-copy-store.js';
|
|
7
7
|
import { chooseOlderSource, mirrorCursorAfter } from '../browser/session-sync/mirror-paging.js';
|
|
8
8
|
import { transcriptIsFragment } from '../core/session-sync/fragment.js';
|
|
9
9
|
import { onTabVisible } from '../browser/session-sync/visibility.js';
|
|
10
10
|
import { useSandboxConnectionStore } from '../browser/stores/sandbox-connection-store.js';
|
|
11
|
-
import { hasOnlyCacheSourcedMessages, useSyncStore } from '../browser/stores/sync-store.js';
|
|
11
|
+
import { hasOnlyCacheSourcedMessages, hasRuntimeConfirmedMessage, useSyncStore } from '../browser/stores/sync-store.js';
|
|
12
12
|
import { useCurrentRuntime } from './use-current-runtime.js';
|
|
13
13
|
import { selectSessionRows } from './session-transcript-subscription.js';
|
|
14
14
|
import { canQueryRuntimeSession } from './use-opencode-sessions/index.js';
|
|
15
|
-
export { loadSessionRuntimeStatus, loadSessionTranscriptMessages };
|
|
15
|
+
export { loadSessionExportMessages, loadSessionRuntimeStatus, loadSessionTranscriptMessages };
|
|
16
16
|
const EMPTY_DIFFS = [];
|
|
17
17
|
const EMPTY_TODOS = [];
|
|
18
18
|
const IDLE_STATUS = { type: 'idle' };
|
|
@@ -197,21 +197,23 @@ export function useSessionSync(sessionId, options = {}) {
|
|
|
197
197
|
setIsLoadingOlderMirror(false);
|
|
198
198
|
mirrorPageInFlight.current = null;
|
|
199
199
|
}, [beeuniSessionScope, sessionId]);
|
|
200
|
+
const savedCursorCovered = useSyncStore(() => !!mirrorCursor && !sync.hasOlder && hasRuntimeConfirmedMessage(sessionId, mirrorCursor));
|
|
201
|
+
const savedCursor = savedCursorCovered ? null : mirrorCursor;
|
|
200
202
|
const loadOlder = useCallback(() => {
|
|
201
203
|
const source = chooseOlderSource({
|
|
202
204
|
runtimeHasOlder: sync.hasOlder,
|
|
203
|
-
mirrorCursor,
|
|
205
|
+
mirrorCursor: savedCursor,
|
|
204
206
|
});
|
|
205
207
|
if (source === 'runtime')
|
|
206
208
|
return controller.loadOlder();
|
|
207
|
-
if (source !== 'mirror' || !
|
|
209
|
+
if (source !== 'mirror' || !savedCursor)
|
|
208
210
|
return Promise.resolve();
|
|
209
211
|
if (mirrorPageInFlight.current)
|
|
210
212
|
return mirrorPageInFlight.current;
|
|
211
213
|
setIsLoadingOlderMirror(true);
|
|
212
214
|
const pending = loadOlderSessionTranscriptMirror({
|
|
213
215
|
beeuniSessionScope,
|
|
214
|
-
before:
|
|
216
|
+
before: savedCursor,
|
|
215
217
|
child: savedChild ? sessionId : undefined,
|
|
216
218
|
})
|
|
217
219
|
.then((envelope) => {
|
|
@@ -231,7 +233,7 @@ export function useSessionSync(sessionId, options = {}) {
|
|
|
231
233
|
});
|
|
232
234
|
mirrorPageInFlight.current = pending;
|
|
233
235
|
return pending;
|
|
234
|
-
}, [controller, beeuniSessionScope,
|
|
236
|
+
}, [controller, beeuniSessionScope, savedCursor, savedChild, sessionId, sync.hasOlder]);
|
|
235
237
|
const retryTranscript = useCallback(() => {
|
|
236
238
|
void controller.reconcile('manual');
|
|
237
239
|
}, [controller]);
|
|
@@ -243,7 +245,7 @@ export function useSessionSync(sessionId, options = {}) {
|
|
|
243
245
|
isBusy,
|
|
244
246
|
isLoading,
|
|
245
247
|
mirrorState,
|
|
246
|
-
hasOlder: sync.hasOlder || Boolean(
|
|
248
|
+
hasOlder: sync.hasOlder || Boolean(savedCursor),
|
|
247
249
|
isLoadingOlder: sync.isLoadingOlder || isLoadingOlderMirror,
|
|
248
250
|
loadOlder,
|
|
249
251
|
diffs: diffs ?? EMPTY_DIFFS,
|
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useQuery } from '@tanstack/react-query';
|
|
3
|
-
import {
|
|
4
|
-
import { OPEN_BUNDLE_TRANSCRIPT_LIMIT, openBundleHistory, settledOpenBundle, } from '../core/session/open-bundle.js';
|
|
5
|
-
import { savedCopyEmptyRoot } from '../core/session-sync/saved-transcript.js';
|
|
3
|
+
import { loadSavedTranscript, savedCopyEmptyRoot } from '../core/session-sync/saved-transcript.js';
|
|
6
4
|
import { qk } from './query-keys.js';
|
|
7
5
|
export function useSessionTranscriptHistory(projectId, sessionId, enabled) {
|
|
8
6
|
const query = useQuery({
|
|
9
7
|
queryKey: [...qk.project.session(projectId, sessionId), 'transcript-history'],
|
|
10
|
-
queryFn: ({ signal }) => {
|
|
11
|
-
const bundle = settledOpenBundle(projectId, sessionId);
|
|
12
|
-
return ((bundle && openBundleHistory(bundle)) ??
|
|
13
|
-
getSessionTranscriptSync(projectId, sessionId, {
|
|
14
|
-
limit: OPEN_BUNDLE_TRANSCRIPT_LIMIT,
|
|
15
|
-
history: true,
|
|
16
|
-
signal,
|
|
17
|
-
}));
|
|
18
|
-
},
|
|
8
|
+
queryFn: ({ signal }) => loadSavedTranscript(projectId, sessionId, { signal }),
|
|
19
9
|
enabled: enabled && !!projectId && !!sessionId,
|
|
20
10
|
staleTime: 0,
|
|
21
11
|
gcTime: 0,
|
|
@@ -11,6 +11,7 @@ export interface SessionTurnObservation {
|
|
|
11
11
|
turns: SessionTurn[];
|
|
12
12
|
last_ended?: SessionTurnEnded;
|
|
13
13
|
recent_failures?: SessionTurnFailure[];
|
|
14
|
+
can_stop?: boolean;
|
|
14
15
|
working?: SessionWorkingVerdict;
|
|
15
16
|
atMs: number;
|
|
16
17
|
}
|
|
@@ -35,3 +36,4 @@ export declare function readSessionTurnObservation(projectId: string, sessionId:
|
|
|
35
36
|
}): Promise<SessionTurnObservation>;
|
|
36
37
|
export declare function useSessionWorking(projectId: string, sessionId: string, options?: UseSessionWorkingOptions): WorkingProjection;
|
|
37
38
|
export declare function useSessionTurnOutcome(projectId: string, sessionId: string): SessionTurnOutcome;
|
|
39
|
+
export declare function useSessionCanStop(projectId: string, sessionId: string): boolean;
|
|
@@ -59,6 +59,7 @@ export async function readSessionTurnObservation(projectId, sessionId, options =
|
|
|
59
59
|
turns: turn.turns,
|
|
60
60
|
last_ended: turn.last_ended,
|
|
61
61
|
recent_failures: turn.recent_failures,
|
|
62
|
+
...(turn.can_stop !== undefined ? { can_stop: turn.can_stop } : {}),
|
|
62
63
|
atMs: turn.atMs,
|
|
63
64
|
};
|
|
64
65
|
}
|
|
@@ -70,6 +71,7 @@ export async function readSessionTurnObservation(projectId, sessionId, options =
|
|
|
70
71
|
turns: status.turns ?? [],
|
|
71
72
|
last_ended: status.last_ended,
|
|
72
73
|
recent_failures: status.recent_failures,
|
|
74
|
+
...(typeof status.can_stop === 'boolean' ? { can_stop: status.can_stop } : {}),
|
|
73
75
|
atMs,
|
|
74
76
|
};
|
|
75
77
|
});
|
|
@@ -215,3 +217,11 @@ export function useSessionTurnOutcome(projectId, sessionId) {
|
|
|
215
217
|
}, [settleInMs, queryClient, projectId, sessionId]);
|
|
216
218
|
return useMemo(() => ({ last_ended: lastEnded, recent_failures: recentFailures, atMs }), [lastEnded, recentFailures, atMs]);
|
|
217
219
|
}
|
|
220
|
+
export function useSessionCanStop(projectId, sessionId) {
|
|
221
|
+
const query = useQuery({
|
|
222
|
+
queryKey: qk.project.sessionTurn(projectId, sessionId),
|
|
223
|
+
queryFn: () => readSessionTurnObservation(projectId, sessionId, { bundle: false }),
|
|
224
|
+
enabled: false,
|
|
225
|
+
});
|
|
226
|
+
return query.data?.can_stop !== false;
|
|
227
|
+
}
|
|
@@ -6,6 +6,7 @@ import { type AbortSettlement, type PromptPart } from './use-opencode-sessions/i
|
|
|
6
6
|
import { type SessionPicks } from './use-session-picks.js';
|
|
7
7
|
export type SessionPhase = 'starting' | 'ready' | 'error';
|
|
8
8
|
export declare function shouldRetrySessionStart(failureCount: number, error: unknown, sessionId: string): boolean;
|
|
9
|
+
export declare function presenceReturnReopensSession(heldByThisTab: boolean, cachedStage: string | null | undefined): boolean;
|
|
9
10
|
export declare const SESSION_START_POLL_MS = 1500;
|
|
10
11
|
export declare function resolveSessionRuntimeUrl(start: Pick<SessionStartResult, 'stage' | 'sandbox' | 'runtime_url'> | null | undefined): string | null;
|
|
11
12
|
export interface SendOptions {
|
|
@@ -153,6 +154,11 @@ export declare function useSession(projectId: string, sessionId: string, options
|
|
|
153
154
|
runtimePhase: import("./use-runtime-phase.js").RuntimePhase;
|
|
154
155
|
working: import("../index.js").WorkingProjection;
|
|
155
156
|
isBusy: boolean;
|
|
157
|
+
canStop: boolean;
|
|
158
|
+
presenceAwake: {
|
|
159
|
+
until: Date;
|
|
160
|
+
capAt: Date;
|
|
161
|
+
} | null;
|
|
156
162
|
isCompacting: boolean;
|
|
157
163
|
isLoading: boolean;
|
|
158
164
|
savedTranscript: import("../core/session-sync/saved-transcript.js").SavedTranscript;
|