@vibesdotdev/code-sessions 0.0.0-stage → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -0
- package/README.md +165 -2
- package/dist/agent/coordinator.agent.descriptor.d.ts +69 -0
- package/dist/agent/coordinator.agent.descriptor.d.ts.map +1 -0
- package/dist/agent/coordinator.agent.descriptor.js +60 -0
- package/dist/agent/coordinator.agent.descriptor.js.map +1 -0
- package/dist/agent/coordinator.prompt.descriptor.d.ts +135 -0
- package/dist/agent/coordinator.prompt.descriptor.d.ts.map +1 -0
- package/dist/agent/coordinator.prompt.descriptor.js +29 -0
- package/dist/agent/coordinator.prompt.descriptor.js.map +1 -0
- package/dist/agent/coordinator.system-prompt.d.ts +3 -0
- package/dist/agent/coordinator.system-prompt.d.ts.map +1 -0
- package/dist/agent/coordinator.system-prompt.js +18 -0
- package/dist/agent/coordinator.system-prompt.js.map +1 -0
- package/dist/agent/developer.agent.descriptor.d.ts +74 -0
- package/dist/agent/developer.agent.descriptor.d.ts.map +1 -0
- package/dist/agent/developer.agent.descriptor.js +138 -0
- package/dist/agent/developer.agent.descriptor.js.map +1 -0
- package/dist/agent/developer.prompt.descriptor.d.ts +137 -0
- package/dist/agent/developer.prompt.descriptor.d.ts.map +1 -0
- package/dist/agent/developer.prompt.descriptor.js +29 -0
- package/dist/agent/developer.prompt.descriptor.js.map +1 -0
- package/dist/agent/reviewer.agent.descriptor.d.ts +69 -0
- package/dist/agent/reviewer.agent.descriptor.d.ts.map +1 -0
- package/dist/agent/reviewer.agent.descriptor.js +60 -0
- package/dist/agent/reviewer.agent.descriptor.js.map +1 -0
- package/dist/agent/reviewer.prompt.descriptor.d.ts +135 -0
- package/dist/agent/reviewer.prompt.descriptor.d.ts.map +1 -0
- package/dist/agent/reviewer.prompt.descriptor.js +29 -0
- package/dist/agent/reviewer.prompt.descriptor.js.map +1 -0
- package/dist/agent/reviewer.system-prompt.d.ts +3 -0
- package/dist/agent/reviewer.system-prompt.d.ts.map +1 -0
- package/dist/agent/reviewer.system-prompt.js +17 -0
- package/dist/agent/reviewer.system-prompt.js.map +1 -0
- package/dist/agent/system-prompt.d.ts +12 -0
- package/dist/agent/system-prompt.d.ts.map +1 -0
- package/dist/agent/system-prompt.js +28 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/api/code-sessions.api-client.descriptor.d.ts +25 -0
- package/dist/api/code-sessions.api-client.descriptor.d.ts.map +1 -0
- package/dist/api/code-sessions.api-client.descriptor.js +26 -0
- package/dist/api/code-sessions.api-client.descriptor.js.map +1 -0
- package/dist/api/code-sessions.api-client.impl.d.ts +156 -0
- package/dist/api/code-sessions.api-client.impl.d.ts.map +1 -0
- package/dist/api/code-sessions.api-client.impl.js +852 -0
- package/dist/api/code-sessions.api-client.impl.js.map +1 -0
- package/dist/api/code-sessions.api-client.schemas.d.ts +2 -0
- package/dist/api/code-sessions.api-client.schemas.d.ts.map +1 -0
- package/dist/api/code-sessions.api-client.schemas.js +2 -0
- package/dist/api/code-sessions.api-client.schemas.js.map +1 -0
- package/dist/api/code-sessions.api-client.types.d.ts +252 -0
- package/dist/api/code-sessions.api-client.types.d.ts.map +1 -0
- package/dist/api/code-sessions.api-client.types.js +77 -0
- package/dist/api/code-sessions.api-client.types.js.map +1 -0
- package/dist/api/index.d.ts +13 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +20 -0
- package/dist/api/index.js.map +1 -0
- package/dist/capability.d.ts +9 -0
- package/dist/capability.d.ts.map +1 -0
- package/dist/capability.js +9 -0
- package/dist/capability.js.map +1 -0
- package/dist/catalog/index.d.ts +2 -0
- package/dist/catalog/index.d.ts.map +1 -0
- package/dist/catalog/index.js +2 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/catalog/session-catalog.d.ts +131 -0
- package/dist/catalog/session-catalog.d.ts.map +1 -0
- package/dist/catalog/session-catalog.impl.consumer.worker.d.ts +113 -0
- package/dist/catalog/session-catalog.impl.consumer.worker.d.ts.map +1 -0
- package/dist/catalog/session-catalog.impl.consumer.worker.js +32 -0
- package/dist/catalog/session-catalog.impl.consumer.worker.js.map +1 -0
- package/dist/catalog/session-catalog.js +126 -0
- package/dist/catalog/session-catalog.js.map +1 -0
- package/dist/clock/clock.client.d.ts +18 -0
- package/dist/clock/clock.client.d.ts.map +1 -0
- package/dist/clock/clock.client.js +43 -0
- package/dist/clock/clock.client.js.map +1 -0
- package/dist/code-sessions.consumer.plugin.d.ts +4 -0
- package/dist/code-sessions.consumer.plugin.d.ts.map +1 -0
- package/dist/code-sessions.consumer.plugin.js +16 -0
- package/dist/code-sessions.consumer.plugin.js.map +1 -0
- package/dist/code-sessions.plugin.d.ts +15 -0
- package/dist/code-sessions.plugin.d.ts.map +1 -0
- package/dist/code-sessions.plugin.js +65 -0
- package/dist/code-sessions.plugin.js.map +1 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +9 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/preparation.d.ts +2 -0
- package/dist/config/preparation.d.ts.map +1 -0
- package/dist/config/preparation.js +2 -0
- package/dist/config/preparation.js.map +1 -0
- package/dist/docs/code-sessions.docs.descriptor.d.ts +4 -0
- package/dist/docs/code-sessions.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/code-sessions.docs.descriptor.js +241 -0
- package/dist/docs/code-sessions.docs.descriptor.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/pull-request-plan.d.ts +68 -0
- package/dist/pull-request-plan.d.ts.map +1 -0
- package/dist/pull-request-plan.js +94 -0
- package/dist/pull-request-plan.js.map +1 -0
- package/dist/schemas/preparation.d.ts +51 -0
- package/dist/schemas/preparation.d.ts.map +1 -0
- package/dist/schemas/preparation.js +20 -0
- package/dist/schemas/preparation.js.map +1 -0
- package/dist/schemas/requests.d.ts +411 -0
- package/dist/schemas/requests.d.ts.map +1 -0
- package/dist/schemas/requests.js +87 -0
- package/dist/schemas/requests.js.map +1 -0
- package/dist/schemas/responses.d.ts +275 -0
- package/dist/schemas/responses.d.ts.map +1 -0
- package/dist/schemas/responses.js +90 -0
- package/dist/schemas/responses.js.map +1 -0
- package/dist/svelte/actions.d.ts +70 -0
- package/dist/svelte/actions.d.ts.map +1 -0
- package/dist/svelte/actions.js +280 -0
- package/dist/svelte/clock.svelte.d.ts +6 -0
- package/dist/svelte/clock.svelte.d.ts.map +1 -0
- package/dist/svelte/clock.svelte.js +33 -0
- package/dist/svelte/components/CreateSessionDialog.svelte +470 -0
- package/dist/svelte/components/CreateSessionDialog.svelte.d.ts +57 -0
- package/dist/svelte/components/CreateSessionDialog.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SessionCard.svelte +216 -0
- package/dist/svelte/components/SessionCard.svelte.d.ts +27 -0
- package/dist/svelte/components/SessionCard.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SessionList.svelte +86 -0
- package/dist/svelte/components/SessionList.svelte.d.ts +23 -0
- package/dist/svelte/components/SessionList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SessionSeed.svelte +60 -0
- package/dist/svelte/components/SessionSeed.svelte.d.ts +9 -0
- package/dist/svelte/components/SessionSeed.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TranscriptView.svelte +360 -0
- package/dist/svelte/components/TranscriptView.svelte.d.ts +26 -0
- package/dist/svelte/components/TranscriptView.svelte.d.ts.map +1 -0
- package/dist/svelte/create-session-form.d.ts +84 -0
- package/dist/svelte/create-session-form.d.ts.map +1 -0
- package/dist/svelte/create-session-form.js +107 -0
- package/dist/svelte/index.d.ts +20 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +18 -0
- package/dist/svelte/live-session.d.ts +156 -0
- package/dist/svelte/live-session.d.ts.map +1 -0
- package/dist/svelte/live-session.js +152 -0
- package/dist/svelte/loaders.d.ts +74 -0
- package/dist/svelte/loaders.d.ts.map +1 -0
- package/dist/svelte/loaders.js +124 -0
- package/dist/svelte/outcome.d.ts +46 -0
- package/dist/svelte/outcome.d.ts.map +1 -0
- package/dist/svelte/outcome.js +49 -0
- package/dist/svelte/relative-time.d.ts +32 -0
- package/dist/svelte/relative-time.d.ts.map +1 -0
- package/dist/svelte/relative-time.js +51 -0
- package/dist/svelte/session-list-item.d.ts +23 -0
- package/dist/svelte/session-list-item.d.ts.map +1 -0
- package/dist/svelte/session-list-item.js +1 -0
- package/dist/svelte/styles.css +8 -0
- package/dist/svelte/transcript-input.d.ts +45 -0
- package/dist/svelte/transcript-input.d.ts.map +1 -0
- package/dist/svelte/transcript-input.js +188 -0
- package/dist/tui/code-sessions-tui.plugin.d.ts +10 -0
- package/dist/tui/code-sessions-tui.plugin.d.ts.map +1 -0
- package/dist/tui/code-sessions-tui.plugin.js +29 -0
- package/dist/tui/code-sessions-tui.plugin.js.map +1 -0
- package/dist/tui/code-sessions.tui-app.descriptor.d.ts +7 -0
- package/dist/tui/code-sessions.tui-app.descriptor.d.ts.map +1 -0
- package/dist/tui/code-sessions.tui-app.descriptor.js +30 -0
- package/dist/tui/code-sessions.tui-app.descriptor.js.map +1 -0
- package/dist/tui/code-sessions.tui-app.impl.consumer.d.ts +14 -0
- package/dist/tui/code-sessions.tui-app.impl.consumer.d.ts.map +1 -0
- package/dist/tui/code-sessions.tui-app.impl.consumer.js +453 -0
- package/dist/tui/code-sessions.tui-app.impl.consumer.js.map +1 -0
- package/dist/tui/code-sessions.tui-client.d.ts +22 -0
- package/dist/tui/code-sessions.tui-client.d.ts.map +1 -0
- package/dist/tui/code-sessions.tui-client.js +95 -0
- package/dist/tui/code-sessions.tui-client.js.map +1 -0
- package/dist/tui/code-sessions.tui-open.descriptor.d.ts +7 -0
- package/dist/tui/code-sessions.tui-open.descriptor.d.ts.map +1 -0
- package/dist/tui/code-sessions.tui-open.descriptor.js +16 -0
- package/dist/tui/code-sessions.tui-open.descriptor.js.map +1 -0
- package/dist/tui/code-sessions.tui-open.impl.consumer.d.ts +7 -0
- package/dist/tui/code-sessions.tui-open.impl.consumer.d.ts.map +1 -0
- package/dist/tui/code-sessions.tui-open.impl.consumer.js +11 -0
- package/dist/tui/code-sessions.tui-open.impl.consumer.js.map +1 -0
- package/dist/tui/code-sessions.tui-state.descriptor.d.ts +16 -0
- package/dist/tui/code-sessions.tui-state.descriptor.d.ts.map +1 -0
- package/dist/tui/code-sessions.tui-state.descriptor.js +50 -0
- package/dist/tui/code-sessions.tui-state.descriptor.js.map +1 -0
- package/dist/tui/code-sessions.tui-state.impl.consumer.d.ts +30 -0
- package/dist/tui/code-sessions.tui-state.impl.consumer.d.ts.map +1 -0
- package/dist/tui/code-sessions.tui-state.impl.consumer.js +533 -0
- package/dist/tui/code-sessions.tui-state.impl.consumer.js.map +1 -0
- package/dist/tui/code-sessions.tui-state.key.d.ts +322 -0
- package/dist/tui/code-sessions.tui-state.key.d.ts.map +1 -0
- package/dist/tui/code-sessions.tui-state.key.js +104 -0
- package/dist/tui/code-sessions.tui-state.key.js.map +1 -0
- package/dist/tui/index.d.ts +9 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +8 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/workspace/index.d.ts +2 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +2 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/workspace-binding.d.ts +74 -0
- package/dist/workspace/workspace-binding.d.ts.map +1 -0
- package/dist/workspace/workspace-binding.impl.consumer.worker.d.ts +17 -0
- package/dist/workspace/workspace-binding.impl.consumer.worker.d.ts.map +1 -0
- package/dist/workspace/workspace-binding.impl.consumer.worker.js +134 -0
- package/dist/workspace/workspace-binding.impl.consumer.worker.js.map +1 -0
- package/dist/workspace/workspace-binding.js +72 -0
- package/dist/workspace/workspace-binding.js.map +1 -0
- package/package.json +238 -4
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { SessionListItem } from '../session-list-item.js';
|
|
3
|
+
|
|
4
|
+
export interface SessionCardProps {
|
|
5
|
+
session: SessionListItem;
|
|
6
|
+
/**
|
|
7
|
+
* Destination for the primary "open this session" navigation.
|
|
8
|
+
*
|
|
9
|
+
* Prefer this over `onopen`. With an href the card's title is a real
|
|
10
|
+
* anchor, so ⌘/ctrl-click, middle-click, "open in new tab" and "copy link
|
|
11
|
+
* address" all work on the feature's main navigation target — none of
|
|
12
|
+
* which are possible through a click handler. SvelteKit still routes it
|
|
13
|
+
* client-side, so nothing is lost.
|
|
14
|
+
*/
|
|
15
|
+
href?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Fallback navigation for callers that cannot express the destination as
|
|
18
|
+
* a URL. Ignored when `href` is set.
|
|
19
|
+
*/
|
|
20
|
+
onopen?: (session: SessionListItem) => void;
|
|
21
|
+
/** Called when the user confirms session deletion. */
|
|
22
|
+
ondelete?: (sessionId: string) => void;
|
|
23
|
+
/** Show the delete action. Defaults to true. */
|
|
24
|
+
showDelete?: boolean;
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<script lang="ts">
|
|
29
|
+
import { Badge } from '@vibesdotdev/kit/components/ui/badge';
|
|
30
|
+
import { Button } from '@vibesdotdev/kit/components/ui/button';
|
|
31
|
+
import { Icon } from '@vibesdotdev/kit/components';
|
|
32
|
+
import { formatAbsoluteTime, formatRelativeAge } from '../relative-time.js';
|
|
33
|
+
import { sharedNow } from '../clock.svelte.js';
|
|
34
|
+
|
|
35
|
+
let { session, href, onopen, ondelete, showDelete = true }: SessionCardProps = $props();
|
|
36
|
+
|
|
37
|
+
const now = sharedNow();
|
|
38
|
+
|
|
39
|
+
function statusColor(status: string): string {
|
|
40
|
+
switch (status) {
|
|
41
|
+
case 'active':
|
|
42
|
+
return 'bg-green-500';
|
|
43
|
+
case 'initializing':
|
|
44
|
+
return 'bg-yellow-400 animate-pulse';
|
|
45
|
+
case 'error':
|
|
46
|
+
return 'bg-red-500';
|
|
47
|
+
default:
|
|
48
|
+
return 'bg-muted-foreground';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function hostLabel(session: SessionListItem): string {
|
|
53
|
+
if (session.hostTarget.kind === 'cloud') return 'Cloud sandbox';
|
|
54
|
+
if (session.hostTarget.kind === 'host') {
|
|
55
|
+
const hostId = session.hostTarget.hostId;
|
|
56
|
+
return hostId === 'local' ? 'Local machine' : `Host: ${hostId}`;
|
|
57
|
+
}
|
|
58
|
+
if (session.hostTarget.kind === 'provisioned')
|
|
59
|
+
return `provisioned:${session.hostTarget.adapter}`;
|
|
60
|
+
return 'Remote';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function capabilityLabel(session: SessionListItem): string {
|
|
64
|
+
return session.capability === 'transcript' ? 'Snapshot execution' : 'Interactive';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const displayName = $derived(
|
|
68
|
+
session.repositoryName ??
|
|
69
|
+
(session.ephemeral ? 'Ephemeral workspace' : session.sessionId.slice(0, 8))
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const age = $derived(formatRelativeAge(session.lastActivityAt, now.value));
|
|
73
|
+
const absoluteAge = $derived(formatAbsoluteTime(session.lastActivityAt));
|
|
74
|
+
|
|
75
|
+
const containerClass =
|
|
76
|
+
'relative block w-full rounded-md border p-3 text-left transition-colors hover:bg-muted/40';
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Native buttons activate on BOTH Enter and Space; a `role="button"` element
|
|
80
|
+
* has to reproduce that itself. The old handler only listened for Enter, so
|
|
81
|
+
* Space scrolled the page instead of opening the focused card.
|
|
82
|
+
*/
|
|
83
|
+
function handleFallbackKeydown(event: KeyboardEvent): void {
|
|
84
|
+
if (event.key !== 'Enter' && event.key !== ' ') return;
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
onopen?.(session);
|
|
87
|
+
}
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<!--
|
|
91
|
+
SessionCard — shows status, host target, age, and optional preview link.
|
|
92
|
+
Zero internal jargon (no "descriptor", "runtimeId", "impl").
|
|
93
|
+
|
|
94
|
+
Two shapes, one body. With an `href` the whole card is a stretched link
|
|
95
|
+
(`after:absolute after:inset-0` on the title anchor); the delete button and
|
|
96
|
+
the preview link are SIBLINGS floated above that overlay on `z-10`, not
|
|
97
|
+
descendants of it.
|
|
98
|
+
|
|
99
|
+
That sibling relationship is the fix. The previous markup made the card
|
|
100
|
+
itself a `role="button"` div that CONTAINED a button and an anchor — nesting
|
|
101
|
+
interactive elements inside a control, which screen readers flatten into one
|
|
102
|
+
ambiguous target. There are still three interactive elements here; the
|
|
103
|
+
difference is that none of them contains another.
|
|
104
|
+
|
|
105
|
+
Load-bearing detail: the title anchor must stay non-`relative`, or its
|
|
106
|
+
`::after` takes the anchor as its containing block and the stretched hit area
|
|
107
|
+
collapses to the width of the title text.
|
|
108
|
+
-->
|
|
109
|
+
{#snippet cardBody()}
|
|
110
|
+
<div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
|
111
|
+
<div class="flex w-full min-w-0 items-start gap-3">
|
|
112
|
+
<div class="relative mt-0.5 shrink-0 rounded-md bg-primary/10 p-2">
|
|
113
|
+
<Icon
|
|
114
|
+
icon={session.capability === 'transcript' ? 'lucide:film' : 'lucide:terminal'}
|
|
115
|
+
class="size-5 text-primary"
|
|
116
|
+
aria-hidden="true"
|
|
117
|
+
/>
|
|
118
|
+
<span
|
|
119
|
+
class={`absolute -bottom-1 -right-1 size-3 rounded-full border-2 border-background ${statusColor(session.status)}`}
|
|
120
|
+
aria-hidden="true"
|
|
121
|
+
></span>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div class="min-w-0 flex-1">
|
|
125
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
126
|
+
{#if href}
|
|
127
|
+
<a
|
|
128
|
+
{href}
|
|
129
|
+
class="truncate font-medium outline-none after:absolute after:inset-0 after:rounded-md after:content-[''] hover:underline focus-visible:after:ring-2 focus-visible:after:ring-ring"
|
|
130
|
+
>
|
|
131
|
+
{displayName}
|
|
132
|
+
</a>
|
|
133
|
+
{:else}
|
|
134
|
+
<p class="truncate font-medium">{displayName}</p>
|
|
135
|
+
{/if}
|
|
136
|
+
<Badge variant="secondary" class="shrink-0 text-xs">
|
|
137
|
+
{capabilityLabel(session)}
|
|
138
|
+
</Badge>
|
|
139
|
+
{#if session.checkoutRef}
|
|
140
|
+
<Badge variant="outline" class="shrink-0 font-mono text-xs">
|
|
141
|
+
{session.checkoutRef}
|
|
142
|
+
</Badge>
|
|
143
|
+
{/if}
|
|
144
|
+
</div>
|
|
145
|
+
<p class="mt-0.5 truncate text-sm text-muted-foreground">{hostLabel(session)}</p>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<div class="relative z-10 flex shrink-0 items-center gap-2 self-end sm:self-auto">
|
|
150
|
+
<Badge variant="outline" class="capitalize">{session.status}</Badge>
|
|
151
|
+
{#if showDelete && ondelete}
|
|
152
|
+
<Button
|
|
153
|
+
variant="ghost"
|
|
154
|
+
size="icon"
|
|
155
|
+
class="size-7 text-muted-foreground hover:text-destructive"
|
|
156
|
+
onclick={(e: MouseEvent) => {
|
|
157
|
+
e.stopPropagation();
|
|
158
|
+
e.preventDefault();
|
|
159
|
+
ondelete?.(session.sessionId);
|
|
160
|
+
}}
|
|
161
|
+
aria-label={`Delete session ${displayName}`}
|
|
162
|
+
>
|
|
163
|
+
<Icon icon="lucide:trash-2" class="size-3.5" aria-hidden="true" />
|
|
164
|
+
</Button>
|
|
165
|
+
{/if}
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<div class="mt-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-muted-foreground">
|
|
170
|
+
<!--
|
|
171
|
+
`relative z-10` so the absolute-time tooltip is actually reachable. The
|
|
172
|
+
title anchor's stretched `::after` covers the whole card, so without
|
|
173
|
+
this, hovering the timestamp hit-tests to the anchor — which has no
|
|
174
|
+
title — and the tooltip could never appear on any card with an href
|
|
175
|
+
(i.e. every card in production).
|
|
176
|
+
-->
|
|
177
|
+
<span class="relative z-10">
|
|
178
|
+
Last active
|
|
179
|
+
<time datetime={session.lastActivityAt} title={absoluteAge ?? undefined}>{age}</time>
|
|
180
|
+
</span>
|
|
181
|
+
{#if session.previewUrl}
|
|
182
|
+
<a
|
|
183
|
+
href={session.previewUrl}
|
|
184
|
+
target="_blank"
|
|
185
|
+
rel="noopener noreferrer"
|
|
186
|
+
class="relative z-10 flex items-center gap-1 text-primary hover:underline"
|
|
187
|
+
onclick={(e: MouseEvent) => e.stopPropagation()}
|
|
188
|
+
>
|
|
189
|
+
<Icon icon="lucide:external-link" class="size-3" aria-hidden="true" />
|
|
190
|
+
Preview
|
|
191
|
+
</a>
|
|
192
|
+
{/if}
|
|
193
|
+
</div>
|
|
194
|
+
{/snippet}
|
|
195
|
+
|
|
196
|
+
{#if href}
|
|
197
|
+
<div class={containerClass}>
|
|
198
|
+
{@render cardBody()}
|
|
199
|
+
</div>
|
|
200
|
+
{:else}
|
|
201
|
+
{#if onopen}
|
|
202
|
+
<div
|
|
203
|
+
role="button"
|
|
204
|
+
tabindex="0"
|
|
205
|
+
class={`${containerClass} focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring`}
|
|
206
|
+
onclick={() => onopen(session)}
|
|
207
|
+
onkeydown={handleFallbackKeydown}
|
|
208
|
+
>
|
|
209
|
+
{@render cardBody()}
|
|
210
|
+
</div>
|
|
211
|
+
{:else}
|
|
212
|
+
<div class={containerClass}>
|
|
213
|
+
{@render cardBody()}
|
|
214
|
+
</div>
|
|
215
|
+
{/if}
|
|
216
|
+
{/if}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SessionListItem } from '../session-list-item.ts';
|
|
2
|
+
export interface SessionCardProps {
|
|
3
|
+
session: SessionListItem;
|
|
4
|
+
/**
|
|
5
|
+
* Destination for the primary "open this session" navigation.
|
|
6
|
+
*
|
|
7
|
+
* Prefer this over `onopen`. With an href the card's title is a real
|
|
8
|
+
* anchor, so ⌘/ctrl-click, middle-click, "open in new tab" and "copy link
|
|
9
|
+
* address" all work on the feature's main navigation target — none of
|
|
10
|
+
* which are possible through a click handler. SvelteKit still routes it
|
|
11
|
+
* client-side, so nothing is lost.
|
|
12
|
+
*/
|
|
13
|
+
href?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Fallback navigation for callers that cannot express the destination as
|
|
16
|
+
* a URL. Ignored when `href` is set.
|
|
17
|
+
*/
|
|
18
|
+
onopen?: (session: SessionListItem) => void;
|
|
19
|
+
/** Called when the user confirms session deletion. */
|
|
20
|
+
ondelete?: (sessionId: string) => void;
|
|
21
|
+
/** Show the delete action. Defaults to true. */
|
|
22
|
+
showDelete?: boolean;
|
|
23
|
+
}
|
|
24
|
+
declare const SessionCard: import("svelte").Component<SessionCardProps, {}, "">;
|
|
25
|
+
type SessionCard = ReturnType<typeof SessionCard>;
|
|
26
|
+
export default SessionCard;
|
|
27
|
+
//# sourceMappingURL=SessionCard.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionCard.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/SessionCard.svelte.ts"],"names":[],"mappings":"AAGC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,eAAe,CAAC;IACzB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC5C,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gDAAgD;IAChD,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAuJF,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { SessionListItem } from '../session-list-item.js';
|
|
3
|
+
|
|
4
|
+
export interface SessionListProps {
|
|
5
|
+
sessions: SessionListItem[];
|
|
6
|
+
loading?: boolean;
|
|
7
|
+
error?: string | null;
|
|
8
|
+
/**
|
|
9
|
+
* Destination for each row's primary navigation. Prefer this over
|
|
10
|
+
* `onopen` — it gives every card a real anchor, so ⌘-click, new tab and
|
|
11
|
+
* copy-link work. Routes differ per app, so the caller supplies the
|
|
12
|
+
* mapping rather than this package assuming `/sessions/<id>`.
|
|
13
|
+
*/
|
|
14
|
+
sessionHref?: (session: SessionListItem) => string;
|
|
15
|
+
/** Fallback navigation for callers that cannot express a URL. */
|
|
16
|
+
onopen?: (session: SessionListItem) => void;
|
|
17
|
+
/** Called when the user confirms deleting a session. */
|
|
18
|
+
ondelete?: (sessionId: string) => void;
|
|
19
|
+
/** Called when the user clicks the "New session" button in the empty state. */
|
|
20
|
+
oncreate?: () => void;
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<script lang="ts">
|
|
25
|
+
import { Button } from '@vibesdotdev/kit/components/ui/button';
|
|
26
|
+
import { Icon } from '@vibesdotdev/kit/components/icon';
|
|
27
|
+
import SessionCard from './SessionCard.svelte';
|
|
28
|
+
|
|
29
|
+
let {
|
|
30
|
+
sessions,
|
|
31
|
+
loading = false,
|
|
32
|
+
error = null,
|
|
33
|
+
sessionHref,
|
|
34
|
+
onopen,
|
|
35
|
+
ondelete,
|
|
36
|
+
oncreate
|
|
37
|
+
}: SessionListProps = $props();
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<!--
|
|
41
|
+
SessionList — list of SessionCards with an empty state that teaches creation.
|
|
42
|
+
Zero internal jargon.
|
|
43
|
+
-->
|
|
44
|
+
<section class="space-y-2" aria-label="Code sessions" aria-busy={loading}>
|
|
45
|
+
{#if loading}
|
|
46
|
+
<div class="flex items-center justify-center py-8 text-sm text-muted-foreground" role="status" aria-live="polite">
|
|
47
|
+
<Icon icon="lucide:loader-2" class="mr-2 size-4 animate-spin" aria-hidden="true" />
|
|
48
|
+
Loading sessions…
|
|
49
|
+
</div>
|
|
50
|
+
{:else if error}
|
|
51
|
+
<div class="rounded-md border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive" role="alert">
|
|
52
|
+
<div class="flex items-center gap-2">
|
|
53
|
+
<Icon icon="lucide:circle-x" class="size-4 shrink-0" aria-hidden="true" />
|
|
54
|
+
<span>{error}</span>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
{:else if sessions.length === 0}
|
|
58
|
+
<!-- Empty state: names the next action and offers it as a button -->
|
|
59
|
+
<div class="flex flex-col items-center gap-4 rounded-lg border border-dashed py-10 text-center" role="status" aria-live="polite">
|
|
60
|
+
<div class="rounded-full bg-muted p-3">
|
|
61
|
+
<Icon icon="lucide:terminal" class="size-6 text-muted-foreground" aria-hidden="true" />
|
|
62
|
+
</div>
|
|
63
|
+
<div class="space-y-1">
|
|
64
|
+
<p class="font-medium">No code sessions yet</p>
|
|
65
|
+
<p class="max-w-xs text-sm text-muted-foreground">
|
|
66
|
+
Start a session to run commands and browse your workspace. Cloud sessions run in seconds.
|
|
67
|
+
</p>
|
|
68
|
+
</div>
|
|
69
|
+
{#if oncreate}
|
|
70
|
+
<Button type="button" onclick={oncreate} size="sm">
|
|
71
|
+
<Icon icon="lucide:plus" class="mr-2 size-4" aria-hidden="true" />
|
|
72
|
+
New session
|
|
73
|
+
</Button>
|
|
74
|
+
{/if}
|
|
75
|
+
</div>
|
|
76
|
+
{:else}
|
|
77
|
+
{#each sessions as session (session.sessionId)}
|
|
78
|
+
<SessionCard
|
|
79
|
+
{session}
|
|
80
|
+
href={sessionHref?.(session)}
|
|
81
|
+
{onopen}
|
|
82
|
+
{ondelete}
|
|
83
|
+
/>
|
|
84
|
+
{/each}
|
|
85
|
+
{/if}
|
|
86
|
+
</section>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SessionListItem } from '../session-list-item.ts';
|
|
2
|
+
export interface SessionListProps {
|
|
3
|
+
sessions: SessionListItem[];
|
|
4
|
+
loading?: boolean;
|
|
5
|
+
error?: string | null;
|
|
6
|
+
/**
|
|
7
|
+
* Destination for each row's primary navigation. Prefer this over
|
|
8
|
+
* `onopen` — it gives every card a real anchor, so ⌘-click, new tab and
|
|
9
|
+
* copy-link work. Routes differ per app, so the caller supplies the
|
|
10
|
+
* mapping rather than this package assuming `/sessions/<id>`.
|
|
11
|
+
*/
|
|
12
|
+
sessionHref?: (session: SessionListItem) => string;
|
|
13
|
+
/** Fallback navigation for callers that cannot express a URL. */
|
|
14
|
+
onopen?: (session: SessionListItem) => void;
|
|
15
|
+
/** Called when the user confirms deleting a session. */
|
|
16
|
+
ondelete?: (sessionId: string) => void;
|
|
17
|
+
/** Called when the user clicks the "New session" button in the empty state. */
|
|
18
|
+
oncreate?: () => void;
|
|
19
|
+
}
|
|
20
|
+
declare const SessionList: import("svelte").Component<SessionListProps, {}, "">;
|
|
21
|
+
type SessionList = ReturnType<typeof SessionList>;
|
|
22
|
+
export default SessionList;
|
|
23
|
+
//# sourceMappingURL=SessionList.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionList.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/SessionList.svelte.ts"],"names":[],"mappings":"AAGC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAChC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,MAAM,CAAC;IACnD,iEAAiE;IACjE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC5C,wDAAwD;IACxD,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAmEF,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { SessionWithCapability } from '@vibesdotdev/code-sessions';
|
|
3
|
+
|
|
4
|
+
export interface SessionSeedProps {
|
|
5
|
+
/** The session whose seed to render. Renders nothing when it has none. */
|
|
6
|
+
session: SessionWithCapability;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Human label for a seed source. Unknown sources fall back to the raw value. */
|
|
10
|
+
function sourceLabel(source: string): string {
|
|
11
|
+
switch (source) {
|
|
12
|
+
case 'work-item':
|
|
13
|
+
return 'Work item';
|
|
14
|
+
default:
|
|
15
|
+
return source;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<script lang="ts">
|
|
21
|
+
import { Icon } from '@vibesdotdev/kit/components';
|
|
22
|
+
|
|
23
|
+
let { session }: SessionSeedProps = $props();
|
|
24
|
+
|
|
25
|
+
const seed = $derived(session.seed);
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<!--
|
|
29
|
+
"Started for …" — the provenance the record has always carried and no surface
|
|
30
|
+
ever showed.
|
|
31
|
+
|
|
32
|
+
`CodeSessionSeed` is persisted verbatim, threaded into the sandbox as
|
|
33
|
+
`VIBES_SEED_*`, and its own type comment says it exists "so surfaces can
|
|
34
|
+
render 'opened for <title>'". Until now nothing did: a session started from a
|
|
35
|
+
work item was indistinguishable from one started cold, so the task a session
|
|
36
|
+
belongs to was write-only data.
|
|
37
|
+
|
|
38
|
+
`ref` is shown as text, NOT a link. There is no work-item detail route to
|
|
39
|
+
link to (hq-web has `/workboard`, which takes no item parameter), and this
|
|
40
|
+
codebase's own rule — see `forgePullRequestUrl` returning `null` rather than
|
|
41
|
+
a dead button — is that a link nobody can follow is worse than none. Make it
|
|
42
|
+
an anchor when a real destination exists.
|
|
43
|
+
-->
|
|
44
|
+
{#if seed}
|
|
45
|
+
<div class="flex items-start gap-2 text-sm">
|
|
46
|
+
<Icon icon="lucide:target" class="mt-0.5 size-4 shrink-0 text-muted-foreground" aria-hidden="true" />
|
|
47
|
+
<div class="min-w-0">
|
|
48
|
+
<p class="text-muted-foreground">
|
|
49
|
+
Started for
|
|
50
|
+
<span class="font-medium text-foreground">{seed.title}</span>
|
|
51
|
+
</p>
|
|
52
|
+
<p class="mt-0.5 text-xs text-muted-foreground">
|
|
53
|
+
{sourceLabel(seed.source)}{#if seed.ref}<span class="ml-1 font-mono">{seed.ref}</span>{/if}
|
|
54
|
+
</p>
|
|
55
|
+
{#if seed.body}
|
|
56
|
+
<p class="mt-1 whitespace-pre-wrap text-xs text-muted-foreground">{seed.body}</p>
|
|
57
|
+
{/if}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
{/if}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SessionWithCapability } from '@vibesdotdev/code-sessions';
|
|
2
|
+
export interface SessionSeedProps {
|
|
3
|
+
/** The session whose seed to render. Renders nothing when it has none. */
|
|
4
|
+
session: SessionWithCapability;
|
|
5
|
+
}
|
|
6
|
+
declare const SessionSeed: import("svelte").Component<SessionSeedProps, {}, "">;
|
|
7
|
+
type SessionSeed = ReturnType<typeof SessionSeed>;
|
|
8
|
+
export default SessionSeed;
|
|
9
|
+
//# sourceMappingURL=SessionSeed.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionSeed.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/SessionSeed.svelte.ts"],"names":[],"mappings":"AAGC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAChC,0EAA0E;IAC1E,OAAO,EAAE,qBAAqB,CAAC;CAC/B;AA8CF,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|