@hienlh/ppm 0.13.9 → 0.13.11

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 (113) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/assets/skills/ppm/SKILL.md +1 -1
  3. package/assets/skills/ppm/references/http-api.md +1 -1
  4. package/bun.lock +2135 -0
  5. package/bunfig.toml +2 -0
  6. package/dist/web/assets/ai-settings-section-ysK_Eixc.js +1 -0
  7. package/dist/web/assets/architecture-PBZL5I3N-By4Nv3Gj.js +1 -0
  8. package/dist/web/assets/{audio-preview-C1p-Q5XZ.js → audio-preview-dOvnFQN8.js} +1 -1
  9. package/dist/web/assets/chat-tab-C6NVtLx3.js +12 -0
  10. package/dist/web/assets/code-editor-3e9UAnzv.js +8 -0
  11. package/dist/web/assets/{conflict-editor-Dcn3HuLD.js → conflict-editor-XMpuwtUv.js} +1 -1
  12. package/dist/web/assets/csv-parser-Dly5nqE1.js +6 -0
  13. package/dist/web/assets/{csv-preview-D5lmgVEy.js → csv-preview-7TsYBQI6.js} +3 -3
  14. package/dist/web/assets/data-grid-overlay-editor-BjjuE4-G.js +1 -0
  15. package/dist/web/assets/data-grid-types-BTQHYBUh.js +1 -0
  16. package/dist/web/assets/database-viewer-GNKYeCIc.js +1 -0
  17. package/dist/web/assets/{diff-viewer-NMLD4V8q.js → diff-viewer-DjFe6idy.js} +1 -1
  18. package/dist/web/assets/dist-0kPgRaVx.js +1 -0
  19. package/dist/web/assets/{esm-nXReYVnB.js → esm-zjerHxpO.js} +1 -1
  20. package/dist/web/assets/{extension-webview-DW2dBswj.js → extension-webview-hgbO93RZ.js} +1 -1
  21. package/dist/web/assets/gitGraph-HDMCJU4V-BLXEKVf1.js +1 -0
  22. package/dist/web/assets/glide-data-grid-nthEL3fk.css +1 -0
  23. package/dist/web/assets/glide-data-grid-uLRTmkwH.js +136 -0
  24. package/dist/web/assets/{image-preview-Dqp1KSus.js → image-preview-CzwOU5op.js} +1 -1
  25. package/dist/web/assets/index-BAPR3hYQ.js +27 -0
  26. package/dist/web/assets/index-COOnLKGB.css +2 -0
  27. package/dist/web/assets/info-3K5VOQVL-CEkPcChg.js +1 -0
  28. package/dist/web/assets/{input-DYWhyaze.js → input-ozrR2DAV.js} +1 -1
  29. package/dist/web/assets/keybindings-store-D9GV2h8K.js +1 -0
  30. package/dist/web/assets/{markdown-renderer-DNIXdY0d.js → markdown-renderer-BD5P19YN.js} +3 -3
  31. package/dist/web/assets/number-overlay-editor-BoRxunFN.js +9 -0
  32. package/dist/web/assets/packet-RMMSAZCW-DECxYTOi.js +1 -0
  33. package/dist/web/assets/{pdf-preview-ChC1gaaZ.js → pdf-preview-DRbBRYIF.js} +1 -1
  34. package/dist/web/assets/pie-UPGHQEXC-cjpNfVG5.js +1 -0
  35. package/dist/web/assets/{port-forwarding-tab-dLhH_g2l.js → port-forwarding-tab-BSFhNv-A.js} +1 -1
  36. package/dist/web/assets/{postgres-viewer-De0pzd1C.js → postgres-viewer-D51L9fxD.js} +3 -3
  37. package/dist/web/assets/radar-KQ55EAFF-Dnpi068b.js +1 -0
  38. package/dist/web/assets/{settings-store-BHBb62gq.js → settings-store-B-OmHo3J.js} +1 -1
  39. package/dist/web/assets/settings-tab-DdbYEmAC.js +1 -0
  40. package/dist/web/assets/sql-query-editor-7pD60nKZ.js +3 -0
  41. package/dist/web/assets/sqlite-viewer-DLNJ_IGM.js +1 -0
  42. package/dist/web/assets/terminal-tab-6T5e8Nar.js +1 -0
  43. package/dist/web/assets/treemap-KZPCXAKY-DRyb1eiw.js +1 -0
  44. package/dist/web/assets/{use-monaco-theme-CP-vyTF8.js → use-monaco-theme-DgzxiZS5.js} +1 -1
  45. package/dist/web/assets/{vendor-mermaid-CMiurk2b.js → vendor-mermaid-CCmA_6Y0.js} +3 -3
  46. package/dist/web/assets/{video-preview-CHPVrMtx.js → video-preview-BwDNFl7v.js} +1 -1
  47. package/dist/web/assets/x-CG-_0yIW.js +1 -0
  48. package/dist/web/index.html +10 -11
  49. package/dist/web/sw.js +1 -1
  50. package/package.json +1 -1
  51. package/src/index.ts +0 -0
  52. package/src/web/components/chat/chat-tab.tsx +4 -1
  53. package/src/web/components/chat/message-input.tsx +28 -14
  54. package/src/web/components/database/database-viewer.tsx +19 -8
  55. package/src/web/components/database/export-button.tsx +38 -18
  56. package/src/web/components/database/glide-column-search.tsx +81 -0
  57. package/src/web/components/database/glide-context-menu.tsx +95 -0
  58. package/src/web/components/database/glide-data-grid.tsx +207 -0
  59. package/src/web/components/database/glide-data-preview-panel.tsx +113 -0
  60. package/src/web/components/database/glide-grid-pagination.tsx +34 -0
  61. package/src/web/components/database/glide-grid-toolbar.tsx +105 -0
  62. package/src/web/components/database/glide-grid-types.ts +2 -0
  63. package/src/web/components/database/glide-header-menu.tsx +111 -0
  64. package/src/web/components/database/glide-save-bar.tsx +33 -0
  65. package/src/web/components/database/sql-query-editor.tsx +14 -4
  66. package/src/web/components/database/use-database.ts +10 -2
  67. package/src/web/components/database/use-glide-cell-content.ts +65 -30
  68. package/src/web/components/database/use-glide-columns.ts +24 -16
  69. package/src/web/components/database/use-glide-grid-actions.ts +164 -0
  70. package/src/web/components/database/use-glide-pending-edits.ts +72 -0
  71. package/src/web/components/database/use-glide-row-pinning.ts +35 -0
  72. package/src/web/components/editor/code-editor.tsx +7 -5
  73. package/src/web/components/layout/editor-panel.tsx +2 -2
  74. package/src/web/components/sqlite/sqlite-viewer.tsx +21 -12
  75. package/src/web/components/sqlite/use-sqlite.ts +1 -1
  76. package/src/web/hooks/use-chat.ts +27 -20
  77. package/src/web/hooks/use-global-keybindings.ts +12 -0
  78. package/src/web/hooks/use-terminal.ts +1 -1
  79. package/dist/web/assets/ai-settings-section-CLNBWLS4.js +0 -1
  80. package/dist/web/assets/architecture-PBZL5I3N-WMbLpD5Y.js +0 -1
  81. package/dist/web/assets/chat-tab-BSJUkgxB.js +0 -12
  82. package/dist/web/assets/code-editor-rNw5_pXh.js +0 -8
  83. package/dist/web/assets/csv-parser-DO0dz4x_.js +0 -6
  84. package/dist/web/assets/data-grid-nZfSIop5.js +0 -5
  85. package/dist/web/assets/database-viewer-CNoq5Uxp.js +0 -1
  86. package/dist/web/assets/gitGraph-HDMCJU4V-BdPTuzO3.js +0 -1
  87. package/dist/web/assets/index-CoMWx5VS.js +0 -27
  88. package/dist/web/assets/index-Dzb3OtrX.css +0 -2
  89. package/dist/web/assets/info-3K5VOQVL-MHX_1JfR.js +0 -1
  90. package/dist/web/assets/keybindings-store-B7nlHmDh.js +0 -1
  91. package/dist/web/assets/packet-RMMSAZCW-CreFbf9A.js +0 -1
  92. package/dist/web/assets/pie-UPGHQEXC-CnaHXUh8.js +0 -1
  93. package/dist/web/assets/radar-KQ55EAFF-UxsdRHvt.js +0 -1
  94. package/dist/web/assets/settings-tab-Mrs9uzCZ.js +0 -1
  95. package/dist/web/assets/sql-completion-provider-tCzZfqWs.js +0 -1
  96. package/dist/web/assets/sql-query-editor-CMQpaOjA.js +0 -3
  97. package/dist/web/assets/sqlite-viewer-BqtIjvil.js +0 -1
  98. package/dist/web/assets/terminal-tab-CeHEtoE2.js +0 -1
  99. package/dist/web/assets/trash-2-CJYoLw7Q.js +0 -1
  100. package/dist/web/assets/treemap-KZPCXAKY-CBVPi4NV.js +0 -1
  101. package/dist/web/assets/x-OGGXhtlb.js +0 -1
  102. /package/dist/web/assets/{arrow-up-Dtrfv490.js → arrow-up-Rcw6_KKu.js} +0 -0
  103. /package/dist/web/assets/{dist-D7KGU7Vl.js → dist-CaKCIxem.js} +0 -0
  104. /package/dist/web/assets/{dist-CGvx1c8C.js → dist-DGSkE2Ml.js} +0 -0
  105. /package/dist/web/assets/{katex-BFE6i_OH.js → katex-BuytEdO1.js} +0 -0
  106. /package/dist/web/assets/{lib-D_kRA9p6.js → lib-DQHnkzGy.js} +0 -0
  107. /package/dist/web/assets/{refresh-cw-CSFrDtiu.js → refresh-cw-LlbZDJpO.js} +0 -0
  108. /package/dist/web/assets/{scroll-area-BEllam7_.js → scroll-area-7H-Q_k8c.js} +0 -0
  109. /package/dist/web/assets/{sparkles-B0mRBy_j.js → sparkles-fWUT5Vzq.js} +0 -0
  110. /package/dist/web/assets/{table-Dq575bPF.js → table-tf7pRkME.js} +0 -0
  111. /package/dist/web/assets/{text-wrap-Cn6BNQfq.js → text-wrap-BV-R4Vvy.js} +0 -0
  112. /package/dist/web/assets/{use-blob-url-Hn6n1730.js → use-blob-url-e9uTXjv5.js} +0 -0
  113. /package/dist/web/assets/{vendor-xterm-u3AZMvTx.js → vendor-xterm-CU2c3f0A.js} +0 -0
@@ -1,8 +1,8 @@
1
- import { useState, useEffect, useRef } from "react";
1
+ import { useState, useEffect, useRef, useCallback } from "react";
2
2
  import { Database, Loader2, AlertCircle } from "lucide-react";
3
3
  import { useSqlite } from "./use-sqlite";
4
4
  import { SqliteTableList } from "./sqlite-table-list";
5
- import { SqliteDataGrid } from "./sqlite-data-grid";
5
+ import { GlideDataGrid } from "../database/glide-data-grid";
6
6
  import { SqliteQueryEditor } from "./sqlite-query-editor";
7
7
 
8
8
  interface SqliteViewerProps {
@@ -118,17 +118,26 @@ function SqliteViewerInner({
118
118
  </div>
119
119
  </div>
120
120
 
121
- {/* Data grid */}
121
+ {/* Data grid — adapter from sqlite rowid-based API to GlideDataGrid's pk-based API */}
122
122
  <div className={`flex-1 overflow-hidden ${queryPanelOpen ? "max-h-[60%]" : ""}`}>
123
- <SqliteDataGrid
124
- tableData={sqlite.tableData}
125
- schema={sqlite.schema}
126
- loading={sqlite.loading}
127
- page={sqlite.page}
128
- onPageChange={sqlite.setPage}
129
- onCellUpdate={sqlite.updateCell}
130
- onRowDelete={sqlite.deleteRow}
131
- />
123
+ {sqlite.tableData ? (
124
+ <GlideDataGrid
125
+ columns={sqlite.tableData.columns}
126
+ rows={sqlite.tableData.rows}
127
+ total={sqlite.tableData.total}
128
+ limit={sqlite.tableData.limit}
129
+ schema={sqlite.schema.map((c) => ({ name: c.name, type: c.type, nullable: !c.notnull, pk: !!c.pk, defaultValue: c.dflt_value, fk: c.fk ?? null }))}
130
+ loading={sqlite.loading}
131
+ page={sqlite.page}
132
+ onPageChange={sqlite.setPage}
133
+ onCellUpdate={(_pkCol, pkVal, col, val) => sqlite.updateCell(pkVal as number, col, val)}
134
+ onRowDelete={(_pkCol, pkVal) => sqlite.deleteRow(pkVal as number)}
135
+ />
136
+ ) : (
137
+ <div className="flex items-center justify-center h-full text-xs text-muted-foreground">
138
+ {sqlite.loading ? <Loader2 className="size-4 animate-spin" /> : "Select a table"}
139
+ </div>
140
+ )}
132
141
  </div>
133
142
 
134
143
  {/* Query editor (collapsible) */}
@@ -2,7 +2,7 @@ import { useState, useEffect, useCallback } from "react";
2
2
  import { api, projectUrl } from "@/lib/api-client";
3
3
 
4
4
  export interface TableInfo { name: string; rowCount: number }
5
- export interface ColumnInfo { cid: number; name: string; type: string; notnull: boolean; pk: boolean; dflt_value: string | null }
5
+ export interface ColumnInfo { cid: number; name: string; type: string; notnull: boolean; pk: boolean; dflt_value: string | null; fk?: { table: string; column: string } | null }
6
6
  export interface QueryResult { columns: string[]; rows: Record<string, unknown>[]; rowsAffected: number; changeType: "select" | "modify"; executionTimeMs?: number }
7
7
  interface TableData { columns: string[]; rows: Record<string, unknown>[]; total: number; page: number; limit: number }
8
8
 
@@ -1,4 +1,4 @@
1
- import { useState, useCallback, useRef, useEffect, useMemo } from "react";
1
+ import { useState, useCallback, useRef, useEffect, useMemo, startTransition } from "react";
2
2
  import { useWebSocket } from "./use-websocket";
3
3
  import { api, getAuthToken, projectUrl } from "@/lib/api-client";
4
4
  import { flattenWithExpansions, prefixPreCompactIds } from "@/lib/flatten-expansions";
@@ -172,32 +172,39 @@ export function useChat(sessionId: string | null, providerId = "claude", project
172
172
  return true;
173
173
  }, []);
174
174
 
175
- /** Flush refs into React state (called from rAF or directly) */
175
+ /** Flush refs into React state (called from throttled timer or directly) */
176
176
  const flushMessages = useCallback(() => {
177
177
  syncRafRef.current = 0;
178
178
  const content = streamingContentRef.current;
179
179
  const events = [...streamingEventsRef.current];
180
180
  const account = streamingAccountRef.current;
181
- setMessages((prev) => {
182
- const last = prev[prev.length - 1];
183
- if (last?.role === "assistant" && !last.id.startsWith("final-")) {
184
- return [...prev.slice(0, -1), { ...last, content, events, ...account }];
185
- }
186
- return [...prev, {
187
- id: `streaming-${Date.now()}`,
188
- role: "assistant" as const,
189
- content,
190
- events,
191
- timestamp: new Date().toISOString(),
192
- ...account,
193
- }];
181
+ // startTransition marks streaming updates as low-priority so React
182
+ // yields to user interactions (text selection, copy, scroll) first.
183
+ startTransition(() => {
184
+ setMessages((prev) => {
185
+ const last = prev[prev.length - 1];
186
+ if (last?.role === "assistant" && !last.id.startsWith("final-")) {
187
+ return [...prev.slice(0, -1), { ...last, content, events, ...account }];
188
+ }
189
+ return [...prev, {
190
+ id: `streaming-${Date.now()}`,
191
+ role: "assistant" as const,
192
+ content,
193
+ events,
194
+ timestamp: new Date().toISOString(),
195
+ ...account,
196
+ }];
197
+ });
194
198
  });
195
199
  }, []);
196
200
 
197
- /** Throttled sync — batches rapid WS events into one render per animation frame */
201
+ /** Throttled sync — batches rapid WS events into one render per ~100ms.
202
+ * Previously used rAF (~16ms / 60fps) which blocked the main thread with
203
+ * frequent ReactMarkdown re-parses, causing lag during text selection/copy.
204
+ * 100ms (10fps) keeps streaming smooth while leaving idle time for interactions. */
198
205
  const syncMessages = useCallback(() => {
199
206
  if (!syncRafRef.current) {
200
- syncRafRef.current = requestAnimationFrame(flushMessages);
207
+ syncRafRef.current = window.setTimeout(flushMessages, 100) as unknown as number;
201
208
  }
202
209
  }, [flushMessages]);
203
210
 
@@ -414,7 +421,7 @@ export function useChat(sessionId: string | null, providerId = "claude", project
414
421
  playNotificationSound("done");
415
422
  }
416
423
  // Cancel any pending throttled sync — done handler writes final state directly
417
- if (syncRafRef.current) { cancelAnimationFrame(syncRafRef.current); syncRafRef.current = 0; }
424
+ if (syncRafRef.current) { clearTimeout(syncRafRef.current); syncRafRef.current = 0; }
418
425
  // Finalize the streaming message — preserve SDK UUID for fork/rewind
419
426
  const finalContent = streamingContentRef.current;
420
427
  const finalEvents = [...streamingEventsRef.current];
@@ -624,7 +631,7 @@ export function useChat(sessionId: string | null, providerId = "claude", project
624
631
  streamingContentRef.current = "";
625
632
  streamingEventsRef.current = [];
626
633
  bashOutputRef.current.clear();
627
- if (syncRafRef.current) { cancelAnimationFrame(syncRafRef.current); syncRafRef.current = 0; }
634
+ if (syncRafRef.current) { clearTimeout(syncRafRef.current); syncRafRef.current = 0; }
628
635
  setIsConnected(false);
629
636
  // Reset team state
630
637
  teamActivityRef.current = { teamNames: new Set(), messages: [] };
@@ -669,7 +676,7 @@ export function useChat(sessionId: string | null, providerId = "claude", project
669
676
 
670
677
  if (isFollowUp) {
671
678
  // Cancel pending throttled sync before finalizing
672
- if (syncRafRef.current) { cancelAnimationFrame(syncRafRef.current); syncRafRef.current = 0; }
679
+ if (syncRafRef.current) { clearTimeout(syncRafRef.current); syncRafRef.current = 0; }
673
680
  // Streaming follow-up: finalize current assistant message, then send
674
681
  const finalContent = streamingContentRef.current;
675
682
  const finalEvents = [...streamingEventsRef.current];
@@ -68,6 +68,18 @@ export function useGlobalKeybindings() {
68
68
  // Skip all shortcuts during IME composition
69
69
  if (composing || e.isComposing) return;
70
70
 
71
+ // When focus is inside a text input, skip most keybinding checks to
72
+ // avoid lag on every keystroke (Shift+arrows, Ctrl+A, Ctrl+C, etc.).
73
+ // Only "locked" shortcuts that override browser defaults still fire.
74
+ const tag = (e.target as HTMLElement)?.tagName;
75
+ const isTextInput = tag === "TEXTAREA" || tag === "INPUT" || (e.target as HTMLElement)?.isContentEditable;
76
+ if (isTextInput) {
77
+ // Still need to intercept Mod+S (save-prevent) inside text fields
78
+ const { matchesEvent: m } = useKeybindingsStore.getState();
79
+ if (m(e, "save-prevent")) { e.preventDefault(); }
80
+ return;
81
+ }
82
+
71
83
  // Re-read matchesEvent on each keydown to pick up live overrides
72
84
  const { matchesEvent: match } = useKeybindingsStore.getState();
73
85
 
@@ -147,7 +147,7 @@ export function useTerminal(
147
147
  if (event.data.startsWith("{")) {
148
148
  try {
149
149
  const msg = JSON.parse(event.data);
150
- if (msg.type === "session" || msg.type === "error" || msg.type === "exited") {
150
+ if (msg.type === "session" || msg.type === "error" || msg.type === "exited" || msg.type === "ping") {
151
151
  if (msg.type === "session" && msg.id) {
152
152
  actualSessionId.current = msg.id; // Save for reconnect
153
153
  }
@@ -1 +0,0 @@
1
- import{o as e}from"./rolldown-runtime-FhOqtrmT.js";import{b as t,x as n}from"./vendor-markdown-0Mxgxy0L.js";import{D as r,_ as i,b as a,c as o,d as s,f as c,g as l,h as u,m as d,p as f,s as p,u as m,v as h,x as g,y as _}from"./vendor-ui-B-89Uj8i.js";import{t as v}from"./createLucideIcon-BjHrJDVb.js";import{i as y}from"./dist-D7KGU7Vl.js";import{a as b,o as x}from"./x-OGGXhtlb.js";import{t as S}from"./input-DYWhyaze.js";import{t as C}from"./refresh-cw-CSFrDtiu.js";import{t as w}from"./trash-2-CJYoLw7Q.js";import{i as T,t as E}from"./api-client-Dvzcc_EO.js";import{n as D}from"./utils-CTg5uAYR.js";import{a as O,h as k}from"./api-settings-D0_eiIYv.js";var A=v(`bell-off`,[[`path`,{d:`M10.268 21a2 2 0 0 0 3.464 0`,key:`vwvbt9`}],[`path`,{d:`M17 17H4a1 1 0 0 1-.74-1.673C4.59 13.956 6 12.499 6 8a6 6 0 0 1 .258-1.742`,key:`178tsu`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M8.668 3.01A6 6 0 0 1 18 8c0 2.687.77 4.653 1.707 6.05`,key:`1hqiys`}]]),j=v(`bot`,[[`path`,{d:`M12 8V4H8`,key:`hb8ula`}],[`rect`,{width:`16`,height:`12`,x:`4`,y:`8`,rx:`2`,key:`enze0r`}],[`path`,{d:`M2 14h2`,key:`vft8re`}],[`path`,{d:`M20 14h2`,key:`4cs60a`}],[`path`,{d:`M15 13v2`,key:`1xurst`}],[`path`,{d:`M9 13v2`,key:`rq6x2g`}]]),M=v(`bug`,[[`path`,{d:`M12 20v-9`,key:`1qisl0`}],[`path`,{d:`M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z`,key:`uouzyp`}],[`path`,{d:`M14.12 3.88 16 2`,key:`qol33r`}],[`path`,{d:`M21 21a4 4 0 0 0-3.81-4`,key:`1b0z45`}],[`path`,{d:`M21 5a4 4 0 0 1-3.55 3.97`,key:`5cxbf6`}],[`path`,{d:`M22 13h-4`,key:`1jl80f`}],[`path`,{d:`M3 21a4 4 0 0 1 3.81-4`,key:`1fjd4g`}],[`path`,{d:`M3 5a4 4 0 0 0 3.55 3.97`,key:`1d7oge`}],[`path`,{d:`M6 13H2`,key:`82j7cp`}],[`path`,{d:`m8 2 1.88 1.88`,key:`fmnt4t`}],[`path`,{d:`M9 7.13V6a3 3 0 1 1 6 0v1.13`,key:`1vgav8`}]]),N=v(`lock`,[[`rect`,{width:`18`,height:`11`,x:`3`,y:`11`,rx:`2`,ry:`2`,key:`1w4ew1`}],[`path`,{d:`M7 11V7a5 5 0 0 1 10 0v4`,key:`fwvmzm`}]]),P=v(`pencil`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]),F=e(n(),1),I=t();function L({className:e,...t}){return(0,I.jsx)(r,{"data-slot":`label`,className:D(`flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50`,e),...t})}var R=F.forwardRef(({className:e,...t},n)=>(0,I.jsx)(p,{className:D(`peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input`,e),...t,ref:n,children:(0,I.jsx)(o,{className:D(`pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0`)})}));R.displayName=p.displayName;function z({...e}){return(0,I.jsx)(l,{"data-slot":`select`,...e})}function B({...e}){return(0,I.jsx)(a,{"data-slot":`select-value`,...e})}function V({className:e,size:t=`default`,children:n,...r}){return(0,I.jsxs)(_,{"data-slot":`select-trigger`,"data-size":t,className:D(`flex w-fit items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[placeholder]:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground`,e),...r,children:[n,(0,I.jsx)(s,{asChild:!0,children:(0,I.jsx)(x,{className:`size-4 opacity-50`})})]})}function H({className:e,children:t,position:n=`item-aligned`,align:r=`center`,...i}){return(0,I.jsx)(u,{children:(0,I.jsxs)(m,{"data-slot":`select-content`,className:D(`relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95`,n===`popper`&&`data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1`,e),position:n,align:r,...i,children:[(0,I.jsx)(W,{}),(0,I.jsx)(g,{className:D(`p-1`,n===`popper`&&`h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1`),children:t}),(0,I.jsx)(G,{})]})})}function U({className:e,children:t,...n}){return(0,I.jsxs)(c,{"data-slot":`select-item`,className:D(`relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2`,e),...n,children:[(0,I.jsx)(`span`,{"data-slot":`select-item-indicator`,className:`absolute right-2 flex size-3.5 items-center justify-center`,children:(0,I.jsx)(f,{children:(0,I.jsx)(y,{className:`size-4`})})}),(0,I.jsx)(d,{children:t})]})}function W({className:e,...t}){return(0,I.jsx)(h,{"data-slot":`select-scroll-up-button`,className:D(`flex cursor-default items-center justify-center py-1`,e),...t,children:(0,I.jsx)(b,{className:`size-4`})})}function G({className:e,...t}){return(0,I.jsx)(i,{"data-slot":`select-scroll-down-button`,className:D(`flex cursor-default items-center justify-center py-1`,e),...t,children:(0,I.jsx)(x,{className:`size-4`})})}var K={claude:`C`,cursor:`▶`,codex:`◆`,gemini:`G`};function q({value:e,onChange:t,projectName:n}){let[r,i]=(0,F.useState)([]),[a,o]=(0,F.useState)(!1),s=(0,F.useRef)(null),c=(0,F.useRef)(0);(0,F.useEffect)(()=>{n&&E.get(`${T(n)}/chat/providers`).then(i).catch(()=>{})},[n]),(0,F.useEffect)(()=>{if(!a)return;let e=e=>{s.current&&!s.current.contains(e.target)&&o(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[a]),(0,F.useEffect)(()=>{a&&(c.current=Math.max(0,r.findIndex(t=>t.id===e)))},[a,e,r]);let l=(0,F.useCallback)(e=>{if(e.key===`Escape`){o(!1);return}if(e.key===`ArrowDown`||e.key===`ArrowUp`){e.preventDefault();let t=e.key===`ArrowDown`?1:-1;c.current=(c.current+t+r.length)%r.length,(s.current?.querySelector(`[data-idx="${c.current}"]`))?.focus()}if(e.key===`Enter`){e.preventDefault();let n=r[c.current];n&&(t(n.id),o(!1))}},[t,r]);if(r.length<=1)return null;let u=r.find(t=>t.id===e),d=K[e]||`?`;return(0,I.jsxs)(`div`,{className:`relative`,children:[(0,I.jsxs)(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),o(e=>!e)},className:`inline-flex items-center gap-1 px-2 py-1 rounded-md text-[11px] text-text-subtle hover:text-text-primary hover:bg-surface-elevated transition-colors border border-transparent hover:border-border`,"aria-label":`AI Provider: ${u?.name??e}`,children:[(0,I.jsx)(`span`,{className:`inline-flex h-3.5 w-3.5 items-center justify-center rounded text-[9px] font-bold bg-surface-elevated shrink-0`,children:d}),(0,I.jsx)(`span`,{className:`max-w-[80px] truncate capitalize`,children:u?.name??e})]}),a&&(0,I.jsxs)(`div`,{ref:s,role:`listbox`,"aria-label":`AI Providers`,onKeyDown:l,onMouseDown:e=>e.stopPropagation(),onClick:e=>e.stopPropagation(),className:`absolute bottom-full left-0 mb-1 z-50 w-56 rounded-lg border border-border bg-surface shadow-lg`,children:[(0,I.jsx)(`div`,{className:`px-3 py-2 border-b border-border`,children:(0,I.jsx)(`span`,{className:`text-xs font-medium text-text-secondary`,children:`Provider`})}),(0,I.jsx)(`div`,{className:`py-1`,children:r.map((n,r)=>{let i=K[n.id]||`?`,a=n.id===e;return(0,I.jsxs)(`button`,{"data-idx":r,role:`option`,"aria-selected":a,tabIndex:0,onClick:()=>{t(n.id),o(!1)},className:`w-full flex items-center gap-3 px-3 py-2 text-left transition-colors hover:bg-surface-elevated focus:bg-surface-elevated focus:outline-none ${a?`bg-surface-elevated`:``}`,children:[(0,I.jsx)(`span`,{className:`inline-flex h-5 w-5 items-center justify-center rounded text-[11px] font-bold bg-surface-elevated text-text-subtle shrink-0`,children:i}),(0,I.jsx)(`span`,{className:`flex-1 text-sm font-medium text-text-primary capitalize`,children:n.name}),a&&(0,I.jsx)(y,{className:`size-4 shrink-0 text-primary`})]},n.id)})})]})]})}function J({providerId:e}){return(0,I.jsx)(`span`,{className:`inline-flex h-4 w-4 items-center justify-center rounded text-[10px] font-bold bg-surface-elevated text-text-subtle shrink-0`,title:e,children:K[e]||`?`})}var Y=[{value:`low`,label:`Low`},{value:`medium`,label:`Medium`},{value:`high`,label:`High`}],X=[{value:`bypassPermissions`,label:`Bypass permissions (default)`},{value:`default`,label:`Ask before edits`},{value:`acceptEdits`,label:`Edit automatically`},{value:`plan`,label:`Plan mode`}],Z={claude:`Claude`,cursor:`Cursor`,codex:`Codex`,gemini:`Gemini`};function Q({compact:e}={}){let[t,n]=(0,F.useState)(null),[r,i]=(0,F.useState)(``),[a,o]=(0,F.useState)([]),[s,c]=(0,F.useState)(!1),[l,u]=(0,F.useState)(!1),[d,f]=(0,F.useState)(null),[p,m]=(0,F.useState)(0);(0,F.useEffect)(()=>{O().then(e=>{n(e),i(e.default_provider??`claude`)}).catch(e=>f(e.message))},[]),(0,F.useEffect)(()=>{r&&(c(!0),E.get(`/api/settings/ai/providers/${r}/models`).then(o).catch(()=>o([])).finally(()=>c(!1)))},[r]);let h=t?Object.keys(t.providers).filter(e=>e!==`mock`).map(e=>({id:e,name:Z[e]??e})):[],g=t?.providers[r],_=g?.type===`agent-sdk`||!g?.type&&r===`claude`,v=async(e,i)=>{if(t){u(!0),f(null);try{n(await k({providers:{[r]:{[e]:i}}})),m(e=>e+1)}catch(e){f(e.message)}finally{u(!1)}}},y=e?`text-[11px]`:`text-sm`,b=e?`text-xs`:`text-sm`,x=e?`space-y-2`:`space-y-4`,C=e?`space-y-1.5`:`space-y-3`,w=e?`space-y-1`:`space-y-1.5`;if(!t)return(0,I.jsxs)(`div`,{className:C,children:[(0,I.jsx)(`h3`,{className:`${b} font-medium text-text-secondary`,children:`AI Settings`}),(0,I.jsx)(`p`,{className:`${y} text-text-subtle`,children:d?`Error: ${d}`:`Loading...`})]});let T=_?a:[{value:`__default__`,label:`Auto (default)`},...a];return(0,I.jsxs)(`div`,{className:x,children:[(0,I.jsx)(`h3`,{className:`${b} font-medium text-text-secondary`,children:`AI Settings`}),h.length>1&&(0,I.jsx)(`div`,{className:`flex gap-0.5 border-b border-border/50 -mx-1 px-1`,children:h.map(e=>(0,I.jsxs)(`button`,{onClick:()=>i(e.id),className:`flex items-center gap-1 px-2 py-1 text-[11px] rounded-t transition-colors ${r===e.id?`text-primary border-b-2 border-primary font-medium`:`text-text-subtle hover:text-text-secondary`}`,children:[(0,I.jsx)(J,{providerId:e.id}),(0,I.jsx)(`span`,{className:`capitalize`,children:e.name})]},e.id))}),(0,I.jsxs)(`div`,{className:C,children:[a.length>0&&(0,I.jsxs)(`div`,{className:w,children:[(0,I.jsx)(L,{htmlFor:`ai-model`,className:e?y:void 0,children:`Model`}),(0,I.jsxs)(z,{value:_?g?.model??a[0]?.value:g?.model||`__default__`,onValueChange:e=>v(`model`,e===`__default__`?void 0:e),disabled:s,children:[(0,I.jsx)(V,{id:`ai-model`,className:`w-full ${e?`h-7 text-[11px]`:``}`,children:(0,I.jsx)(B,{placeholder:s?`Loading models...`:`Select model`})}),(0,I.jsx)(H,{className:`max-h-[300px]`,children:T.map(e=>(0,I.jsx)(U,{value:e.value,children:e.label},e.value))})]})]}),_&&(0,I.jsxs)(I.Fragment,{children:[(0,I.jsxs)(`div`,{className:w,children:[(0,I.jsx)(L,{htmlFor:`ai-base-url`,className:e?y:void 0,children:`Base URL`}),(0,I.jsx)(S,{id:`ai-base-url`,type:`url`,defaultValue:g?.base_url??``,placeholder:`https://api.anthropic.com (default)`,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{v(`base_url`,e.target.value.trim()||void 0)}},`baseurl-${r}-${p}`)]}),(0,I.jsxs)(`div`,{className:w,children:[(0,I.jsx)(L,{htmlFor:`ai-api-key`,className:e?y:void 0,children:`API Key / Token`}),(0,I.jsx)(S,{id:`ai-api-key`,type:`password`,defaultValue:g?.api_key??``,placeholder:`sk-ant-... (optional, overrides accounts)`,className:e?`h-7 text-[11px] font-mono`:`font-mono`,onBlur:e=>{let t=e.target.value.trim();t.startsWith(`••••`)||v(`api_key`,t||void 0)}},`apikey-${r}-${p}`),(0,I.jsx)(`p`,{className:`${e?`text-[9px]`:`text-[11px]`} text-muted-foreground`,children:`Direct API key or OAuth token. Leave empty to use connected accounts.`})]}),(0,I.jsxs)(`div`,{className:w,children:[(0,I.jsx)(L,{htmlFor:`ai-effort`,className:e?y:void 0,children:`Effort`}),(0,I.jsxs)(z,{value:g?.effort??`high`,onValueChange:e=>v(`effort`,e),children:[(0,I.jsx)(V,{id:`ai-effort`,className:`w-full ${e?`h-7 text-[11px]`:``}`,children:(0,I.jsx)(B,{})}),(0,I.jsx)(H,{children:Y.map(e=>(0,I.jsx)(U,{value:e.value,children:e.label},e.value))})]})]}),(0,I.jsxs)(`div`,{className:w,children:[(0,I.jsx)(L,{htmlFor:`ai-max-turns`,className:e?y:void 0,children:`Max Turns (1-500)`}),(0,I.jsx)(S,{id:`ai-max-turns`,type:`number`,min:1,max:500,defaultValue:g?.max_turns??100,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{let t=parseInt(e.target.value);isNaN(t)||v(`max_turns`,t)}},`turns-${r}-${p}`)]}),(0,I.jsxs)(`div`,{className:w,children:[(0,I.jsx)(L,{htmlFor:`ai-budget`,className:e?y:void 0,children:`Max Budget (USD)`}),(0,I.jsx)(S,{id:`ai-budget`,type:`number`,step:.1,min:.01,max:50,defaultValue:g?.max_budget_usd??``,placeholder:`No limit`,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{let t=parseFloat(e.target.value);v(`max_budget_usd`,isNaN(t)?void 0:t)}},`budget-${r}-${p}`)]}),(0,I.jsxs)(`div`,{className:w,children:[(0,I.jsx)(L,{htmlFor:`ai-thinking`,className:e?y:void 0,children:`Thinking Budget (tokens)`}),(0,I.jsx)(S,{id:`ai-thinking`,type:`number`,min:0,defaultValue:g?.thinking_budget_tokens??``,placeholder:`Disabled`,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{let t=parseInt(e.target.value);v(`thinking_budget_tokens`,isNaN(t)?void 0:t)}},`thinking-${r}-${p}`)]}),(0,I.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,I.jsxs)(`div`,{children:[(0,I.jsx)(L,{htmlFor:`ai-agent-teams`,className:e?y:void 0,children:`Agent Teams`}),(0,I.jsx)(`p`,{className:`${e?`text-[9px]`:`text-[11px]`} text-muted-foreground`,children:`Experimental. Enables multi-agent collaboration with shared tasks and messaging. Uses ~7x more tokens.`})]}),(0,I.jsx)(R,{id:`ai-agent-teams`,checked:g?.agent_teams??!1,onCheckedChange:e=>v(`agent_teams`,e)})]}),g?.agent_teams&&(0,I.jsx)($,{compact:e})]}),(0,I.jsxs)(`div`,{className:w,children:[(0,I.jsx)(L,{htmlFor:`ai-permission-mode`,className:e?y:void 0,children:`Default Permission Mode`}),(0,I.jsxs)(z,{value:g?.permission_mode??`bypassPermissions`,onValueChange:e=>v(`permission_mode`,e),children:[(0,I.jsx)(V,{id:`ai-permission-mode`,className:`w-full ${e?`h-7 text-[11px]`:``}`,children:(0,I.jsx)(B,{})}),(0,I.jsx)(H,{children:X.map(e=>(0,I.jsx)(U,{value:e.value,children:e.label},e.value))})]})]}),(0,I.jsxs)(`div`,{className:w,children:[(0,I.jsx)(L,{htmlFor:`ai-system-prompt`,className:e?y:void 0,children:`Additional Instructions`}),(0,I.jsx)(`textarea`,{id:`ai-system-prompt`,rows:e?3:4,defaultValue:g?.system_prompt??``,placeholder:`Enter additional instructions for ${r}...`,className:`w-full rounded-md border border-input bg-background px-3 py-2 ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ${e?`text-[11px]`:`text-sm`}`,onBlur:e=>{v(`system_prompt`,e.target.value.trim()||void 0)}},`sysprompt-${r}-${p}`)]})]}),l&&(0,I.jsx)(`p`,{className:`text-xs text-text-subtle`,children:`Saving...`}),d&&(0,I.jsx)(`p`,{className:`text-xs text-red-500`,children:d})]})}function $({compact:e}){let[t,n]=(0,F.useState)([]),[r,i]=(0,F.useState)(!1),[a,o]=(0,F.useState)(null),s=(0,F.useCallback)(async()=>{i(!0);try{n(await E.get(`/api/teams`)??[])}catch{}i(!1)},[]);(0,F.useEffect)(()=>{s()},[s]);let c=async e=>{try{await E.del(`/api/teams/${encodeURIComponent(e)}`),n(t=>t.filter(t=>t.name!==e)),o(null)}catch{}};return t.length===0&&!r?null:(0,I.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,I.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,I.jsxs)(L,{className:e?`text-[11px]`:void 0,children:[`Teams (`,t.length,`)`]}),(0,I.jsx)(`button`,{onClick:s,className:`text-text-subtle hover:text-foreground p-1`,"aria-label":`Refresh teams`,children:(0,I.jsx)(C,{className:`size-3 ${r?`animate-spin`:``}`})})]}),t.map(e=>(0,I.jsxs)(`div`,{className:`flex items-center justify-between p-2 rounded bg-surface-elevated text-xs`,children:[(0,I.jsxs)(`div`,{className:`min-w-0`,children:[(0,I.jsx)(`div`,{className:`font-medium truncate`,children:e.name}),e.description&&(0,I.jsx)(`div`,{className:`text-text-subtle truncate`,children:e.description}),(0,I.jsxs)(`div`,{className:`text-text-subtle`,children:[e.members?.length??e.memberCount??0,` members`,e.createdAt?` · ${new Date(e.createdAt).toLocaleDateString()}`:``]})]}),a===e.name?(0,I.jsxs)(`div`,{className:`flex gap-1 shrink-0 ml-2`,children:[(0,I.jsx)(`button`,{onClick:()=>c(e.name),className:`px-2 py-1 bg-red-600 text-white rounded text-[10px]`,children:`Delete`}),(0,I.jsx)(`button`,{onClick:()=>o(null),className:`px-2 py-1 bg-zinc-600 text-white rounded text-[10px]`,children:`Cancel`})]}):(0,I.jsx)(`button`,{onClick:()=>o(e.name),className:`shrink-0 text-text-subtle hover:text-red-500 p-1 ml-2`,"aria-label":`Delete team ${e.name}`,children:(0,I.jsx)(w,{className:`size-3.5`})})]},e.name))]})}export{H as a,B as c,P as d,N as f,A as h,z as i,R as l,j as m,J as n,U as o,M as p,q as r,V as s,Q as t,L as u};
@@ -1 +0,0 @@
1
- import{W as e}from"./vendor-mermaid-CMiurk2b.js";export{e as createArchitectureServices};