kcg-code 0.0.0-stage → 0.1.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 (286) hide show
  1. package/README.md +228 -2
  2. package/bin/kcgcode.ts +13 -0
  3. package/bun-env.d.ts +19 -0
  4. package/kcg-code.config.example.json +3 -0
  5. package/package.json +83 -4
  6. package/public/logo.svg +1 -0
  7. package/public/manifest.json +18 -0
  8. package/public/sw.js +49 -0
  9. package/src/App.tsx +39 -0
  10. package/src/__tests__/manifest.test.ts +61 -0
  11. package/src/build-config.ts +9 -0
  12. package/src/cli/__tests__/dashboard.test.ts +62 -0
  13. package/src/cli/args.ts +123 -0
  14. package/src/cli/commands.ts +174 -0
  15. package/src/cli/dashboard.tsx +343 -0
  16. package/src/cli/index.ts +37 -0
  17. package/src/cli/theme.ts +100 -0
  18. package/src/components/auth/AuthGate.tsx +182 -0
  19. package/src/components/auth/AvatarEditor.tsx +236 -0
  20. package/src/components/auth/LockScreen.tsx +714 -0
  21. package/src/components/auth/ProfileAvatar.tsx +60 -0
  22. package/src/components/auth/WelcomeScreen.tsx +672 -0
  23. package/src/components/auth/__tests__/WelcomeScreen.test.tsx +42 -0
  24. package/src/components/auth/avatar-icons.tsx +114 -0
  25. package/src/components/layout/AppShell.tsx +142 -0
  26. package/src/components/layout/AppSidebar.tsx +419 -0
  27. package/src/components/layout/SearchDialog.tsx +189 -0
  28. package/src/components/layout/SidebarAccount.tsx +111 -0
  29. package/src/components/layout/SidebarSessionMenu.tsx +163 -0
  30. package/src/components/layout/ThemeToggle.tsx +67 -0
  31. package/src/components/projects/FolderBrowser.tsx +142 -0
  32. package/src/components/projects/HomeChat.tsx +250 -0
  33. package/src/components/projects/NewProjectDialog.tsx +249 -0
  34. package/src/components/projects/PanelSection.tsx +102 -0
  35. package/src/components/projects/ProjectInstructions.tsx +229 -0
  36. package/src/components/projects/ProjectRow.tsx +58 -0
  37. package/src/components/projects/ProjectSidePanel.tsx +448 -0
  38. package/src/components/sessions/AgentModeList.tsx +265 -0
  39. package/src/components/sessions/AgentPicker.tsx +123 -0
  40. package/src/components/sessions/AssistantTurn.tsx +145 -0
  41. package/src/components/sessions/AttachmentTile.tsx +161 -0
  42. package/src/components/sessions/CodeBlock.tsx +107 -0
  43. package/src/components/sessions/ComposerActionSheet.tsx +96 -0
  44. package/src/components/sessions/ConfirmDeleteProjectDialog.tsx +80 -0
  45. package/src/components/sessions/ConfirmSessionDeleteDialog.tsx +72 -0
  46. package/src/components/sessions/ContextPanel.tsx +561 -0
  47. package/src/components/sessions/DropPlate.tsx +165 -0
  48. package/src/components/sessions/FileDropOverlay.tsx +232 -0
  49. package/src/components/sessions/FileMentionDropdown.tsx +47 -0
  50. package/src/components/sessions/ImageLightbox.tsx +173 -0
  51. package/src/components/sessions/MarkdownContent.tsx +187 -0
  52. package/src/components/sessions/Mascot.tsx +47 -0
  53. package/src/components/sessions/MessageActions.tsx +60 -0
  54. package/src/components/sessions/MessageRail.tsx +121 -0
  55. package/src/components/sessions/ModelPicker.tsx +209 -0
  56. package/src/components/sessions/ModelSearchList.tsx +151 -0
  57. package/src/components/sessions/NewSessionDialog.tsx +189 -0
  58. package/src/components/sessions/PendingAttachments.tsx +127 -0
  59. package/src/components/sessions/PromptCard.tsx +1085 -0
  60. package/src/components/sessions/PromptPanel.tsx +112 -0
  61. package/src/components/sessions/SessionComposer.tsx +640 -0
  62. package/src/components/sessions/SessionHeader.tsx +175 -0
  63. package/src/components/sessions/SessionList.tsx +396 -0
  64. package/src/components/sessions/SessionRow.tsx +137 -0
  65. package/src/components/sessions/SessionTimeline.tsx +275 -0
  66. package/src/components/sessions/SessionTimelineSkeleton.tsx +83 -0
  67. package/src/components/sessions/SessionView.tsx +236 -0
  68. package/src/components/sessions/ThoughtProcessBlock.tsx +199 -0
  69. package/src/components/sessions/UserMessage.tsx +177 -0
  70. package/src/components/sessions/__tests__/ContextPanel.test.tsx +220 -0
  71. package/src/components/sessions/__tests__/MarkdownContent.test.tsx +89 -0
  72. package/src/components/sessions/__tests__/MessageRail.test.tsx +40 -0
  73. package/src/components/sessions/__tests__/PermissionCard.test.tsx +79 -0
  74. package/src/components/sessions/__tests__/PromptCard.test.ts +166 -0
  75. package/src/components/sessions/__tests__/QuestionCard.test.tsx +166 -0
  76. package/src/components/sessions/__tests__/SessionTimelineSkeleton.test.tsx +32 -0
  77. package/src/components/sessions/__tests__/SessionView.test.ts +386 -0
  78. package/src/components/settings/AboutGroup.tsx +170 -0
  79. package/src/components/settings/AccountGroup.tsx +122 -0
  80. package/src/components/settings/DevicesGroup.tsx +151 -0
  81. package/src/components/settings/LhrRemoteAccess.tsx +262 -0
  82. package/src/components/settings/PasskeysGroup.tsx +551 -0
  83. package/src/components/settings/RemoteAccessGroup.tsx +1226 -0
  84. package/src/components/settings/SecurityGroup.tsx +566 -0
  85. package/src/components/settings/WorkspaceGroup.tsx +370 -0
  86. package/src/components/settings/__tests__/AboutGroup.test.tsx +47 -0
  87. package/src/components/settings/__tests__/PasskeysGroup.test.tsx +109 -0
  88. package/src/components/settings/__tests__/WorkspaceGroup.test.tsx +49 -0
  89. package/src/components/settings/prefs.tsx +265 -0
  90. package/src/components/skills/InstallNotifications.tsx +325 -0
  91. package/src/components/skills/InstallSkillDialog.tsx +233 -0
  92. package/src/components/skills/SkillCards.tsx +210 -0
  93. package/src/components/skills/SkillsProjectPicker.tsx +178 -0
  94. package/src/components/ui/alert-dialog.tsx +179 -0
  95. package/src/components/ui/alert.tsx +60 -0
  96. package/src/components/ui/badge.tsx +46 -0
  97. package/src/components/ui/bubble.tsx +125 -0
  98. package/src/components/ui/button.tsx +62 -0
  99. package/src/components/ui/card.tsx +75 -0
  100. package/src/components/ui/collapsible.tsx +19 -0
  101. package/src/components/ui/dialog.tsx +142 -0
  102. package/src/components/ui/dropdown-menu.tsx +225 -0
  103. package/src/components/ui/empty.tsx +94 -0
  104. package/src/components/ui/field.tsx +234 -0
  105. package/src/components/ui/input-group.tsx +161 -0
  106. package/src/components/ui/input.tsx +21 -0
  107. package/src/components/ui/label.tsx +19 -0
  108. package/src/components/ui/message-scroller.tsx +131 -0
  109. package/src/components/ui/message.tsx +85 -0
  110. package/src/components/ui/popover.tsx +46 -0
  111. package/src/components/ui/select.tsx +172 -0
  112. package/src/components/ui/separator.tsx +28 -0
  113. package/src/components/ui/sheet.tsx +138 -0
  114. package/src/components/ui/sidebar.tsx +699 -0
  115. package/src/components/ui/skeleton.tsx +15 -0
  116. package/src/components/ui/sonner.tsx +45 -0
  117. package/src/components/ui/spinner.tsx +16 -0
  118. package/src/components/ui/switch.tsx +32 -0
  119. package/src/components/ui/textarea.tsx +18 -0
  120. package/src/components/ui/tooltip.tsx +51 -0
  121. package/src/config.ts +85 -0
  122. package/src/db.ts +146 -0
  123. package/src/frontend.tsx +51 -0
  124. package/src/hooks/__tests__/useMention.test.ts +79 -0
  125. package/src/hooks/__tests__/useResyncOnReconnect.test.ts +128 -0
  126. package/src/hooks/__tests__/useRouter.test.ts +17 -0
  127. package/src/hooks/__tests__/useSmoothText.react.test.ts +194 -0
  128. package/src/hooks/__tests__/useSmoothText.test.ts +61 -0
  129. package/src/hooks/__tests__/useTheme.test.ts +118 -0
  130. package/src/hooks/use-mobile.ts +16 -0
  131. package/src/hooks/useAgentPicker.ts +97 -0
  132. package/src/hooks/useMediaQuery.ts +49 -0
  133. package/src/hooks/useMention.ts +236 -0
  134. package/src/hooks/useProjects.ts +88 -0
  135. package/src/hooks/useResyncOnReconnect.ts +28 -0
  136. package/src/hooks/useRouter.ts +92 -0
  137. package/src/hooks/useSessionChat.ts +427 -0
  138. package/src/hooks/useSessionContext.ts +106 -0
  139. package/src/hooks/useSessionList.ts +234 -0
  140. package/src/hooks/useSidebarData.ts +108 -0
  141. package/src/hooks/useSmoothText.ts +122 -0
  142. package/src/hooks/useTheme.ts +164 -0
  143. package/src/hooks/useWebSocket.ts +196 -0
  144. package/src/index.css +27 -0
  145. package/src/index.html +14 -0
  146. package/src/index.ts +49 -0
  147. package/src/lib/__tests__/attachments.test.ts +58 -0
  148. package/src/lib/__tests__/avatar-presets.test.ts +25 -0
  149. package/src/lib/__tests__/collapsible.test.ts +101 -0
  150. package/src/lib/__tests__/composer.test.ts +118 -0
  151. package/src/lib/__tests__/highlight.test.ts +42 -0
  152. package/src/lib/__tests__/home-chat.test.ts +64 -0
  153. package/src/lib/__tests__/lock-screen.test.ts +64 -0
  154. package/src/lib/__tests__/model-picker.test.ts +205 -0
  155. package/src/lib/__tests__/onboarding.test.ts +41 -0
  156. package/src/lib/__tests__/permission-info.test.ts +61 -0
  157. package/src/lib/__tests__/project-extensions.test.ts +52 -0
  158. package/src/lib/__tests__/project-overview.test.ts +173 -0
  159. package/src/lib/__tests__/references.test.ts +121 -0
  160. package/src/lib/__tests__/routes.test.ts +134 -0
  161. package/src/lib/__tests__/session-summary.test.ts +115 -0
  162. package/src/lib/__tests__/session-title.test.ts +58 -0
  163. package/src/lib/__tests__/sidebar-groups.test.ts +100 -0
  164. package/src/lib/__tests__/skill-installs.test.ts +134 -0
  165. package/src/lib/__tests__/skills-catalog.test.ts +96 -0
  166. package/src/lib/__tests__/tone.test.ts +37 -0
  167. package/src/lib/__tests__/turns-delta.test.ts +55 -0
  168. package/src/lib/api.ts +306 -0
  169. package/src/lib/attachments.ts +203 -0
  170. package/src/lib/auth.ts +92 -0
  171. package/src/lib/avatar-presets.ts +31 -0
  172. package/src/lib/collapsible.ts +75 -0
  173. package/src/lib/composer.ts +89 -0
  174. package/src/lib/data-events.ts +17 -0
  175. package/src/lib/headlines.ts +30 -0
  176. package/src/lib/highlight.ts +186 -0
  177. package/src/lib/layout.ts +20 -0
  178. package/src/lib/lock-screen.ts +54 -0
  179. package/src/lib/model-picker.ts +133 -0
  180. package/src/lib/onboarding.ts +38 -0
  181. package/src/lib/passkeys.ts +113 -0
  182. package/src/lib/pending-prompt.ts +53 -0
  183. package/src/lib/permission-info.ts +101 -0
  184. package/src/lib/project-extensions.ts +74 -0
  185. package/src/lib/project-overview.ts +117 -0
  186. package/src/lib/prompts.ts +87 -0
  187. package/src/lib/references.ts +106 -0
  188. package/src/lib/routes.ts +115 -0
  189. package/src/lib/session-handoff.ts +25 -0
  190. package/src/lib/session-status.ts +45 -0
  191. package/src/lib/session-summary.ts +68 -0
  192. package/src/lib/session-title.ts +63 -0
  193. package/src/lib/sidebar-groups.ts +78 -0
  194. package/src/lib/skill-installs.ts +360 -0
  195. package/src/lib/skills-catalog.ts +99 -0
  196. package/src/lib/time.ts +22 -0
  197. package/src/lib/tone.ts +80 -0
  198. package/src/lib/turns.ts +320 -0
  199. package/src/lib/utils.ts +6 -0
  200. package/src/logo.svg +31 -0
  201. package/src/pages/projects/ProjectDetailPage.tsx +130 -0
  202. package/src/pages/projects/ProjectsPage.tsx +97 -0
  203. package/src/pages/sessions/SessionPage.tsx +122 -0
  204. package/src/pages/settings/SettingsPage.tsx +299 -0
  205. package/src/pages/settings/__tests__/SettingsPage.test.ts +9 -0
  206. package/src/pages/skills/SkillsPage.tsx +701 -0
  207. package/src/paths.ts +121 -0
  208. package/src/runtime.ts +24 -0
  209. package/src/server/__tests__/app.test.ts +1031 -0
  210. package/src/server/__tests__/auth.test.ts +370 -0
  211. package/src/server/__tests__/config.test.ts +101 -0
  212. package/src/server/__tests__/db.test.ts +485 -0
  213. package/src/server/__tests__/host.test.ts +14 -0
  214. package/src/server/__tests__/tunnel-config.test.ts +38 -0
  215. package/src/server/app.ts +415 -0
  216. package/src/server/db/auth.ts +311 -0
  217. package/src/server/db/messages.ts +50 -0
  218. package/src/server/db/projects.ts +106 -0
  219. package/src/server/db/prompts.ts +78 -0
  220. package/src/server/db/rows.ts +150 -0
  221. package/src/server/db/schema.ts +221 -0
  222. package/src/server/db/sessions.ts +239 -0
  223. package/src/server/db/tunnel.ts +124 -0
  224. package/src/server/host.ts +12 -0
  225. package/src/server/result.ts +15 -0
  226. package/src/server/routes/auth-guard.ts +156 -0
  227. package/src/server/routes/auth.routes.ts +287 -0
  228. package/src/server/routes/helpers.ts +165 -0
  229. package/src/server/routes/meta.routes.ts +24 -0
  230. package/src/server/routes/passkeys.routes.ts +161 -0
  231. package/src/server/routes/projects.routes.ts +157 -0
  232. package/src/server/routes/sessions.routes.ts +197 -0
  233. package/src/server/routes/skills.routes.ts +117 -0
  234. package/src/server/routes/tunnel.routes.ts +132 -0
  235. package/src/server/routes/types.ts +35 -0
  236. package/src/server/routes/uploads.routes.ts +54 -0
  237. package/src/server/routes/workspace.routes.ts +127 -0
  238. package/src/server/services/__tests__/app-info.test.ts +18 -0
  239. package/src/server/services/__tests__/attachments.test.ts +159 -0
  240. package/src/server/services/__tests__/auth-passkeys.test.ts +358 -0
  241. package/src/server/services/__tests__/auth.test.ts +341 -0
  242. package/src/server/services/__tests__/frpc-installer.test.ts +83 -0
  243. package/src/server/services/__tests__/git-info.test.ts +74 -0
  244. package/src/server/services/__tests__/opencode.test.ts +320 -0
  245. package/src/server/services/__tests__/project-manager.test.ts +190 -0
  246. package/src/server/services/__tests__/sandbox.test.ts +141 -0
  247. package/src/server/services/__tests__/session-manager.test.ts +3469 -0
  248. package/src/server/services/__tests__/skill-install-jobs.test.ts +226 -0
  249. package/src/server/services/__tests__/skills-registry.test.ts +359 -0
  250. package/src/server/services/__tests__/tunnel-lhr.test.ts +234 -0
  251. package/src/server/services/__tests__/tunnel.test.ts +367 -0
  252. package/src/server/services/__tests__/websocket-gateway.test.ts +677 -0
  253. package/src/server/services/__tests__/workspace.test.ts +249 -0
  254. package/src/server/services/app-info.ts +29 -0
  255. package/src/server/services/attachments.ts +193 -0
  256. package/src/server/services/auth-passkeys.ts +459 -0
  257. package/src/server/services/auth.ts +633 -0
  258. package/src/server/services/frpc-installer.ts +183 -0
  259. package/src/server/services/git-info.ts +87 -0
  260. package/src/server/services/opencode-client.ts +714 -0
  261. package/src/server/services/opencode-server.ts +319 -0
  262. package/src/server/services/opencode-sse.ts +82 -0
  263. package/src/server/services/project-manager.ts +147 -0
  264. package/src/server/services/sandbox.ts +83 -0
  265. package/src/server/services/session-events.ts +256 -0
  266. package/src/server/services/session-manager.ts +1374 -0
  267. package/src/server/services/skill-install-jobs.ts +262 -0
  268. package/src/server/services/skills-registry.ts +468 -0
  269. package/src/server/services/tunnel-api.ts +207 -0
  270. package/src/server/services/tunnel-config.ts +45 -0
  271. package/src/server/services/tunnel-lhr.ts +387 -0
  272. package/src/server/services/tunnel.ts +633 -0
  273. package/src/server/services/turn-stream.ts +339 -0
  274. package/src/server/services/websocket-gateway.ts +374 -0
  275. package/src/server/services/workspace.ts +223 -0
  276. package/src/server/services/ws-transport.ts +121 -0
  277. package/src/types/context.ts +69 -0
  278. package/src/types/index.ts +13 -0
  279. package/src/types/message.ts +58 -0
  280. package/src/types/project.ts +16 -0
  281. package/src/types/prompt.ts +118 -0
  282. package/src/types/session.ts +52 -0
  283. package/src/types/turns.ts +47 -0
  284. package/src/ws-protocol.ts +93 -0
  285. package/styles/globals.css +311 -0
  286. package/tsconfig.json +37 -0
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Blok kode Markdown dengan syntax highlighting (Shiki) + tombol salin.
3
+ *
4
+ * - Teks polos dirender LANGSUNG (tanpa menunggu), lalu diganti token
5
+ * berwarna begitu grammar siap — tidak ada kedipan kosong / layout shift.
6
+ * - Saat streaming, isi blok berubah tiap token baru. Highlight di-debounce
7
+ * singkat; selama itu token lama tetap tampil untuk bagian yang sudah
8
+ * ada dan sisanya teks polos.
9
+ * - Token dirender sebagai `<span>` React (bukan innerHTML), warna lewat CSS
10
+ * variable `--shiki-light` / `--shiki-dark` (lihat `.shiki-code` di
11
+ * `styles/globals.css`).
12
+ */
13
+ import { CheckIcon, CopyIcon } from "lucide-react";
14
+ import { useEffect, useState } from "react";
15
+ import { type CodeToken, highlightCode, resolveLang } from "@/lib/highlight";
16
+ import { cn } from "@/lib/utils";
17
+
18
+ export interface CodeBlockProps {
19
+ code: string;
20
+ /** Info-string fence (`ts`, `language-tsx`, …). */
21
+ language: string | null;
22
+ }
23
+
24
+ /** Jeda highlight ulang saat isi berubah (streaming). */
25
+ const DEBOUNCE_MS = 120;
26
+
27
+ export function CodeBlock({ code, language }: CodeBlockProps) {
28
+ const lang = resolveLang(language);
29
+ const [tokens, setTokens] = useState<{ code: string; lines: CodeToken[][] } | null>(null);
30
+ const [copied, setCopied] = useState(false);
31
+
32
+ useEffect(() => {
33
+ if (!lang) return;
34
+ let cancelled = false;
35
+ const id = setTimeout(() => {
36
+ void highlightCode(code, lang).then((lines) => {
37
+ if (!cancelled && lines) setTokens({ code, lines });
38
+ });
39
+ }, DEBOUNCE_MS);
40
+ return () => {
41
+ cancelled = true;
42
+ clearTimeout(id);
43
+ };
44
+ }, [code, lang]);
45
+
46
+ const copy = async () => {
47
+ try {
48
+ await navigator.clipboard.writeText(code);
49
+ setCopied(true);
50
+ setTimeout(() => setCopied(false), 1500);
51
+ } catch {
52
+ /* Clipboard butuh konteks aman; abaikan diam-diam. */
53
+ }
54
+ };
55
+
56
+ // Token masih cocok dengan awal kode (streaming menambah di akhir):
57
+ // tampilkan token + sisa teks polos. Isi berubah di tengah -> teks polos.
58
+ const fresh = tokens && code.startsWith(tokens.code) ? tokens : null;
59
+ const tail = fresh ? code.slice(fresh.code.length) : code;
60
+ const label = language?.replace(/^language-/, "") || "text";
61
+
62
+ return (
63
+ // Tanpa border: blok dibedakan dari teks hanya lewat latar & sudut besar
64
+ // (ala Gemini). Header tanpa garis pemisah, menyatu dengan isi.
65
+ <div className="my-3 max-w-full overflow-hidden rounded-2xl bg-muted/70 first:mt-0 last:mb-0 dark:bg-muted/50">
66
+ <div className="flex items-center justify-between gap-2 pt-4 pr-4 pl-6 sm:pl-7">
67
+ <span className="text-[13px] font-medium text-foreground/80 uppercase">{label}</span>
68
+ <button
69
+ type="button"
70
+ onClick={() => void copy()}
71
+ aria-label={copied ? "Copied" : "Copy code"}
72
+ title={copied ? "Copied" : "Copy code"}
73
+ className="flex size-8 items-center justify-center rounded-full text-muted-foreground transition-colors outline-none hover:bg-foreground/10 hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/40"
74
+ >
75
+ {copied ? (
76
+ <CheckIcon className="size-4" aria-hidden />
77
+ ) : (
78
+ <CopyIcon className="size-4" aria-hidden />
79
+ )}
80
+ </button>
81
+ </div>
82
+ <pre
83
+ className={cn(
84
+ // Padding lega, line-height rapat (1.45) agar kode padat terbaca.
85
+ "overflow-x-auto px-6 pt-3 pb-6 font-mono sm:px-7 text-[14px] leading-[1.45]",
86
+ fresh && "shiki-code",
87
+ )}
88
+ >
89
+ <code>
90
+ {fresh?.lines.map((line, i) => (
91
+ // biome-ignore lint/suspicious/noArrayIndexKey: baris = posisi dalam kode
92
+ <span key={i}>
93
+ {line.map((t, j) => (
94
+ // biome-ignore lint/suspicious/noArrayIndexKey: token = posisi dalam baris
95
+ <span key={j} style={t.style}>
96
+ {t.content}
97
+ </span>
98
+ ))}
99
+ {i < fresh.lines.length - 1 ? "\n" : ""}
100
+ </span>
101
+ ))}
102
+ {tail}
103
+ </code>
104
+ </pre>
105
+ </div>
106
+ );
107
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Sheet aksi mobile di composer (lampirkan file + ganti agent mode).
3
+ *
4
+ * Susunan: judul kecil "Add to message" + aksi lampiran sebagai baris
5
+ * (ikon, label, keterangan) — lalu grup "Mode" berisi pilihan agent ala
6
+ * radio. Mode pembantu (compaction/title/summary) dilipat di "More modes".
7
+ */
8
+ import { ChevronRightIcon, PaperclipIcon } from "lucide-react";
9
+ import { AgentModeList } from "@/components/sessions/AgentModeList";
10
+ import { SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ui/sheet";
11
+ import type { UseAgentPickerResult } from "@/hooks/useAgentPicker";
12
+
13
+ export interface ComposerActionSheetProps {
14
+ /** Input tidak boleh dipakai (Session mati / sibuk) — aksi ikut terkunci. */
15
+ disabled: boolean;
16
+ /** Buka file picker (sheet ditutup oleh pemanggil). */
17
+ onPickImage: () => void;
18
+ agentPicker: UseAgentPickerResult;
19
+ activeAgent: string | null;
20
+ onPickAgent: (name: string | null) => void;
21
+ }
22
+
23
+ export function ComposerActionSheet({
24
+ disabled,
25
+ onPickImage,
26
+ agentPicker,
27
+ activeAgent,
28
+ onPickAgent,
29
+ }: ComposerActionSheetProps) {
30
+ return (
31
+ <SheetContent
32
+ side="bottom"
33
+ className="max-h-[80dvh] gap-0 pb-[max(0.75rem,env(safe-area-inset-bottom))]"
34
+ >
35
+ <SheetHeader className="sr-only">
36
+ <SheetTitle>Message options</SheetTitle>
37
+ <SheetDescription>Attach files or choose how the agent works.</SheetDescription>
38
+ </SheetHeader>
39
+
40
+ <div className="flex min-h-0 flex-col gap-4 overflow-y-auto overscroll-contain px-3 pt-1 pb-1">
41
+ {/* Lampiran */}
42
+ <section aria-labelledby="sheet-attach" className="flex flex-col gap-1">
43
+ <h3 id="sheet-attach" className="px-3 pb-1 text-xs font-medium text-muted-foreground">
44
+ Add to message
45
+ </h3>
46
+ <button
47
+ type="button"
48
+ disabled={disabled}
49
+ onClick={onPickImage}
50
+ className="flex min-h-14 w-full items-center gap-3 rounded-xl px-3 py-2.5 text-left transition-colors outline-none hover:bg-muted/60 focus-visible:ring-[3px] focus-visible:ring-ring/50 active:bg-muted disabled:opacity-50"
51
+ >
52
+ <span
53
+ className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-sky-500/10 text-sky-600 dark:text-sky-400"
54
+ aria-hidden
55
+ >
56
+ <PaperclipIcon className="size-[18px]" />
57
+ </span>
58
+ <span className="flex min-w-0 flex-1 flex-col">
59
+ <span className="text-[15px] leading-5">Photos and files</span>
60
+ <span className="text-[13px] leading-snug text-muted-foreground">
61
+ Images, documents, code, and more
62
+ </span>
63
+ </span>
64
+ <ChevronRightIcon className="size-4 shrink-0 text-muted-foreground" aria-hidden />
65
+ </button>
66
+ </section>
67
+
68
+ <div className="mx-3 border-t" />
69
+
70
+ {/* Mode agent */}
71
+ <section aria-labelledby="sheet-mode" className="flex flex-col gap-1">
72
+ <div className="flex flex-col px-3 pb-1">
73
+ <h3 id="sheet-mode" className="text-xs font-medium text-muted-foreground">
74
+ Mode
75
+ </h3>
76
+ <p className="text-[12px] text-muted-foreground/80">
77
+ How the agent handles your next message
78
+ </p>
79
+ </div>
80
+ <div>
81
+ <AgentModeList
82
+ variant="sheet"
83
+ agents={agentPicker.agents}
84
+ loading={agentPicker.loading}
85
+ error={agentPicker.error}
86
+ activeAgent={activeAgent}
87
+ saving={agentPicker.saving}
88
+ disabled={disabled}
89
+ onPick={onPickAgent}
90
+ />
91
+ </div>
92
+ </section>
93
+ </div>
94
+ </SheetContent>
95
+ );
96
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Konfirmasi hapus Project (beserta seluruh Session-nya) dari halaman daftar
3
+ * Session. Server membersihkan Session terlebih dahulu; direktori kerja di
4
+ * filesystem tidak disentuh.
5
+ */
6
+
7
+ import {
8
+ AlertDialog,
9
+ AlertDialogAction,
10
+ AlertDialogCancel,
11
+ AlertDialogContent,
12
+ AlertDialogDescription,
13
+ AlertDialogFooter,
14
+ AlertDialogHeader,
15
+ AlertDialogTitle,
16
+ } from "@/components/ui/alert-dialog";
17
+ import { Spinner } from "@/components/ui/spinner";
18
+
19
+ export interface ConfirmDeleteProjectDialogProps {
20
+ open: boolean;
21
+ /** Tutup dialog (ditolak bila aksi sedang berjalan). */
22
+ onOpenChange: (open: boolean) => void;
23
+ projectName: string;
24
+ /** Jumlah Session milik project — disertakan ke teks peringatan. */
25
+ sessionTotal: number;
26
+ deleting: boolean;
27
+ /** Jalankan penghapusan Project. */
28
+ onConfirm: () => void;
29
+ }
30
+
31
+ export function ConfirmDeleteProjectDialog({
32
+ open,
33
+ onOpenChange,
34
+ projectName,
35
+ sessionTotal,
36
+ deleting,
37
+ onConfirm,
38
+ }: ConfirmDeleteProjectDialogProps) {
39
+ return (
40
+ <AlertDialog
41
+ open={open}
42
+ onOpenChange={(next) => {
43
+ if (!deleting) onOpenChange(next);
44
+ }}
45
+ >
46
+ <AlertDialogContent>
47
+ <AlertDialogHeader>
48
+ <AlertDialogTitle>Delete project “{projectName}”?</AlertDialogTitle>
49
+ <AlertDialogDescription>
50
+ {sessionTotal > 0
51
+ ? `${sessionTotal} session${sessionTotal === 1 ? "" : "s"} of this project will also be permanently deleted, including their conversation history on the opencode server. `
52
+ : ""}
53
+ The working folder on the server is not deleted — only the project registration in KCG
54
+ Code. This action cannot be undone.
55
+ </AlertDialogDescription>
56
+ </AlertDialogHeader>
57
+ <AlertDialogFooter>
58
+ <AlertDialogCancel disabled={deleting}>Cancel</AlertDialogCancel>
59
+ <AlertDialogAction
60
+ variant="destructive"
61
+ onClick={(e) => {
62
+ e.preventDefault();
63
+ onConfirm();
64
+ }}
65
+ disabled={deleting}
66
+ >
67
+ {deleting ? (
68
+ <>
69
+ <Spinner data-icon="inline-start" />
70
+ Deleting…
71
+ </>
72
+ ) : (
73
+ "Delete project"
74
+ )}
75
+ </AlertDialogAction>
76
+ </AlertDialogFooter>
77
+ </AlertDialogContent>
78
+ </AlertDialog>
79
+ );
80
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Konfirmasi hapus Session permanen (dipakai header chat `SessionView` dan
3
+ * menu baris `SessionList`). Menghapus juga riwayat percakapan di server
4
+ * opencode — tidak bisa dibatalkan.
5
+ */
6
+
7
+ import {
8
+ AlertDialog,
9
+ AlertDialogAction,
10
+ AlertDialogCancel,
11
+ AlertDialogContent,
12
+ AlertDialogDescription,
13
+ AlertDialogFooter,
14
+ AlertDialogHeader,
15
+ AlertDialogTitle,
16
+ } from "@/components/ui/alert-dialog";
17
+ import { Spinner } from "@/components/ui/spinner";
18
+
19
+ export interface ConfirmSessionDeleteDialogProps {
20
+ open: boolean;
21
+ /** Tutup dialog (ditolak bila aksi sedang berjalan). */
22
+ onOpenChange: (open: boolean) => void;
23
+ deleting: boolean;
24
+ /** Jalankan penghapusan (engine). */
25
+ onConfirm: () => void;
26
+ }
27
+
28
+ export function ConfirmSessionDeleteDialog({
29
+ open,
30
+ onOpenChange,
31
+ deleting,
32
+ onConfirm,
33
+ }: ConfirmSessionDeleteDialogProps) {
34
+ return (
35
+ <AlertDialog
36
+ open={open}
37
+ onOpenChange={(next) => {
38
+ if (!deleting) onOpenChange(next);
39
+ }}
40
+ >
41
+ <AlertDialogContent>
42
+ <AlertDialogHeader>
43
+ <AlertDialogTitle>Delete this session?</AlertDialogTitle>
44
+ <AlertDialogDescription>
45
+ The conversation history on the opencode server will also be permanently deleted. This
46
+ action cannot be undone.
47
+ </AlertDialogDescription>
48
+ </AlertDialogHeader>
49
+ <AlertDialogFooter>
50
+ <AlertDialogCancel disabled={deleting}>Cancel</AlertDialogCancel>
51
+ <AlertDialogAction
52
+ variant="destructive"
53
+ onClick={(e) => {
54
+ e.preventDefault();
55
+ onConfirm();
56
+ }}
57
+ disabled={deleting}
58
+ >
59
+ {deleting ? (
60
+ <>
61
+ <Spinner data-icon="inline-start" />
62
+ Deleting…
63
+ </>
64
+ ) : (
65
+ "Delete permanently"
66
+ )}
67
+ </AlertDialogAction>
68
+ </AlertDialogFooter>
69
+ </AlertDialogContent>
70
+ </AlertDialog>
71
+ );
72
+ }