@kortix/ui 0.14.5 → 0.14.7
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/dist/_vendor/kortix-shared.js +489 -381
- package/dist/access/access/access-dialog.js +8 -5
- package/dist/access/access/copy-row.js +2 -2
- package/dist/access/sharing-picker.js +2 -1
- package/dist/browser/app-in-browser.js +5 -3
- package/dist/browser/browser-panel.js +6 -6
- package/dist/browser/sandbox-browser-chrome.d.ts +4 -1
- package/dist/browser/sandbox-browser-chrome.js +4 -3
- package/dist/customize/agents/agent-access.d.ts +20 -0
- package/dist/customize/agents/agent-access.js +17 -0
- package/dist/customize/agents/agent-authority-card.js +1 -2
- package/dist/customize/agents/agent-detail-aside.js +15 -14
- package/dist/customize/agents/agent-drives-section.js +5 -6
- package/dist/customize/agents/agent-grant-pages.js +73 -76
- package/dist/customize/agents/agent-nav.prototype.d.ts +35 -0
- package/dist/customize/agents/agent-nav.prototype.js +95 -0
- package/dist/customize/agents/agent-page.js +59 -23
- package/dist/customize/agents/agent-people-section.js +18 -17
- package/dist/customize/agents/agent-triggers-section.js +6 -5
- package/dist/customize/agents/agents-page.js +18 -1
- package/dist/customize/connectors/add-mcp/add-mcp-server.js +4 -2
- package/dist/customize/connectors/catalog/catalog-entry.d.ts +14 -0
- package/dist/customize/connectors/catalog/catalog-entry.js +18 -1
- package/dist/customize/connectors/catalog/connector-browse.d.ts +28 -0
- package/dist/customize/connectors/catalog/connector-browse.js +18 -5
- package/dist/customize/connectors/connector-routes.d.ts +3 -1
- package/dist/customize/connectors/connector-routes.js +18 -0
- package/dist/customize/connectors/connectors-page.js +23 -4
- package/dist/customize/connectors/detail/app-page.js +19 -5
- package/dist/customize/connectors/detail/connector-advanced-tools.js +4 -6
- package/dist/customize/connectors/detail/connector-modal.d.ts +10 -13
- package/dist/customize/connectors/detail/connector-modal.js +18 -101
- package/dist/customize/connectors/detail/connector-notice.js +6 -2
- package/dist/customize/connectors/detail/connector-page.d.ts +30 -0
- package/dist/customize/connectors/detail/connector-page.js +26 -13
- package/dist/customize/providers/provider-accordion.js +2 -1
- package/dist/customize/providers/provider-connect.js +2 -1
- package/dist/customize/sections/component/telegram-channel-row.js +1 -1
- package/dist/customize/sections/connector-connection-modal.js +11 -9
- package/dist/customize/sections/connectors-view.js +11 -13
- package/dist/customize/sections/llm-provider/custom-provider-form.js +24 -7
- package/dist/customize/sections/llm-provider/custom-provider-panel.js +44 -8
- package/dist/customize/sections/llm-provider/types.d.ts +3 -0
- package/dist/customize/sections/llm-provider/utils.js +2 -2
- package/dist/customize/sections/view/agent-editor-access-fields.d.ts +9 -16
- package/dist/customize/sections/view/agent-editor-access-fields.js +30 -30
- package/dist/customize/sections/view/agent-editor-basics-fields.js +3 -10
- package/dist/customize/sections/view/agent-editor-primitives.d.ts +28 -10
- package/dist/customize/sections/view/agent-editor-primitives.js +32 -19
- package/dist/customize/sections/view/agent-editor.js +3 -3
- package/dist/customize/sections/view/gateway/gateway-routing.js +18 -21
- package/dist/customize/sections/view/grant-mode-field.d.ts +2 -5
- package/dist/customize/sections/view/grant-mode-field.js +10 -18
- package/dist/customize/sections/view/permission-editor.js +11 -8
- package/dist/customize/sections/view/secrets-view.js +2 -1
- package/dist/customize/settings/rail-copy-context.js +5 -3
- package/dist/customize/settings/tabs/general-tab.d.ts +9 -2
- package/dist/customize/settings/tabs/general-tab.js +33 -11
- package/dist/customize/settings/tabs/sandbox-template-form.js +9 -12
- package/dist/customize/settings/tabs/transfer-workspace-dialog.d.ts +4 -0
- package/dist/customize/settings/tabs/transfer-workspace-dialog.js +82 -0
- package/dist/customize/shared/capability-tabs.js +2 -1
- package/dist/customize/skills/skills-page.js +3 -5
- package/dist/customize/triggers/schedule/event-trigger-copy.js +3 -2
- package/dist/customize/triggers/schedule/schedule-builder.js +7 -4
- package/dist/customize/triggers/schedule/trigger-composer.js +5 -2
- package/dist/customize/triggers/schedule/when-event.js +1 -1
- package/dist/diff/diff-view.js +9 -10
- package/dist/files/editor/code-editor.js +2 -3
- package/dist/files/project/api/runtime-files.js +3 -2
- package/dist/files/project/components/change-request-detail-dialog.d.ts +3 -1
- package/dist/files/project/components/change-request-detail-dialog.js +3 -5
- package/dist/files/project/components/change-request-status-badge.d.ts +12 -0
- package/dist/files/project/components/change-request-status-badge.js +27 -0
- package/dist/files/project/components/change-requests-panel.js +1 -1
- package/dist/files/project/components/drive-explorer.js +2 -1
- package/dist/files/project/components/drive-grid-view.js +11 -7
- package/dist/files/project/components/drive-list-view.js +4 -4
- package/dist/files/project/components/file-breadcrumbs.js +1 -1
- package/dist/files/project/components/file-explorer-page.js +1 -1
- package/dist/files/project/components/file-history-popover.js +1 -6
- package/dist/files/project/components/file-search.js +6 -1
- package/dist/files/project/components/open-change-request-dialog.js +2 -1
- package/dist/files/project/components/version-selector-logic.d.ts +11 -0
- package/dist/files/project/components/version-selector-logic.js +26 -0
- package/dist/files/project/components/version-selector.js +11 -20
- package/dist/files/project/file-source.js +18 -1
- package/dist/files/project/hooks/use-file-content.js +2 -0
- package/dist/files/project/hooks/use-server-health.js +17 -15
- package/dist/files/renderers/docx/docx-viewer.js +0 -5
- package/dist/files/renderers/image-renderer.js +6 -24
- package/dist/files/renderers/pdf/pdf-viewer.js +1 -1
- package/dist/files/renderers/presentation/FullScreenPresentationViewer.js +2 -11
- package/dist/files/renderers/show-content-renderer.js +1 -1
- package/dist/files/renderers/sqlite-renderer.js +8 -3
- package/dist/files/renderers/xlsx/xlsx-viewer.js +15 -16
- package/dist/files/tree/components/file-tree-item.js +1 -1
- package/dist/files/viewer/file-header.js +1 -1
- package/dist/files/viewer/file-preview-modal.d.ts +1 -1
- package/dist/files/viewer/file-preview-modal.js +13 -3
- package/dist/files/viewer/file-source.d.ts +3 -1
- package/dist/files/viewer/use-file-content-state.js +27 -8
- package/dist/files/viewer/viewer-actions.js +2 -2
- package/dist/i18n/en.d.ts +355 -12
- package/dist/i18n/en.js +360 -17
- package/dist/internal/desktop/desktop-back-button.js +5 -3
- package/dist/internal/files/types.d.ts +2 -0
- package/dist/internal/goals/goal-meta.d.ts +30 -0
- package/dist/internal/goals/goal-meta.js +55 -0
- package/dist/internal/hooks/use-auto-scroll.js +5 -3
- package/dist/internal/lib/query-client-singleton.d.ts +9 -3
- package/dist/internal/lib/query-client-singleton.js +18 -12
- package/dist/internal/notifications/notification-rows.js +2 -1
- package/dist/internal/outcomes/outcome-types.d.ts +5 -0
- package/dist/internal/share/session-shares-modal.js +3 -7
- package/dist/internal/stores/kortix-computer-store.js +14 -2
- package/dist/internal/stores/session-hover-store.d.ts +32 -0
- package/dist/internal/stores/session-hover-store.js +38 -0
- package/dist/internal/stores/sidebar-nav-store.d.ts +1 -1
- package/dist/internal/stores/sidebar-nav-store.js +3 -1
- package/dist/lib/routes.d.ts +2 -0
- package/dist/lib/routes.js +1 -0
- package/dist/markdown/code/inline-code.js +8 -0
- package/dist/markdown/code/output-paths-context.d.ts +18 -0
- package/dist/markdown/code/output-paths-context.js +35 -0
- package/dist/markdown/genui/components/charts.js +6 -5
- package/dist/primitives/map.js +2 -1
- package/dist/primitives/preview-image.js +4 -2
- package/dist/primitives/settings-section-header.d.ts +1 -1
- package/dist/primitives/textarea.js +1 -1
- package/dist/primitives/typed-title.js +12 -14
- package/dist/primitives/typing-animation.js +4 -2
- package/dist/session/composer/agent-selector.js +6 -1
- package/dist/session/composer/attachment-tile.d.ts +0 -2
- package/dist/session/composer/attachment-tile.js +0 -8
- package/dist/session/composer/clipboard-files.d.ts +2 -1
- package/dist/session/composer/composer-chat-input.js +5 -3
- package/dist/session/composer/composer-draft-recovery.d.ts +1 -2
- package/dist/session/composer/composer-draft-recovery.js +0 -13
- package/dist/session/composer/composer-logic.js +8 -7
- package/dist/session/composer/context-ring.d.ts +1 -1
- package/dist/session/composer/context-ring.js +2 -2
- package/dist/session/composer/context-usage.d.ts +3 -6
- package/dist/session/composer/context-usage.js +3 -6
- package/dist/session/composer/draft/composer-draft.js +4 -4
- package/dist/session/composer/inbox-row-claims.d.ts +2 -2
- package/dist/session/composer/inbox-row-claims.js +1 -1
- package/dist/session/composer/pasted-text.js +3 -2
- package/dist/session/composer/queue-projection.d.ts +3 -2
- package/dist/session/composer/queued-prompt-edit.d.ts +1 -1
- package/dist/session/composer/reasoning-effort-selector.d.ts +2 -1
- package/dist/session/composer/session-composer-readiness.d.ts +7 -22
- package/dist/session/composer/session-composer-readiness.js +12 -40
- package/dist/session/composer/stores/queued-draft-store.js +3 -2
- package/dist/session/composer/token-progress.d.ts +1 -1
- package/dist/session/composer/token-progress.js +2 -2
- package/dist/session/header/reminder-parts.d.ts +11 -2
- package/dist/session/header/reminder-parts.js +9 -4
- package/dist/session/header/session-goal-indicator.d.ts +1 -0
- package/dist/session/header/session-goal-indicator.js +41 -0
- package/dist/session/header/session-site-header.js +2 -1
- package/dist/session/media/sandbox-url-detector.js +0 -7
- package/dist/session/outcomes/change-request-outcomes.js +24 -3
- package/dist/session/overrides/provider-secret-pool-editor.js +2 -1
- package/dist/session/panel/advanced/advanced-panel.js +3 -7
- package/dist/session/panel/easy/app-preview.js +12 -2
- package/dist/session/panel/easy/easy-panel-logic.d.ts +1 -1
- package/dist/session/panel/easy/easy-panel-logic.js +1 -1
- package/dist/session/panel/easy/outputs-card.js +2 -1
- package/dist/session/panel/easy/panel-card.js +5 -3
- package/dist/session/panel/easy/preview-load.d.ts +14 -0
- package/dist/session/panel/easy/preview-load.js +15 -0
- package/dist/session/panel/easy/step-detail-body.js +2 -7
- package/dist/session/panel/session-action-panel-column.js +11 -1
- package/dist/session/panel/session-audit-shared.d.ts +0 -4
- package/dist/session/panel/session-audit-shared.js +1 -1
- package/dist/session/panel/session-changes-shared.d.ts +2 -1
- package/dist/session/panel/session-panel-provider.js +6 -2
- package/dist/session/panel/shared/use-panel-derivations.js +6 -4
- package/dist/session/panel/use-session-panel-layout.js +7 -5
- package/dist/session/print/session-print-header.js +9 -8
- package/dist/session/prompts/session-permission-prompt.js +6 -3
- package/dist/session/status/provisioning-failure.d.ts +2 -1
- package/dist/session/status/session-error-banner.js +8 -6
- package/dist/session/status/session-starting-loader.d.ts +24 -31
- package/dist/session/status/session-starting-loader.js +32 -81
- package/dist/session/thread/chat-minimap-items.d.ts +4 -4
- package/dist/session/thread/first-prompt-handover.d.ts +3 -2
- package/dist/session/thread/message-parsing.d.ts +3 -3
- package/dist/session/thread/session-chat.js +15 -19
- package/dist/session/thread/session-history-scroll.d.ts +2 -1
- package/dist/session/thread/session-history.js +3 -1
- package/dist/session/thread/session-thread.js +1 -1
- package/dist/session/thread/transcript.js +13 -7
- package/dist/session/tool/shared/file-list.js +19 -2
- package/dist/session/tool/shared/infrastructure-contexts.d.ts +7 -0
- package/dist/session/tool/shared/infrastructure-contexts.js +7 -0
- package/dist/session/tool/shared/infrastructure-output.js +9 -5
- package/dist/session/tool/shared/infrastructure-row-header.js +9 -1
- package/dist/session/tool/shared/infrastructure-rows.js +7 -5
- package/dist/session/tool/tools/bash-tool.js +10 -6
- package/dist/session/tool/tools/web-search-tool.js +25 -3
- package/dist/session/turn/recovered-failures.d.ts +8 -0
- package/dist/session/turn/recovered-failures.js +32 -0
- package/dist/session/turn/streaming-cadence.js +5 -8
- package/dist/styles.css +1 -1
- package/dist/terminal/pty-connection.d.ts +5 -4
- package/dist/terminal/session-terminal-panel.js +3 -5
- package/dist/theme/theme.js +2 -1
- package/dist/workspace/index.d.ts +1 -0
- package/dist/workspace/index.js +1 -0
- package/dist/workspace/projects/modal/github-import-pickers.js +7 -6
- package/dist/workspace/review/review-center.js +13 -10
- package/dist/workspace/saved-session-skeleton-shape.d.ts +4 -3
- package/dist/workspace/saved-session-skeleton.d.ts +5 -1
- package/dist/workspace/saved-session-skeleton.js +5 -4
- package/dist/workspace/session-workspace.js +9 -14
- package/dist/workspace/sessions/deleted-session-row.js +5 -2
- package/dist/workspace/sidebar/footer/project-computer-nav.js +6 -4
- package/dist/workspace/sidebar/footer/project-goals-nav.d.ts +6 -0
- package/dist/workspace/sidebar/footer/project-goals-nav.js +26 -0
- package/dist/workspace/sidebar/footer/project-mcp-nav.js +6 -2
- package/dist/workspace/sidebar/modal/rename-session-modal.js +8 -3
- package/dist/workspace/sidebar/modal/session-embed-section.d.ts +25 -0
- package/dist/workspace/sidebar/modal/session-embed-section.js +71 -0
- package/dist/workspace/sidebar/modal/share-session-modal.js +2 -2
- package/dist/workspace/sidebar/nav-row-meta.js +14 -2
- package/dist/workspace/sidebar/project-nav-items.js +3 -0
- package/dist/workspace/sidebar/project-session-list.js +12 -3
- package/dist/workspace/sidebar/session-brief-hover-card.js +5 -8
- package/package.json +4 -4
- package/skills/kortix-ui/references/modules.md +2 -0
- package/dist/session/status/use-readiness-settling.d.ts +0 -18
- package/dist/session/status/use-readiness-settling.js +0 -43
- package/dist/workspace/sidebar/modal/session-public-link-section.d.ts +0 -13
- package/dist/workspace/sidebar/modal/session-public-link-section.js +0 -66
|
@@ -140,6 +140,12 @@ function GatewayMetaLine({ leading, details, }) {
|
|
|
140
140
|
function DiagnosticFold({ summary, children }) {
|
|
141
141
|
return (_jsxs("details", { className: "group/fold text-xs", children: [_jsxs("summary", { className: cn('text-muted-foreground hover:text-foreground flex w-fit cursor-pointer list-none', 'duration-fast items-center gap-1 transition-colors select-none', '[&::-webkit-details-marker]:hidden'), children: [_jsx(CaretRightIcon, { className: "size-3 shrink-0 group-open/fold:rotate-90" }), summary] }), children] }));
|
|
142
142
|
}
|
|
143
|
+
function FailureList({ failures, className }) {
|
|
144
|
+
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
145
|
+
return (_jsx("ol", { className: className, children: failures.map((failure) => (_jsxs("li", { children: [_jsx("span", { className: "text-foreground font-medium", children: failureTarget(failure) }), " \u00B7", ' ', failure.status !== undefined
|
|
146
|
+
? tI18nComplete('textf6a6d0e934f4', { value0: failure.status })
|
|
147
|
+
: '', String(failure.code), " \u00B7 ", failure.message] }, failure.attempt))) }));
|
|
148
|
+
}
|
|
143
149
|
/**
|
|
144
150
|
* The per-candidate failure chain, collapsed. It is the diagnostic, not the
|
|
145
151
|
* message: a reader who wants to know WHY every route failed opens it; everyone
|
|
@@ -150,9 +156,7 @@ function GatewayAttemptFailureList({ details }) {
|
|
|
150
156
|
const failures = details?.attemptFailures;
|
|
151
157
|
if (!failures?.length)
|
|
152
158
|
return null;
|
|
153
|
-
return (_jsx(DiagnosticFold, { summary: failures.length === 1 ? tI18nComplete.raw('textce4c96225f63') : `${failures.length} attempts`, children: _jsx(
|
|
154
|
-
? tI18nComplete('textf6a6d0e934f4', { value0: failure.status })
|
|
155
|
-
: '', String(failure.code), " \u00B7 ", failure.message] }, failure.attempt))) }) }));
|
|
159
|
+
return (_jsx(DiagnosticFold, { summary: failures.length === 1 ? tI18nComplete.raw('textce4c96225f63') : `${failures.length} attempts`, children: _jsx(FailureList, { failures: failures, className: "text-muted-foreground mt-1 list-decimal space-y-1 pl-4 wrap-anywhere" }) }));
|
|
156
160
|
}
|
|
157
161
|
/**
|
|
158
162
|
* Which row a plain-text turn error renders, and whether it opens. The one
|
|
@@ -212,9 +216,7 @@ function TurnErrorCheckpoint({ text, gateway, raw, defaultOpen, action, modelOpt
|
|
|
212
216
|
if (!canOpen) {
|
|
213
217
|
return (_jsxs("div", { role: "alert", className: className, children: [row, hint, action] }));
|
|
214
218
|
}
|
|
215
|
-
return (_jsx("div", { role: "alert", className: className, children: _jsx(ChainOfThoughtStep, { defaultOpen: defaultOpen, children: _jsxs(_Fragment, { children: [_jsx(DisclosureTrigger, { children: _jsx("div", { className: "group/trigger cursor-pointer", children: row }) }), hint, action, _jsx(DisclosureContent, { children: _jsxs("div", { className: "mt-3 flex flex-col gap-2 pl-7", children: [_jsx(GatewayMetaLine, { details: gateway }), failures.length > 0 ? (_jsx(
|
|
216
|
-
? tI18nComplete('textf6a6d0e934f4', { value0: failure.status })
|
|
217
|
-
: '', String(failure.code), " \u00B7 ", failure.message] }, failure.attempt))) })) : null, raw ? (_jsx("pre", { className: "bg-muted text-muted-foreground max-h-40 overflow-auto rounded-md px-3 py-2 font-mono text-xs whitespace-pre-wrap wrap-anywhere", children: raw })) : null] }) })] }) }) }));
|
|
219
|
+
return (_jsx("div", { role: "alert", className: className, children: _jsx(ChainOfThoughtStep, { defaultOpen: defaultOpen, children: _jsxs(_Fragment, { children: [_jsx(DisclosureTrigger, { children: _jsx("div", { className: "group/trigger cursor-pointer", children: row }) }), hint, action, _jsx(DisclosureContent, { children: _jsxs("div", { className: "mt-3 flex flex-col gap-2 pl-7", children: [_jsx(GatewayMetaLine, { details: gateway }), failures.length > 0 ? (_jsx(FailureList, { failures: failures, className: "text-muted-foreground list-decimal space-y-1 pl-4 text-xs wrap-anywhere" })) : null, raw ? (_jsx("pre", { className: "bg-muted text-muted-foreground max-h-40 overflow-auto rounded-md px-3 py-2 font-mono text-xs whitespace-pre-wrap wrap-anywhere", children: raw })) : null] }) })] }) }) }));
|
|
218
220
|
}
|
|
219
221
|
/**
|
|
220
222
|
* Renders a turn-level or send-failure error inline.
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { type SessionStartResult
|
|
1
|
+
import { type SessionStartResult } from '@kortix/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* What a session shows while its Kortix Computer comes up: nothing, unless the
|
|
4
|
+
* wake needs attention. Opening a session wakes its computer in the background,
|
|
5
|
+
* and a send goes out as soon as it is up, so a routine wake has nothing to
|
|
6
|
+
* say. Two states speak: an escalation or retry note from the server, and a
|
|
7
|
+
* wake stuck past `STUCK_AFTER_MS` that the caller may restart.
|
|
8
|
+
*
|
|
9
|
+
* All the heavy lifting (provision / wake / runtime readiness) is server-side
|
|
10
|
+
* behind POST /sessions/:id/start.
|
|
11
|
+
*/
|
|
2
12
|
/**
|
|
3
13
|
* After this long, offer a manual restart. Sandboxes occasionally wedge (e.g. a
|
|
4
14
|
* stuck provider-side proxy) with no server-side signal that anything is wrong —
|
|
5
15
|
* a stop/start of the sandbox is the known fix, so surface it as a fallback
|
|
6
|
-
* instead of leaving the user
|
|
16
|
+
* instead of leaving the user waiting indefinitely.
|
|
7
17
|
*/
|
|
8
18
|
export declare const STUCK_AFTER_MS = 45000;
|
|
9
|
-
interface Step {
|
|
10
|
-
/** User-visible label for the active startup stage. */
|
|
11
|
-
label: string;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Accepted for input compatibility. Both values intentionally render the same
|
|
15
|
-
* loader.
|
|
16
|
-
*/
|
|
17
|
-
type BootStepVariant = 'stepper' | 'compact';
|
|
18
19
|
type StartFailure = SessionStartResult['failure'];
|
|
19
20
|
/**
|
|
20
21
|
* Keep the server's retry visible while `/start` waits for its retry clock.
|
|
@@ -26,14 +27,6 @@ export declare function sessionWakeStatusNote(input: {
|
|
|
26
27
|
note?: string | null;
|
|
27
28
|
now: number;
|
|
28
29
|
}): string | null;
|
|
29
|
-
/** Copy is deliberately parallel, so stage changes read as one continuous task. */
|
|
30
|
-
export declare const STEPS: Step[];
|
|
31
|
-
/**
|
|
32
|
-
* Resolve which step is CURRENTLY active from the backend stage plus how long
|
|
33
|
-
* we've been in it. The index is the floor we KNOW we're at — earlier steps are
|
|
34
|
-
* genuinely complete, later ones haven't started.
|
|
35
|
-
*/
|
|
36
|
-
export declare function activeStep(stage: SessionStartStage, msInStage: number): number;
|
|
37
30
|
/**
|
|
38
31
|
* Whether the stuck-boot restart offer may render. Restart is the session
|
|
39
32
|
* owner's or a project manager's; the server answers anyone else 403
|
|
@@ -53,31 +46,31 @@ export declare function RestartFallback({ show, pending, onRestart, className, b
|
|
|
53
46
|
className?: string;
|
|
54
47
|
buttonClassName?: string;
|
|
55
48
|
}): import("react").JSX.Element | null;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
/**
|
|
50
|
+
* The wake's status where nothing else can paint: the side panel, a chat with
|
|
51
|
+
* no runtime yet, a resume with nothing saved. A routine wake renders nothing.
|
|
52
|
+
*/
|
|
53
|
+
export declare function SessionStartingLoader({ projectId, sessionId,
|
|
59
54
|
/** Honest one-liner from the SDK wake escalation ladder. */
|
|
60
55
|
note, reason, failure, }: {
|
|
61
|
-
stage?: SessionStartStage;
|
|
62
|
-
delayMs?: number;
|
|
63
56
|
projectId?: string;
|
|
64
57
|
sessionId?: string;
|
|
65
|
-
variant?: BootStepVariant;
|
|
66
58
|
note?: string | null;
|
|
67
59
|
reason?: string | null;
|
|
68
60
|
failure?: StartFailure;
|
|
69
|
-
}): import("react").JSX.Element;
|
|
61
|
+
}): import("react").JSX.Element | null;
|
|
70
62
|
/**
|
|
71
|
-
* Compact status above a readable conversation while its runtime wakes
|
|
72
|
-
*
|
|
63
|
+
* Compact status above a readable conversation while its runtime wakes, shown
|
|
64
|
+
* only when the wake needs attention: an escalation or retry note, or a stuck
|
|
65
|
+
* wake with a Restart. A normal wake renders nothing. The transcript remains
|
|
66
|
+
* scrollable because only the restart control accepts input.
|
|
73
67
|
*/
|
|
74
|
-
export declare function SessionConnectingBanner({
|
|
75
|
-
stage?: SessionStartStage;
|
|
68
|
+
export declare function SessionConnectingBanner({ projectId, sessionId, className, note, reason, failure, }: {
|
|
76
69
|
projectId?: string;
|
|
77
70
|
sessionId?: string;
|
|
78
71
|
className?: string;
|
|
79
72
|
note?: string | null;
|
|
80
73
|
reason?: string | null;
|
|
81
74
|
failure?: StartFailure;
|
|
82
|
-
}): import("react").JSX.Element;
|
|
75
|
+
}): import("react").JSX.Element | null;
|
|
83
76
|
export {};
|
|
@@ -3,37 +3,26 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { Button } from '../../primitives/button.js';
|
|
4
4
|
import Loading from '../../primitives/loading.js';
|
|
5
5
|
import { useRestartProjectSession } from '../../internal/hooks/projects/use-restart-project-session.js';
|
|
6
|
-
import { useLocalizedUiCatalog } from '../../i18n/ui-catalog/use-localized-ui-catalog.js';
|
|
7
6
|
import { useTranslations } from '../../i18n/index.js';
|
|
8
7
|
import { cn } from '../../lib/utils.js';
|
|
9
8
|
import { useProjectSession } from '@kortix/sdk/react';
|
|
10
9
|
import { ArrowCounterClockwiseIcon as RotateCcw } from '@phosphor-icons/react';
|
|
11
10
|
import { useEffect, useRef, useState } from 'react';
|
|
12
11
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* What a session shows while its Kortix Computer comes up: nothing, unless the
|
|
13
|
+
* wake needs attention. Opening a session wakes its computer in the background,
|
|
14
|
+
* and a send goes out as soon as it is up, so a routine wake has nothing to
|
|
15
|
+
* say. Two states speak: an escalation or retry note from the server, and a
|
|
16
|
+
* wake stuck past `STUCK_AFTER_MS` that the caller may restart.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* only when the backend stage advances, so it never claims progress we do not
|
|
21
|
-
* have.
|
|
18
|
+
* All the heavy lifting (provision / wake / runtime readiness) is server-side
|
|
19
|
+
* behind POST /sessions/:id/start.
|
|
22
20
|
*/
|
|
23
|
-
const LOADER_DELAY_MS = 100;
|
|
24
|
-
/**
|
|
25
|
-
* How long we sit in the backend `starting` stage before softly advancing from
|
|
26
|
-
* "Loading your workspace" to "Waking the agent". Both happen within that one
|
|
27
|
-
* backend stage (clone → OpenCode boot), so the advance reflects real order.
|
|
28
|
-
*/
|
|
29
|
-
const STARTING_SUBSTEP_MS = 5_000;
|
|
30
|
-
/** After this long, show copy that sets expectations for a cold start. */
|
|
31
|
-
const SLOW_AFTER_MS = 15_000;
|
|
32
21
|
/**
|
|
33
22
|
* After this long, offer a manual restart. Sandboxes occasionally wedge (e.g. a
|
|
34
23
|
* stuck provider-side proxy) with no server-side signal that anything is wrong —
|
|
35
24
|
* a stop/start of the sandbox is the known fix, so surface it as a fallback
|
|
36
|
-
* instead of leaving the user
|
|
25
|
+
* instead of leaving the user waiting indefinitely.
|
|
37
26
|
*/
|
|
38
27
|
export const STUCK_AFTER_MS = 45_000;
|
|
39
28
|
/**
|
|
@@ -64,42 +53,14 @@ export function sessionWakeStatusNote(input) {
|
|
|
64
53
|
const duration = minutes > 0 ? `${minutes}m\u00a0${remainder}s` : `${remainder}s`;
|
|
65
54
|
return `Still starting your computer. Trying again in ${duration} (attempt ${nextAttempt}).`;
|
|
66
55
|
}
|
|
67
|
-
/**
|
|
68
|
-
|
|
69
|
-
{ label: 'Reserving your computer' },
|
|
70
|
-
{ label: 'Loading your workspace' },
|
|
71
|
-
{ label: 'Waking the agent' },
|
|
72
|
-
{ label: 'Connecting' },
|
|
73
|
-
];
|
|
74
|
-
/**
|
|
75
|
-
* Resolve which step is CURRENTLY active from the backend stage plus how long
|
|
76
|
-
* we've been in it. The index is the floor we KNOW we're at — earlier steps are
|
|
77
|
-
* genuinely complete, later ones haven't started.
|
|
78
|
-
*/
|
|
79
|
-
export function activeStep(stage, msInStage) {
|
|
80
|
-
if (stage === 'provisioning')
|
|
81
|
-
return 0;
|
|
82
|
-
if (stage === 'starting')
|
|
83
|
-
return msInStage >= STARTING_SUBSTEP_MS ? 2 : 1;
|
|
84
|
-
return 3;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* The shared boot clock: a 1s tick that resolves the current active step from
|
|
88
|
-
* the backend stage plus time-in-stage, and exposes `now` for elapsed-time UI.
|
|
89
|
-
*/
|
|
90
|
-
function useBootProgress(stage) {
|
|
56
|
+
/** A 1 s tick: the retry countdown and the stuck clock read it. */
|
|
57
|
+
function useNow() {
|
|
91
58
|
const [now, setNow] = useState(() => Date.now());
|
|
92
59
|
useEffect(() => {
|
|
93
60
|
const id = setInterval(() => setNow(Date.now()), 1_000);
|
|
94
61
|
return () => clearInterval(id);
|
|
95
62
|
}, []);
|
|
96
|
-
|
|
97
|
-
const [prevStage, setPrevStage] = useState(stage);
|
|
98
|
-
if (prevStage !== stage) {
|
|
99
|
-
setPrevStage(stage);
|
|
100
|
-
setStageEnteredAt(now);
|
|
101
|
-
}
|
|
102
|
-
return { active: activeStep(stage, now - stageEnteredAt), now };
|
|
63
|
+
return now;
|
|
103
64
|
}
|
|
104
65
|
/**
|
|
105
66
|
* The boot clock a restart carries. The shared restart hook owns the whole
|
|
@@ -139,52 +100,42 @@ export function RestartFallback({ show, pending, onRestart, className, buttonCla
|
|
|
139
100
|
return (_jsxs("div", { className: cn('mt-5 w-full', className), children: [_jsx("p", { className: "text-muted-foreground mb-2 text-xs text-pretty", children: tI18nComplete.raw('textbeda94e911d3') }), _jsxs(Button, { type: "button", variant: "secondary", size: "sm", className: cn('w-full active:scale-[0.96]', buttonClassName), disabled: pending, onClick: onRestart, children: [pending ? (_jsx(Loading, { className: "size-3.5 shrink-0 text-current motion-reduce:animate-none" })) : (_jsx(RotateCcw, { className: "size-3.5 shrink-0" })), pending ? tI18nComplete.raw('text75d0f1469d16') : tI18nComplete.raw('textcb886371afc6')] })] }));
|
|
140
101
|
}
|
|
141
102
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
103
|
+
* The wake's status where nothing else can paint: the side panel, a chat with
|
|
104
|
+
* no runtime yet, a resume with nothing saved. A routine wake renders nothing.
|
|
144
105
|
*/
|
|
145
|
-
function
|
|
146
|
-
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
147
|
-
const steps = useLocalizedUiCatalog(STEPS);
|
|
148
|
-
const step = steps[Math.min(active, steps.length - 1)];
|
|
149
|
-
return (_jsx("div", { className: "flex h-full min-h-0 w-full flex-1 items-center justify-center px-4 sm:px-8", children: show ? (_jsxs("div", { role: "status", "aria-live": "polite", className: "flex w-full max-w-xs items-start gap-3", children: [_jsx(Loading, { variant: "spokes", className: "text-muted-foreground mt-0.5 size-4 shrink-0 motion-reduce:animate-none" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h2", { className: "text-foreground text-sm font-medium text-balance", children: tI18nComplete.raw('textac4e05b19878') }), _jsx("p", { className: "text-muted-foreground mt-1 text-xs text-pretty", children: note ?? step.label }), _jsx("div", { role: "progressbar", "aria-label": tI18nComplete.raw('text4cbf9c0d5628'), "aria-valuemin": 1, "aria-valuemax": steps.length, "aria-valuenow": active + 1, "aria-valuetext": `Step ${active + 1} of ${steps.length}: ${step.label}`, className: "mt-3 grid grid-cols-4 gap-1.5", children: steps.map((item, index) => (_jsx("span", { "aria-hidden": true, className: cn('h-1 rounded-full', index <= active ? 'bg-kortix-green' : 'bg-border/70') }, item.label))) }), slow ? (_jsx("p", { className: "text-muted-foreground mt-3 text-xs text-pretty", children: tI18nComplete.raw('textbb2ab0401c3c') })) : null, _jsx(RestartFallback, { show: stuck && canRestart, pending: pending, onRestart: onRestart })] })] })) : null }));
|
|
150
|
-
}
|
|
151
|
-
export function SessionStartingLoader({ stage = 'provisioning',
|
|
152
|
-
/** Delay before the content appears. Warm opens avoid flashing the loader. */
|
|
153
|
-
delayMs = LOADER_DELAY_MS, projectId, sessionId,
|
|
106
|
+
export function SessionStartingLoader({ projectId, sessionId,
|
|
154
107
|
/** Honest one-liner from the SDK wake escalation ladder. */
|
|
155
108
|
note, reason, failure, }) {
|
|
156
|
-
const [delayElapsed, setDelayElapsed] = useState(false);
|
|
157
|
-
const show = delayMs <= 0 || delayElapsed;
|
|
158
|
-
useEffect(() => {
|
|
159
|
-
if (delayMs <= 0)
|
|
160
|
-
return;
|
|
161
|
-
const timeout = setTimeout(() => setDelayElapsed(true), delayMs);
|
|
162
|
-
return () => clearTimeout(timeout);
|
|
163
|
-
}, [delayMs]);
|
|
164
109
|
const { data: session } = useProjectSession(projectId, sessionId);
|
|
165
110
|
const restart = useRestartProjectSession(projectId ?? '', sessionId ?? '');
|
|
166
|
-
const
|
|
111
|
+
const now = useNow();
|
|
167
112
|
const statusNote = sessionWakeStatusNote({ reason, failure, note, now });
|
|
168
113
|
const clockStart = useRestartedBootClock(restart);
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return (_jsx(
|
|
114
|
+
const restartable = now - clockStart >= STUCK_AFTER_MS && canOfferBootRestart(session, projectId, sessionId);
|
|
115
|
+
if (!statusNote && !restartable)
|
|
116
|
+
return null;
|
|
117
|
+
return (_jsx("div", { className: "flex h-full min-h-0 w-full flex-1 items-center justify-center px-4 sm:px-8", children: _jsxs("div", { role: "status", "aria-live": "polite", className: "flex w-full max-w-xs items-start gap-3", children: [_jsx(Loading, { variant: "spokes", className: "text-muted-foreground mt-0.5 size-4 shrink-0 motion-reduce:animate-none" }), _jsxs("div", { className: "min-w-0 flex-1", children: [statusNote ? _jsx("p", { className: "text-muted-foreground text-xs text-pretty", children: statusNote }) : null, _jsx(RestartFallback, { show: restartable, pending: restart.isPending, onRestart: restart.restart, className: statusNote ? 'mt-3' : 'mt-0' })] })] }) }));
|
|
173
118
|
}
|
|
174
119
|
/**
|
|
175
|
-
* Compact status above a readable conversation while its runtime wakes
|
|
176
|
-
*
|
|
120
|
+
* Compact status above a readable conversation while its runtime wakes, shown
|
|
121
|
+
* only when the wake needs attention: an escalation or retry note, or a stuck
|
|
122
|
+
* wake with a Restart. A normal wake renders nothing. The transcript remains
|
|
123
|
+
* scrollable because only the restart control accepts input.
|
|
177
124
|
*/
|
|
178
|
-
export function SessionConnectingBanner({
|
|
125
|
+
export function SessionConnectingBanner({ projectId, sessionId, className, note, reason, failure, }) {
|
|
179
126
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
180
127
|
const { data: session } = useProjectSession(projectId, sessionId);
|
|
181
128
|
const restart = useRestartProjectSession(projectId ?? '', sessionId ?? '');
|
|
182
|
-
const
|
|
129
|
+
const now = useNow();
|
|
183
130
|
const statusNote = sessionWakeStatusNote({ reason, failure, note, now });
|
|
184
131
|
const clockStart = useRestartedBootClock(restart);
|
|
185
132
|
const stuck = now - clockStart >= STUCK_AFTER_MS;
|
|
186
133
|
const canRestart = canOfferBootRestart(session, projectId, sessionId);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
134
|
+
// A normal wake is silent: opening the session wakes its computer in the
|
|
135
|
+
// background, and a send goes out as soon as it is up. The pill speaks only
|
|
136
|
+
// when something is wrong: the wake escalated or waits on a retry
|
|
137
|
+
// (`statusNote`), or it is stuck and can be restarted.
|
|
138
|
+
if (!statusNote && !(stuck && canRestart))
|
|
139
|
+
return null;
|
|
140
|
+
return (_jsx("div", { role: "status", "aria-live": "polite", "data-session-connecting-banner": "", className: cn('pointer-events-none absolute inset-x-0 top-0 z-30 flex justify-center px-3 pt-3', className), children: _jsxs("div", { className: "bg-background/85 text-muted-foreground flex max-w-full items-center gap-2 rounded-full border px-3 py-1.5 text-xs shadow-xs backdrop-blur-sm", children: [_jsx(Loading, { variant: "spokes", className: "size-3.5 shrink-0 text-current motion-reduce:animate-none" }), _jsx("span", { className: "min-w-0 text-pretty", children: statusNote ?? tI18nComplete.raw('textbeda94e911d3') }), stuck && canRestart ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "pointer-events-auto -mr-2 h-6 px-2 text-xs", disabled: restart.isPending, onClick: restart.restart, children: restart.isPending ? tI18nComplete.raw('text75d0f1469d16') : 'Restart' })) : null] }) }));
|
|
190
141
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { SessionLogTurn } from '@kortix/sdk';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
type MinimapMentionKind = 'agent' | 'file';
|
|
3
|
+
interface MinimapSegment {
|
|
4
4
|
/** For a mention this is the bare name — the `@` is drawn as an icon. */
|
|
5
5
|
text: string;
|
|
6
6
|
mention?: MinimapMentionKind;
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
interface MinimapAttachment {
|
|
9
9
|
key: string;
|
|
10
10
|
name: string;
|
|
11
11
|
}
|
|
@@ -17,7 +17,7 @@ export interface MinimapItem {
|
|
|
17
17
|
segments: MinimapSegment[];
|
|
18
18
|
attachments: MinimapAttachment[];
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
interface MinimapDash {
|
|
21
21
|
item: MinimapItem;
|
|
22
22
|
index: number;
|
|
23
23
|
}
|
|
@@ -15,7 +15,7 @@ export declare function transcriptCarriesFirstPrompt(turns: readonly Pick<Sessio
|
|
|
15
15
|
* stand-in knew — text and file names — so it keeps drawing the bubble and the
|
|
16
16
|
* pending tiles through any frame where its own parts are still streaming.
|
|
17
17
|
*/
|
|
18
|
-
|
|
18
|
+
interface FirstPromptHandoverInput {
|
|
19
19
|
/** The producer's copy exists (the boot preview store has this session). */
|
|
20
20
|
hasPreview: boolean;
|
|
21
21
|
/** The transcript's first user message carries its text right now. */
|
|
@@ -43,7 +43,7 @@ export interface FirstPromptHandoverInput {
|
|
|
43
43
|
*/
|
|
44
44
|
transcriptEmpty?: boolean;
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
interface FirstPromptHandover {
|
|
47
47
|
/** Draw the stand-in bubble. */
|
|
48
48
|
showStandIn: boolean;
|
|
49
49
|
/** Hand the preview's text + file names to the real first turn. */
|
|
@@ -52,3 +52,4 @@ export interface FirstPromptHandover {
|
|
|
52
52
|
released: boolean;
|
|
53
53
|
}
|
|
54
54
|
export declare function resolveFirstPromptHandover(input: FirstPromptHandoverInput): FirstPromptHandover;
|
|
55
|
+
export {};
|
|
@@ -18,7 +18,7 @@ export declare function parseSessionReferences(text: string): {
|
|
|
18
18
|
cleanText: string;
|
|
19
19
|
sessions: ParsedSessionRef[];
|
|
20
20
|
};
|
|
21
|
-
|
|
21
|
+
interface ParsedProjectRef {
|
|
22
22
|
id?: string;
|
|
23
23
|
name: string;
|
|
24
24
|
path?: string;
|
|
@@ -28,11 +28,11 @@ export declare function parseProjectReferences(text: string): {
|
|
|
28
28
|
cleanText: string;
|
|
29
29
|
projects: ParsedProjectRef[];
|
|
30
30
|
};
|
|
31
|
-
|
|
31
|
+
interface ParsedFileMentionRef {
|
|
32
32
|
path: string;
|
|
33
33
|
name: string;
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
interface ParsedAgentMentionRef {
|
|
36
36
|
name: string;
|
|
37
37
|
}
|
|
38
38
|
export declare function parseFileMentionReferences(text: string): {
|
|
@@ -95,7 +95,6 @@ import { resolveSessionContentState } from '../status/session-load-state.js';
|
|
|
95
95
|
import { nextOlderAutoloadArm, olderAutoloadExhausted, shouldLoadOlderHistory, } from './session-older-autoload.js';
|
|
96
96
|
import { OLDER_LOADING_MIN_MS, useHeldOlderLoading } from './session-older-loading.js';
|
|
97
97
|
import { HELD_COMMAND_ROW_PREFIX, canReleaseHeldCommand, heldCommandRows, } from '../composer/held-commands.js';
|
|
98
|
-
import { useReadinessSettling } from '../status/use-readiness-settling.js';
|
|
99
98
|
import { useSessionHistoryViewStore } from '../../internal/stores/session-history-view-store.js';
|
|
100
99
|
import { downloadBlob } from '../../internal/lib/utils/download.js';
|
|
101
100
|
import { RestoreNotice, hasOutOfContext } from './session-history.js';
|
|
@@ -389,7 +388,9 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
|
|
|
389
388
|
const messages = thread?.messages.length ? thread.messages : undefined;
|
|
390
389
|
// The thread for handlers that read it at call time (the optimistic answers cache).
|
|
391
390
|
const threadRef = useRef(thread);
|
|
392
|
-
|
|
391
|
+
useLayoutEffect(() => {
|
|
392
|
+
threadRef.current = thread;
|
|
393
|
+
}, [thread]);
|
|
393
394
|
const messagesLoading = syncMessagesLoading;
|
|
394
395
|
// Who wrote each user message. A one-person session stays unlabelled.
|
|
395
396
|
const viewerId = useUiViewerId();
|
|
@@ -1285,6 +1286,7 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
|
|
|
1285
1286
|
autoLoadedPages,
|
|
1286
1287
|
handleLoadOlder,
|
|
1287
1288
|
scrollRef,
|
|
1289
|
+
spacerElRef,
|
|
1288
1290
|
sessionId,
|
|
1289
1291
|
transcriptOnLog,
|
|
1290
1292
|
]);
|
|
@@ -1506,7 +1508,9 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
|
|
|
1506
1508
|
const harnessSwitches = useMemo(() => sessionLogHarnessSwitches(sessionRecord?.harness?.history, turns), [sessionRecord?.harness?.history, turns]);
|
|
1507
1509
|
// P5.6: load the whole of every text a turn shows as a preview, on request only.
|
|
1508
1510
|
const fullTextsRef = useRef(loaded);
|
|
1509
|
-
|
|
1511
|
+
useLayoutEffect(() => {
|
|
1512
|
+
fullTextsRef.current = loaded;
|
|
1513
|
+
});
|
|
1510
1514
|
const loadFullTexts = useCallback((turnId, refs) => {
|
|
1511
1515
|
const key = fullTextsRef.current.key;
|
|
1512
1516
|
const mark = (state) => setFullTexts((prev) => {
|
|
@@ -3201,6 +3205,7 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
|
|
|
3201
3205
|
? 'duration-slow max-h-130 translate-y-0 opacity-100'
|
|
3202
3206
|
: 'duration-slow pointer-events-none max-h-0 -translate-y-1 opacity-0'), children: _jsx(QuestionPrompt, { ref: questionPromptRef, request: renderedQuestion, onReply: handleQuestionReply, onReject: handleQuestionReject, onActionChange: handleQuestionActionChange }, renderedQuestion.id) })) : null] })), [
|
|
3203
3207
|
sessionId,
|
|
3208
|
+
sessionScopeAgentName,
|
|
3204
3209
|
pendingPermissions,
|
|
3205
3210
|
handlePermissionReply,
|
|
3206
3211
|
renderedQuestion,
|
|
@@ -3208,10 +3213,6 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
|
|
|
3208
3213
|
handleQuestionReply,
|
|
3209
3214
|
handleQuestionReject,
|
|
3210
3215
|
handleQuestionActionChange,
|
|
3211
|
-
tHardcodedUi,
|
|
3212
|
-
local.model.fallback,
|
|
3213
|
-
local.model.list,
|
|
3214
|
-
handleModelChange,
|
|
3215
3216
|
]);
|
|
3216
3217
|
// The rewound-path notice lives on the composer toolbar, beside send/stop —
|
|
3217
3218
|
// send is what commits the path, so the control sits at the moment of
|
|
@@ -3271,15 +3272,10 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
|
|
|
3271
3272
|
// its cause attached instead of a shrug. An actionable cause reports to
|
|
3272
3273
|
// Sentry; a routine browser tab discard only leaves a breadcrumb.
|
|
3273
3274
|
useReloadForensics(projectSessionId);
|
|
3274
|
-
// Nothing has answered yet and the mount is young: the difference between
|
|
3275
|
-
// "this session is asleep" and "we have not looked yet". Without it, every
|
|
3276
|
-
// page load painted the waking notice for a beat over a session that was
|
|
3277
|
-
// never asleep — which reads as a disconnect. See `settling`.
|
|
3278
|
-
const composerSettling = useReadinessSettling(runtimePhase === 'connecting');
|
|
3279
3275
|
// ONE answer for every surface that draws this session's runtime, and the
|
|
3280
3276
|
// reason the composer no longer guesses: `unknown` and `connecting` are
|
|
3281
|
-
// waits, and a wait is not a fault.
|
|
3282
|
-
//
|
|
3277
|
+
// waits, and a wait is not a fault. A routine wake says nothing either; only
|
|
3278
|
+
// a parked box with no wake under way earns the asleep notice.
|
|
3283
3279
|
const sessionConnection = projectSessionConnection({
|
|
3284
3280
|
sandbox: projectSessionRow?.status ?? null,
|
|
3285
3281
|
runtimeReady,
|
|
@@ -3292,7 +3288,6 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
|
|
|
3292
3288
|
pendingPrompt: allowSendBeforeReady && working.state === 'working',
|
|
3293
3289
|
pendingDelivery: working.pendingDelivery,
|
|
3294
3290
|
connection: sessionConnection,
|
|
3295
|
-
settling: composerSettling,
|
|
3296
3291
|
// Only an OPEN TURN the control plane is holding counts here. This tab's
|
|
3297
3292
|
// optimistic receipt and a stream frame both survive a box that died
|
|
3298
3293
|
// mid-turn, and a durable inbox row (which the projection also sources to
|
|
@@ -3405,8 +3400,9 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
|
|
|
3405
3400
|
// Change requests are the only kind a turn produces. `external` exists on
|
|
3406
3401
|
// the union for `setup-links/setup-link-button.tsx`, which renders this
|
|
3407
3402
|
// card inline in prose and handles its own open.
|
|
3408
|
-
if (outcome.kind === 'change_request')
|
|
3409
|
-
setOpenCrId(outcome.id.slice('cr:'.length));
|
|
3403
|
+
if (outcome.kind === 'change_request') {
|
|
3404
|
+
setOpenCrId(outcome.action.target ?? outcome.id.slice('cr:'.length));
|
|
3405
|
+
}
|
|
3410
3406
|
}, [setOpenCrId]);
|
|
3411
3407
|
// While the session is still connecting / loading its content, render ONLY the
|
|
3412
3408
|
// staged loader — never the session shell (header + input) at the same time.
|
|
@@ -3422,7 +3418,7 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
|
|
|
3422
3418
|
if (transcriptFreshness === 'error' && !hasMessages) {
|
|
3423
3419
|
return (_jsx("div", { className: "bg-background relative flex h-full flex-col", "data-testid": "session-chat", children: _jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 p-6", "data-testid": "session-transcript-error", children: [_jsx("p", { className: "text-muted-foreground text-sm", children: tHardcodedUi.raw('i18nComplete.text8d0cef2d3405') }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => retryTranscript(), children: tHardcodedUi.raw('i18nComplete.text942087cc2d41') })] }) }));
|
|
3424
3420
|
}
|
|
3425
|
-
return (_jsx("div", { className: "bg-background relative flex h-full flex-col", "data-testid": "session-chat", children: _jsx(SessionStartingLoader, {
|
|
3421
|
+
return (_jsx("div", { className: "bg-background relative flex h-full flex-col", "data-testid": "session-chat", children: _jsx(SessionStartingLoader, { projectId: projectId, sessionId: projectSessionId }) }));
|
|
3426
3422
|
}
|
|
3427
3423
|
return (
|
|
3428
3424
|
// Outcomes' cache coherence and the shareable `?cr=` link both hinge on
|
|
@@ -3439,7 +3435,7 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
|
|
|
3439
3435
|
: welcomeWallpaper, !hideHeader && (_jsx(SessionSiteHeader, { sessionId: sessionId, sessionTitle: session?.title || 'Untitled', leadingAction: headerLeadingAction, parent: parentCrumb })), _jsx(SessionContextModal, { open: contextModalOpen, onOpenChange: setContextModalOpen,
|
|
3440
3436
|
// A chat with no `useSession` source: the raw explorer lists the
|
|
3441
3437
|
// rows `useSessionSync` read for it.
|
|
3442
|
-
detachedRows: sessionState ? undefined : hookMessages, source: sessionState ?? DETACHED_SESSION_MESSAGES, session: session, providers: providers, allSessions: allSessions, servedModel: sessionServedModel, billedCost: sessionBilledCost(modelUsage) }), _jsx(CompactModal, { sessionId: sessionId, open: compactModalOpen, onOpenChange: setCompactModalOpen }), _jsx(ChangeRequestDetailDialog, { crId: openCrId, onClose: () => setOpenCrId(null) }), _jsxs(SessionBodyRow, { actionPanel: !hideHeader && !readOnly, children: [isNotFound ? (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col items-center justify-center gap-3 px-6 text-center", children: [_jsx("div", { className: "text-muted-foreground text-sm", children: tHardcodedUi.raw('componentsSessionSessionChat.line5821JsxTextThisSessionIsNotAccessibleRightNow') }), _jsx(Button, { asChild: true, variant: "outline", size: "sm", children: _jsx(Link, { href: "/", prefetch: true, onClick: () => {
|
|
3438
|
+
detachedRows: sessionState ? undefined : hookMessages, source: sessionState ?? DETACHED_SESSION_MESSAGES, session: session, providers: providers, allSessions: allSessions, servedModel: sessionServedModel, billedCost: sessionBilledCost(modelUsage) }), _jsx(CompactModal, { sessionId: sessionId, open: compactModalOpen, onOpenChange: setCompactModalOpen }), _jsx(ChangeRequestDetailDialog, { crId: openCrId, onClose: () => setOpenCrId(null), onOpenChangeRequest: setOpenCrId }), _jsxs(SessionBodyRow, { actionPanel: !hideHeader && !readOnly, children: [isNotFound ? (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col items-center justify-center gap-3 px-6 text-center", children: [_jsx("div", { className: "text-muted-foreground text-sm", children: tHardcodedUi.raw('componentsSessionSessionChat.line5821JsxTextThisSessionIsNotAccessibleRightNow') }), _jsx(Button, { asChild: true, variant: "outline", size: "sm", children: _jsx(Link, { href: "/", prefetch: true, onClick: () => {
|
|
3443
3439
|
try {
|
|
3444
3440
|
if (sessionId)
|
|
3445
3441
|
useTabStore.getState().closeTab?.(sessionId);
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* runs after layout and before paint. No frame is painted with the jump,
|
|
37
37
|
* whenever the content lands.
|
|
38
38
|
*/
|
|
39
|
-
|
|
39
|
+
interface TurnScrollAnchor {
|
|
40
40
|
element: HTMLElement;
|
|
41
41
|
/** The anchor's position in content space at capture time. */
|
|
42
42
|
contentTop: number;
|
|
@@ -53,3 +53,4 @@ export declare function captureTurnScrollAnchor(container: HTMLElement): TurnScr
|
|
|
53
53
|
* idempotent. An anchor that left the DOM is never written.
|
|
54
54
|
*/
|
|
55
55
|
export declare function holdTurnScrollAnchor(container: HTMLElement, content: HTMLElement, anchor: TurnScrollAnchor | null): () => void;
|
|
56
|
+
export {};
|
|
@@ -15,6 +15,7 @@ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
|
15
15
|
*/
|
|
16
16
|
import { ArrowsLeftRightIcon, ClockCounterClockwiseIcon, XIcon } from '@phosphor-icons/react';
|
|
17
17
|
import { sessionLogFullTextAction, sessionLogReferencedTexts, } from '@kortix/sdk';
|
|
18
|
+
import { useMemo } from 'react';
|
|
18
19
|
import { Button } from '../../primitives/button.js';
|
|
19
20
|
import { InfoBanner } from '../../primitives/info-banner.js';
|
|
20
21
|
import { useLocale, useTranslations } from '../../i18n/index.js';
|
|
@@ -51,7 +52,8 @@ function missingLabel(t, kind, count) {
|
|
|
51
52
|
export function RestoreNotice({ notice, onDismiss }) {
|
|
52
53
|
const t = useTranslations('sessionUi.history');
|
|
53
54
|
const locale = useLocale();
|
|
54
|
-
const
|
|
55
|
+
const listFormat = useMemo(() => new Intl.ListFormat(locale, { style: 'narrow', type: 'unit' }), [locale]);
|
|
56
|
+
const items = listFormat.format(notice.missing.map((m) => missingLabel(t, m.kind, m.count)));
|
|
55
57
|
return (
|
|
56
58
|
// `info`: the neutral tone keeps `Alert`'s default fill under a hairline (two boundaries).
|
|
57
59
|
_jsxs(InfoBanner, { tone: "info", role: "status", "data-restore-notice": "", className: "mb-6 rounded-md", icon: ClockCounterClockwiseIcon, title: t('restoreTitle'), action: _jsx(Button, { variant: "ghost", size: "icon-sm", onClick: onDismiss, "aria-label": t('restoreDismiss'), className: "text-muted-foreground", children: _jsx(XIcon, { className: "size-4" }) }), children: [notice.missing.length > 0 && _jsxs("span", { children: [t('restoreMissing', { items }), " "] }), t('restoreAgent')] }));
|
|
@@ -9,5 +9,5 @@ import { SessionStartingLoader } from '../status/session-starting-loader.js';
|
|
|
9
9
|
import '../tool/tools/register.js';
|
|
10
10
|
export function SessionThread({ session, hideHeader = false, readOnly = false, quote, className }) {
|
|
11
11
|
const { projectId, sessionId, runtimeSessionId } = session;
|
|
12
|
-
return (_jsx(ProjectScope, { projectId: projectId, sessionId: sessionId, children: _jsx(ProviderPoolDraftBoundary, { identity: `${projectId}/${sessionId}`, children: _jsxs("div", { "data-slot": "session-thread", className: cn('relative flex h-full min-h-0 flex-col', className), children: [runtimeSessionId ? (_jsx(SessionChat, { sessionId: runtimeSessionId, projectSessionId: sessionId, projectId: projectId, sessionState: session, hideHeader: hideHeader, readOnly: readOnly, hostQuote: quote }, runtimeSessionId)) : (_jsx(SessionStartingLoader, {
|
|
12
|
+
return (_jsx(ProjectScope, { projectId: projectId, sessionId: sessionId, children: _jsx(ProviderPoolDraftBoundary, { identity: `${projectId}/${sessionId}`, children: _jsxs("div", { "data-slot": "session-thread", className: cn('relative flex h-full min-h-0 flex-col', className), children: [runtimeSessionId ? (_jsx(SessionChat, { sessionId: runtimeSessionId, projectSessionId: sessionId, projectId: projectId, sessionState: session, hideHeader: hideHeader, readOnly: readOnly, hostQuote: quote }, runtimeSessionId)) : (_jsx(SessionStartingLoader, { projectId: projectId, sessionId: sessionId })), _jsx(SessionPanelFallback, { projectId: projectId, projectSessionId: sessionId, runtimeSessionId: runtimeSessionId })] }) }) }));
|
|
13
13
|
}
|
|
@@ -43,6 +43,8 @@ import { Disclosure, DisclosureContent, DisclosureTrigger } from '../../primitiv
|
|
|
43
43
|
import { useUserPreferencesStore } from '../../internal/stores/user-preferences-store.js';
|
|
44
44
|
import { SubSessionModal } from './sub-session-modal.js';
|
|
45
45
|
import { ToolPartRenderer, TurnLiveContext } from '../tool/tool-renderers.js';
|
|
46
|
+
import { RecoveredCallsContext } from '../tool/shared/infrastructure.js';
|
|
47
|
+
import { recoveredShellFailures } from '../turn/recovered-failures.js';
|
|
46
48
|
import { cn } from '../../lib/utils.js';
|
|
47
49
|
import { extractKortixSystemMessages, extractSessionReport, stripKortixSystemTags, } from '../../internal/lib/utils/kortix-system-tags.js';
|
|
48
50
|
// Shared UI primitives (framework-agnostic, reusable on mobile)
|
|
@@ -959,6 +961,8 @@ function TurnUserBubble(props) {
|
|
|
959
961
|
? () => onRemoveQueued(pendingPrompt.prompt_id)
|
|
960
962
|
: undefined })) : queuedStatus === 'sending' || queuedStatus === 'queued' || queuedStatus === 'interrupted' ? (_jsx(QueuedPromptProgress, { state: queuedStatus })) : undefined }) })) }));
|
|
961
963
|
}
|
|
964
|
+
/** One shared empty set: a live turn has no recovered calls yet. */
|
|
965
|
+
const NO_RECOVERED_CALLS = new Set();
|
|
962
966
|
/** The assistant's part tree: bursts, standalone deliverables, and prose
|
|
963
967
|
* between them, under one live-context provider. */
|
|
964
968
|
function TurnToolBlocks(props) {
|
|
@@ -972,6 +976,8 @@ function TurnToolBlocks(props) {
|
|
|
972
976
|
// Settled turns only: while working the split is null anyway, and the
|
|
973
977
|
// filter re-runs the burst steps on every SSE frame.
|
|
974
978
|
const split = useMemo(() => (fold && !working ? splitSessionLogTurnWork(segments.filter(segmentRendersSomething), { working }) : null), [fold, segments, working]);
|
|
979
|
+
// Settled turns only: while the turn runs, the next step has not happened yet.
|
|
980
|
+
const recovered = useMemo(() => (working ? NO_RECOVERED_CALLS : recoveredShellFailures(turnBlocks(turn))), [turn, working]);
|
|
975
981
|
const renderSegment = (segment) => {
|
|
976
982
|
const key = turnSegmentKey(segment);
|
|
977
983
|
if (key === null)
|
|
@@ -984,13 +990,13 @@ function TurnToolBlocks(props) {
|
|
|
984
990
|
// will. Provided here rather than per-row because `working` is a fact
|
|
985
991
|
// about the TURN, and this block is the turn's whole part tree.
|
|
986
992
|
// See `TurnLiveContext`.
|
|
987
|
-
_jsx(TurnLiveContext.Provider, { value: working, children: _jsx("div", { className: "space-y-3", children: split
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
993
|
+
_jsx(TurnLiveContext.Provider, { value: working, children: _jsx(RecoveredCallsContext.Provider, { value: recovered, children: _jsx("div", { className: "space-y-3", children: split
|
|
994
|
+
? [
|
|
995
|
+
_jsx(TurnWorkAccordion, { durationMs: durationMs, children: split.work.map(renderSegment) }, "turn-work"),
|
|
996
|
+
...split.hoisted.map(renderSegment),
|
|
997
|
+
...split.final.map(renderSegment),
|
|
998
|
+
]
|
|
999
|
+
: segments.map(renderSegment) }) }) })) }));
|
|
994
1000
|
}
|
|
995
1001
|
/** One segment of the turn's steps section: a burst, a show group, a
|
|
996
1002
|
* standalone deliverable, or prose between bursts. Keyed by the first
|