@hienlh/ppm 0.22.1 → 0.22.2

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 (124) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/assets/skills/ppm/SKILL.md +1 -1
  3. package/assets/skills/ppm/references/cli-reference.md +4 -4
  4. package/assets/skills/ppm/references/http-api.md +1 -1
  5. package/dist/web/assets/{accounts-settings-section-D3BylchP.js → accounts-settings-section-CLEAA_Jc.js} +1 -1
  6. package/dist/web/assets/{ai-resource-editor-BLPcnhTM.js → ai-resource-editor-C4ecid2g.js} +1 -1
  7. package/dist/web/assets/ai-settings-section-BOwGdiyH.js +1 -0
  8. package/dist/web/assets/ai-settings-section-Cqz13gRt.js +1 -0
  9. package/dist/web/assets/{api-client-C1ZwRL4Y.js → api-client-Jn3njtNw.js} +1 -1
  10. package/dist/web/assets/api-client-rSFnnCj4.js +1 -0
  11. package/dist/web/assets/{api-settings-_7Q-ULxp.js → api-settings-BxijvPBR.js} +1 -1
  12. package/dist/web/assets/{api-themes-DRAERo4Q.js → api-themes-CSUarkzD.js} +1 -1
  13. package/dist/web/assets/{appearance-settings-section-CiMdk3sb.js → appearance-settings-section-DbA8L-Vz.js} +1 -1
  14. package/dist/web/assets/{audio-preview-DsYvgKqj.js → audio-preview-CxJd8wRV.js} +1 -1
  15. package/dist/web/assets/{branch-review-tab-B1pFjlKM.js → branch-review-tab-CMTa2uSR.js} +1 -1
  16. package/dist/web/assets/chat-tab-BpdgqjSL.js +15 -0
  17. package/dist/web/assets/{code-editor-BJhOEsnZ.js → code-editor-B7y7-5KE.js} +3 -3
  18. package/dist/web/assets/{codex-daily-guard-CaCQJ4r_.js → codex-daily-guard-ChDPiXDx.js} +1 -1
  19. package/dist/web/assets/{conflict-editor-B7u_p49h.js → conflict-editor-Axs9Ad7A.js} +1 -1
  20. package/dist/web/assets/{csv-preview-CttjJU1e.js → csv-preview-DTUAW2HW.js} +1 -1
  21. package/dist/web/assets/{database-viewer-Ca4HxIfx.js → database-viewer-qXDiWeXj.js} +1 -1
  22. package/dist/web/assets/{diff-viewer-9-XjLIwa.js → diff-viewer-BtLiSpqe.js} +1 -1
  23. package/dist/web/assets/{docx-preview-CXuk-emm.js → docx-preview-Dxvy6h13.js} +1 -1
  24. package/dist/web/assets/{editor-language-service-D0DuEOs_.js → editor-language-service-D75GuLXP.js} +1 -1
  25. package/dist/web/assets/{explorer-body-VdCBqcZu.js → explorer-body-xg1-MhlW.js} +1 -1
  26. package/dist/web/assets/{explorer-window-content-BIsbl7Th.js → explorer-window-content-BeQocW3i.js} +1 -1
  27. package/dist/web/assets/{extension-manager-section-HkY7geS5.js → extension-manager-section-Bm2v3P-n.js} +1 -1
  28. package/dist/web/assets/{extension-webview-DZG8YHX9.js → extension-webview-CzxrAHyL.js} +1 -1
  29. package/dist/web/assets/{file-icons-BXdvggK2.js → file-icons-wS-OmEVu.js} +1 -1
  30. package/dist/web/assets/{file-store-ojgMXgAw.js → file-store-Ds3qJ4hC.js} +1 -1
  31. package/dist/web/assets/{files-settings-section-qnRtkX05.js → files-settings-section-Bd-_GeZU.js} +1 -1
  32. package/dist/web/assets/{format-file-meta-C77h04cZ.js → format-file-meta-PPi3ptkm.js} +1 -1
  33. package/dist/web/assets/{general-settings-section-BAFSZmCE.js → general-settings-section-CfNPHQUk.js} +1 -1
  34. package/dist/web/assets/{git-log-panel-2sGpfEla.js → git-log-panel-CtGxPzH6.js} +1 -1
  35. package/dist/web/assets/{git-repo-store-88Z8v-pF.js → git-repo-store-BCEPfUGT.js} +1 -1
  36. package/dist/web/assets/{glide-data-grid-f0hyITiF.js → glide-data-grid-iSo2vP0q.js} +1 -1
  37. package/dist/web/assets/{group-chat-tab-Ck6sk7yY.js → group-chat-tab-D1lx0zz-.js} +1 -1
  38. package/dist/web/assets/{image-preview-CzCc4_Do.js → image-preview-DeGD0HJu.js} +1 -1
  39. package/dist/web/assets/{index-CEZVxM4G.js → index-CN0G8uYY.js} +5 -5
  40. package/dist/web/assets/{jira-watcher-section-CeLmhvu1.js → jira-watcher-section-kyifZPTv.js} +1 -1
  41. package/dist/web/assets/keybindings-store-L5vV8DEJ.js +1 -0
  42. package/dist/web/assets/{keyboard-shortcuts-section-PVz6kuh2.js → keyboard-shortcuts-section-D2uJq4x9.js} +1 -1
  43. package/dist/web/assets/{markdown-renderer-C140Ijk0.js → markdown-renderer-BX1Q00sC.js} +1 -1
  44. package/dist/web/assets/markdown-renderer-CLUux0vA.js +1 -0
  45. package/dist/web/assets/{media-url-yfqHpPz0.js → media-url-DKK0YHxL.js} +1 -1
  46. package/dist/web/assets/{mobile-explorer-sheet-CUG_owdf.js → mobile-explorer-sheet-BHQDzpwK.js} +1 -1
  47. package/dist/web/assets/notification-store-BHgSy-ci.js +1 -0
  48. package/dist/web/assets/panel-store-D20Zuf3i.js +1 -0
  49. package/dist/web/assets/{pdf-preview-CmBI6E7d.js → pdf-preview-DAcfhfGm.js} +1 -1
  50. package/dist/web/assets/{postgres-viewer-8ZAqEALv.js → postgres-viewer-DPRsmgP5.js} +1 -1
  51. package/dist/web/assets/{ppmbot-settings-section-Cji-Mil-.js → ppmbot-settings-section-B5N1jHgm.js} +1 -1
  52. package/dist/web/assets/{problems-panel-a6_hrWvl.js → problems-panel-D_wZ4_Qg.js} +1 -1
  53. package/dist/web/assets/{process-table-CiIqlOIK.js → process-table-DahflyQn.js} +1 -1
  54. package/dist/web/assets/{project-framework-store-B70Q3dNM.js → project-framework-store-ViZgce6y.js} +1 -1
  55. package/dist/web/assets/{project-store-B87hLRSk.js → project-store-hNvwfqX3.js} +1 -1
  56. package/dist/web/assets/{proxy-settings-section-BjI4IFgp.js → proxy-settings-section-CLg_nlxn.js} +1 -1
  57. package/dist/web/assets/{query-audit-section-By6qyqdB.js → query-audit-section-BrfSo0s_.js} +1 -1
  58. package/dist/web/assets/{remote-desktop-clipboard-notice-eXYvwgx7.js → remote-desktop-clipboard-notice-Fi6cieGM.js} +1 -1
  59. package/dist/web/assets/{remote-desktop-mobile-sheet-Doh-fci-.js → remote-desktop-mobile-sheet-lLZ-oK73.js} +2 -2
  60. package/dist/web/assets/{remote-desktop-mobile-view-Dt8Akc3p.js → remote-desktop-mobile-view-j3v-4rYa.js} +1 -1
  61. package/dist/web/assets/{remote-desktop-readiness-gate-t83fqbID.js → remote-desktop-readiness-gate-CeLvcX_w.js} +1 -1
  62. package/dist/web/assets/{remote-desktop-window-content-CguhZMmx.js → remote-desktop-window-content-lwbkLsTC.js} +1 -1
  63. package/dist/web/assets/{run-in-terminal-CdefEe_R.js → run-in-terminal-D7W4IKb9.js} +1 -1
  64. package/dist/web/assets/{schedules-settings-section-BVkpW5ms.js → schedules-settings-section-C8OS0o80.js} +1 -1
  65. package/dist/web/assets/{send-to-chat-F207yH3u.js → send-to-chat-DNKhmHbi.js} +1 -1
  66. package/dist/web/assets/{settings-body-CoIxYAh6.js → settings-body-DgN22Z0W.js} +2 -2
  67. package/dist/web/assets/{settings-store-krC6bc79.js → settings-store-CsVSVgLp.js} +2 -2
  68. package/dist/web/assets/{settings-tab-7DKVUTbM.js → settings-tab-ChOs94iB.js} +1 -1
  69. package/dist/web/assets/{settings-window-content-3_39TeX-.js → settings-window-content-BnKMmg2a.js} +1 -1
  70. package/dist/web/assets/{sql-query-editor-CQB7Yp7U.js → sql-query-editor-BJZIIQsm.js} +1 -1
  71. package/dist/web/assets/{sqlite-viewer-Bd7rjr1D.js → sqlite-viewer--cMeCZum.js} +1 -1
  72. package/dist/web/assets/{system-monitor-body-DsRXeMyU.js → system-monitor-body-CXiIrn0N.js} +2 -2
  73. package/dist/web/assets/system-monitor-tab-BJKrTSl0.js +1 -0
  74. package/dist/web/assets/{system-monitor-window-content-ClPo4-El.js → system-monitor-window-content-Dy9fZJE3.js} +1 -1
  75. package/dist/web/assets/{tab-host-window-content-d2TAD4PU.js → tab-host-window-content-BezqrAwC.js} +1 -1
  76. package/dist/web/assets/{tab-store-OJa1GPCq.js → tab-store-krAuHQ6_.js} +1 -1
  77. package/dist/web/assets/{team-member-sheet-7d2Qp-ie.js → team-member-sheet-CVM2QC3H.js} +2 -2
  78. package/dist/web/assets/{team-member-window-content-Bctg2gmg.js → team-member-window-content-D4RYKplm.js} +1 -1
  79. package/dist/web/assets/{terminal-tab-0HQic25V.js → terminal-tab-jikhQLct.js} +1 -1
  80. package/dist/web/assets/{tool-cards-CmLLRACd.js → tool-cards-D5jCQvqn.js} +2 -2
  81. package/dist/web/assets/{use-blob-url-CPtCcY3i.js → use-blob-url-DMGlPCQD.js} +1 -1
  82. package/dist/web/assets/{use-inline-blame-sDMjcz1-.js → use-inline-blame-BF8Y1KfV.js} +1 -1
  83. package/dist/web/assets/{use-lsp-CBgID-EU.js → use-lsp-Bx4oVtlk.js} +1 -1
  84. package/dist/web/assets/{use-monaco-theme-gvhJ_jZh.js → use-monaco-theme-DHczXLMb.js} +1 -1
  85. package/dist/web/assets/{use-websocket-C9wlRliB.js → use-websocket-BWZkbleJ.js} +1 -1
  86. package/dist/web/assets/{video-preview-CSDK5j6H.js → video-preview-D191TvX9.js} +1 -1
  87. package/dist/web/assets/{window-pip-registry-yD6esSju.js → window-pip-registry-D1oXq-Dq.js} +1 -1
  88. package/dist/web/assets/ws-auth-BG-cdrQ8.js +1 -0
  89. package/dist/web/index.html +13 -13
  90. package/dist/web/sw.js +1 -1
  91. package/docs/architecture/workspace-and-ui.md +13 -0
  92. package/package.json +1 -1
  93. package/src/cli/commands/init.ts +1 -0
  94. package/src/providers/codex-app-server/codex-history.ts +26 -7
  95. package/src/providers/codex-app-server/codex-provider.ts +6 -4
  96. package/src/server/routes/chat.ts +1 -1
  97. package/src/server/routes/settings.ts +11 -5
  98. package/src/services/config.service.ts +2 -0
  99. package/src/types/chat.ts +1 -1
  100. package/src/types/config.ts +12 -1
  101. package/src/web/components/chat/chat-tab.tsx +162 -38
  102. package/src/web/components/chat/message-input.tsx +24 -0
  103. package/src/web/components/chat/model-thinking-selector.tsx +25 -5
  104. package/src/web/components/chat/new-chat-provider-gate.tsx +68 -0
  105. package/src/web/components/layout/editor-panel.tsx +1 -1
  106. package/src/web/components/layout/reparenting-tab.tsx +4 -2
  107. package/src/web/components/layout/tab-bar.tsx +1 -1
  108. package/src/web/components/settings/ai-settings-section.tsx +36 -0
  109. package/src/web/hooks/use-draft.ts +25 -4
  110. package/src/web/hooks/use-usage.ts +6 -4
  111. package/src/web/lib/api-client.ts +7 -1
  112. package/src/web/lib/api-settings.ts +1 -0
  113. package/src/web/lib/new-chat-provider.ts +8 -0
  114. package/src/web/stores/panel-store.ts +46 -3
  115. package/dist/web/assets/ai-settings-section-BtR7rF-T.js +0 -1
  116. package/dist/web/assets/ai-settings-section-r9JctHNM.js +0 -1
  117. package/dist/web/assets/api-client-pQL53cDQ.js +0 -1
  118. package/dist/web/assets/chat-tab-DZagX06m.js +0 -15
  119. package/dist/web/assets/keybindings-store-C_3ChOEf.js +0 -1
  120. package/dist/web/assets/markdown-renderer-Dz7-DYUg.js +0 -1
  121. package/dist/web/assets/notification-store-6vib1ISy.js +0 -1
  122. package/dist/web/assets/panel-store-CboGJAwh.js +0 -1
  123. package/dist/web/assets/system-monitor-tab-DdSZgux3.js +0 -1
  124. package/dist/web/assets/ws-auth-CEYVQ8NH.js +0 -1
@@ -26,8 +26,9 @@ interface UseUsageReturn {
26
26
  * `sessionId` scopes the reported account to this session's binding. Without it the header
27
27
  * shows whichever account ran last across every open session, which is wrong for all but one.
28
28
  */
29
- export function useUsage(projectName: string, providerId = "claude", sessionId?: string): UseUsageReturn {
30
- const scope = JSON.stringify([projectName, providerId, sessionId]);
29
+ export function useUsage(projectName: string, providerId = "claude", sessionId?: string, pickedAccountId?: string): UseUsageReturn {
30
+ const previewAccountId = providerId === "codex" && !sessionId ? pickedAccountId : undefined;
31
+ const scope = JSON.stringify([projectName, providerId, sessionId, previewAccountId]);
31
32
  const [snapshot, setSnapshot] = useState<{ scope: string; usage: UsageInfo; fetchedAt: string | null } | null>(null);
32
33
  const [usageLoading, setUsageLoading] = useState(false);
33
34
  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
@@ -39,11 +40,12 @@ export function useUsage(projectName: string, providerId = "claude", sessionId?:
39
40
  setUsageLoading(true);
40
41
  const qs = forceRefresh ? "&refresh=1" : "";
41
42
  const sessionQs = sessionId ? `&session=${encodeURIComponent(sessionId)}` : "";
43
+ const accountQs = previewAccountId ? `&accountId=${encodeURIComponent(previewAccountId)}` : "";
42
44
  // Via api.get, not raw fetch: the toolbar's loading state is gated on this
43
45
  // settling, and a raw fetch has no timeout to stop it stalling forever.
44
46
  return api
45
47
  .get<(UsageInfo & { lastFetchedAt?: string }) | null>(
46
- `${projectUrl(projectName)}/chat/usage?providerId=${providerId}${sessionQs}${qs}`,
48
+ `${projectUrl(projectName)}/chat/usage?providerId=${providerId}${sessionQs}${accountQs}${qs}`,
47
49
  )
48
50
  .then((data) => {
49
51
  if (request !== requestRef.current) return;
@@ -55,7 +57,7 @@ export function useUsage(projectName: string, providerId = "claude", sessionId?:
55
57
  .finally(() => {
56
58
  if (request === requestRef.current) setUsageLoading(false);
57
59
  });
58
- }, [projectName, providerId, sessionId, scope]);
60
+ }, [projectName, providerId, sessionId, previewAccountId, scope]);
59
61
 
60
62
  // Read cache on mount + auto-read every POLL_INTERVAL
61
63
  useEffect(() => {
@@ -122,11 +122,17 @@ export class ApiClient {
122
122
  }
123
123
  }
124
124
 
125
- async post<T>(path: string, body?: unknown): Promise<T> {
125
+ /**
126
+ * No default timeout, unlike `get`: a POST is not idempotent, so cutting one off
127
+ * mid-flight can leave the server having done the work with nobody to tell. A
128
+ * caller that would rather fail loudly than wait passes its own `signal`.
129
+ */
130
+ async post<T>(path: string, body?: unknown, options?: { signal?: AbortSignal }): Promise<T> {
126
131
  const res = await fetch(`${this.baseUrl}${path}`, {
127
132
  method: "POST",
128
133
  headers: this.headers(),
129
134
  body: body != null ? JSON.stringify(body) : undefined,
135
+ signal: options?.signal,
130
136
  });
131
137
  return this.handleResponse<T>(res);
132
138
  }
@@ -212,6 +212,7 @@ export interface AIProviderSettings {
212
212
 
213
213
  export interface AISettings {
214
214
  default_provider: string;
215
+ new_chat_provider_mode?: "default" | "follow-focus";
215
216
  share_provider_context?: boolean;
216
217
  providers: Record<string, AIProviderSettings>;
217
218
  }
@@ -0,0 +1,8 @@
1
+ import type { AISettings } from "./api-settings";
2
+
3
+ /** The source is captured when the tab opens, before another panel can gain focus. */
4
+ export function resolveNewChatProvider(settings: AISettings, focusedProvider?: string): string {
5
+ return settings.new_chat_provider_mode === "follow-focus" && focusedProvider
6
+ ? focusedProvider
7
+ : settings.default_provider || "claude";
8
+ }
@@ -89,6 +89,8 @@ export interface PanelStore {
89
89
  grid: string[][];
90
90
  focusedPanelId: string;
91
91
  currentProject: string | null;
92
+ /** Session-local focus memory, isolated by project; non-chat tabs do not clear it. */
93
+ lastFocusedChatProviders: Record<string, string>;
92
94
 
93
95
  /** Keep-alive: per-project grid snapshots (for hidden workspaces) */
94
96
  projectGrids: Record<string, string[][]>;
@@ -106,7 +108,7 @@ export interface PanelStore {
106
108
  reloadProject: (projectName: string) => void;
107
109
 
108
110
  // Panel focus
109
- setFocusedPanel: (panelId: string) => void;
111
+ setFocusedPanel: (panelId: string, rememberChat?: boolean) => void;
110
112
 
111
113
  // Tab operations (operate on focused panel by default)
112
114
  openTab: (tab: Omit<Tab, "id">, panelId?: string) => string;
@@ -210,6 +212,7 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
210
212
  return {
211
213
  ...defaultLayout(),
212
214
  currentProject: null,
215
+ lastFocusedChatProviders: {},
213
216
  projectGrids: {},
214
217
  projectFocused: {},
215
218
  dock: { visible: false, height: 30 },
@@ -459,10 +462,13 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
459
462
  get().switchProject(projectName);
460
463
  },
461
464
 
462
- setFocusedPanel: (panelId) => {
465
+ setFocusedPanel: (panelId, rememberChat = true) => {
463
466
  // Focus drives where the next tab opens, so it must stay on a real, on-grid panel.
464
467
  if (isWindowPanelId(panelId)) return;
465
- if (get().panels[panelId]) set({ focusedPanelId: panelId });
468
+ const panel = get().panels[panelId];
469
+ if (!panel) return;
470
+ set({ focusedPanelId: panelId });
471
+ if (rememberChat) rememberChatProvider(panel.tabs.find((t) => t.id === panel.activeTabId));
466
472
  },
467
473
 
468
474
  openTab: (tabDef, panelId?) => {
@@ -474,6 +480,15 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
474
480
  const panel = get().panels[pid];
475
481
  if (!panel) return "";
476
482
 
483
+ if (tabDef.type === "chat" && !tabDef.metadata?.sessionId && !tabDef.metadata?.providerId) {
484
+ const project = tabDef.projectId ?? (tabDef.metadata?.projectName as string | undefined) ?? get().currentProject;
485
+ tabDef = { ...tabDef, metadata: {
486
+ ...tabDef.metadata,
487
+ providerPending: true,
488
+ focusedProviderOnOpen: project ? get().lastFocusedChatProviders[project] : undefined,
489
+ } };
490
+ }
491
+
477
492
  // Terminal: compute next available index if not provided
478
493
  if (tabDef.type === "terminal" && !tabDef.metadata?.terminalIndex) {
479
494
  const allTabs = Object.values(get().panels).flatMap((p) => p.tabs);
@@ -499,6 +514,7 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
499
514
  for (const p of Object.values(get().panels)) {
500
515
  const existing = p.tabs.find((t) => t.type === "chat" && t.metadata?.sessionId === sid);
501
516
  if (existing) {
517
+ rememberChatProvider(existing);
502
518
  set((s) => ({
503
519
  focusedPanelId: focusAfterActivate(p.id),
504
520
  panels: {
@@ -664,6 +680,7 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
664
680
  setActiveTab: (tabId, panelId?) => {
665
681
  const panel = panelId ? get().panels[panelId] : findPanel(tabId);
666
682
  if (!panel) return;
683
+ rememberChatProvider(panel.tabs.find((t) => t.id === tabId));
667
684
  const pid = panel.id;
668
685
  set((s) => {
669
686
  const p = s.panels[pid]!;
@@ -862,3 +879,29 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
862
879
  isMobile: () => typeof window !== "undefined" && window.innerWidth < 768,
863
880
  };
864
881
  });
882
+
883
+ // Observe activation as well as a provider change in the focused composer. Updates
884
+ // from background chats must never replace the user's most recent focus choice.
885
+ function rememberChatProvider(tab: Tab | undefined) {
886
+ const state = usePanelStore.getState();
887
+ if (tab?.type !== "chat" || tab.metadata?.providerPending) return;
888
+ const project = tab.projectId ?? (tab.metadata?.projectName as string | undefined) ?? state.currentProject;
889
+ const provider = (tab.metadata?.providerId as string | undefined) ?? "claude";
890
+ if (!project || state.lastFocusedChatProviders[project] === provider) return;
891
+ usePanelStore.setState({ lastFocusedChatProviders: {
892
+ ...state.lastFocusedChatProviders, [project]: provider,
893
+ } });
894
+ }
895
+
896
+ usePanelStore.subscribe((state, previous) => {
897
+ const panel = state.panels[state.focusedPanelId];
898
+ const tab = panel?.tabs.find((t) => t.id === panel.activeTabId);
899
+ // A panel's chrome can change the destination for new tabs without focusing
900
+ // its chat. Actual body/tab focus is recorded explicitly by the actions above.
901
+ const oldPanel = previous.panels[state.focusedPanelId];
902
+ const oldTab = oldPanel?.tabs.find((t) => t.id === oldPanel.activeTabId);
903
+ if (tab?.id === oldTab?.id
904
+ && tab?.metadata?.providerId === oldTab?.metadata?.providerId
905
+ && state.currentProject === previous.currentProject) return;
906
+ rememberChatProvider(tab);
907
+ });
@@ -1 +0,0 @@
1
- import"./vendor-markdown-CuWCHIVb.js";import"./vendor-ui-DmZ-Mb-H.js";import"./icons-DQjqk0lJ.js";import"./api-client-C1ZwRL4Y.js";import"./portal-container-context-BarKmT4S.js";import"./panel-store-CboGJAwh.js";import"./window-store-UC1jJeLM.js";import"./tab-store-OJa1GPCq.js";import"./use-is-mobile-TkcwP1Gx.js";import"./input-C7Q8FxeL.js";import{t as e}from"./ai-settings-section-r9JctHNM.js";export{e as AISettingsSection};
@@ -1 +0,0 @@
1
- import{o as e}from"./rolldown-runtime-FhOqtrmT.js";import{C as t,S as n}from"./vendor-markdown-CuWCHIVb.js";import{Qn as r,ct as i,wr as a}from"./icons-DQjqk0lJ.js";import{n as o}from"./api-client-C1ZwRL4Y.js";import{t as s}from"./input-C7Q8FxeL.js";import{G as c,J as l,K as u,W as d,Y as f,fn as p,q as m,rn as h,rt as g}from"./index-CEZVxM4G.js";import{getAISettings as _,updateAISettings as v}from"./api-settings-_7Q-ULxp.js";var y=e(t(),1),b=n(),x=[128e3,272e3,4e5,512e3,872e3,1e6],S=[1e5,2e5,23e4,35e4,45e4,75e4,9e5];function C({id:e,label:t,value:n,presets:r,disabled:i,compact:a,onChange:o}){let[c,l]=(0,y.useState)(!!n&&!r.includes(Number(n))),u=a?`text-[11px]`:`text-sm`;return(0,b.jsxs)(`div`,{className:`space-y-1`,children:[(0,b.jsx)(g,{htmlFor:e,className:u,children:t}),(0,b.jsxs)(`select`,{id:e,value:c?`custom`:n||`default`,disabled:i,"aria-describedby":`codex-context-help`,className:`w-full min-h-11 sm:min-h-0 rounded-md border border-input bg-background px-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 ${a?`h-7`:`h-9`} ${u}`,onChange:e=>{let t=e.target.value;l(t===`custom`),t!==`custom`&&o(t===`default`?``:t)},children:[(0,b.jsx)(`option`,{value:`default`,children:`Codex default`}),r.map(e=>(0,b.jsxs)(`option`,{value:String(e),children:[e===1e6?`1M`:`${e/1e3}K`,` tokens`]},e)),(0,b.jsx)(`option`,{value:`custom`,children:`Custom...`})]}),c&&(0,b.jsx)(s,{id:`${e}-custom`,"aria-label":`Custom ${t.toLowerCase()}`,type:`number`,min:1,step:1,required:!0,value:n,disabled:i,placeholder:`Enter tokens`,"aria-describedby":`codex-context-help`,className:`min-h-11 sm:min-h-0 ${a?`h-7 text-[11px]`:``}`,onChange:e=>o(e.target.value)})]})}function w({config:e,compact:t,saving:n,onSave:r}){let[i,a]=(0,y.useState)(String(e?.model_context_window??``)),[o,s]=(0,y.useState)(String(e?.model_auto_compact_token_limit??``)),[c,l]=(0,y.useState)(null),u=t?`text-[11px]`:`text-sm`,d=t?`text-[9px]`:`text-[11px]`;async function f(e){e.preventDefault();let t=i.trim()?Number(i):null,n=o.trim()?Number(o):null;if([t,n].some(e=>e!==null&&(!Number.isSafeInteger(e)||e<=0))){l(`Enter positive whole numbers of tokens, or leave blank for Codex defaults.`);return}if(t!==null&&n!==null&&n>t){l(`Auto-compact threshold must not exceed the context window.`);return}l(null),await r({model_context_window:t,model_auto_compact_token_limit:n})}return(0,b.jsxs)(`form`,{onSubmit:f,className:`space-y-2 rounded-md border border-border p-3`,children:[(0,b.jsxs)(`div`,{className:`grid grid-cols-1 gap-3 sm:grid-cols-2`,children:[(0,b.jsx)(C,{id:`codex-context-window`,label:`Context window (tokens)`,value:i,presets:x,disabled:n,compact:t,onChange:e=>{a(e),l(null)}}),(0,b.jsx)(C,{id:`codex-compact-threshold`,label:`Auto-compact threshold (tokens)`,value:o,presets:S,disabled:n,compact:t,onChange:e=>{s(e),l(null)}})]}),(0,b.jsx)(`p`,{id:`codex-context-help`,className:`${d} text-muted-foreground`,children:`Choose Codex default to use Codex configuration and model defaults, or Custom to enter a value. Presets are shortcuts, not a list of limits supported by your model; increasing these values does not unlock a larger context window. Applies to new sessions and sessions resumed after a PPM restart.`}),c&&(0,b.jsx)(`p`,{role:`alert`,className:`${u} text-error`,children:c}),(0,b.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,b.jsx)(`a`,{href:`https://learn.chatgpt.com/docs/config-file/config-reference`,target:`_blank`,rel:`noreferrer`,className:`${d} text-primary underline`,children:`Codex context documentation`}),(0,b.jsx)(`button`,{type:`submit`,disabled:n,className:`min-h-11 sm:min-h-0 rounded-md border border-border px-3 py-1.5 hover:bg-surface-elevated disabled:opacity-50 ${u}`,children:n?`Saving...`:`Save context settings`})]})]})}var T=[{value:`low`,label:`Low`},{value:`medium`,label:`Medium`},{value:`high`,label:`High`},{value:`xhigh`,label:`Extra`},{value:`max`,label:`Max`}],E=[{value:`bypassPermissions`,label:`Bypass permissions (default)`},{value:`default`,label:`Ask before edits`},{value:`acceptEdits`,label:`Edit automatically`},{value:`plan`,label:`Plan mode`}],D={claude:`Claude`,cursor:`Cursor`,codex:`Codex`,gemini:`Gemini`};function O({compact:e}={}){let[t,n]=(0,y.useState)(null),[r,a]=(0,y.useState)(``),[x,S]=(0,y.useState)([]),[C,O]=(0,y.useState)(!1),[A,j]=(0,y.useState)(!1),[M,N]=(0,y.useState)(null),[P,F]=(0,y.useState)(0);(0,y.useEffect)(()=>{_().then(e=>{n(e),a(e.default_provider??`claude`)}).catch(e=>N(e.message))},[]),(0,y.useEffect)(()=>{r&&(O(!0),o.get(`/api/settings/ai/providers/${r}/models`).then(S).catch(()=>S([])).finally(()=>O(!1)))},[r]);let I=t?Object.keys(t.providers).filter(e=>e!==`mock`).map(e=>({id:e,name:D[e]??e})):[],L=t?.providers[r],R=L?.type===`agent-sdk`||!L?.type&&r===`claude`,z=async e=>{if(!t)return!1;j(!0),N(null);try{return n(await v(e)),F(e=>e+1),!0}catch(e){return N(e.message),!1}finally{j(!1)}},B=(e,t)=>z({providers:{[r]:{[e]:t}}}),V=e?`text-[11px]`:`text-sm`,H=e?`text-xs`:`text-sm`,U=e?`space-y-2`:`space-y-4`,W=e?`space-y-1.5`:`space-y-3`,G=e?`space-y-1`:`space-y-1.5`;if(!t)return(0,b.jsxs)(`div`,{className:W,children:[(0,b.jsx)(`h3`,{className:`${H} font-medium text-text-secondary`,children:`AI Settings`}),(0,b.jsx)(`p`,{className:`${V} text-text-subtle`,children:M?`Error: ${M}`:`Loading...`})]});let K=R?x:[{value:`__default__`,label:`Auto (default)`},...x];return(0,b.jsxs)(`div`,{className:U,children:[(0,b.jsx)(`h3`,{className:`${H} font-medium text-text-secondary`,children:`AI Settings`}),(0,b.jsxs)(`div`,{className:`flex items-start justify-between gap-3 rounded-md border border-border p-3`,children:[(0,b.jsxs)(`div`,{className:G,children:[(0,b.jsx)(g,{htmlFor:`ai-share-provider-context`,className:e?V:void 0,children:`Share rules and memory between providers`}),(0,b.jsx)(`p`,{id:`ai-share-provider-context-description`,className:`${e?`text-[9px]`:`text-[11px]`} text-muted-foreground`,children:`Share project rules and memory, plus global instruction files, across providers. Applies from the next project-chat message. Turning off keeps context already sent.`})]}),(0,b.jsx)(f,{id:`ai-share-provider-context`,"aria-describedby":`ai-share-provider-context-description`,checked:t.share_provider_context??!0,disabled:A,onCheckedChange:e=>z({share_provider_context:e})})]}),I.length>1&&(0,b.jsx)(`div`,{className:`flex gap-0.5 border-b border-border/50 -mx-1 px-1`,children:I.map(e=>(0,b.jsxs)(`button`,{onClick:()=>a(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,b.jsx)(p,{providerId:e.id}),(0,b.jsx)(`span`,{className:`capitalize`,children:e.name})]},e.id))}),(0,b.jsxs)(`div`,{className:W,children:[r===`codex`&&(0,b.jsxs)(`button`,{type:`button`,onClick:()=>h(`accounts`),className:`w-full flex items-center justify-between gap-2 rounded-md border border-border px-2.5 py-2 text-left cursor-pointer hover:bg-surface-elevated transition-colors`,children:[(0,b.jsx)(`span`,{className:`${V} text-text-secondary`,children:`Codex accounts & login`}),(0,b.jsx)(i,{className:`size-3.5 text-text-subtle shrink-0`})]}),x.length>0&&(0,b.jsxs)(`div`,{className:G,children:[(0,b.jsx)(g,{htmlFor:`ai-model`,className:e?V:void 0,children:`Model`}),(0,b.jsxs)(d,{value:R?L?.model??x[0]?.value:L?.model||`__default__`,onValueChange:e=>B(`model`,e===`__default__`?void 0:e),disabled:C,children:[(0,b.jsx)(m,{id:`ai-model`,className:`w-full ${e?`h-7 text-[11px]`:``}`,children:(0,b.jsx)(l,{placeholder:C?`Loading models...`:`Select model`})}),(0,b.jsx)(c,{className:`max-h-[300px]`,children:K.map(e=>(0,b.jsx)(u,{value:e.value,children:e.label},e.value))})]})]}),r===`codex`&&(0,b.jsx)(w,{config:L,compact:e,saving:A,onSave:e=>z({providers:{codex:e}})},JSON.stringify([L?.model_context_window,L?.model_auto_compact_token_limit])),R&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:G,children:[(0,b.jsx)(g,{htmlFor:`ai-base-url`,className:e?V:void 0,children:`Base URL`}),(0,b.jsx)(s,{id:`ai-base-url`,type:`url`,defaultValue:L?.base_url??``,placeholder:`https://api.anthropic.com (default)`,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{B(`base_url`,e.target.value.trim()||void 0)}},`baseurl-${r}-${P}`)]}),(0,b.jsxs)(`div`,{className:G,children:[(0,b.jsx)(g,{htmlFor:`ai-api-key`,className:e?V:void 0,children:`API Key / Token`}),(0,b.jsx)(s,{id:`ai-api-key`,type:`password`,defaultValue:L?.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(`••••`)||B(`api_key`,t||void 0)}},`apikey-${r}-${P}`),(0,b.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,b.jsxs)(`div`,{className:G,children:[(0,b.jsx)(g,{htmlFor:`ai-effort`,className:e?V:void 0,children:`Effort`}),(0,b.jsxs)(d,{value:L?.effort??`high`,onValueChange:e=>B(`effort`,e),children:[(0,b.jsx)(m,{id:`ai-effort`,className:`w-full ${e?`h-7 text-[11px]`:``}`,children:(0,b.jsx)(l,{})}),(0,b.jsx)(c,{children:T.map(e=>(0,b.jsx)(u,{value:e.value,children:e.label},e.value))})]})]}),(0,b.jsxs)(`div`,{className:G,children:[(0,b.jsx)(g,{htmlFor:`ai-max-turns`,className:e?V:void 0,children:`Max Turns (1-500)`}),(0,b.jsx)(s,{id:`ai-max-turns`,type:`number`,min:1,max:500,defaultValue:L?.max_turns??100,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{let t=parseInt(e.target.value);isNaN(t)||B(`max_turns`,t)}},`turns-${r}-${P}`)]}),(0,b.jsxs)(`div`,{className:G,children:[(0,b.jsx)(g,{htmlFor:`ai-budget`,className:e?V:void 0,children:`Max Budget (USD)`}),(0,b.jsx)(s,{id:`ai-budget`,type:`number`,step:.1,min:.01,max:50,defaultValue:L?.max_budget_usd??``,placeholder:`No limit`,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{let t=parseFloat(e.target.value);B(`max_budget_usd`,isNaN(t)?void 0:t)}},`budget-${r}-${P}`)]}),(0,b.jsxs)(`div`,{className:G,children:[(0,b.jsx)(g,{htmlFor:`ai-thinking`,className:e?V:void 0,children:`Thinking Budget (tokens)`}),(0,b.jsx)(s,{id:`ai-thinking`,type:`number`,min:0,defaultValue:L?.thinking_budget_tokens??``,placeholder:`Adaptive (model decides)`,className:e?`h-7 text-[11px]`:void 0,onBlur:e=>{let t=parseInt(e.target.value);B(`thinking_budget_tokens`,isNaN(t)?void 0:t)}},`thinking-${r}-${P}`)]}),(0,b.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(g,{htmlFor:`ai-agent-teams`,className:e?V:void 0,children:`Agent Teams`}),(0,b.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,b.jsx)(f,{id:`ai-agent-teams`,checked:L?.agent_teams??!1,onCheckedChange:e=>B(`agent_teams`,e)})]}),L?.agent_teams&&(0,b.jsx)(k,{compact:e}),(0,b.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(g,{htmlFor:`ai-context-1m`,className:e?V:void 0,children:`1M Context Window`}),(0,b.jsx)(`p`,{className:`${e?`text-[9px]`:`text-[11px]`} text-muted-foreground`,children:`Requires an entitled account (Max/Team/Enterprise) and an Opus 4 / Sonnet 4 model. Other accounts will error.`})]}),(0,b.jsx)(f,{id:`ai-context-1m`,checked:L?.context_1m??!1,onCheckedChange:e=>B(`context_1m`,e)})]}),(0,b.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(g,{htmlFor:`ai-inherit-mcp`,className:e?V:void 0,children:`Inherit Claude Code MCP`}),(0,b.jsx)(`p`,{className:`${e?`text-[9px]`:`text-[11px]`} text-muted-foreground`,children:`Auto-load MCP servers from Claude Code's ~/.claude.json (global + per-project). Your own MCP servers override inherited ones.`})]}),(0,b.jsx)(f,{id:`ai-inherit-mcp`,checked:L?.inherit_claude_mcp??!0,onCheckedChange:e=>B(`inherit_claude_mcp`,e)})]})]}),(0,b.jsxs)(`div`,{className:G,children:[(0,b.jsx)(g,{htmlFor:`ai-permission-mode`,className:e?V:void 0,children:`Default Permission Mode`}),(0,b.jsxs)(d,{value:L?.permission_mode??`bypassPermissions`,onValueChange:e=>B(`permission_mode`,e),children:[(0,b.jsx)(m,{id:`ai-permission-mode`,className:`w-full ${e?`h-7 text-[11px]`:``}`,children:(0,b.jsx)(l,{})}),(0,b.jsx)(c,{children:E.map(e=>(0,b.jsx)(u,{value:e.value,children:e.label},e.value))})]})]}),(0,b.jsxs)(`div`,{className:G,children:[(0,b.jsx)(g,{htmlFor:`ai-system-prompt`,className:e?V:void 0,children:`Additional Instructions`}),(0,b.jsx)(`textarea`,{id:`ai-system-prompt`,rows:e?3:4,defaultValue:L?.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=>{B(`system_prompt`,e.target.value.trim()||void 0)}},`sysprompt-${r}-${P}`)]})]}),A&&(0,b.jsx)(`p`,{className:`text-xs text-text-subtle`,children:`Saving...`}),M&&(0,b.jsx)(`p`,{className:`text-xs text-error`,children:M})]})}function k({compact:e}){let[t,n]=(0,y.useState)([]),[i,s]=(0,y.useState)(!1),[c,l]=(0,y.useState)(null),u=(0,y.useCallback)(async()=>{s(!0);try{n(await o.get(`/api/teams`)??[])}catch{}s(!1)},[]);(0,y.useEffect)(()=>{u()},[u]);let d=async e=>{try{await o.del(`/api/teams/${encodeURIComponent(e)}`),n(t=>t.filter(t=>t.name!==e)),l(null)}catch{}};return t.length===0&&!i?null:(0,b.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,b.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,b.jsxs)(g,{className:e?`text-[11px]`:void 0,children:[`Teams (`,t.length,`)`]}),(0,b.jsx)(`button`,{onClick:u,className:`text-text-subtle hover:text-foreground p-1`,"aria-label":`Refresh teams`,children:(0,b.jsx)(r,{className:`size-3 ${i?`animate-spin`:``}`})})]}),t.map(e=>(0,b.jsxs)(`div`,{className:`flex items-center justify-between p-2 rounded bg-surface-elevated text-xs`,children:[(0,b.jsxs)(`div`,{className:`min-w-0`,children:[(0,b.jsx)(`div`,{className:`font-medium truncate`,children:e.name}),e.description&&(0,b.jsx)(`div`,{className:`text-text-subtle truncate`,children:e.description}),(0,b.jsxs)(`div`,{className:`text-text-subtle`,children:[e.members?.length??e.memberCount??0,` members`,e.createdAt?` · ${new Date(e.createdAt).toLocaleDateString()}`:``]})]}),c===e.name?(0,b.jsxs)(`div`,{className:`flex gap-1 shrink-0 ml-2`,children:[(0,b.jsx)(`button`,{onClick:()=>d(e.name),className:`px-2 py-1 bg-error text-white rounded text-[10px]`,children:`Delete`}),(0,b.jsx)(`button`,{onClick:()=>l(null),className:`px-2 py-1 bg-panel-2 text-text rounded text-[10px]`,children:`Cancel`})]}):(0,b.jsx)(`button`,{onClick:()=>l(e.name),className:`shrink-0 text-text-subtle hover:text-error p-1 ml-2`,"aria-label":`Delete team ${e.name}`,children:(0,b.jsx)(a,{className:`size-3.5`})})]},e.name))]})}export{O as t};
@@ -1 +0,0 @@
1
- import"./vendor-markdown-CuWCHIVb.js";import"./vendor-ui-DmZ-Mb-H.js";import{i as e,n as t}from"./api-client-C1ZwRL4Y.js";export{t as api,e as projectUrl};