@vibesdotdev/code-sessions 0.0.0-stage → 1.0.0-rc.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.
Files changed (217) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +165 -2
  3. package/dist/agent/coordinator.agent.descriptor.d.ts +69 -0
  4. package/dist/agent/coordinator.agent.descriptor.d.ts.map +1 -0
  5. package/dist/agent/coordinator.agent.descriptor.js +60 -0
  6. package/dist/agent/coordinator.agent.descriptor.js.map +1 -0
  7. package/dist/agent/coordinator.prompt.descriptor.d.ts +135 -0
  8. package/dist/agent/coordinator.prompt.descriptor.d.ts.map +1 -0
  9. package/dist/agent/coordinator.prompt.descriptor.js +29 -0
  10. package/dist/agent/coordinator.prompt.descriptor.js.map +1 -0
  11. package/dist/agent/coordinator.system-prompt.d.ts +3 -0
  12. package/dist/agent/coordinator.system-prompt.d.ts.map +1 -0
  13. package/dist/agent/coordinator.system-prompt.js +18 -0
  14. package/dist/agent/coordinator.system-prompt.js.map +1 -0
  15. package/dist/agent/developer.agent.descriptor.d.ts +74 -0
  16. package/dist/agent/developer.agent.descriptor.d.ts.map +1 -0
  17. package/dist/agent/developer.agent.descriptor.js +138 -0
  18. package/dist/agent/developer.agent.descriptor.js.map +1 -0
  19. package/dist/agent/developer.prompt.descriptor.d.ts +137 -0
  20. package/dist/agent/developer.prompt.descriptor.d.ts.map +1 -0
  21. package/dist/agent/developer.prompt.descriptor.js +29 -0
  22. package/dist/agent/developer.prompt.descriptor.js.map +1 -0
  23. package/dist/agent/reviewer.agent.descriptor.d.ts +69 -0
  24. package/dist/agent/reviewer.agent.descriptor.d.ts.map +1 -0
  25. package/dist/agent/reviewer.agent.descriptor.js +60 -0
  26. package/dist/agent/reviewer.agent.descriptor.js.map +1 -0
  27. package/dist/agent/reviewer.prompt.descriptor.d.ts +135 -0
  28. package/dist/agent/reviewer.prompt.descriptor.d.ts.map +1 -0
  29. package/dist/agent/reviewer.prompt.descriptor.js +29 -0
  30. package/dist/agent/reviewer.prompt.descriptor.js.map +1 -0
  31. package/dist/agent/reviewer.system-prompt.d.ts +3 -0
  32. package/dist/agent/reviewer.system-prompt.d.ts.map +1 -0
  33. package/dist/agent/reviewer.system-prompt.js +17 -0
  34. package/dist/agent/reviewer.system-prompt.js.map +1 -0
  35. package/dist/agent/system-prompt.d.ts +12 -0
  36. package/dist/agent/system-prompt.d.ts.map +1 -0
  37. package/dist/agent/system-prompt.js +28 -0
  38. package/dist/agent/system-prompt.js.map +1 -0
  39. package/dist/api/code-sessions.api-client.descriptor.d.ts +25 -0
  40. package/dist/api/code-sessions.api-client.descriptor.d.ts.map +1 -0
  41. package/dist/api/code-sessions.api-client.descriptor.js +26 -0
  42. package/dist/api/code-sessions.api-client.descriptor.js.map +1 -0
  43. package/dist/api/code-sessions.api-client.impl.d.ts +156 -0
  44. package/dist/api/code-sessions.api-client.impl.d.ts.map +1 -0
  45. package/dist/api/code-sessions.api-client.impl.js +852 -0
  46. package/dist/api/code-sessions.api-client.impl.js.map +1 -0
  47. package/dist/api/code-sessions.api-client.schemas.d.ts +2 -0
  48. package/dist/api/code-sessions.api-client.schemas.d.ts.map +1 -0
  49. package/dist/api/code-sessions.api-client.schemas.js +2 -0
  50. package/dist/api/code-sessions.api-client.schemas.js.map +1 -0
  51. package/dist/api/code-sessions.api-client.types.d.ts +252 -0
  52. package/dist/api/code-sessions.api-client.types.d.ts.map +1 -0
  53. package/dist/api/code-sessions.api-client.types.js +77 -0
  54. package/dist/api/code-sessions.api-client.types.js.map +1 -0
  55. package/dist/api/index.d.ts +13 -0
  56. package/dist/api/index.d.ts.map +1 -0
  57. package/dist/api/index.js +20 -0
  58. package/dist/api/index.js.map +1 -0
  59. package/dist/capability.d.ts +9 -0
  60. package/dist/capability.d.ts.map +1 -0
  61. package/dist/capability.js +9 -0
  62. package/dist/capability.js.map +1 -0
  63. package/dist/catalog/index.d.ts +2 -0
  64. package/dist/catalog/index.d.ts.map +1 -0
  65. package/dist/catalog/index.js +2 -0
  66. package/dist/catalog/index.js.map +1 -0
  67. package/dist/catalog/session-catalog.d.ts +131 -0
  68. package/dist/catalog/session-catalog.d.ts.map +1 -0
  69. package/dist/catalog/session-catalog.impl.consumer.worker.d.ts +113 -0
  70. package/dist/catalog/session-catalog.impl.consumer.worker.d.ts.map +1 -0
  71. package/dist/catalog/session-catalog.impl.consumer.worker.js +32 -0
  72. package/dist/catalog/session-catalog.impl.consumer.worker.js.map +1 -0
  73. package/dist/catalog/session-catalog.js +126 -0
  74. package/dist/catalog/session-catalog.js.map +1 -0
  75. package/dist/clock/clock.client.d.ts +18 -0
  76. package/dist/clock/clock.client.d.ts.map +1 -0
  77. package/dist/clock/clock.client.js +43 -0
  78. package/dist/clock/clock.client.js.map +1 -0
  79. package/dist/code-sessions.consumer.plugin.d.ts +4 -0
  80. package/dist/code-sessions.consumer.plugin.d.ts.map +1 -0
  81. package/dist/code-sessions.consumer.plugin.js +16 -0
  82. package/dist/code-sessions.consumer.plugin.js.map +1 -0
  83. package/dist/code-sessions.plugin.d.ts +15 -0
  84. package/dist/code-sessions.plugin.d.ts.map +1 -0
  85. package/dist/code-sessions.plugin.js +65 -0
  86. package/dist/code-sessions.plugin.js.map +1 -0
  87. package/dist/config/index.d.ts +9 -0
  88. package/dist/config/index.d.ts.map +1 -0
  89. package/dist/config/index.js +9 -0
  90. package/dist/config/index.js.map +1 -0
  91. package/dist/config/preparation.d.ts +2 -0
  92. package/dist/config/preparation.d.ts.map +1 -0
  93. package/dist/config/preparation.js +2 -0
  94. package/dist/config/preparation.js.map +1 -0
  95. package/dist/docs/code-sessions.docs.descriptor.d.ts +4 -0
  96. package/dist/docs/code-sessions.docs.descriptor.d.ts.map +1 -0
  97. package/dist/docs/code-sessions.docs.descriptor.js +241 -0
  98. package/dist/docs/code-sessions.docs.descriptor.js.map +1 -0
  99. package/dist/index.d.ts +26 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +28 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/pull-request-plan.d.ts +68 -0
  104. package/dist/pull-request-plan.d.ts.map +1 -0
  105. package/dist/pull-request-plan.js +94 -0
  106. package/dist/pull-request-plan.js.map +1 -0
  107. package/dist/schemas/preparation.d.ts +51 -0
  108. package/dist/schemas/preparation.d.ts.map +1 -0
  109. package/dist/schemas/preparation.js +20 -0
  110. package/dist/schemas/preparation.js.map +1 -0
  111. package/dist/schemas/requests.d.ts +411 -0
  112. package/dist/schemas/requests.d.ts.map +1 -0
  113. package/dist/schemas/requests.js +87 -0
  114. package/dist/schemas/requests.js.map +1 -0
  115. package/dist/schemas/responses.d.ts +275 -0
  116. package/dist/schemas/responses.d.ts.map +1 -0
  117. package/dist/schemas/responses.js +90 -0
  118. package/dist/schemas/responses.js.map +1 -0
  119. package/dist/svelte/actions.d.ts +70 -0
  120. package/dist/svelte/actions.d.ts.map +1 -0
  121. package/dist/svelte/actions.js +280 -0
  122. package/dist/svelte/clock.svelte.d.ts +6 -0
  123. package/dist/svelte/clock.svelte.d.ts.map +1 -0
  124. package/dist/svelte/clock.svelte.js +33 -0
  125. package/dist/svelte/components/CreateSessionDialog.svelte +470 -0
  126. package/dist/svelte/components/CreateSessionDialog.svelte.d.ts +57 -0
  127. package/dist/svelte/components/CreateSessionDialog.svelte.d.ts.map +1 -0
  128. package/dist/svelte/components/SessionCard.svelte +216 -0
  129. package/dist/svelte/components/SessionCard.svelte.d.ts +27 -0
  130. package/dist/svelte/components/SessionCard.svelte.d.ts.map +1 -0
  131. package/dist/svelte/components/SessionList.svelte +86 -0
  132. package/dist/svelte/components/SessionList.svelte.d.ts +23 -0
  133. package/dist/svelte/components/SessionList.svelte.d.ts.map +1 -0
  134. package/dist/svelte/components/SessionSeed.svelte +60 -0
  135. package/dist/svelte/components/SessionSeed.svelte.d.ts +9 -0
  136. package/dist/svelte/components/SessionSeed.svelte.d.ts.map +1 -0
  137. package/dist/svelte/components/TranscriptView.svelte +360 -0
  138. package/dist/svelte/components/TranscriptView.svelte.d.ts +26 -0
  139. package/dist/svelte/components/TranscriptView.svelte.d.ts.map +1 -0
  140. package/dist/svelte/create-session-form.d.ts +84 -0
  141. package/dist/svelte/create-session-form.d.ts.map +1 -0
  142. package/dist/svelte/create-session-form.js +107 -0
  143. package/dist/svelte/index.d.ts +20 -0
  144. package/dist/svelte/index.d.ts.map +1 -0
  145. package/dist/svelte/index.js +18 -0
  146. package/dist/svelte/live-session.d.ts +156 -0
  147. package/dist/svelte/live-session.d.ts.map +1 -0
  148. package/dist/svelte/live-session.js +152 -0
  149. package/dist/svelte/loaders.d.ts +74 -0
  150. package/dist/svelte/loaders.d.ts.map +1 -0
  151. package/dist/svelte/loaders.js +124 -0
  152. package/dist/svelte/outcome.d.ts +46 -0
  153. package/dist/svelte/outcome.d.ts.map +1 -0
  154. package/dist/svelte/outcome.js +49 -0
  155. package/dist/svelte/relative-time.d.ts +32 -0
  156. package/dist/svelte/relative-time.d.ts.map +1 -0
  157. package/dist/svelte/relative-time.js +51 -0
  158. package/dist/svelte/session-list-item.d.ts +23 -0
  159. package/dist/svelte/session-list-item.d.ts.map +1 -0
  160. package/dist/svelte/session-list-item.js +1 -0
  161. package/dist/svelte/styles.css +8 -0
  162. package/dist/svelte/transcript-input.d.ts +45 -0
  163. package/dist/svelte/transcript-input.d.ts.map +1 -0
  164. package/dist/svelte/transcript-input.js +188 -0
  165. package/dist/tui/code-sessions-tui.plugin.d.ts +10 -0
  166. package/dist/tui/code-sessions-tui.plugin.d.ts.map +1 -0
  167. package/dist/tui/code-sessions-tui.plugin.js +29 -0
  168. package/dist/tui/code-sessions-tui.plugin.js.map +1 -0
  169. package/dist/tui/code-sessions.tui-app.descriptor.d.ts +7 -0
  170. package/dist/tui/code-sessions.tui-app.descriptor.d.ts.map +1 -0
  171. package/dist/tui/code-sessions.tui-app.descriptor.js +30 -0
  172. package/dist/tui/code-sessions.tui-app.descriptor.js.map +1 -0
  173. package/dist/tui/code-sessions.tui-app.impl.consumer.d.ts +14 -0
  174. package/dist/tui/code-sessions.tui-app.impl.consumer.d.ts.map +1 -0
  175. package/dist/tui/code-sessions.tui-app.impl.consumer.js +453 -0
  176. package/dist/tui/code-sessions.tui-app.impl.consumer.js.map +1 -0
  177. package/dist/tui/code-sessions.tui-client.d.ts +22 -0
  178. package/dist/tui/code-sessions.tui-client.d.ts.map +1 -0
  179. package/dist/tui/code-sessions.tui-client.js +95 -0
  180. package/dist/tui/code-sessions.tui-client.js.map +1 -0
  181. package/dist/tui/code-sessions.tui-open.descriptor.d.ts +7 -0
  182. package/dist/tui/code-sessions.tui-open.descriptor.d.ts.map +1 -0
  183. package/dist/tui/code-sessions.tui-open.descriptor.js +16 -0
  184. package/dist/tui/code-sessions.tui-open.descriptor.js.map +1 -0
  185. package/dist/tui/code-sessions.tui-open.impl.consumer.d.ts +7 -0
  186. package/dist/tui/code-sessions.tui-open.impl.consumer.d.ts.map +1 -0
  187. package/dist/tui/code-sessions.tui-open.impl.consumer.js +11 -0
  188. package/dist/tui/code-sessions.tui-open.impl.consumer.js.map +1 -0
  189. package/dist/tui/code-sessions.tui-state.descriptor.d.ts +16 -0
  190. package/dist/tui/code-sessions.tui-state.descriptor.d.ts.map +1 -0
  191. package/dist/tui/code-sessions.tui-state.descriptor.js +50 -0
  192. package/dist/tui/code-sessions.tui-state.descriptor.js.map +1 -0
  193. package/dist/tui/code-sessions.tui-state.impl.consumer.d.ts +30 -0
  194. package/dist/tui/code-sessions.tui-state.impl.consumer.d.ts.map +1 -0
  195. package/dist/tui/code-sessions.tui-state.impl.consumer.js +533 -0
  196. package/dist/tui/code-sessions.tui-state.impl.consumer.js.map +1 -0
  197. package/dist/tui/code-sessions.tui-state.key.d.ts +322 -0
  198. package/dist/tui/code-sessions.tui-state.key.d.ts.map +1 -0
  199. package/dist/tui/code-sessions.tui-state.key.js +104 -0
  200. package/dist/tui/code-sessions.tui-state.key.js.map +1 -0
  201. package/dist/tui/index.d.ts +9 -0
  202. package/dist/tui/index.d.ts.map +1 -0
  203. package/dist/tui/index.js +8 -0
  204. package/dist/tui/index.js.map +1 -0
  205. package/dist/workspace/index.d.ts +2 -0
  206. package/dist/workspace/index.d.ts.map +1 -0
  207. package/dist/workspace/index.js +2 -0
  208. package/dist/workspace/index.js.map +1 -0
  209. package/dist/workspace/workspace-binding.d.ts +74 -0
  210. package/dist/workspace/workspace-binding.d.ts.map +1 -0
  211. package/dist/workspace/workspace-binding.impl.consumer.worker.d.ts +17 -0
  212. package/dist/workspace/workspace-binding.impl.consumer.worker.d.ts.map +1 -0
  213. package/dist/workspace/workspace-binding.impl.consumer.worker.js +134 -0
  214. package/dist/workspace/workspace-binding.impl.consumer.worker.js.map +1 -0
  215. package/dist/workspace/workspace-binding.js +72 -0
  216. package/dist/workspace/workspace-binding.js.map +1 -0
  217. 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"}