@blade-hq/agent-kit 0.4.5 → 0.4.7

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 (52) hide show
  1. package/README.md +39 -1
  2. package/dist/{SkillStatusBar-DItrW2vv.d.ts → SkillStatusBar-DQyipdzn.d.ts} +112 -8
  3. package/dist/chunk-2UP7MG3J.js +66 -0
  4. package/dist/chunk-2UP7MG3J.js.map +1 -0
  5. package/dist/chunk-4VWLTG5L.js +2984 -0
  6. package/dist/chunk-4VWLTG5L.js.map +1 -0
  7. package/dist/chunk-7LEKQI47.js +32 -0
  8. package/dist/chunk-7LEKQI47.js.map +1 -0
  9. package/dist/chunk-CGOQI7ZL.js +8124 -0
  10. package/dist/chunk-CGOQI7ZL.js.map +1 -0
  11. package/dist/chunk-DQCXSPHP.js +33 -0
  12. package/dist/chunk-DQCXSPHP.js.map +1 -0
  13. package/dist/chunk-I3FFV63W.js +30 -0
  14. package/dist/chunk-I3FFV63W.js.map +1 -0
  15. package/dist/chunk-J3XVFPOV.js +58 -0
  16. package/dist/chunk-J3XVFPOV.js.map +1 -0
  17. package/dist/chunk-JCJFFJ42.js +39 -0
  18. package/dist/chunk-JCJFFJ42.js.map +1 -0
  19. package/dist/chunk-OKQWPNE3.js +1077 -0
  20. package/dist/chunk-OKQWPNE3.js.map +1 -0
  21. package/dist/chunk-PZ5AY32C.js +10 -0
  22. package/dist/chunk-PZ5AY32C.js.map +1 -0
  23. package/dist/chunk-TC5BBLWO.js +29 -0
  24. package/dist/chunk-TC5BBLWO.js.map +1 -0
  25. package/dist/chunk-VD4CKRMT.js +127 -0
  26. package/dist/chunk-VD4CKRMT.js.map +1 -0
  27. package/dist/chunk-X6MEYCU7.js +1401 -0
  28. package/dist/chunk-X6MEYCU7.js.map +1 -0
  29. package/dist/client/index.js +24 -1052
  30. package/dist/client/index.js.map +1 -1
  31. package/dist/react/api/licenses.js +11 -1470
  32. package/dist/react/api/licenses.js.map +1 -1
  33. package/dist/react/api/vibe-coding.js +25 -1481
  34. package/dist/react/api/vibe-coding.js.map +1 -1
  35. package/dist/react/cards/register.js +45 -138
  36. package/dist/react/cards/register.js.map +1 -1
  37. package/dist/react/components/chat/index.d.ts +7 -21
  38. package/dist/react/components/chat/index.js +28 -11366
  39. package/dist/react/components/chat/index.js.map +1 -1
  40. package/dist/react/components/plan/index.js +135 -3054
  41. package/dist/react/components/plan/index.js.map +1 -1
  42. package/dist/react/components/session/index.js +21 -1499
  43. package/dist/react/components/session/index.js.map +1 -1
  44. package/dist/react/components/workspace/index.js +116 -1715
  45. package/dist/react/components/workspace/index.js.map +1 -1
  46. package/dist/react/devtools/bridge-devtools/index.js +8 -51
  47. package/dist/react/devtools/bridge-devtools/index.js.map +1 -1
  48. package/dist/react/index.d.ts +2 -2
  49. package/dist/react/index.js +625 -14035
  50. package/dist/react/index.js.map +1 -1
  51. package/dist/style.css +1 -1
  52. package/package.json +1 -1
@@ -1,2980 +1,61 @@
1
- // src/react/components/plan/debug-log.ts
2
- var events = [];
3
- var verbose = typeof window !== "undefined" && (window.location?.hostname === "localhost" || window.location?.hostname === "127.0.0.1");
4
- function exportPlanLog() {
5
- return [...events];
6
- }
7
- function downloadPlanLog() {
8
- const blob = new Blob([JSON.stringify(events, null, 2)], { type: "application/json" });
9
- const url = URL.createObjectURL(blob);
10
- const a = document.createElement("a");
11
- a.href = url;
12
- a.download = `plan-timeline-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace(/:/g, "-")}.json`;
13
- a.click();
14
- URL.revokeObjectURL(url);
15
- }
16
-
17
- // src/react/components/plan/extract-plan-messages.ts
18
- function parseModeChange(message) {
19
- if (message.kind !== "mode_change" || typeof message.content !== "string") {
20
- return null;
21
- }
22
- try {
23
- const parsed = JSON.parse(message.content);
24
- if (typeof parsed.from === "string" && typeof parsed.to === "string") {
25
- return { from: parsed.from, to: parsed.to };
26
- }
27
- } catch {
28
- }
29
- return null;
30
- }
31
- function isPlanningEnter(message) {
32
- if (message.kind === "planning_enter") {
33
- return true;
34
- }
35
- const modeChange = parseModeChange(message);
36
- return modeChange?.to === "planning";
37
- }
38
- function isPlanningExit(message) {
39
- if (message.kind === "planning_exit") {
40
- return true;
41
- }
42
- const modeChange = parseModeChange(message);
43
- return modeChange?.from === "planning";
44
- }
45
- function extractLatestPlanMessages(messages) {
46
- const safeMessages = Array.isArray(messages) ? messages : [];
47
- let enterIndex = -1;
48
- let exitIndex = -1;
49
- for (let i = safeMessages.length - 1; i >= 0; i -= 1) {
50
- const message = safeMessages[i];
51
- if (isPlanningExit(message) && exitIndex === -1) {
52
- exitIndex = i;
53
- continue;
54
- }
55
- if (isPlanningEnter(message)) {
56
- enterIndex = i;
57
- break;
58
- }
59
- }
60
- if (enterIndex === -1) {
61
- return [];
62
- }
63
- return safeMessages.slice(enterIndex + 1).filter((message, offset) => {
64
- const absoluteIndex = enterIndex + 1 + offset;
65
- if (isPlanningEnter(message) || isPlanningExit(message)) {
66
- return false;
67
- }
68
- if (exitIndex !== -1 && absoluteIndex > exitIndex) {
69
- return message.kind === "plan_status";
70
- }
71
- return true;
72
- });
73
- }
74
-
75
- // src/react/components/plan/PlanSummaryCard.tsx
76
- import { CheckCircle2, ChevronRight, PencilLine, Play, Sparkles } from "lucide-react";
77
- import { useMemo as useMemo4, useState as useState4 } from "react";
78
-
79
- // src/react/lib/utils.ts
80
- import { clsx } from "clsx";
81
- import { twMerge } from "tailwind-merge";
82
- function cn(...inputs) {
83
- return twMerge(clsx(inputs));
84
- }
85
- async function copyToClipboard(text) {
86
- if (navigator.clipboard) {
87
- try {
88
- await navigator.clipboard.writeText(text);
89
- return true;
90
- } catch {
91
- }
92
- }
93
- const textarea = document.createElement("textarea");
94
- textarea.value = text;
95
- textarea.style.position = "fixed";
96
- textarea.style.opacity = "0";
97
- document.body.appendChild(textarea);
98
- textarea.select();
99
- try {
100
- return document.execCommand("copy");
101
- } finally {
102
- document.body.removeChild(textarea);
103
- }
104
- }
105
-
106
- // src/react/stores/ui-store.ts
107
- import { create } from "zustand";
108
-
109
- // src/react/stores/client-aware.ts
110
- function createClientActions(set) {
111
- return {
112
- _client: null,
113
- setClient: (client) => set({ _client: client })
114
- };
115
- }
116
-
117
- // src/react/stores/ui-store.ts
118
- var isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
119
- function resolveEffectiveTheme(theme) {
120
- if (theme !== "system") return theme;
121
- return isBrowser && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
122
- }
123
- function applyTheme(theme) {
124
- if (!isBrowser) return;
125
- const effective = resolveEffectiveTheme(theme);
126
- document.documentElement.setAttribute("data-theme", effective);
127
- }
128
- var storedTheme = isBrowser ? localStorage.getItem("blade-theme") ?? "light" : "light";
129
- applyTheme(storedTheme);
130
- if (isBrowser) {
131
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
132
- const current = useUiStore?.getState?.()?.theme;
133
- if (current === "system") applyTheme("system");
134
- });
135
- }
136
- function removeArtifactAtIndex(state, index) {
137
- const next = state.artifacts.filter((_, i) => i !== index);
138
- let nextActive = state.activeArtifactIndex;
139
- if (next.length === 0) {
140
- return { artifacts: [], activeArtifactIndex: -1, rightPanelCollapsed: true };
141
- }
142
- if (index < nextActive) {
143
- nextActive -= 1;
144
- } else if (index === nextActive) {
145
- nextActive = Math.min(index, next.length - 1);
146
- }
147
- return { artifacts: next, activeArtifactIndex: nextActive };
148
- }
149
- function upsertArtifactState(state, target, options) {
150
- const reveal = options?.reveal ?? true;
151
- const activate = options?.activate ?? true;
152
- const targetKey = target.key ?? target.title;
153
- const applyUiState = (partial) => ({
154
- ...partial,
155
- ...reveal ? { rightPanelCollapsed: false, activeRightTab: "preview" } : {}
156
- });
157
- const existing = state.artifacts.findIndex((artifact) => targetKey && (artifact.key ?? artifact.title) === targetKey);
158
- if (existing >= 0) {
159
- const updated = [...state.artifacts];
160
- updated[existing] = target;
161
- return applyUiState({
162
- artifacts: updated,
163
- activeArtifactIndex: activate ? existing : state.activeArtifactIndex
164
- });
165
- }
166
- const next = [...state.artifacts, target];
167
- return applyUiState({
168
- artifacts: next,
169
- activeArtifactIndex: activate ? next.length - 1 : state.activeArtifactIndex >= 0 ? state.activeArtifactIndex : 0
170
- });
171
- }
172
- var useUiStore = create()((set) => ({
173
- ...createClientActions(set),
174
- leftPanelSize: 20,
175
- rightPanelSize: 25,
176
- leftPanelCollapsed: false,
177
- rightPanelCollapsed: false,
178
- activeRightTab: "situation",
179
- artifacts: [],
180
- activeArtifactIndex: -1,
181
- theme: storedTheme,
182
- setLeftPanelSize: (size) => set({ leftPanelSize: size }),
183
- setRightPanelSize: (size) => set({ rightPanelSize: size }),
184
- setLeftPanelCollapsed: (collapsed) => set({ leftPanelCollapsed: collapsed }),
185
- setRightPanelCollapsed: (collapsed) => set({ rightPanelCollapsed: collapsed }),
186
- toggleLeftPanel: () => set((s) => ({ leftPanelCollapsed: !s.leftPanelCollapsed })),
187
- toggleRightPanel: () => set((s) => ({ rightPanelCollapsed: !s.rightPanelCollapsed })),
188
- setActiveRightTab: (tab) => set({ activeRightTab: tab }),
189
- pushArtifact: (target) => set((state) => upsertArtifactState(state, target)),
190
- upsertArtifact: (target, options) => set((state) => upsertArtifactState(state, target, options)),
191
- setActiveArtifact: (index) => set({ activeArtifactIndex: index }),
192
- closeArtifact: (index) => set((state) => removeArtifactAtIndex(state, index)),
193
- removeArtifactByKey: (key) => set((state) => {
194
- const index = state.artifacts.findIndex((artifact) => (artifact.key ?? artifact.title) === key);
195
- if (index < 0) return state;
196
- return removeArtifactAtIndex(state, index);
197
- }),
198
- clearArtifacts: () => set({ artifacts: [], activeArtifactIndex: -1 }),
199
- setPreviewTarget: (target) => set(() => {
200
- if (target === null) {
201
- return { artifacts: [], activeArtifactIndex: -1 };
202
- }
203
- return {
204
- artifacts: [target],
205
- activeArtifactIndex: 0,
206
- rightPanelCollapsed: false,
207
- activeRightTab: "preview"
208
- };
209
- }),
210
- setTheme: (theme) => {
211
- localStorage.setItem("blade-theme", theme);
212
- applyTheme(theme);
213
- set({ theme });
214
- }
215
- }));
216
-
217
- // src/react/components/chat/AskUserQuestionBlock.tsx
218
- import { Check as Check2, Loader2, MessageSquareMore } from "lucide-react";
219
- import { useEffect as useEffect3, useMemo as useMemo3, useState as useState3 } from "react";
220
-
221
- // src/react/components/markdown/MarkdownContent.tsx
222
- import { mermaid } from "@streamdown/mermaid";
223
- import { Check, Copy, Download } from "lucide-react";
224
- import {
225
- useEffect as useEffect2,
226
- useMemo as useMemo2,
227
- useRef,
228
- useState as useState2
229
- } from "react";
230
- import { Streamdown } from "streamdown";
231
-
232
- // src/client/resources/models.ts
233
- import { type } from "arktype";
234
- var ModelOption = type({
235
- id: "string",
236
- label: "string"
237
- });
238
- var ModelsConfig = type({
239
- default: "string",
240
- models: ModelOption.array()
241
- });
242
-
243
- // src/client/socket.ts
244
- import { io } from "socket.io-client";
245
-
246
- // src/react/schemas/partner-skill.ts
247
- import { type as type2 } from "arktype";
248
- var PartnerSkillName = type2("/^[a-z0-9-]+\\/[a-z0-9-]+$/");
249
- var PartnerSkillFile = type2({
250
- path: "string > 0",
251
- content: "string"
252
- });
253
- var PartnerSkillInstallPayload = type2({
254
- name: PartnerSkillName,
255
- files: PartnerSkillFile.array().atLeastLength(1)
256
- });
257
- var PartnerSkillInstallResult = type2({
258
- name: PartnerSkillName,
259
- skill_dir: "string",
260
- file_count: "number.integer >= 0",
261
- overwritten: "boolean"
262
- });
263
-
264
- // src/react/stores/ui-bridge-store.ts
265
- import { create as create2 } from "zustand";
266
- function buildSignalId() {
267
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
268
- return crypto.randomUUID();
269
- }
270
- return `bridge-${Date.now()}-${Math.random().toString(36).slice(2)}`;
271
- }
272
- function clearSignalRecord(record, sessionId) {
273
- if (!(sessionId in record)) {
274
- return record;
275
- }
276
- const next = { ...record };
277
- delete next[sessionId];
278
- return next;
279
- }
280
- var useUiBridgeStore = create2()((set, get) => ({
281
- ...createClientActions(set),
282
- pendingContexts: {},
283
- draftAppends: {},
284
- sendRequests: {},
285
- addPendingContext: (sessionId, context) => set((state) => ({
286
- pendingContexts: {
287
- ...state.pendingContexts,
288
- [sessionId]: [
289
- ...state.pendingContexts[sessionId] ?? [],
290
- {
291
- id: buildSignalId(),
292
- label: context.label,
293
- content: context.content
294
- }
295
- ]
296
- }
297
- })),
298
- removePendingContext: (sessionId, contextId) => set((state) => {
299
- const contexts = state.pendingContexts[sessionId];
300
- if (!contexts?.length) {
301
- return state;
302
- }
303
- const nextContexts = contexts.filter((context) => context.id !== contextId);
304
- if (nextContexts.length === contexts.length) {
305
- return state;
306
- }
307
- return {
308
- pendingContexts: nextContexts.length > 0 ? {
309
- ...state.pendingContexts,
310
- [sessionId]: nextContexts
311
- } : clearSignalRecord(state.pendingContexts, sessionId)
312
- };
313
- }),
314
- consumePendingContexts: (sessionId) => {
315
- const signals = get().pendingContexts[sessionId] ?? [];
316
- if (signals.length === 0) return [];
317
- set((state) => ({
318
- pendingContexts: clearSignalRecord(state.pendingContexts, sessionId)
319
- }));
320
- return signals;
321
- },
322
- clearPendingContexts: (sessionId) => set((state) => ({
323
- pendingContexts: clearSignalRecord(state.pendingContexts, sessionId)
324
- })),
325
- addDraftAppend: (sessionId, text) => set((state) => ({
326
- draftAppends: {
327
- ...state.draftAppends,
328
- [sessionId]: [
329
- ...state.draftAppends[sessionId] ?? [],
330
- {
331
- id: buildSignalId(),
332
- text
333
- }
334
- ]
335
- }
336
- })),
337
- consumeDraftAppends: (sessionId) => {
338
- const signals = get().draftAppends[sessionId] ?? [];
339
- if (signals.length === 0) return [];
340
- set((state) => ({
341
- draftAppends: clearSignalRecord(state.draftAppends, sessionId)
342
- }));
343
- return signals;
344
- },
345
- clearDraftAppends: (sessionId) => set((state) => ({
346
- draftAppends: clearSignalRecord(state.draftAppends, sessionId)
347
- })),
348
- addSendRequest: (sessionId) => set((state) => ({
349
- sendRequests: {
350
- ...state.sendRequests,
351
- [sessionId]: [
352
- ...state.sendRequests[sessionId] ?? [],
353
- {
354
- id: buildSignalId()
355
- }
356
- ]
357
- }
358
- })),
359
- consumeSendRequests: (sessionId) => {
360
- const signals = get().sendRequests[sessionId] ?? [];
361
- if (signals.length === 0) return [];
362
- set((state) => ({
363
- sendRequests: clearSignalRecord(state.sendRequests, sessionId)
364
- }));
365
- return signals;
366
- },
367
- clearSendRequests: (sessionId) => set((state) => ({
368
- sendRequests: clearSignalRecord(state.sendRequests, sessionId)
369
- })),
370
- clearSession: (sessionId) => set((state) => ({
371
- pendingContexts: clearSignalRecord(state.pendingContexts, sessionId),
372
- draftAppends: clearSignalRecord(state.draftAppends, sessionId),
373
- sendRequests: clearSignalRecord(state.sendRequests, sessionId)
374
- }))
375
- }));
376
-
377
- // src/react/lib/chat.ts
378
- function normalizeMessageContent(content) {
379
- if (typeof content === "string") return content;
380
- if (Array.isArray(content)) return content;
381
- return String(content ?? "");
382
- }
383
-
384
- // src/react/stores/auth-store.ts
385
- import { create as create6 } from "zustand";
386
- import { createJSONStorage, persist } from "zustand/middleware";
387
-
388
- // src/react/api/auth.ts
389
- var r = () => getClient().auth;
390
- var getMe = (...args) => r().getMe(...args);
391
- var logout = (...args) => r().logout(...args);
392
-
393
- // src/react/sockets/socket-state.ts
394
- var agentSocket = null;
395
-
396
- // src/react/stores/session-store.ts
397
- import { create as create5 } from "zustand";
398
-
399
- // src/react/api/sessions.ts
400
- var r2 = () => getClient().sessions;
401
- var listSessions = (...args) => r2().listSessions(...args);
402
- var createSession = (...args) => r2().createSession(...args);
403
- var getSession = (...args) => r2().getSession(...args);
404
- var pinSession = (...args) => r2().pinSession(...args);
405
- var updateSharing = (...args) => r2().updateSharing(...args);
406
- var getSessionTasks = (...args) => r2().getSessionTasks(...args);
407
- var getSessionTurns = (...args) => r2().getSessionTurns(...args);
408
- var deleteSession = (...args) => r2().deleteSession(...args);
409
-
410
- // src/react/stores/chat-store.ts
411
- import { create as create3 } from "zustand";
412
-
413
- // src/react/components/chat/display-utils.ts
414
- var TOOL_NAME_ALIASES = {
415
- agent: "Agent",
416
- ask_user_question: "AskUserQuestion",
417
- bash: "Bash",
418
- bg_bash: "BgBash",
419
- edit: "Edit",
420
- exit_plan_mode: "ExitPlanMode",
421
- file_edit: "Edit",
422
- file_read: "Read",
423
- file_write: "Write",
424
- finish_task: "FinishTask",
425
- get_skill_content: "GetSkillContent",
426
- glob: "Glob",
427
- grep: "Grep",
428
- list_skill_tools: "ListSkillTools",
429
- load_skill_tools: "LoadSkillTools",
430
- ls: "Ls",
431
- read: "Read",
432
- run_skill_tool: "RunSkillTool",
433
- search_skills: "SearchSkills",
434
- web_fetch: "WebFetch",
435
- web_search: "WebSearch",
436
- write: "Write"
437
- };
438
- var TOOL_DISPLAY_LABELS = {
439
- Bash: "\u6267\u884C\u547D\u4EE4",
440
- BgBash: "\u540E\u53F0\u6267\u884C\u547D\u4EE4",
441
- Read: "\u8BFB\u53D6\u6587\u4EF6",
442
- Write: "\u5199\u5165\u6587\u4EF6",
443
- Edit: "\u7F16\u8F91\u6587\u4EF6",
444
- Ls: "\u5217\u51FA\u76EE\u5F55",
445
- Glob: "\u5339\u914D\u6587\u4EF6",
446
- Grep: "\u641C\u7D22\u6587\u672C",
447
- WebSearch: "\u641C\u7D22\u7F51\u9875",
448
- WebFetch: "\u6574\u7406\u7F51\u9875\u5185\u5BB9",
449
- Agent: "\u6D3E\u751F\u5B50\u667A\u80FD\u4F53",
450
- AskUserQuestion: "\u5411\u7528\u6237\u63D0\u95EE",
451
- SearchSkills: "\u641C\u7D22\u6280\u80FD",
452
- GetSkillContent: "\u8BFB\u53D6\u6280\u80FD",
453
- ListSkillTools: "\u67E5\u770B\u5DE5\u5177\u5217\u8868",
454
- LoadSkillTools: "\u52A0\u8F7D\u6280\u80FD",
455
- RunSkillTool: "\u6267\u884C\u6280\u80FD\u5DE5\u5177",
456
- FinishTask: "\u4EFB\u52A1\u5B8C\u6210",
457
- ExitPlanMode: "\u63D0\u4EA4\u8BA1\u5212",
458
- ListSessions: "\u5217\u51FA\u5386\u53F2\u4F1A\u8BDD",
459
- GetSessionHistory: "\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2"
460
- };
461
- var GENERIC_DISPLAY_NAMES = new Set(Object.values(TOOL_DISPLAY_LABELS));
462
- function formatToolName(name) {
463
- const trimmed = name.trim();
464
- if (!trimmed) return name;
465
- const stripped = trimmed.split(":").pop()?.split("/").pop()?.split(".").pop()?.trim() || trimmed;
466
- const normalized = stripped.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
467
- return TOOL_NAME_ALIASES[normalized] ?? stripped;
468
- }
469
-
470
- // src/react/stores/chat-store.ts
471
- var _getActiveSessionId = null;
472
- function setChatStoreSessionAccessor(fn) {
473
- _getActiveSessionId = fn;
474
- }
475
- function parseAgentDescription(argumentsJson) {
476
- try {
477
- return JSON.parse(argumentsJson)?.description ?? "\u5B50\u667A\u80FD\u4F53";
478
- } catch {
479
- return "\u5B50\u667A\u80FD\u4F53";
480
- }
481
- }
482
- function inferLoopStatusFromMessages(messages) {
483
- const toolCalls = messages.flatMap((message) => message.tool_calls ?? []);
484
- if (messages.some((message) => message.status === "streaming")) return "running";
485
- if (toolCalls.some((toolCall) => toolCall.status === "awaiting_answer")) return "awaiting_answer";
486
- if (toolCalls.some((toolCall) => toolCall.status === "error")) return "error";
487
- if (toolCalls.some((toolCall) => toolCall.status === "cancelled")) return "cancelled";
488
- if (toolCalls.some((toolCall) => toolCall.status === "pending")) return "running";
489
- return "done";
490
- }
491
- function inferLoopStatusFromTurns(turns, messages) {
492
- const latestAgentNotification = [...turns].reverse().flatMap((turn) => turn.blocks).find((block) => {
493
- if (block.type !== "system_notification" || !isRecord(block.content)) return false;
494
- return block.content.notification_type === "agent:start" || block.content.notification_type === "agent:end";
495
- });
496
- if (latestAgentNotification?.type === "system_notification" && isRecord(latestAgentNotification.content)) {
497
- const notificationType = latestAgentNotification.content.notification_type;
498
- const status = latestAgentNotification.content.status;
499
- if (notificationType === "agent:start" || status === "running") return "running";
500
- if (status === "error") return "error";
501
- if (status === "cancelled") return "cancelled";
502
- }
503
- return inferLoopStatusFromMessages(messages);
504
- }
505
- function isRecord(value) {
506
- return typeof value === "object" && value !== null && !Array.isArray(value);
507
- }
508
- function parentForkToolCallIdFromTurn(turn) {
509
- if (typeof turn.parent_fork_tool_call_id === "string" && turn.parent_fork_tool_call_id.length > 0) {
510
- return turn.parent_fork_tool_call_id;
511
- }
512
- for (const block of turn.blocks) {
513
- if (block.type !== "system_notification" || !isRecord(block.content)) continue;
514
- const metadata = block.content.metadata;
515
- if (!isRecord(metadata)) continue;
516
- const parentId = metadata.parent_fork_tool_call_id;
517
- if (typeof parentId === "string" && parentId.length > 0) return parentId;
518
- }
519
- return null;
520
- }
521
- function buildMessageContent(turn) {
522
- const textBlocks = turn.blocks.filter((block) => block.type === "text");
523
- if (textBlocks.length === 0) return "";
524
- if (textBlocks.length === 1) return normalizeMessageContent(textBlocks[0].content);
525
- return textBlocks.map((block) => {
526
- if (typeof block.content === "string") return block.content;
527
- return JSON.stringify(block.content);
528
- }).join("");
529
- }
530
- function buildReasoning(turn) {
531
- const thinking = turn.blocks.filter((block) => block.type === "thinking").map((block) => typeof block.content === "string" ? block.content : JSON.stringify(block.content)).filter(Boolean);
532
- if (thinking.length === 0) return void 0;
533
- return thinking.join("\n\n");
534
- }
535
- function isModeChangeContent(value) {
536
- return typeof value === "object" && value !== null && typeof value.from === "string" && typeof value.to === "string";
537
- }
538
- function extractModeFromBlocks(blocks) {
539
- const modeBlock = blocks.find((block) => block.type === "mode_change");
540
- if (modeBlock && isModeChangeContent(modeBlock.content)) {
541
- return modeBlock.content.to === "planning" || modeBlock.content.to === "executing" ? modeBlock.content.to : null;
542
- }
543
- if (blocks.some((block) => block.type === "planning_enter")) return "planning";
544
- if (blocks.some((block) => block.type === "planning_exit")) return "executing";
545
- return null;
546
- }
547
- function projectionToMessage(turn) {
548
- if (turn.kind === "compaction" && turn.compaction_id) {
549
- return {
550
- role: "assistant",
551
- content: turn.summary_preview ?? "",
552
- kind: "compaction",
553
- loop_name: turn.loop_id,
554
- entry_id: turn.turn_id,
555
- status: turn.status,
556
- compaction: {
557
- compaction_id: turn.compaction_id,
558
- summary_preview: turn.summary_preview,
559
- summary_full: turn.summary_full,
560
- archived_count: turn.archived_count,
561
- archived_files: turn.archived_files,
562
- archived_tool_calls: turn.archived_tool_calls,
563
- tokens_before: turn.tokens_before,
564
- tokens_after: turn.tokens_after,
565
- saved_ratio: turn.saved_ratio,
566
- trigger: turn.trigger,
567
- failure_reason: turn.failure_reason,
568
- fallback_applied: turn.fallback_applied
569
- }
570
- };
571
- }
572
- const planningBlock = turn.blocks.find(
573
- (block) => block.type === "mode_change" || block.type === "planning_enter" || block.type === "planning_exit" || block.type === "plan_status"
574
- );
575
- if (planningBlock) {
576
- if (planningBlock.type === "plan_status") {
577
- return {
578
- role: "tool",
579
- content: typeof planningBlock.content === "string" ? planningBlock.content : JSON.stringify(planningBlock.content ?? {}, null, 2),
580
- kind: "plan_status",
581
- loop_name: turn.loop_id,
582
- entry_id: turn.turn_id,
583
- status: turn.status
584
- };
585
- }
586
- return {
587
- role: "assistant",
588
- content: planningBlock.type === "mode_change" ? typeof planningBlock.content === "string" ? planningBlock.content : JSON.stringify(planningBlock.content ?? {}) : "",
589
- kind: planningBlock.type,
590
- loop_name: turn.loop_id,
591
- entry_id: turn.turn_id,
592
- status: turn.status
593
- };
594
- }
595
- if (turn.blocks.some((block) => block.type === "ask_user_answer")) {
596
- return null;
597
- }
598
- const content = buildMessageContent(turn);
599
- const reasoning = buildReasoning(turn);
600
- const toolCalls = turn.tool_calls.length > 0 ? turn.tool_calls.map((toolCall) => ({
601
- id: toolCall.id,
602
- name: toolCall.tool_name,
603
- display_name: toolCall.display_name,
604
- arguments: toolCall.arguments,
605
- result: toolCall.result ?? void 0,
606
- pending_question_ref: toolCall.pending_question_ref ?? void 0,
607
- status: toolCall.status === "pending" || toolCall.status === "awaiting_answer" || toolCall.status === "done" || toolCall.status === "error" || toolCall.status === "cancelled" ? toolCall.status : "pending",
608
- ...typeof toolCall.duration_ms === "number" ? { duration_ms: toolCall.duration_ms } : {}
609
- })) : void 0;
610
- if (turn.role === "system" && !content && !toolCalls?.length) {
611
- return null;
612
- }
613
- return {
614
- role: turn.role === "system" ? "assistant" : turn.role,
615
- content,
616
- blocks: turn.blocks,
617
- ...reasoning ? { reasoning } : {},
618
- ...toolCalls ? { tool_calls: toolCalls } : {},
619
- loop_name: turn.loop_id,
620
- entry_id: turn.turn_id,
621
- status: turn.status,
622
- ...typeof turn.duration_ms === "number" ? { duration_ms: turn.duration_ms } : {},
623
- ...turn.started_at ? { timestamp: turn.started_at } : {},
624
- ...turn.memory_refs?.length ? { memory_refs: turn.memory_refs } : {}
625
- };
626
- }
627
- function rebuildAgentLoops(turns) {
628
- const messages = turns.map(projectionToMessage).filter(Boolean);
629
- const childLoopNames = [...new Set(turns.map((turn) => turn.loop_id).filter((name) => name !== "root"))];
630
- if (childLoopNames.length === 0) return {};
631
- const agentToolCalls = messages.filter((message) => message.role === "assistant" && (message.loop_name ?? "root") === "root").flatMap((message) => message.tool_calls ?? []).filter((toolCall) => formatToolName(toolCall.name) === "Agent");
632
- const loops = {};
633
- const agentToolCallsById = new Map(agentToolCalls.map((toolCall) => [toolCall.id, toolCall]));
634
- const explicitParentToolCallIds = new Set(
635
- turns.map(parentForkToolCallIdFromTurn).filter((id) => id !== null)
636
- );
637
- const usedToolCallIds = /* @__PURE__ */ new Set();
638
- for (const loopName of childLoopNames) {
639
- const loopMessages = messages.filter((message) => (message.loop_name ?? "root") === loopName);
640
- const loopTurns = turns.filter((turn) => turn.loop_id === loopName);
641
- const parentToolCallId = loopTurns.map(parentForkToolCallIdFromTurn).find(Boolean);
642
- const explicitToolCall = parentToolCallId && !usedToolCallIds.has(parentToolCallId) ? agentToolCallsById.get(parentToolCallId) ?? null : null;
643
- const fallbackToolCall = explicitToolCall === null ? agentToolCalls.find(
644
- (toolCall2) => !usedToolCallIds.has(toolCall2.id) && !explicitParentToolCallIds.has(toolCall2.id)
645
- ) : null;
646
- const toolCall = explicitToolCall ?? fallbackToolCall;
647
- if (!toolCall) continue;
648
- usedToolCallIds.add(toolCall.id);
649
- loops[loopName] = {
650
- toolCallId: toolCall.id,
651
- description: parseAgentDescription(toolCall.arguments),
652
- status: inferLoopStatusFromTurns(loopTurns, loopMessages)
653
- };
654
- }
655
- return loops;
656
- }
657
- function applyPlanningSideEffects(sessionId, turns) {
658
- const latestMode = [...turns].reverse().map((turn) => extractModeFromBlocks(turn.blocks)).find((mode) => mode !== null);
659
- if (latestMode !== "planning") return;
660
- if (_getActiveSessionId?.() !== sessionId) return;
661
- const ui = useUiStore.getState();
662
- ui.setActiveRightTab("situation");
663
- if (ui.rightPanelCollapsed) {
664
- ui.toggleRightPanel();
665
- }
666
- }
667
- function materialize(turns) {
668
- const messages = turns.map(projectionToMessage).filter((message) => message !== null);
669
- const activeCompaction = [...turns].reverse().find(
670
- (turn) => turn.kind === "compaction" && turn.status === "streaming" && typeof turn.compaction_id === "string"
671
- );
672
- return {
673
- messages,
674
- agentLoops: rebuildAgentLoops(turns),
675
- activeCompaction: activeCompaction ? {
676
- turn_id: activeCompaction.turn_id,
677
- status: activeCompaction.status,
678
- compaction_id: activeCompaction.compaction_id,
679
- summary_preview: activeCompaction.summary_preview,
680
- summary_full: activeCompaction.summary_full,
681
- archived_count: activeCompaction.archived_count,
682
- archived_files: activeCompaction.archived_files,
683
- archived_tool_calls: activeCompaction.archived_tool_calls,
684
- tokens_before: activeCompaction.tokens_before,
685
- tokens_after: activeCompaction.tokens_after,
686
- saved_ratio: activeCompaction.saved_ratio,
687
- trigger: activeCompaction.trigger,
688
- failure_reason: activeCompaction.failure_reason,
689
- fallback_applied: activeCompaction.fallback_applied
690
- } : null
691
- };
692
- }
693
- var ERROR_ANCHOR_PREFIX = "error-anchor:";
694
- function updateSessionState(state, sessionId, turns) {
695
- const orderedTurns = [...turns].sort((left, right) => left.sequence - right.sequence);
696
- const { messages, agentLoops, activeCompaction } = materialize(orderedTurns);
697
- applyPlanningSideEffects(sessionId, orderedTurns);
698
- const lastTurnId = orderedTurns[orderedTurns.length - 1]?.turn_id ?? null;
699
- const preservedErrors = lastTurnId ? (state.messages[sessionId] ?? []).filter(
700
- (m) => m.role === "error" && typeof m.entry_id === "string" && m.entry_id.startsWith(`${ERROR_ANCHOR_PREFIX}${lastTurnId}:`)
701
- ) : [];
702
- const mergedMessages = preservedErrors.length > 0 ? [...messages, ...preservedErrors] : messages;
703
- return {
704
- turns: { ...state.turns, [sessionId]: orderedTurns },
705
- messages: { ...state.messages, [sessionId]: mergedMessages },
706
- agentLoops: { ...state.agentLoops, [sessionId]: agentLoops },
707
- activeCompactions: { ...state.activeCompactions, [sessionId]: activeCompaction }
708
- };
709
- }
710
- var useChatStore = create3()((set) => ({
711
- ...createClientActions(set),
712
- turns: {},
713
- messages: {},
714
- askAnswers: {},
715
- isStreaming: {},
716
- agentLoops: {},
717
- activeCompactions: {},
718
- addUserMessage: (sessionId, content) => {
719
- set((state) => {
720
- const existing = state.turns[sessionId] ?? [];
721
- const turnId = `local-user-${Date.now()}`;
722
- const optimisticTurn = {
723
- id: turnId,
724
- sequence: Math.max(0, ...existing.map((turn) => turn.sequence)) + 1,
725
- turn_id: turnId,
726
- loop_id: "root",
727
- role: "user",
728
- status: "completed",
729
- blocks: [{ type: "text", content }],
730
- tool_calls: [],
731
- model: null,
732
- usage: null,
733
- duration_ms: 0
734
- };
735
- return updateSessionState(state, sessionId, [...existing, optimisticTurn]);
736
- });
737
- },
738
- setTurns: (sessionId, turns) => {
739
- set((state) => updateSessionState(state, sessionId, [...turns]));
740
- },
741
- upsertTurn: (sessionId, turn) => {
742
- set((state) => {
743
- const existing = [...state.turns[sessionId] ?? []];
744
- const index = existing.findIndex((item) => item.turn_id === turn.turn_id);
745
- if (index >= 0) {
746
- existing[index] = turn;
747
- } else {
748
- existing.push(turn);
749
- }
750
- return {
751
- ...updateSessionState(state, sessionId, existing)
752
- };
753
- });
754
- },
755
- applyTurnPatch: (sessionId, patch) => {
756
- set((state) => {
757
- const turn = patch.data.turn;
758
- if (!turn) return state;
759
- const existing = [...state.turns[sessionId] ?? []];
760
- const index = existing.findIndex((item) => item.turn_id === turn.turn_id);
761
- const lastSequence = index >= 0 ? existing[index].sequence : null;
762
- if (lastSequence !== null && patch.sequence <= lastSequence) {
763
- return state;
764
- }
765
- const nextTurn = {
766
- ...turn,
767
- sequence: patch.sequence
768
- };
769
- if (index >= 0) {
770
- existing[index] = nextTurn;
771
- } else {
772
- existing.push(nextTurn);
773
- }
774
- return {
775
- ...updateSessionState(state, sessionId, existing)
776
- };
777
- });
778
- },
779
- addErrorMessage: (sessionId, content) => {
780
- set((state) => {
781
- const turns = state.turns[sessionId] ?? [];
782
- const anchorTurnId = turns[turns.length - 1]?.turn_id ?? null;
783
- const entry_id = anchorTurnId ? `${ERROR_ANCHOR_PREFIX}${anchorTurnId}:${Date.now()}` : void 0;
784
- return {
785
- messages: {
786
- ...state.messages,
787
- [sessionId]: [
788
- ...state.messages[sessionId] ?? [],
789
- { role: "error", content, loop_name: "root", entry_id }
790
- ]
791
- }
792
- };
793
- });
794
- },
795
- markInterrupted: (sessionId) => {
796
- set((state) => {
797
- const turns = (state.turns[sessionId] ?? []).map((turn) => {
798
- if (turn.status !== "streaming") return turn;
799
- return {
800
- ...turn,
801
- status: "interrupted",
802
- tool_calls: turn.tool_calls.map(
803
- (toolCall) => toolCall.status === "pending" || toolCall.status === "awaiting_answer" ? { ...toolCall, status: "cancelled" } : toolCall
804
- )
805
- };
806
- });
807
- return {
808
- ...updateSessionState(state, sessionId, turns)
809
- };
810
- });
811
- },
812
- markFailed: (sessionId) => {
813
- set((state) => {
814
- const turns = (state.turns[sessionId] ?? []).map((turn) => {
815
- if (turn.status !== "streaming") return turn;
816
- return {
817
- ...turn,
818
- status: "failed",
819
- tool_calls: turn.tool_calls.map(
820
- (toolCall) => toolCall.status === "pending" || toolCall.status === "awaiting_answer" ? { ...toolCall, status: "error" } : toolCall
821
- )
822
- };
823
- });
824
- return {
825
- ...updateSessionState(state, sessionId, turns)
826
- };
827
- });
828
- },
829
- setStreaming: (sessionId, streaming) => {
830
- set((state) => ({
831
- isStreaming: { ...state.isStreaming, [sessionId]: streaming }
832
- }));
833
- },
834
- setAskAnswers: (sessionId, answers) => {
835
- set((state) => ({
836
- askAnswers: {
837
- ...state.askAnswers,
838
- [sessionId]: answers
839
- }
840
- }));
841
- },
842
- clearMessages: (sessionId) => {
843
- set((state) => {
844
- const { [sessionId]: _turns, ...restTurns } = state.turns;
845
- const { [sessionId]: _messages, ...restMessages } = state.messages;
846
- const { [sessionId]: _answers, ...restAnswers } = state.askAnswers;
847
- const { [sessionId]: _loops, ...restLoops } = state.agentLoops;
848
- const { [sessionId]: _compaction, ...restCompactions } = state.activeCompactions;
849
- return {
850
- turns: restTurns,
851
- messages: restMessages,
852
- askAnswers: restAnswers,
853
- agentLoops: restLoops,
854
- activeCompactions: restCompactions
855
- };
856
- });
857
- }
858
- }));
859
-
860
- // src/react/stores/task-store.ts
861
- import { create as create4 } from "zustand";
862
- var EMPTY_TASKS = [];
863
- var useTaskStore = create4()((set, get) => ({
864
- ...createClientActions(set),
865
- tasks: {},
866
- setTasks: (sessionId, tasks) => {
867
- set((state) => ({
868
- tasks: { ...state.tasks, [sessionId]: tasks }
869
- }));
870
- },
871
- getTasks: (sessionId) => {
872
- return get().tasks[sessionId] ?? EMPTY_TASKS;
873
- }
874
- }));
875
-
876
- // src/react/stores/session-store.ts
877
- var DEFAULT_SESSION_MODE = "executing";
878
- var onSessionChange = null;
879
- function invalidateHomeSidebarSessions() {
880
- const queryClient = globalThis.__agentQueryClient;
881
- if (!queryClient) return;
882
- void queryClient.invalidateQueries({ queryKey: ["sessions", "home-sidebar"] });
883
- }
884
- function isSessionAccessRevoked(error) {
885
- if (error instanceof Error) {
886
- const msg = error.message;
887
- return msg.includes("API 403") || msg.includes("API 404");
888
- }
889
- return false;
890
- }
891
- function removeSessionArtifacts(sessionId) {
892
- useChatStore.getState().clearMessages(sessionId);
893
- useTaskStore.getState().setTasks(sessionId, []);
894
- }
895
- function pruneSessionState(state, sessionId) {
896
- const nextFresh = new Set(state._freshSessions);
897
- nextFresh.delete(sessionId);
898
- const { [sessionId]: _mode, ...modes } = state.modes;
899
- const { [sessionId]: _rewindDraft, ...rewindDrafts } = state.rewindDrafts;
900
- return {
901
- sessions: state.sessions.filter((session) => session.id !== sessionId),
902
- activeSessionId: state.activeSessionId === sessionId ? null : state.activeSessionId,
903
- modes,
904
- rewindDrafts,
905
- _freshSessions: nextFresh
906
- };
907
- }
908
- function navigateAwayFromSession(sessionId) {
909
- if (typeof window === "undefined") return;
910
- if (window.location.pathname !== `/chat/${sessionId}`) return;
911
- window.history.replaceState(window.history.state, "", "/chat");
912
- window.dispatchEvent(new PopStateEvent("popstate"));
913
- }
914
- function handleUnreadableSession(set, get, sessionId) {
915
- const wasActive = get().activeSessionId === sessionId;
916
- removeSessionArtifacts(sessionId);
917
- set((state) => pruneSessionState(state, sessionId));
918
- if (wasActive) {
919
- onSessionChange?.(null);
920
- navigateAwayFromSession(sessionId);
921
- }
922
- invalidateHomeSidebarSessions();
923
- }
924
- function isPlainRecord(value) {
925
- return typeof value === "object" && value !== null && !Array.isArray(value);
926
- }
927
- function extractModeFromBlocks2(blocks) {
928
- const modeBlock = blocks.find((block) => block.type === "mode_change");
929
- if (modeBlock && isPlainRecord(modeBlock.content) && (modeBlock.content.to === "planning" || modeBlock.content.to === "executing")) {
930
- return modeBlock.content.to;
931
- }
932
- if (blocks.some((block) => block.type === "planning_enter")) return "planning";
933
- if (blocks.some((block) => block.type === "planning_exit")) return "executing";
934
- return null;
935
- }
936
- function toSelectionMap(value) {
937
- if (!isPlainRecord(value)) return {};
938
- const entries = Object.entries(value).map(([questionKey, optionIndexes]) => {
939
- if (!Array.isArray(optionIndexes)) return null;
940
- const parsedIndexes = optionIndexes.map((item) => typeof item === "number" ? item : Number(item)).filter((item) => Number.isInteger(item));
941
- return [Number(questionKey), parsedIndexes];
942
- }).filter((entry) => entry !== null);
943
- return Object.fromEntries(entries);
944
- }
945
- function toCustomMap(value) {
946
- if (!isPlainRecord(value)) return {};
947
- const entries = Object.entries(value).filter(([, text]) => typeof text === "string").map(([questionKey, text]) => [Number(questionKey), text]);
948
- return Object.fromEntries(entries);
949
- }
950
- function extractAskAnswers(turns) {
951
- const answers = {};
952
- for (const turn of turns) {
953
- for (const block of turn.blocks) {
954
- if (block.type !== "ask_user_answer" || typeof block.tool_call_id !== "string") continue;
955
- answers[block.tool_call_id] = {
956
- selections: toSelectionMap(isPlainRecord(block.content) ? block.content.selections : void 0),
957
- custom: toCustomMap(isPlainRecord(block.content) ? block.content.custom : void 0)
958
- };
959
- }
960
- }
961
- return answers;
962
- }
963
- function registerCreatedSessionState(set, session, mode = DEFAULT_SESSION_MODE) {
964
- useChatStore.getState().setTurns(session.id, []);
965
- useTaskStore.getState().setTasks(session.id, []);
966
- set((state) => ({
967
- sessions: [session, ...state.sessions.filter((item) => item.id !== session.id)],
968
- modes: { ...state.modes, [session.id]: state.modes[session.id] ?? mode },
969
- _freshSessions: new Set(state._freshSessions).add(session.id)
970
- }));
971
- }
972
- async function revalidateViewerSessions(existingSessions) {
973
- const viewerSessions = existingSessions.filter((session) => session.viewer_role === "viewer");
974
- if (viewerSessions.length === 0) {
975
- return [];
976
- }
977
- const refreshed = await Promise.all(
978
- viewerSessions.map(async (session) => {
979
- try {
980
- return await getSession(session.id);
981
- } catch (error) {
982
- if (isSessionAccessRevoked(error)) {
983
- return null;
984
- }
985
- return session;
986
- }
987
- })
988
- );
989
- return refreshed.filter((session) => session !== null);
990
- }
991
- var useSessionStore = create5()((set, get) => ({
992
- ...createClientActions(set),
993
- sessions: [],
994
- activeSessionId: null,
995
- loading: false,
996
- modes: {},
997
- rewindDrafts: {},
998
- _freshSessions: /* @__PURE__ */ new Set(),
999
- fetchSessions: async () => {
1000
- set({ loading: true });
1001
- try {
1002
- const currentState = get();
1003
- const [sessions, viewerSessions] = await Promise.all([
1004
- listSessions(),
1005
- revalidateViewerSessions(currentState.sessions)
1006
- ]);
1007
- const knownSessionIds = new Set(sessions.map((session) => session.id));
1008
- const mergedSessions = [
1009
- ...sessions,
1010
- ...viewerSessions.filter((session) => !knownSessionIds.has(session.id))
1011
- ];
1012
- const removedSessionIds = currentState.sessions.filter(
1013
- (session) => session.viewer_role === "viewer" && !mergedSessions.some((candidate) => candidate.id === session.id)
1014
- ).map((session) => session.id);
1015
- const activeSessionId = currentState.activeSessionId;
1016
- for (const sessionId of removedSessionIds) {
1017
- removeSessionArtifacts(sessionId);
1018
- }
1019
- let nextState = {
1020
- sessions: mergedSessions,
1021
- activeSessionId: currentState.activeSessionId,
1022
- loading: false,
1023
- modes: currentState.modes,
1024
- rewindDrafts: currentState.rewindDrafts,
1025
- _freshSessions: currentState._freshSessions
1026
- };
1027
- for (const sessionId of removedSessionIds) {
1028
- nextState = {
1029
- ...nextState,
1030
- ...pruneSessionState(
1031
- {
1032
- ...currentState,
1033
- sessions: nextState.sessions ?? currentState.sessions,
1034
- activeSessionId: nextState.activeSessionId ?? currentState.activeSessionId,
1035
- loading: nextState.loading ?? currentState.loading,
1036
- modes: nextState.modes ?? currentState.modes,
1037
- rewindDrafts: nextState.rewindDrafts ?? currentState.rewindDrafts,
1038
- _freshSessions: nextState._freshSessions ?? currentState._freshSessions
1039
- },
1040
- sessionId
1041
- )
1042
- };
1043
- }
1044
- set(nextState);
1045
- if (activeSessionId && removedSessionIds.includes(activeSessionId)) {
1046
- onSessionChange?.(null);
1047
- navigateAwayFromSession(activeSessionId);
1048
- }
1049
- invalidateHomeSidebarSessions();
1050
- } catch (error) {
1051
- set({ loading: false });
1052
- throw error;
1053
- }
1054
- },
1055
- createSession: async (intent) => {
1056
- const { session_id } = await createSession(intent);
1057
- const now = (/* @__PURE__ */ new Date()).toISOString();
1058
- get().registerCreatedSession({
1059
- id: session_id,
1060
- intent: intent ?? "",
1061
- status: "created",
1062
- created_at: now,
1063
- updated_at: now
1064
- });
1065
- get().setActiveSession(session_id);
1066
- invalidateHomeSidebarSessions();
1067
- get().fetchSessions().catch(() => {
1068
- });
1069
- return session_id;
1070
- },
1071
- registerCreatedSession: (session, mode = DEFAULT_SESSION_MODE) => {
1072
- registerCreatedSessionState(set, session, mode);
1073
- },
1074
- upsertSession: (session) => {
1075
- set((state) => ({
1076
- sessions: state.sessions.some((item) => item.id === session.id) ? state.sessions.map((item) => item.id === session.id ? { ...item, ...session } : item) : [session, ...state.sessions]
1077
- }));
1078
- },
1079
- isFreshSession: (sessionId) => get()._freshSessions.has(sessionId),
1080
- setActiveSession: (id) => {
1081
- set({ activeSessionId: id });
1082
- onSessionChange?.(id);
1083
- getSession(id).then((detail) => {
1084
- set((state) => ({
1085
- sessions: state.sessions.some((s) => s.id === id) ? state.sessions.map(
1086
- (s) => s.id === id ? { ...s, status: detail.status, updated_at: detail.updated_at } : s
1087
- ) : [detail, ...state.sessions]
1088
- }));
1089
- }).catch(() => {
1090
- });
1091
- const tasksPromise = getSessionTasks(id).catch(() => null);
1092
- Promise.all([getSessionTurns(id), tasksPromise]).then(([turns, tasks]) => {
1093
- if (tasks) useTaskStore.getState().setTasks(id, tasks);
1094
- useChatStore.getState().setAskAnswers(id, extractAskAnswers(turns));
1095
- let inferredMode = DEFAULT_SESSION_MODE;
1096
- for (const turn of turns) {
1097
- const nextMode = extractModeFromBlocks2(turn.blocks);
1098
- if (nextMode) {
1099
- inferredMode = nextMode;
1100
- }
1101
- }
1102
- set((state) => {
1103
- if (state.modes[id] == null) {
1104
- return { modes: { ...state.modes, [id]: inferredMode } };
1105
- }
1106
- return state;
1107
- });
1108
- const isFresh = get()._freshSessions.has(id);
1109
- if (isFresh) {
1110
- set((state) => {
1111
- const next = new Set(state._freshSessions);
1112
- next.delete(id);
1113
- return { _freshSessions: next };
1114
- });
1115
- if (turns.length > 0) {
1116
- useChatStore.getState().setTurns(id, turns);
1117
- }
1118
- } else {
1119
- useChatStore.getState().setTurns(id, turns);
1120
- }
1121
- }).catch((error) => {
1122
- if (isSessionAccessRevoked(error)) {
1123
- handleUnreadableSession(set, get, id);
1124
- return;
1125
- }
1126
- console.error("Failed to load session data", error);
1127
- });
1128
- },
1129
- clearActiveSession: () => {
1130
- set({ activeSessionId: null });
1131
- onSessionChange?.(null);
1132
- },
1133
- deleteSession: async (id) => {
1134
- await deleteSession(id);
1135
- invalidateHomeSidebarSessions();
1136
- const wasActive = get().activeSessionId === id;
1137
- await get().fetchSessions();
1138
- if (!wasActive) {
1139
- return;
1140
- }
1141
- const nextId = get().sessions[0]?.id ?? null;
1142
- if (nextId) {
1143
- get().setActiveSession(nextId);
1144
- return;
1145
- }
1146
- get().clearActiveSession();
1147
- },
1148
- updateSessionStatus: (sessionId, status) => {
1149
- set((state) => ({
1150
- sessions: state.sessions.map((s) => s.id === sessionId ? { ...s, status } : s)
1151
- }));
1152
- if (status === "failed" || status === "interrupted") {
1153
- useChatStore.getState().setStreaming(sessionId, false);
1154
- if (status === "interrupted") {
1155
- useChatStore.getState().markInterrupted(sessionId);
1156
- } else {
1157
- useChatStore.getState().markFailed(sessionId);
1158
- }
1159
- }
1160
- },
1161
- updateSessionIntent: (sessionId, intent) => {
1162
- set((state) => ({
1163
- sessions: state.sessions.map((s) => s.id === sessionId ? { ...s, intent } : s)
1164
- }));
1165
- },
1166
- patchSession: (sessionId, patch) => {
1167
- set((state) => ({
1168
- sessions: state.sessions.map(
1169
- (s) => s.id === sessionId ? { ...s, ...patch } : s
1170
- )
1171
- }));
1172
- },
1173
- pinSession: async (sessionId, pinned) => {
1174
- const updated = await pinSession(sessionId, pinned);
1175
- set((state) => ({
1176
- sessions: state.sessions.map(
1177
- (s) => s.id === sessionId ? { ...s, is_pinned: updated.is_pinned, pinned_at: updated.pinned_at } : s
1178
- )
1179
- }));
1180
- invalidateHomeSidebarSessions();
1181
- },
1182
- setRewindDraft: (sessionId, text) => {
1183
- set((state) => {
1184
- if (text == null) {
1185
- const { [sessionId]: _, ...rest } = state.rewindDrafts;
1186
- return { rewindDrafts: rest };
1187
- }
1188
- return {
1189
- rewindDrafts: {
1190
- ...state.rewindDrafts,
1191
- [sessionId]: text
1192
- }
1193
- };
1194
- });
1195
- },
1196
- setMode: (sessionId, mode) => {
1197
- set((state) => ({ modes: { ...state.modes, [sessionId]: mode } }));
1198
- },
1199
- togglePlanningMode: (sessionId) => {
1200
- const current = get().modes[sessionId] ?? DEFAULT_SESSION_MODE;
1201
- const next = current === "executing" ? "planning" : "executing";
1202
- set((state) => ({ modes: { ...state.modes, [sessionId]: next } }));
1203
- },
1204
- toggleSharing: async (sessionId) => {
1205
- const session = get().sessions.find((s) => s.id === sessionId);
1206
- if (!session) return;
1207
- const newShared = !session.shared;
1208
- const result = await updateSharing(sessionId, newShared);
1209
- set((state) => ({
1210
- sessions: state.sessions.map(
1211
- (s) => s.id === sessionId ? { ...s, shared: result.shared } : s
1212
- )
1213
- }));
1214
- },
1215
- reset: () => {
1216
- set({
1217
- sessions: [],
1218
- activeSessionId: null,
1219
- loading: false,
1220
- modes: {},
1221
- rewindDrafts: {},
1222
- _freshSessions: /* @__PURE__ */ new Set()
1223
- });
1224
- invalidateHomeSidebarSessions();
1225
- }
1226
- }));
1227
- setChatStoreSessionAccessor(() => useSessionStore.getState().activeSessionId);
1228
-
1229
- // src/react/stores/auth-store.ts
1230
- var noopStorage = {
1231
- getItem: () => null,
1232
- setItem: () => {
1233
- },
1234
- removeItem: () => {
1235
- }
1236
- };
1237
- function shouldClearPersistedAuthState(value) {
1238
- try {
1239
- const parsed = JSON.parse(value);
1240
- return parsed.state?.token == null && parsed.state?.user == null;
1241
- } catch {
1242
- return false;
1243
- }
1244
- }
1245
- var authStorage = createJSONStorage(() => {
1246
- if (typeof localStorage === "undefined") {
1247
- return noopStorage;
1248
- }
1249
- return {
1250
- getItem: (name) => localStorage.getItem(name),
1251
- setItem: (name, value) => {
1252
- if (shouldClearPersistedAuthState(value)) {
1253
- localStorage.removeItem(name);
1254
- return;
1255
- }
1256
- localStorage.setItem(name, value);
1257
- },
1258
- removeItem: (name) => localStorage.removeItem(name)
1259
- };
1260
- });
1261
- function finishAuth(set, payload) {
1262
- set({
1263
- token: payload.token,
1264
- socketAuthToken: null,
1265
- user: payload.user,
1266
- loading: false,
1267
- error: null
1268
- });
1269
- agentSocket?.reconnect();
1270
- useSessionStore.getState().fetchSessions().catch(() => {
1271
- });
1272
- }
1273
- function finishCookieHydration(set, payload) {
1274
- set({
1275
- token: null,
1276
- socketAuthToken: payload.token,
1277
- user: payload.user,
1278
- loading: false,
1279
- error: null
1280
- });
1281
- agentSocket?.reconnect();
1282
- useSessionStore.getState().fetchSessions().catch(() => {
1283
- });
1284
- }
1285
- function toUser(info) {
1286
- return {
1287
- id: info.id,
1288
- username: info.username,
1289
- display_name: info.display_name,
1290
- avatar_url: info.avatar_url,
1291
- is_admin: info.is_admin
1292
- };
1293
- }
1294
- var useAuthStore = create6()(
1295
- persist(
1296
- (set, get) => ({
1297
- ...createClientActions(set),
1298
- token: null,
1299
- socketAuthToken: null,
1300
- user: null,
1301
- loading: false,
1302
- error: null,
1303
- logout: () => {
1304
- void logout().catch(() => {
1305
- });
1306
- set({ token: null, socketAuthToken: null, user: null, error: null });
1307
- agentSocket?.disconnect();
1308
- useSessionStore.getState().reset();
1309
- },
1310
- checkAuth: async () => {
1311
- const token = get().token;
1312
- if (!token) return;
1313
- try {
1314
- const auth = await getMe();
1315
- finishAuth(set, { token: auth.token, user: toUser(auth) });
1316
- } catch {
1317
- set({ token: null, socketAuthToken: null, user: null, error: null });
1318
- useSessionStore.getState().reset();
1319
- }
1320
- },
1321
- hydrateFromCookie: async () => {
1322
- set({ loading: true, error: null });
1323
- const previousToken = get().token;
1324
- if (previousToken) {
1325
- try {
1326
- const auth = await getMe();
1327
- finishAuth(set, { token: auth.token, user: toUser(auth) });
1328
- return;
1329
- } catch {
1330
- set({ token: null, socketAuthToken: null, user: null, error: null });
1331
- useSessionStore.getState().reset();
1332
- }
1333
- }
1334
- try {
1335
- const auth = await getMe();
1336
- finishCookieHydration(set, { token: auth.token, user: toUser(auth) });
1337
- } catch {
1338
- set({
1339
- token: null,
1340
- socketAuthToken: null,
1341
- user: null,
1342
- loading: false,
1343
- error: null
1344
- });
1345
- useSessionStore.getState().reset();
1346
- }
1347
- }
1348
- }),
1349
- {
1350
- name: "agent-auth",
1351
- storage: authStorage,
1352
- partialize: (state) => {
1353
- if (state.socketAuthToken) {
1354
- return { token: null, user: null };
1355
- }
1356
- return { token: state.token, user: state.user };
1357
- }
1358
- }
1359
- )
1360
- );
1361
-
1362
- // src/react/stores/background-store.ts
1363
- import { create as create7 } from "zustand";
1364
- var useBackgroundStore = create7()((set) => ({
1365
- ...createClientActions(set),
1366
- tasks: {},
1367
- selectedTaskId: {},
1368
- setTasks: (sessionId, tasks) => set((state) => ({
1369
- tasks: { ...state.tasks, [sessionId]: tasks },
1370
- selectedTaskId: {
1371
- ...state.selectedTaskId,
1372
- [sessionId]: state.selectedTaskId[sessionId] ?? tasks[0]?.id ?? null
1373
- }
1374
- })),
1375
- upsertTask: (sessionId, task) => set((state) => {
1376
- const existing = state.tasks[sessionId] ?? [];
1377
- const index = existing.findIndex((item) => item.id === task.id);
1378
- const next = [...existing];
1379
- if (index >= 0) {
1380
- next[index] = { ...next[index], ...task };
1381
- } else {
1382
- next.unshift(task);
1383
- }
1384
- return {
1385
- tasks: { ...state.tasks, [sessionId]: next },
1386
- selectedTaskId: {
1387
- ...state.selectedTaskId,
1388
- [sessionId]: state.selectedTaskId[sessionId] ?? task.id
1389
- }
1390
- };
1391
- }),
1392
- selectTask: (sessionId, taskId) => set((state) => ({
1393
- selectedTaskId: { ...state.selectedTaskId, [sessionId]: taskId }
1394
- }))
1395
- }));
1396
-
1397
- // src/react/stores/card-state-store.ts
1398
- import { create as create8 } from "zustand";
1399
- var useCardStateStore = create8((set, get) => ({
1400
- ...createClientActions(set),
1401
- states: {},
1402
- getCardState: (cardId) => {
1403
- return get().states[cardId];
1404
- },
1405
- setCardState: (cardId, state) => {
1406
- set((prev) => ({
1407
- states: { ...prev.states, [cardId]: state }
1408
- }));
1409
- },
1410
- removeCardState: (cardId) => {
1411
- set((prev) => {
1412
- const { [cardId]: _, ...rest } = prev.states;
1413
- return { states: rest };
1414
- });
1415
- },
1416
- clearAllStates: () => {
1417
- set({ states: {} });
1418
- }
1419
- }));
1420
-
1421
- // src/react/stores/connection-store.ts
1422
- import { create as create9 } from "zustand";
1423
- var initialConnectionState = {
1424
- status: "disconnected",
1425
- reconnectAttempt: 0,
1426
- lastConnectedAt: null,
1427
- lastDisconnectedAt: null,
1428
- hasEverConnected: false
1429
- };
1430
- var useConnectionStore = create9()((set) => ({
1431
- ...createClientActions(set),
1432
- ...initialConnectionState,
1433
- markConnecting: (attempt = 0) => set({
1434
- status: "connecting",
1435
- reconnectAttempt: attempt
1436
- }),
1437
- markConnected: () => set({
1438
- status: "connected",
1439
- reconnectAttempt: 0,
1440
- lastConnectedAt: Date.now(),
1441
- hasEverConnected: true
1442
- }),
1443
- markDisconnected: () => set({
1444
- status: "disconnected",
1445
- reconnectAttempt: 0,
1446
- lastDisconnectedAt: Date.now()
1447
- }),
1448
- reset: () => set(initialConnectionState)
1449
- }));
1450
-
1451
- // src/react/stores/runtime-store.ts
1452
- import { create as create10 } from "zustand";
1453
- var useRuntimeStore = create10()((set) => ({
1454
- ...createClientActions(set),
1455
- events: {},
1456
- addEvent: (sessionId, event) => set((state) => {
1457
- const current = state.events[sessionId] ?? [];
1458
- const nextEvent = {
1459
- ...event,
1460
- id: `${Date.now()}-${current.length}`,
1461
- sessionId,
1462
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1463
- };
1464
- return {
1465
- events: {
1466
- ...state.events,
1467
- [sessionId]: [...current.slice(-59), nextEvent]
1468
- }
1469
- };
1470
- }),
1471
- clearSession: (sessionId) => set((state) => ({
1472
- events: { ...state.events, [sessionId]: [] }
1473
- }))
1474
- }));
1475
-
1476
- // src/react/stores/gis-store.ts
1477
- import { create as create11 } from "zustand";
1478
- var EMPTY_GOALS = [];
1479
- var EMPTY_RESOURCES = [];
1480
- var EMPTY_TARGETS = [];
1481
- var EMPTY_COMMANDS = [];
1482
- function newCommandId() {
1483
- if (typeof globalThis !== "undefined" && "crypto" in globalThis) {
1484
- return globalThis.crypto?.randomUUID?.() ?? `gis-map-${Date.now()}-${Math.random()}`;
1485
- }
1486
- return `gis-map-${Date.now()}-${Math.random()}`;
1487
- }
1488
- var useGisStore = create11()((set, get) => ({
1489
- ...createClientActions(set),
1490
- goalsBySession: {},
1491
- resourcesBySession: {},
1492
- targetsBySession: {},
1493
- pendingMapCommandsBySession: {},
1494
- setGoals: (sessionId, goals) => {
1495
- set((state) => ({
1496
- goalsBySession: { ...state.goalsBySession, [sessionId]: goals }
1497
- }));
1498
- },
1499
- setResources: (sessionId, resources) => {
1500
- set((state) => ({
1501
- resourcesBySession: { ...state.resourcesBySession, [sessionId]: resources }
1502
- }));
1503
- },
1504
- setTargets: (sessionId, targets) => {
1505
- set((state) => ({
1506
- targetsBySession: { ...state.targetsBySession, [sessionId]: targets }
1507
- }));
1508
- },
1509
- pushMapCommand: (sessionId, command) => {
1510
- set((state) => ({
1511
- pendingMapCommandsBySession: {
1512
- ...state.pendingMapCommandsBySession,
1513
- [sessionId]: [
1514
- ...state.pendingMapCommandsBySession[sessionId] ?? EMPTY_COMMANDS,
1515
- {
1516
- ...command,
1517
- id: newCommandId(),
1518
- createdAt: Date.now()
1519
- }
1520
- ]
1521
- }
1522
- }));
1523
- },
1524
- consumeMapCommand: (sessionId, commandId) => {
1525
- set((state) => ({
1526
- pendingMapCommandsBySession: {
1527
- ...state.pendingMapCommandsBySession,
1528
- [sessionId]: (state.pendingMapCommandsBySession[sessionId] ?? EMPTY_COMMANDS).filter(
1529
- (command) => command.id !== commandId
1530
- )
1531
- }
1532
- }));
1533
- },
1534
- getGoals: (sessionId) => get().goalsBySession[sessionId] ?? EMPTY_GOALS,
1535
- getResources: (sessionId) => get().resourcesBySession[sessionId] ?? EMPTY_RESOURCES,
1536
- getTargets: (sessionId) => get().targetsBySession[sessionId] ?? EMPTY_TARGETS,
1537
- getPendingMapCommands: (sessionId) => get().pendingMapCommandsBySession[sessionId] ?? EMPTY_COMMANDS
1538
- }));
1539
-
1540
- // src/react/stores/answer-callback-store.ts
1541
- import { create as create12 } from "zustand";
1542
- var useAnswerCallbackStore = create12()((set) => ({
1543
- ...createClientActions(set),
1544
- callbacks: {},
1545
- setAnswerCallback: (sessionId, callback) => {
1546
- set((state) => ({
1547
- callbacks: {
1548
- ...state.callbacks,
1549
- [sessionId]: callback
1550
- }
1551
- }));
1552
- }
1553
- }));
1554
-
1555
- // src/react/stores/runtime-features-store.ts
1556
- import { create as create13 } from "zustand";
1557
- var useRuntimeFeaturesStore = create13((set) => ({
1558
- ...createClientActions(set),
1559
- asrEnabled: false,
1560
- asrProvider: "volcengine",
1561
- publicSharingEnabled: false,
1562
- memoryEnabled: false,
1563
- setFeatures: (features) => set((prev) => ({
1564
- asrEnabled: features.asrEnabled ?? prev.asrEnabled,
1565
- asrProvider: features.asrProvider ?? prev.asrProvider,
1566
- publicSharingEnabled: features.publicSharingEnabled ?? prev.publicSharingEnabled,
1567
- memoryEnabled: features.memoryEnabled ?? prev.memoryEnabled
1568
- }))
1569
- }));
1570
-
1571
- // src/react/bootstrap.ts
1572
- var bootstrappedClient = null;
1573
- function getBootstrappedClient() {
1574
- if (!bootstrappedClient) {
1575
- throw new Error("bootstrapBladeClient() must be called before any SDK usage");
1576
- }
1577
- return bootstrappedClient;
1578
- }
1579
-
1580
- // src/react/api/client.ts
1581
- function getAuthedUrl(path) {
1582
- return getClient().buildAuthedUrl(path);
1583
- }
1584
- function getClient() {
1585
- return getBootstrappedClient();
1586
- }
1587
-
1588
- // src/react/components/card/CardCodeBlock.tsx
1589
- import { useIsCodeFenceIncomplete } from "streamdown";
1590
-
1591
- // src/react/lib/card-registry.ts
1592
- var CardComponentRegistry = class {
1593
- components;
1594
- constructor(initial) {
1595
- if (initial instanceof Map) {
1596
- this.components = new Map(initial);
1597
- } else if (initial) {
1598
- this.components = new Map(Object.entries(initial));
1599
- } else {
1600
- this.components = /* @__PURE__ */ new Map();
1601
- }
1602
- }
1603
- register(type3, component) {
1604
- this.components.set(type3, component);
1605
- }
1606
- get(type3) {
1607
- return this.components.get(type3);
1608
- }
1609
- has(type3) {
1610
- return this.components.has(type3);
1611
- }
1612
- keys() {
1613
- return Array.from(this.components.keys());
1614
- }
1615
- clear() {
1616
- this.components.clear();
1617
- }
1618
- get size() {
1619
- return this.components.size;
1620
- }
1621
- };
1622
- var cardRegistry = new CardComponentRegistry();
1623
- var CardJSON = {
1624
- safeParseJSON(text) {
1625
- try {
1626
- const value = JSON.parse(text);
1627
- return { ok: true, value };
1628
- } catch (error) {
1629
- return {
1630
- ok: false,
1631
- error: error instanceof Error ? error.message : "Unknown parsing error"
1632
- };
1633
- }
1634
- },
1635
- toCardArray(value) {
1636
- if (value && typeof value === "object" && "type" in value && typeof value.type === "string") {
1637
- return [value];
1638
- }
1639
- if (Array.isArray(value)) {
1640
- const cards = value.filter(
1641
- (item) => item && typeof item === "object" && "type" in item && typeof item.type === "string"
1642
- );
1643
- return cards.length > 0 ? cards : null;
1644
- }
1645
- return null;
1646
- },
1647
- isCardsLanguage(lang) {
1648
- return lang === "card+json";
1649
- }
1650
- };
1651
-
1652
- // src/react/lib/code-highlight.ts
1653
- import { useEffect, useMemo, useState } from "react";
1654
- var DARK_THEME = "github-dark-default";
1655
- var LIGHT_THEME = "github-light-default";
1656
- var LANGUAGE_ALIASES = {
1657
- bash: "bash",
1658
- css: "css",
1659
- go: "go",
1660
- golang: "go",
1661
- htm: "html",
1662
- html: "html",
1663
- javascript: "javascript",
1664
- js: "javascript",
1665
- json: "json",
1666
- jsonc: "json",
1667
- jsx: "jsx",
1668
- markdown: "markdown",
1669
- md: "markdown",
1670
- py: "python",
1671
- python: "python",
1672
- rs: "rust",
1673
- rust: "rust",
1674
- scss: "css",
1675
- sh: "bash",
1676
- shell: "bash",
1677
- ts: "typescript",
1678
- tsx: "tsx",
1679
- typescript: "typescript",
1680
- yaml: "yaml",
1681
- yml: "yaml",
1682
- zsh: "bash"
1683
- };
1684
- var highlighterPromise = null;
1685
- var CACHE_MAX_SIZE = 200;
1686
- var highlightCache = /* @__PURE__ */ new Map();
1687
- function normalizeCodeLanguage(language) {
1688
- if (!language) return null;
1689
- return LANGUAGE_ALIASES[language.trim().toLowerCase()] ?? null;
1690
- }
1691
- function useHighlightedCodeHtml(code, language) {
1692
- const normalizedLanguage = useMemo(() => normalizeCodeLanguage(language), [language]);
1693
- const [highlightedHtml, setHighlightedHtml] = useState(null);
1694
- useEffect(() => {
1695
- let cancelled = false;
1696
- setHighlightedHtml(null);
1697
- if (!normalizedLanguage) {
1698
- return () => {
1699
- cancelled = true;
1700
- };
1701
- }
1702
- void highlightCodeToInnerHtml(code, normalizedLanguage).then((result) => {
1703
- if (!cancelled) {
1704
- setHighlightedHtml(result);
1705
- }
1706
- });
1707
- return () => {
1708
- cancelled = true;
1709
- };
1710
- }, [code, normalizedLanguage]);
1711
- return { highlightedHtml, language: normalizedLanguage };
1712
- }
1713
- async function highlightCodeToInnerHtml(code, language) {
1714
- const cacheKey = `${language}\0${code}`;
1715
- const cached = highlightCache.get(cacheKey);
1716
- if (cached) {
1717
- return cached;
1718
- }
1719
- const request = loadCodeHighlighter().then((highlighter) => {
1720
- const html = highlighter.codeToHtml(code, {
1721
- lang: language,
1722
- themes: { light: LIGHT_THEME, dark: DARK_THEME },
1723
- defaultColor: false
1724
- });
1725
- return extractInnerCodeHtml(html);
1726
- }).catch(() => {
1727
- highlightCache.delete(cacheKey);
1728
- return null;
1729
- });
1730
- if (highlightCache.size >= CACHE_MAX_SIZE) {
1731
- const oldest = highlightCache.keys().next().value;
1732
- if (oldest !== void 0) highlightCache.delete(oldest);
1733
- }
1734
- highlightCache.set(cacheKey, request);
1735
- return request;
1736
- }
1737
- async function loadCodeHighlighter() {
1738
- if (!highlighterPromise) {
1739
- highlighterPromise = Promise.all([
1740
- import("shiki/core"),
1741
- import("shiki/engine/javascript"),
1742
- import("@shikijs/langs/bash"),
1743
- import("@shikijs/langs/css"),
1744
- import("@shikijs/langs/go"),
1745
- import("@shikijs/langs/html"),
1746
- import("@shikijs/langs/javascript"),
1747
- import("@shikijs/langs/json"),
1748
- import("@shikijs/langs/jsx"),
1749
- import("@shikijs/langs/markdown"),
1750
- import("@shikijs/langs/python"),
1751
- import("@shikijs/langs/rust"),
1752
- import("@shikijs/langs/tsx"),
1753
- import("@shikijs/langs/typescript"),
1754
- import("@shikijs/langs/yaml"),
1755
- import("@shikijs/themes/github-dark-default"),
1756
- import("@shikijs/themes/github-light-default")
1757
- ]).then(
1758
- ([
1759
- core,
1760
- engine,
1761
- bash,
1762
- css,
1763
- go,
1764
- html,
1765
- javascript,
1766
- json,
1767
- jsx13,
1768
- markdown,
1769
- python,
1770
- rust,
1771
- tsx,
1772
- typescript,
1773
- yaml,
1774
- darkTheme,
1775
- lightTheme
1776
- ]) => core.createHighlighterCore({
1777
- engine: engine.createJavaScriptRegexEngine(),
1778
- langs: [
1779
- bash.default,
1780
- css.default,
1781
- go.default,
1782
- html.default,
1783
- javascript.default,
1784
- json.default,
1785
- jsx13.default,
1786
- markdown.default,
1787
- python.default,
1788
- rust.default,
1789
- tsx.default,
1790
- typescript.default,
1791
- yaml.default
1792
- ],
1793
- themes: [darkTheme.default, lightTheme.default]
1794
- })
1795
- ).catch((err) => {
1796
- highlighterPromise = null;
1797
- throw err;
1798
- });
1799
- }
1800
- return highlighterPromise;
1801
- }
1802
- function extractInnerCodeHtml(html) {
1803
- const match = html.match(/<code[^>]*>([\s\S]*)<\/code><\/pre>\s*$/);
1804
- return match?.[1] ?? null;
1805
- }
1806
-
1807
- // src/react/components/card/CardRenderer.tsx
1808
- import { Component } from "react";
1809
-
1810
- // src/react/components/card/CardContext.tsx
1811
- import { createContext, useContext } from "react";
1812
- var CardContext = createContext({});
1813
- var useCardContext = () => useContext(CardContext);
1814
-
1815
- // src/react/components/card/CardStates.tsx
1816
- import { jsx, jsxs } from "react/jsx-runtime";
1817
- function CardLoadingState({ content }) {
1818
- return /* @__PURE__ */ jsxs("div", { className: "my-4 rounded-md border border-[hsl(var(--primary)/0.2)] bg-[hsl(var(--primary)/0.05)] p-4", children: [
1819
- /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2", children: [
1820
- /* @__PURE__ */ jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-[hsl(var(--primary))] border-t-transparent" }),
1821
- /* @__PURE__ */ jsx("p", { className: "text-sm text-[hsl(var(--primary))]", children: "\u6B63\u5728\u52A0\u8F7D\u5361\u7247\u6570\u636E..." })
1822
- ] }),
1823
- /* @__PURE__ */ jsxs("details", { className: "mt-2", children: [
1824
- /* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-xs text-[hsl(var(--primary)/0.7)]", children: "\u67E5\u770B\u63A5\u6536\u4E2D\u7684\u6570\u636E" }),
1825
- /* @__PURE__ */ jsx("pre", { className: "mt-1 whitespace-pre-wrap rounded bg-[hsl(var(--primary)/0.1)] p-2 font-mono text-xs text-[hsl(var(--primary)/0.8)]", children: content })
1826
- ] })
1827
- ] });
1828
- }
1829
- function CardErrorState({ content, message }) {
1830
- return /* @__PURE__ */ jsxs("div", { className: "my-4 rounded-md border border-red-500/20 bg-red-500/5 p-4", children: [
1831
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-sm text-red-400", children: message || "\u5361\u7247\u6570\u636E\u89E3\u6790\u5931\u8D25" }),
1832
- /* @__PURE__ */ jsxs("details", { className: "mt-2", children: [
1833
- /* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-xs text-red-400/70 hover:underline", children: "\u67E5\u770B\u539F\u59CB\u4EE3\u7801\u5757" }),
1834
- /* @__PURE__ */ jsx("pre", { className: "mt-2 overflow-x-auto whitespace-pre-wrap rounded bg-red-500/10 p-3 font-mono text-xs text-red-400/80", children: content })
1835
- ] })
1836
- ] });
1837
- }
1838
- function CardWarningState({ content, message }) {
1839
- return /* @__PURE__ */ jsxs("div", { className: "my-4 rounded-md border border-yellow-500/20 bg-yellow-500/5 p-4", children: [
1840
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-sm text-yellow-400", children: message || "\u6570\u636E\u683C\u5F0F\u4E0D\u7B26\u5408\u5361\u7247\u8981\u6C42" }),
1841
- /* @__PURE__ */ jsxs("details", { className: "mt-2", children: [
1842
- /* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-xs text-yellow-400/70", children: "\u67E5\u770B\u539F\u59CB\u6570\u636E" }),
1843
- /* @__PURE__ */ jsx("pre", { className: "mt-1 whitespace-pre-wrap rounded bg-yellow-500/10 p-2 font-mono text-xs text-yellow-400/80", children: content })
1844
- ] })
1845
- ] });
1846
- }
1847
-
1848
- // src/react/components/card/CardRenderer.tsx
1849
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1850
- function looksIncomplete(text) {
1851
- const t = text.trim();
1852
- if (!t) return true;
1853
- const openBraces = (t.match(/{/g) || []).length;
1854
- const closeBraces = (t.match(/}/g) || []).length;
1855
- const openBrackets = (t.match(/\[/g) || []).length;
1856
- const closeBrackets = (t.match(/]/g) || []).length;
1857
- const quotes = (t.match(/"/g) || []).length;
1858
- return !t.endsWith("}") && !t.endsWith("]") || openBraces !== closeBraces || openBrackets !== closeBrackets || t.endsWith(",") || t.endsWith(":") || quotes % 2 !== 0;
1859
- }
1860
- var CardErrorBoundary = class extends Component {
1861
- state = { hasError: false };
1862
- static getDerivedStateFromError() {
1863
- return { hasError: true };
1864
- }
1865
- componentDidCatch(error, info) {
1866
- console.error("Card render error:", error, info);
1867
- }
1868
- render() {
1869
- if (this.state.hasError) return this.props.fallback;
1870
- return this.props.children;
1871
- }
1872
- };
1873
- function OpenInPreviewButton({ card }) {
1874
- const pushArtifact = useUiStore((s) => s.pushArtifact);
1875
- return /* @__PURE__ */ jsx2(
1876
- "button",
1877
- {
1878
- type: "button",
1879
- onClick: () => pushArtifact({
1880
- type: "card",
1881
- content: JSON.stringify(card, null, 2),
1882
- title: card.title || card.type,
1883
- key: `card-${card.id}`
1884
- }),
1885
- className: "absolute right-2 top-2 rounded bg-[hsl(var(--accent))] px-1.5 py-0.5 text-[10px] text-[hsl(var(--muted-foreground))] opacity-0 transition-opacity group-hover/card:opacity-100 hover:text-[hsl(var(--foreground))]",
1886
- children: "\u9884\u89C8"
1887
- }
1888
- );
1889
- }
1890
- function CardRenderer({ raw, blockPosition, isCodeFenceIncomplete }) {
1891
- const { sessionId, messageId, sendMessage } = useCardContext();
1892
- const trimmed = raw.trim();
1893
- if (!trimmed) return /* @__PURE__ */ jsx2(CardLoadingState, { content: "" });
1894
- if (isCodeFenceIncomplete) {
1895
- return /* @__PURE__ */ jsx2(CardLoadingState, { content: trimmed });
1896
- }
1897
- const parsed = CardJSON.safeParseJSON(trimmed);
1898
- if (!parsed.ok) {
1899
- if (looksIncomplete(trimmed)) {
1900
- return /* @__PURE__ */ jsx2(CardLoadingState, { content: trimmed });
1901
- }
1902
- return /* @__PURE__ */ jsx2(CardErrorState, { content: trimmed, message: parsed.error });
1903
- }
1904
- const cards = CardJSON.toCardArray(parsed.value);
1905
- if (!cards) {
1906
- return /* @__PURE__ */ jsx2(CardWarningState, { content: trimmed, message: "JSON \u683C\u5F0F\u6B63\u786E\u4F46\u4E0D\u7B26\u5408\u5361\u7247\u7ED3\u6784" });
1907
- }
1908
- const cardsWithIds = cards.map((c, i) => {
1909
- if (c.id) return c;
1910
- return {
1911
- ...c,
1912
- id: `${messageId || "msg"}-block-${blockPosition ?? 0}-card-${i}`
1913
- };
1914
- });
1915
- return /* @__PURE__ */ jsx2(Fragment, { children: cardsWithIds.map((card) => {
1916
- const CardComponent = cardRegistry.get(card.type);
1917
- if (!CardComponent) {
1918
- return /* @__PURE__ */ jsx2(
1919
- CardWarningState,
1920
- {
1921
- content: JSON.stringify(card, null, 2),
1922
- message: `\u672A\u77E5\u7684\u5361\u7247\u7C7B\u578B: ${card.type}`
1923
- },
1924
- card.id
1925
- );
1926
- }
1927
- return /* @__PURE__ */ jsx2("div", { className: "group/card relative my-4", children: /* @__PURE__ */ jsxs2(
1928
- CardErrorBoundary,
1929
- {
1930
- fallback: /* @__PURE__ */ jsx2(
1931
- CardErrorState,
1932
- {
1933
- content: JSON.stringify(card, null, 2),
1934
- message: "\u5361\u7247\u6E32\u67D3\u51FA\u9519"
1935
- }
1936
- ),
1937
- children: [
1938
- /* @__PURE__ */ jsx2(CardComponent, { card, sendMessage, sessionId }),
1939
- /* @__PURE__ */ jsx2(OpenInPreviewButton, { card })
1940
- ]
1941
- }
1942
- ) }, card.id);
1943
- }) });
1944
- }
1945
-
1946
- // src/react/components/card/CardCodeBlock.tsx
1947
- import { jsx as jsx3 } from "react/jsx-runtime";
1948
- function CardCodeBlock({ className, children, node, ...props }) {
1949
- const isIncomplete = useIsCodeFenceIncomplete();
1950
- const match = /language-(\S+)/.exec(className || "");
1951
- const lang = match?.[1];
1952
- const isInline = !className;
1953
- const raw = String(children ?? "");
1954
- const normalizedLang = normalizeCodeLanguage(lang);
1955
- const { highlightedHtml } = useHighlightedCodeHtml(raw, normalizedLang);
1956
- if (!isInline && CardJSON.isCardsLanguage(lang)) {
1957
- return /* @__PURE__ */ jsx3(
1958
- CardRenderer,
1959
- {
1960
- raw,
1961
- blockPosition: node?.position?.start?.line,
1962
- isCodeFenceIncomplete: isIncomplete
1963
- }
1964
- );
1965
- }
1966
- if (!isInline && highlightedHtml) {
1967
- return /* @__PURE__ */ jsx3(
1968
- "code",
1969
- {
1970
- className,
1971
- ...props,
1972
- dangerouslySetInnerHTML: { __html: highlightedHtml }
1973
- }
1974
- );
1975
- }
1976
- return /* @__PURE__ */ jsx3("code", { className, ...props, children });
1977
- }
1978
-
1979
- // src/react/components/markdown/MarkdownContent.tsx
1980
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1981
- var STREAMDOWN_PLUGINS = { mermaid };
1982
- var SYSTEM_REMINDER_TAG = "system-reminder";
1983
- var HIDDEN_SYSTEM_REMINDER_TAGS = {
1984
- [SYSTEM_REMINDER_TAG]: []
1985
- };
1986
- var HIDDEN_SYSTEM_REMINDER_COMPONENTS = {
1987
- [SYSTEM_REMINDER_TAG]: () => null
1988
- };
1989
- function CodeBlockPre({ children, node: _node, ...props }) {
1990
- const preRef = useRef(null);
1991
- const [copied, setCopied] = useState2(false);
1992
- const [hasCodeNode, setHasCodeNode] = useState2(false);
1993
- useEffect2(() => {
1994
- setHasCodeNode(!!preRef.current?.querySelector("code"));
1995
- }, []);
1996
- const getRawCode = () => preRef.current?.querySelector("code")?.textContent ?? "";
1997
- const handleCopy = async () => {
1998
- const ok = await copyToClipboard(getRawCode());
1999
- if (ok) {
2000
- setCopied(true);
2001
- setTimeout(() => setCopied(false), 2e3);
2002
- }
2003
- };
2004
- const handleDownload = () => {
2005
- const codeEl = preRef.current?.querySelector("code");
2006
- const text = codeEl?.textContent ?? "";
2007
- const ext = codeEl?.className.match(/language-(\S+)/)?.[1] ?? "txt";
2008
- const blob = new Blob([text], { type: "text/plain" });
2009
- const url = URL.createObjectURL(blob);
2010
- const a = document.createElement("a");
2011
- a.href = url;
2012
- a.download = `code.${ext}`;
2013
- a.click();
2014
- URL.revokeObjectURL(url);
2015
- };
2016
- return /* @__PURE__ */ jsxs3("div", { className: "relative group", children: [
2017
- /* @__PURE__ */ jsx4("pre", { ref: preRef, ...props, children }),
2018
- hasCodeNode && /* @__PURE__ */ jsxs3("div", { className: "absolute top-2 right-2 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
2019
- /* @__PURE__ */ jsxs3(
2020
- "button",
2021
- {
2022
- type: "button",
2023
- onClick: handleCopy,
2024
- className: cn(
2025
- "flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] transition-colors",
2026
- copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))] hover:bg-[hsl(var(--accent))]"
2027
- ),
2028
- children: [
2029
- copied ? /* @__PURE__ */ jsx4(Check, { size: 12 }) : /* @__PURE__ */ jsx4(Copy, { size: 12 }),
2030
- /* @__PURE__ */ jsx4("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
2031
- ]
2032
- }
2033
- ),
2034
- /* @__PURE__ */ jsxs3(
2035
- "button",
2036
- {
2037
- type: "button",
2038
- onClick: handleDownload,
2039
- className: "flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] transition-colors text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))] hover:bg-[hsl(var(--accent))]",
2040
- children: [
2041
- /* @__PURE__ */ jsx4(Download, { size: 12 }),
2042
- /* @__PURE__ */ jsx4("span", { children: "\u4E0B\u8F7D" })
2043
- ]
2044
- }
2045
- )
2046
- ] })
2047
- ] });
2048
- }
2049
- function isExternalImageSrc(src) {
2050
- if (!src) return false;
2051
- if (src.startsWith("data:") || src.startsWith("blob:")) return true;
2052
- if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(src)) return true;
2053
- if (src.startsWith("/")) return true;
2054
- return false;
2055
- }
2056
- function decodeMarkdownPath(src) {
2057
- try {
2058
- return decodeURIComponent(src);
2059
- } catch {
2060
- return src;
2061
- }
2062
- }
2063
- var MARKDOWN_IMAGE_PATTERN = /!\[((?:\\.|[^\]\\])*)\]\(\s*(?:<([^>\n]+)>|([^\s)]+))(\s+(?:"[^"]*"|'[^']*'|\([^)]*\)))?\s*\)/g;
2064
- function resolveSessionImageMarkdown(children, sessionId) {
2065
- return children.replace(
2066
- MARKDOWN_IMAGE_PATTERN,
2067
- (match, alt, angleSrc, plainSrc, title = "") => {
2068
- const src = angleSrc ?? plainSrc;
2069
- if (!src || isExternalImageSrc(src)) {
2070
- return match;
2071
- }
2072
- const resolved = getAuthedUrl(
2073
- `/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(decodeMarkdownPath(src))}`
2074
- );
2075
- return `![${alt}](<${resolved}>${title})`;
2076
- }
2077
- );
2078
- }
2079
- function MarkdownContent({
2080
- allowedTags,
2081
- children,
2082
- components,
2083
- mode,
2084
- plugins,
2085
- sessionId,
2086
- ...props
2087
- }) {
2088
- const resolvedChildren = useMemo2(
2089
- () => sessionId && typeof children === "string" ? resolveSessionImageMarkdown(children, sessionId) : children,
2090
- [children, sessionId]
2091
- );
2092
- return /* @__PURE__ */ jsx4(
2093
- Streamdown,
2094
- {
2095
- ...props,
2096
- mode: mode ?? "static",
2097
- allowedTags: {
2098
- ...allowedTags ?? {},
2099
- ...HIDDEN_SYSTEM_REMINDER_TAGS
2100
- },
2101
- components: {
2102
- code: CardCodeBlock,
2103
- pre: CodeBlockPre,
2104
- ...components ?? {},
2105
- ...HIDDEN_SYSTEM_REMINDER_COMPONENTS
2106
- },
2107
- plugins: {
2108
- ...STREAMDOWN_PLUGINS,
2109
- ...plugins ?? {}
2110
- },
2111
- children: resolvedChildren
2112
- }
2113
- );
2114
- }
2115
-
2116
- // src/react/components/chat/AskUserQuestionBlock.tsx
2117
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
2118
- function AskUserQuestionBlock({
2119
- data,
2120
- answered,
2121
- toolCallId,
2122
- sessionStatus,
2123
- answerData,
2124
- onAnswer
2125
- }) {
2126
- const [selections, setSelections] = useState3(/* @__PURE__ */ new Map());
2127
- const [customTexts, setCustomTexts] = useState3(/* @__PURE__ */ new Map());
2128
- const [usingCustom, setUsingCustom] = useState3(/* @__PURE__ */ new Set());
2129
- const [submitted, setSubmitted] = useState3(false);
2130
- useEffect3(() => {
2131
- if (sessionStatus === "failed" || sessionStatus === "interrupted") {
2132
- setSubmitted(false);
2133
- }
2134
- }, [sessionStatus]);
2135
- const displayAnswerState = useMemo3(() => {
2136
- if (!(answered && answerData)) {
2137
- return {
2138
- selections,
2139
- customTexts,
2140
- usingCustom
2141
- };
2142
- }
2143
- const nextSelections = /* @__PURE__ */ new Map();
2144
- const nextCustomTexts = /* @__PURE__ */ new Map();
2145
- const nextUsingCustom = /* @__PURE__ */ new Set();
2146
- for (const [questionKey, optionIndexes] of Object.entries(answerData.selections)) {
2147
- nextSelections.set(Number(questionKey), new Set(optionIndexes));
2148
- }
2149
- for (const [questionKey, text] of Object.entries(answerData.custom)) {
2150
- const qIdx = Number(questionKey);
2151
- nextCustomTexts.set(qIdx, text);
2152
- nextUsingCustom.add(qIdx);
2153
- }
2154
- return {
2155
- selections: nextSelections,
2156
- customTexts: nextCustomTexts,
2157
- usingCustom: nextUsingCustom
2158
- };
2159
- }, [answerData, answered, customTexts, selections, usingCustom]);
2160
- const displaySelections = displayAnswerState.selections;
2161
- const displayCustomTexts = displayAnswerState.customTexts;
2162
- const displayUsingCustom = displayAnswerState.usingCustom;
2163
- const toggleOption = (qIdx, optIdx, multi) => {
2164
- if (answered || submitted) return;
2165
- setSelections((prev) => {
2166
- const next = new Map(prev);
2167
- const current = new Set(next.get(qIdx) ?? []);
2168
- if (multi) {
2169
- if (current.has(optIdx)) current.delete(optIdx);
2170
- else current.add(optIdx);
2171
- } else {
2172
- current.clear();
2173
- current.add(optIdx);
2174
- }
2175
- next.set(qIdx, current);
2176
- return next;
2177
- });
2178
- setUsingCustom((prev) => {
2179
- const next = new Set(prev);
2180
- next.delete(qIdx);
2181
- return next;
2182
- });
2183
- };
2184
- const handleCustomFocus = (qIdx) => {
2185
- if (answered || submitted) return;
2186
- setSelections((prev) => {
2187
- const next = new Map(prev);
2188
- next.delete(qIdx);
2189
- return next;
2190
- });
2191
- setUsingCustom((prev) => new Set(prev).add(qIdx));
2192
- };
2193
- const setCustomText = (qIdx, text) => {
2194
- if (answered || submitted) return;
2195
- setCustomTexts((prev) => new Map(prev).set(qIdx, text));
2196
- };
2197
- const getAnswer = (qIdx) => {
2198
- const q = data.questions[qIdx];
2199
- if (usingCustom.has(qIdx)) {
2200
- const text = (customTexts.get(qIdx) ?? "").trim();
2201
- return text || null;
2202
- }
2203
- const sel = selections.get(qIdx);
2204
- if (!sel || sel.size === 0) return null;
2205
- return [...sel].sort().map((i) => q.options[i].label).join(", ");
2206
- };
2207
- const allAnswered = data.questions.every((_, i) => getAnswer(i) !== null);
2208
- const handleSubmit = () => {
2209
- if (answered || submitted || !allAnswered || !onAnswer) return;
2210
- const nextAnswerData = {
2211
- selections: Object.fromEntries(
2212
- Array.from(selections.entries()).map(([qIdx, optionIndexes]) => [
2213
- qIdx,
2214
- Array.from(optionIndexes).sort((a, b) => a - b)
2215
- ])
2216
- ),
2217
- custom: Object.fromEntries(
2218
- Array.from(usingCustom).map((qIdx) => [qIdx, (customTexts.get(qIdx) ?? "").trim()]).filter(([, text2]) => text2.length > 0)
2219
- )
2220
- };
2221
- const parts = data.questions.map((q, i) => `- ${q.question} -> ${getAnswer(i)}`);
2222
- const text = `\u5173\u4E8E\u9700\u8981\u786E\u8BA4\u7684\u95EE\u9898\uFF0C\u7528\u6237\u7684\u56DE\u7B54\u5982\u4E0B\uFF1A
2223
- ${parts.join("\n")}`;
2224
- setSubmitted(true);
2225
- onAnswer(text, toolCallId, nextAnswerData);
2226
- };
2227
- return /* @__PURE__ */ jsxs4(
2228
- "div",
2229
- {
2230
- className: cn(
2231
- "ml-4 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))]",
2232
- answered ? "max-w-2xl space-y-3 p-3 text-xs text-[hsl(var(--muted-foreground))] opacity-80" : "max-w-lg space-y-5 p-4 text-sm"
2233
- ),
2234
- children: [
2235
- data.source_loop?.description && /* @__PURE__ */ jsxs4("div", { className: "rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
2236
- "\u5B50\u667A\u80FD\u4F53\u300C",
2237
- data.source_loop.description,
2238
- "\u300D\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54"
2239
- ] }),
2240
- data.questions.map((q, qIdx) => /* @__PURE__ */ jsx5(
2241
- QuestionCard,
2242
- {
2243
- question: q,
2244
- qIdx,
2245
- answered,
2246
- selected: displaySelections.get(qIdx) ?? /* @__PURE__ */ new Set(),
2247
- isCustom: displayUsingCustom.has(qIdx),
2248
- customText: displayCustomTexts.get(qIdx) ?? "",
2249
- onToggle: toggleOption,
2250
- onCustomFocus: handleCustomFocus,
2251
- onCustomChange: setCustomText
2252
- },
2253
- q.question
2254
- )),
2255
- !answered && !submitted && onAnswer && /* @__PURE__ */ jsx5(
2256
- "button",
2257
- {
2258
- type: "button",
2259
- onClick: handleSubmit,
2260
- disabled: !allAnswered,
2261
- className: "w-full rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60",
2262
- children: allAnswered ? "\u786E\u8BA4" : "\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u9009\u9879"
2263
- }
2264
- ),
2265
- submitted && !answered && /* @__PURE__ */ jsxs4(
2266
- "button",
2267
- {
2268
- type: "button",
2269
- disabled: true,
2270
- className: "flex w-full items-center justify-center gap-2 rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] opacity-80",
2271
- children: [
2272
- /* @__PURE__ */ jsx5(Loader2, { size: 14, className: "animate-spin" }),
2273
- "\u786E\u8BA4\u4E2D"
2274
- ]
2275
- }
2276
- )
2277
- ]
2278
- }
2279
- );
2280
- }
2281
- function QuestionCard({
2282
- question,
2283
- qIdx,
2284
- answered,
2285
- selected,
2286
- isCustom,
2287
- customText,
2288
- onToggle,
2289
- onCustomFocus,
2290
- onCustomChange
2291
- }) {
2292
- const multi = question.multiSelect ?? false;
2293
- return /* @__PURE__ */ jsxs4("div", { children: [
2294
- /* @__PURE__ */ jsxs4("div", { className: cn("flex items-start gap-2", answered ? "mb-2" : "mb-3"), children: [
2295
- /* @__PURE__ */ jsx5(
2296
- MessageSquareMore,
2297
- {
2298
- size: answered ? 12 : 13,
2299
- className: "mt-0.5 shrink-0 text-[hsl(var(--primary))]"
2300
- }
2301
- ),
2302
- /* @__PURE__ */ jsx5(
2303
- "div",
2304
- {
2305
- className: cn(
2306
- "min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]",
2307
- answered ? "text-xs" : "text-sm"
2308
- ),
2309
- children: /* @__PURE__ */ jsx5(
2310
- MarkdownContent,
2311
- {
2312
- className: cn(
2313
- "prose prose-sm prose-invert max-w-none [&_li>p]:inline [&_ol]:my-1 [&_p]:my-1 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0 [&_ul]:my-1",
2314
- answered ? "text-xs" : "text-sm"
2315
- ),
2316
- controls: { code: true },
2317
- children: question.question
2318
- }
2319
- )
2320
- }
2321
- )
2322
- ] }),
2323
- /* @__PURE__ */ jsxs4("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
2324
- question.options.map((opt, optIdx) => {
2325
- const isSel = selected.has(optIdx);
2326
- return /* @__PURE__ */ jsxs4(
2327
- "button",
2328
- {
2329
- type: "button",
2330
- disabled: answered,
2331
- onClick: () => onToggle(qIdx, optIdx, multi),
2332
- className: cn(
2333
- "flex items-start gap-2.5 rounded-lg border text-left transition-all",
2334
- answered ? "px-2.5 py-1.5" : "px-3 py-2.5",
2335
- isSel && !answered ? "border-[hsl(var(--primary)/0.8)] bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]" : isSel ? "border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.08)] text-[hsl(var(--foreground))]" : "border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.2)]",
2336
- !answered && !isSel && "hover:border-[hsl(var(--ring)/0.4)] hover:bg-[hsl(var(--accent))]",
2337
- answered && "cursor-default opacity-70"
2338
- ),
2339
- children: [
2340
- multi && /* @__PURE__ */ jsx5(
2341
- "div",
2342
- {
2343
- className: cn(
2344
- "mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
2345
- isSel && !answered ? "border-[hsl(var(--primary-foreground)/0.6)] bg-[hsl(var(--primary-foreground)/0.2)]" : isSel ? "border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.12)]" : "border-[hsl(var(--border))]"
2346
- ),
2347
- children: isSel && /* @__PURE__ */ jsx5(
2348
- Check2,
2349
- {
2350
- size: 9,
2351
- className: answered ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--primary-foreground))]"
2352
- }
2353
- )
2354
- }
2355
- ),
2356
- /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
2357
- /* @__PURE__ */ jsx5("div", { className: cn("font-medium", answered ? "text-xs" : "text-[13px]"), children: opt.label }),
2358
- opt.description && /* @__PURE__ */ jsx5(
2359
- "div",
2360
- {
2361
- className: cn(
2362
- "mt-0.5",
2363
- answered ? "text-[11px]" : "text-xs",
2364
- isSel && !answered ? "opacity-75" : "text-[hsl(var(--muted-foreground))]"
2365
- ),
2366
- children: opt.description
2367
- }
2368
- )
2369
- ] })
2370
- ]
2371
- },
2372
- opt.label
2373
- );
2374
- }),
2375
- answered && !isCustom ? null : /* @__PURE__ */ jsxs4(
2376
- "div",
2377
- {
2378
- className: cn(
2379
- "flex items-center gap-2 rounded-lg border transition-all",
2380
- answered ? "px-2.5 py-1.5" : "px-3 py-2.5",
2381
- isCustom ? "border-[hsl(var(--ring)/0.6)] bg-[hsl(var(--accent))]" : "border-[hsl(var(--border))] hover:border-[hsl(var(--ring)/0.3)] hover:bg-[hsl(var(--accent))]",
2382
- answered && "cursor-default opacity-70"
2383
- ),
2384
- children: [
2385
- /* @__PURE__ */ jsx5("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
2386
- /* @__PURE__ */ jsx5(
2387
- "input",
2388
- {
2389
- type: "text",
2390
- value: customText,
2391
- disabled: answered,
2392
- onChange: (e) => onCustomChange(qIdx, e.target.value),
2393
- onFocus: () => onCustomFocus(qIdx),
2394
- "aria-label": "\u81EA\u5B9A\u4E49\u56DE\u7B54",
2395
- placeholder: "\u8F93\u5165\u4F60\u7684\u7B54\u6848...",
2396
- className: cn(
2397
- "min-w-0 flex-1 bg-transparent text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.5)]",
2398
- answered ? "text-xs" : "text-sm"
2399
- )
2400
- }
2401
- )
2402
- ]
2403
- }
2404
- )
2405
- ] })
2406
- ] });
2407
- }
2408
- function parseAskUserQuestion(toolResult) {
2409
- if (!toolResult) return null;
2410
- try {
2411
- const parsed = JSON.parse(toolResult);
2412
- let questions = parsed?.questions;
2413
- if (typeof questions === "string") {
2414
- try {
2415
- questions = JSON.parse(questions);
2416
- } catch {
2417
- return null;
2418
- }
2419
- }
2420
- if (Array.isArray(questions) && questions.every(isQuestionItem)) {
2421
- return { ...parsed, questions };
2422
- }
2423
- } catch {
2424
- }
2425
- return null;
2426
- }
2427
- function isQuestionItem(value) {
2428
- if (!value || typeof value !== "object") return false;
2429
- const question = value.question;
2430
- const options = value.options;
2431
- return typeof question === "string" && Array.isArray(options) && options.every(isOptionItem);
2432
- }
2433
- function isOptionItem(value) {
2434
- if (!value || typeof value !== "object") return false;
2435
- const option = value;
2436
- return typeof option.label === "string" && typeof option.description === "string";
2437
- }
2438
-
2439
- // src/react/components/plan/parse-plan-tree.ts
2440
- import { load } from "js-yaml";
2441
- function isNonEmptyString(value) {
2442
- return typeof value === "string" && value.trim().length > 0;
2443
- }
2444
- function isPlanStep(value) {
2445
- if (!value || typeof value !== "object") return false;
2446
- const step = value;
2447
- if (!isNonEmptyString(step.label)) return false;
2448
- if ("skill" in step && step.skill !== void 0 && !isNonEmptyString(step.skill)) return false;
2449
- if ("children" in step && !Array.isArray(step.children)) return false;
2450
- const children = Array.isArray(step.children) ? step.children : [];
2451
- if (children.length > 0 && !isNonEmptyString(step.skill)) return false;
2452
- return children.every((child) => isPlanStep(child));
2453
- }
2454
- function isPlanDocument(value) {
2455
- if (!value || typeof value !== "object") return false;
2456
- const doc = value;
2457
- if (!isNonEmptyString(doc.title) || !isNonEmptyString(doc.objective)) return false;
2458
- if (!Array.isArray(doc.steps) || doc.steps.length === 0) return false;
2459
- if (!doc.steps.every((step) => isPlanStep(step))) return false;
2460
- if ("notes" in doc) {
2461
- if (!Array.isArray(doc.notes)) return false;
2462
- if (!doc.notes.every((note) => isNonEmptyString(note))) return false;
2463
- }
2464
- return true;
2465
- }
2466
- function getPlanDocumentError(value) {
2467
- if (!value || typeof value !== "object") return "PLAN.yaml \u9876\u5C42\u7ED3\u6784\u5FC5\u987B\u662F\u5BF9\u8C61";
2468
- const doc = value;
2469
- if (!isNonEmptyString(doc.title)) return "PLAN.yaml \u7F3A\u5C11\u975E\u7A7A title";
2470
- if (!isNonEmptyString(doc.objective)) return "PLAN.yaml \u7F3A\u5C11\u975E\u7A7A objective";
2471
- if (!Array.isArray(doc.steps) || doc.steps.length === 0) return "PLAN.yaml \u7F3A\u5C11\u975E\u7A7A steps";
2472
- if (!doc.steps.every((step) => isPlanStep(step))) {
2473
- return "PLAN.yaml \u6B65\u9AA4\u7ED3\u6784\u65E0\u6548\uFF0C\u8BF7\u68C0\u67E5 label / skill / children";
2474
- }
2475
- if ("notes" in doc) {
2476
- if (!Array.isArray(doc.notes) || !doc.notes.every((note) => isNonEmptyString(note))) {
2477
- return "PLAN.yaml notes \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\u5217\u8868";
2478
- }
2479
- }
2480
- return "PLAN.yaml \u7ED3\u6784\u65E0\u6548";
2481
- }
2482
- function toPlanStatus(value) {
2483
- if (!isNonEmptyString(value)) return "pending";
2484
- const normalized = value.trim().toLowerCase();
2485
- return normalized === "pending" || normalized === "running" || normalized === "done" || normalized === "failed" ? normalized : "pending";
2486
- }
2487
- function applyPlanStatusesById(root, statuses) {
2488
- const nextStatus = statuses[root.id] ?? root.status;
2489
- const children = Array.isArray(root.children) ? root.children : [];
2490
- return {
2491
- ...root,
2492
- status: nextStatus,
2493
- children: children.map((child) => applyPlanStatusesById(child, statuses))
2494
- };
2495
- }
2496
- function parsePlanTreeResult(content) {
2497
- if (!content.trim()) {
2498
- return { plan: null, error: null };
2499
- }
2500
- let parsed;
2501
- try {
2502
- parsed = load(content);
2503
- } catch (error) {
2504
- return {
2505
- plan: null,
2506
- error: error instanceof Error ? `PLAN.yaml YAML \u8BED\u6CD5\u9519\u8BEF\uFF1A${error.message}` : "PLAN.yaml YAML \u8BED\u6CD5\u9519\u8BEF"
2507
- };
2508
- }
2509
- if (!isPlanDocument(parsed)) {
2510
- return { plan: null, error: getPlanDocumentError(parsed) };
2511
- }
2512
- const createNode = (step, depth, fallbackId) => {
2513
- const children = Array.isArray(step.children) ? step.children : [];
2514
- return {
2515
- id: isNonEmptyString(step.id) ? step.id.trim() : fallbackId,
2516
- label: step.label.trim(),
2517
- skillRef: isNonEmptyString(step.skill) ? step.skill.trim() : null,
2518
- status: toPlanStatus(step.status),
2519
- children: children.map((child, index) => createNode(child, depth + 1, `${fallbackId}.${index + 1}`)),
2520
- depth
2521
- };
2522
- };
2523
- const root = {
2524
- id: "plan-root",
2525
- label: parsed.title.trim(),
2526
- skillRef: null,
2527
- status: "pending",
2528
- children: parsed.steps.map((step, index) => createNode(step, 1, `${index + 1}`)),
2529
- depth: 0
2530
- };
2531
- const notes = [parsed.objective.trim(), ...(parsed.notes ?? []).map((note) => note.trim())];
2532
- return { plan: { root, notes }, error: null };
2533
- }
2534
-
2535
- // src/react/components/plan/parse-plan-messages.ts
2536
- function resultAsString(result) {
2537
- if (typeof result === "string") return result;
2538
- return null;
2539
- }
2540
- var PAUSE_TOOLS = /* @__PURE__ */ new Set(["AskUserQuestion", "ExitPlanMode"]);
2541
- var READ_FILE_TOOLS = /* @__PURE__ */ new Set(["Read"]);
2542
- var PLAN_WRITE_TOOLS = /* @__PURE__ */ new Set(["Write"]);
2543
- var PLAN_EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit"]);
2544
- function getSkillId(payload) {
2545
- if (!payload) {
2546
- return "";
2547
- }
2548
- if (typeof payload.skill_id === "string" && payload.skill_id) {
2549
- return payload.skill_id;
2550
- }
2551
- if (typeof payload.name === "string" && payload.name) {
2552
- return payload.name;
2553
- }
2554
- return "";
2555
- }
2556
- function getSkillDisplayName(payload) {
2557
- if (!payload || typeof payload.display_name !== "string") {
2558
- return void 0;
2559
- }
2560
- const displayName = payload.display_name.trim();
2561
- if (!displayName) {
2562
- return void 0;
2563
- }
2564
- const skillId = getSkillId(payload);
2565
- return displayName === skillId ? void 0 : displayName;
2566
- }
2567
- function parseModeChange2(message) {
2568
- if (message.kind !== "mode_change" || typeof message.content !== "string") {
2569
- return null;
2570
- }
2571
- try {
2572
- const parsed = JSON.parse(message.content);
2573
- if (typeof parsed.from === "string" && typeof parsed.to === "string") {
2574
- return { from: parsed.from, to: parsed.to };
2575
- }
2576
- } catch {
2577
- }
2578
- return null;
2579
- }
2580
- function isPlanningBoundaryMessage(message) {
2581
- if (message.kind === "planning_enter" || message.kind === "planning_exit") {
2582
- return true;
2583
- }
2584
- const modeChange = parseModeChange2(message);
2585
- if (!modeChange) {
2586
- return false;
2587
- }
2588
- return modeChange.to === "planning" || modeChange.from === "planning";
2589
- }
2590
- function parsePlanMessages(allMessages) {
2591
- const messages = Array.isArray(allMessages) ? allMessages : [];
2592
- let intent = "";
2593
- for (const msg of messages) {
2594
- if (!msg.tool_calls) continue;
2595
- const searchTc = msg.tool_calls.find(
2596
- (tc) => tc.name === "search_skills" || tc.name === "SearchSkills"
2597
- );
2598
- if (searchTc) {
2599
- try {
2600
- intent = JSON.parse(searchTc.arguments).query ?? "";
2601
- } catch {
2602
- }
2603
- if (intent) break;
2604
- }
2605
- }
2606
- const plannerMsgs = messages.filter(
2607
- (message) => !isPlanningBoundaryMessage(message)
2608
- );
2609
- const searchResults = [];
2610
- const searchMap = /* @__PURE__ */ new Map();
2611
- const selectedSkills = [];
2612
- const selectedSet = /* @__PURE__ */ new Set();
2613
- const askQuestions = [];
2614
- const readFiles = [];
2615
- let lastPauseTool = null;
2616
- let planContent = "";
2617
- let planContentPriority = 0;
2618
- let latestStatuses = {};
2619
- const setPlanContent = (nextContent, priority) => {
2620
- if (typeof nextContent !== "string" || !nextContent.trim()) {
2621
- return;
2622
- }
2623
- if (priority < planContentPriority) {
2624
- return;
2625
- }
2626
- planContent = nextContent;
2627
- planContentPriority = priority;
2628
- };
2629
- const applyPlanEdit = (args) => {
2630
- const oldString = typeof args.old_string === "string" ? args.old_string : "";
2631
- const newString = typeof args.new_string === "string" ? args.new_string : "";
2632
- if (!planContent || !oldString || !planContent.includes(oldString)) {
2633
- return;
2634
- }
2635
- planContent = planContent.replace(oldString, newString);
2636
- };
2637
- const maybeParsePlanStatus = (msg) => {
2638
- if (msg.kind !== "plan_status") return;
2639
- if (typeof msg.content !== "string" || !msg.content.trim()) return;
2640
- try {
2641
- const data = JSON.parse(msg.content);
2642
- setPlanContent(data.plan_yaml, 3);
2643
- if (data.statuses && typeof data.statuses === "object" && !Array.isArray(data.statuses)) {
2644
- latestStatuses = Object.fromEntries(
2645
- Object.entries(data.statuses).filter((entry) => typeof entry[0] === "string" && typeof entry[1] === "string").map(([stepId, status]) => [stepId, normalizePlanStatus(status)])
2646
- );
2647
- }
2648
- } catch {
2649
- }
2650
- };
2651
- for (const msg of plannerMsgs) {
2652
- maybeParsePlanStatus(msg);
2653
- if (!msg.tool_calls) continue;
2654
- for (const tc of msg.tool_calls) {
2655
- if ((tc.name === "search_skills" || tc.name === "SearchSkills") && resultAsString(tc.result)) {
2656
- try {
2657
- const parsed = JSON.parse(resultAsString(tc.result));
2658
- const results = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.results) ? parsed.results : [];
2659
- for (const r3 of results) {
2660
- const skillId = getSkillId(r3);
2661
- if (!skillId || searchMap.has(skillId)) continue;
2662
- const skill = {
2663
- skillId,
2664
- displayName: getSkillDisplayName(r3),
2665
- description: r3.description ?? ""
2666
- };
2667
- searchMap.set(skillId, skill);
2668
- searchResults.push(skill);
2669
- }
2670
- } catch {
2671
- }
2672
- }
2673
- if ((tc.name === "get_skill_content" || tc.name === "GetSkillContent") && resultAsString(tc.result)) {
2674
- try {
2675
- const data = JSON.parse(resultAsString(tc.result));
2676
- const skillId = getSkillId(data);
2677
- if (!skillId || selectedSet.has(skillId)) continue;
2678
- let existing = searchMap.get(skillId);
2679
- if (!existing) {
2680
- existing = {
2681
- skillId,
2682
- displayName: getSkillDisplayName(data),
2683
- description: data.description ?? ""
2684
- };
2685
- searchMap.set(skillId, existing);
2686
- searchResults.push(existing);
2687
- }
2688
- existing.displayName ??= getSkillDisplayName(data);
2689
- existing.content = data.content;
2690
- existing.references = extractRefs(data.content ?? "");
2691
- selectedSkills.push(existing);
2692
- selectedSet.add(skillId);
2693
- } catch {
2694
- }
2695
- }
2696
- if (tc.name === "AskUserQuestion" && resultAsString(tc.result)) {
2697
- const data = parseAskUserQuestion(resultAsString(tc.result));
2698
- if (data) {
2699
- askQuestions.push({ toolCallId: tc.id, data });
2700
- }
2701
- }
2702
- if (READ_FILE_TOOLS.has(tc.name) && tc.arguments) {
2703
- try {
2704
- const args = JSON.parse(tc.arguments);
2705
- if (typeof args.file_path === "string" && args.file_path) {
2706
- readFiles.push({ path: args.file_path, status: tc.status ?? "done" });
2707
- }
2708
- } catch {
2709
- }
2710
- }
2711
- if (PLAN_WRITE_TOOLS.has(tc.name) && tc.arguments && tc.status === "done" && !(typeof tc.result === "string" && tc.result.startsWith("\u9519\u8BEF"))) {
2712
- try {
2713
- const args = JSON.parse(tc.arguments);
2714
- if (typeof args.file_path === "string" && (args.file_path === "PLAN.yaml" || args.file_path.endsWith("/PLAN.yaml")) && typeof args.content === "string") {
2715
- setPlanContent(args.content, 1);
2716
- }
2717
- } catch {
2718
- }
2719
- }
2720
- if (PLAN_EDIT_TOOLS.has(tc.name) && tc.arguments && tc.status === "done" && !(typeof tc.result === "string" && tc.result.startsWith("\u9519\u8BEF"))) {
2721
- try {
2722
- const args = JSON.parse(tc.arguments);
2723
- if (typeof args.file_path === "string" && (args.file_path === "PLAN.yaml" || args.file_path.endsWith("/PLAN.yaml"))) {
2724
- applyPlanEdit(args);
2725
- }
2726
- } catch {
2727
- }
2728
- }
2729
- if (PAUSE_TOOLS.has(tc.name) && tc.status === "done") {
2730
- lastPauseTool = tc.name;
2731
- }
2732
- if (tc.name === "ExitPlanMode" && resultAsString(tc.result)) {
2733
- try {
2734
- const data = JSON.parse(resultAsString(tc.result));
2735
- setPlanContent(data.plan, 2);
2736
- } catch {
2737
- }
2738
- }
2739
- }
2740
- }
2741
- const { plan: parsedPlan, error: parseError } = parsePlanTreeResult(planContent);
2742
- const plan = parsedPlan == null ? null : {
2743
- ...parsedPlan,
2744
- root: applyPlanStatusesById(parsedPlan.root, latestStatuses)
2745
- };
2746
- return {
2747
- intent,
2748
- searchResults,
2749
- selectedSkills,
2750
- plan,
2751
- hasPlanContent: planContent.trim().length > 0,
2752
- parseError,
2753
- askQuestions,
2754
- readFiles,
2755
- lastPauseTool
2756
- };
2757
- }
2758
- function normalizePlanStatus(value) {
2759
- const normalized = value.trim().toLowerCase();
2760
- return normalized === "running" || normalized === "done" || normalized === "failed" ? normalized : "pending";
2761
- }
2762
- function extractRefs(content) {
2763
- const seen = /* @__PURE__ */ new Set();
2764
- const refs = [];
2765
- for (const m of content.matchAll(/\[\[([^\]]+)\]\]/g)) {
2766
- const ref = m[1].trim();
2767
- if (ref && !seen.has(ref)) {
2768
- seen.add(ref);
2769
- refs.push(ref);
2770
- }
2771
- }
2772
- return refs;
2773
- }
1
+ import {
2
+ AskUserQuestionBlock,
3
+ PlanSummaryCard,
4
+ extractLatestPlanMessages,
5
+ parsePlanMessages
6
+ } from "../../../chunk-X6MEYCU7.js";
7
+ import "../../../chunk-2UP7MG3J.js";
8
+ import "../../../chunk-4VWLTG5L.js";
9
+ import "../../../chunk-J3XVFPOV.js";
10
+ import "../../../chunk-OKQWPNE3.js";
11
+ import {
12
+ cn
13
+ } from "../../../chunk-7LEKQI47.js";
14
+ import "../../../chunk-JCJFFJ42.js";
15
+ import "../../../chunk-PZ5AY32C.js";
2774
16
 
2775
- // src/react/components/plan/PlanSummaryCard.tsx
2776
- import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
2777
- function PlanSummaryCard({
2778
- messages,
2779
- sessionStatus,
2780
- onConfirmPlan
2781
- }) {
2782
- const data = useMemo4(() => parsePlanMessages(messages), [messages]);
2783
- const rightPanelCollapsed = useUiStore((state) => state.rightPanelCollapsed);
2784
- const toggleRightPanel = useUiStore((state) => state.toggleRightPanel);
2785
- const setActiveRightTab = useUiStore((state) => state.setActiveRightTab);
2786
- const summaryState = useMemo4(() => getSummaryState(data, sessionStatus), [data, sessionStatus]);
2787
- const stepCount = useMemo4(() => countPlanSteps(data.plan), [data.plan]);
2788
- const isWaitingForInput = sessionStatus === "waiting_for_input";
2789
- const canConfirm = Boolean(onConfirmPlan) && isWaitingForInput && data.lastPauseTool === "ExitPlanMode";
2790
- const openPlanPanel = () => {
2791
- if (rightPanelCollapsed) {
2792
- toggleRightPanel();
2793
- }
2794
- setActiveRightTab("situation");
2795
- };
2796
- return /* @__PURE__ */ jsxs5("div", { className: "flex w-full flex-col gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.55)] p-4", children: [
2797
- /* @__PURE__ */ jsxs5(
2798
- "button",
2799
- {
2800
- type: "button",
2801
- onClick: openPlanPanel,
2802
- className: "flex w-full flex-col gap-4 text-left transition-colors hover:text-[hsl(var(--foreground))]",
2803
- children: [
2804
- /* @__PURE__ */ jsxs5("div", { className: "flex items-start justify-between gap-3", children: [
2805
- /* @__PURE__ */ jsxs5("div", { className: "min-w-0 space-y-2", children: [
2806
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
2807
- /* @__PURE__ */ jsx6(Sparkles, { size: 12 }),
2808
- /* @__PURE__ */ jsx6("span", { children: "\u89C4\u5212\u6458\u8981" })
2809
- ] }),
2810
- /* @__PURE__ */ jsx6("div", { className: "truncate text-base font-medium text-[hsl(var(--foreground))]", children: data.intent || "\u5F53\u524D\u89C4\u5212" }),
2811
- /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap items-center gap-2 text-xs", children: summaryState.kind === "progress" ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
2812
- /* @__PURE__ */ jsx6("span", { className: "rounded-full bg-[hsl(var(--accent))] px-2.5 py-1 text-[hsl(var(--foreground))]", children: summaryState.label }),
2813
- /* @__PURE__ */ jsx6("span", { className: "font-mono tracking-[0.25em] text-[hsl(var(--muted-foreground))]", children: summaryState.dots })
2814
- ] }) : /* @__PURE__ */ jsx6(
2815
- "span",
2816
- {
2817
- className: cn(
2818
- "rounded-full px-2.5 py-1",
2819
- summaryState.kind === "complete" && "bg-[hsl(var(--primary)/0.12)] text-[hsl(var(--primary))]",
2820
- summaryState.kind === "failed" && "bg-[hsl(var(--destructive)/0.12)] text-[hsl(var(--destructive))]",
2821
- summaryState.kind === "interrupted" && "bg-orange-500/12 text-orange-300"
2822
- ),
2823
- children: summaryState.label
2824
- }
2825
- ) })
2826
- ] }),
2827
- /* @__PURE__ */ jsx6(
2828
- ChevronRight,
2829
- {
2830
- size: 16,
2831
- className: "mt-1 shrink-0 text-[hsl(var(--muted-foreground))]",
2832
- "aria-hidden": "true"
2833
- }
2834
- )
2835
- ] }),
2836
- summaryState.kind === "complete" && /* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
2837
- /* @__PURE__ */ jsxs5("span", { className: "rounded-full border border-[hsl(var(--border))] px-2.5 py-1", children: [
2838
- data.selectedSkills.length,
2839
- " \u4E2A\u6280\u80FD"
2840
- ] }),
2841
- /* @__PURE__ */ jsxs5("span", { className: "rounded-full border border-[hsl(var(--border))] px-2.5 py-1", children: [
2842
- stepCount,
2843
- " \u4E2A\u6B65\u9AA4"
2844
- ] }),
2845
- /* @__PURE__ */ jsxs5("span", { className: "inline-flex items-center gap-1 text-[hsl(var(--muted-foreground))]", children: [
2846
- /* @__PURE__ */ jsx6(CheckCircle2, { size: 12 }),
2847
- "\u53F3\u4FA7\u67E5\u770B\u8BE6\u60C5"
2848
- ] })
2849
- ] })
2850
- ]
2851
- }
2852
- ),
2853
- canConfirm && /* @__PURE__ */ jsx6(PlanConfirmationPanel, { onConfirmPlan })
2854
- ] });
2855
- }
2856
- function PlanConfirmationPanel({
2857
- onConfirmPlan
2858
- }) {
2859
- const [isEditing, setIsEditing] = useState4(false);
2860
- const [revisionText, setRevisionText] = useState4("");
2861
- const submitRevision = () => {
2862
- const trimmed = revisionText.trim();
2863
- if (!trimmed) return;
2864
- onConfirmPlan?.("revise", trimmed);
2865
- setRevisionText("");
2866
- setIsEditing(false);
2867
- };
2868
- return /* @__PURE__ */ jsxs5("div", { className: "space-y-3 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--background)/0.45)] p-3", children: [
2869
- /* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap gap-2", children: [
2870
- /* @__PURE__ */ jsxs5(
2871
- "button",
2872
- {
2873
- type: "button",
2874
- onClick: () => onConfirmPlan?.("execute"),
2875
- className: "inline-flex items-center gap-1.5 rounded-lg bg-[hsl(var(--primary))] px-3 py-2 text-sm font-medium text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90",
2876
- children: [
2877
- /* @__PURE__ */ jsx6(Play, { size: 14 }),
2878
- "\u5F00\u59CB\u6267\u884C"
2879
- ]
2880
- }
2881
- ),
2882
- /* @__PURE__ */ jsxs5(
2883
- "button",
2884
- {
2885
- type: "button",
2886
- onClick: () => setIsEditing((value) => !value),
2887
- className: "inline-flex items-center gap-1.5 rounded-lg border border-[hsl(var(--border))] px-3 py-2 text-sm text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]",
2888
- children: [
2889
- /* @__PURE__ */ jsx6(PencilLine, { size: 14 }),
2890
- "\u4FEE\u6539"
2891
- ]
2892
- }
2893
- )
2894
- ] }),
2895
- isEditing && /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
2896
- /* @__PURE__ */ jsx6(
2897
- "textarea",
2898
- {
2899
- value: revisionText,
2900
- onChange: (event) => setRevisionText(event.target.value),
2901
- placeholder: "\u8F93\u5165\u4FEE\u6539\u5EFA\u8BAE...",
2902
- className: "min-h-24 w-full resize-y rounded-lg border border-[hsl(var(--border))] bg-transparent px-3 py-2 text-sm text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground))]"
2903
- }
2904
- ),
2905
- /* @__PURE__ */ jsx6("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx6(
2906
- "button",
2907
- {
2908
- type: "button",
2909
- disabled: !revisionText.trim(),
2910
- onClick: submitRevision,
2911
- className: "rounded-lg bg-[hsl(var(--primary))] px-3 py-1.5 text-xs font-medium text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:opacity-30",
2912
- children: "\u63D0\u4EA4\u4FEE\u6539\u610F\u89C1"
2913
- }
2914
- ) })
2915
- ] })
2916
- ] });
2917
- }
2918
- function getSummaryState(data, sessionStatus) {
2919
- if (sessionStatus === "failed") {
2920
- return { kind: "failed", label: "\u51FA\u9519" };
2921
- }
2922
- if (sessionStatus === "interrupted") {
2923
- return { kind: "interrupted", label: "\u5DF2\u4E2D\u65AD" };
2924
- }
2925
- if (data.parseError) {
2926
- return { kind: "failed", label: "\u89E3\u6790\u5931\u8D25" };
2927
- }
2928
- if (data.hasPlanContent || data.plan != null) {
2929
- return { kind: "complete", label: "\u5DF2\u751F\u6210" };
2930
- }
2931
- if (data.selectedSkills.length > 0) {
2932
- return { kind: "progress", label: "\u6280\u80FD\u5206\u6790\u4E2D", dots: "\u25CF\u25CF\u25CB" };
2933
- }
2934
- if (data.searchResults.length > 0) {
2935
- return { kind: "progress", label: "\u6280\u80FD\u53D1\u73B0\u4E2D", dots: "\u25CF\u25CB\u25CB" };
2936
- }
2937
- return { kind: "progress", label: "\u89C4\u5212\u51C6\u5907\u4E2D", dots: "\u25CB\u25CB\u25CB" };
17
+ // src/react/components/plan/debug-log.ts
18
+ var events = [];
19
+ var verbose = typeof window !== "undefined" && (window.location?.hostname === "localhost" || window.location?.hostname === "127.0.0.1");
20
+ function exportPlanLog() {
21
+ return [...events];
2938
22
  }
2939
- function countPlanSteps(plan) {
2940
- if (!plan) return 0;
2941
- const countNode = (node) => {
2942
- const children = Array.isArray(node.children) ? node.children : [];
2943
- return 1 + children.reduce((total, child) => total + countNode(child), 0);
2944
- };
2945
- if (plan.root.id === "plan-root") {
2946
- const children = Array.isArray(plan.root.children) ? plan.root.children : [];
2947
- return children.reduce((total, child) => total + countNode(child), 0);
2948
- }
2949
- return countNode(plan.root);
23
+ function downloadPlanLog() {
24
+ const blob = new Blob([JSON.stringify(events, null, 2)], { type: "application/json" });
25
+ const url = URL.createObjectURL(blob);
26
+ const a = document.createElement("a");
27
+ a.href = url;
28
+ a.download = `plan-timeline-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace(/:/g, "-")}.json`;
29
+ a.click();
30
+ URL.revokeObjectURL(url);
2950
31
  }
2951
32
 
2952
33
  // src/react/components/plan/PlanVisualization.tsx
2953
34
  import { BookOpen as BookOpen2, GitBranch as GitBranch2, Search as Search2 } from "lucide-react";
2954
- import { useMemo as useMemo7, useRef as useRef2, useState as useState6 } from "react";
35
+ import { useMemo as useMemo3, useRef, useState as useState2 } from "react";
2955
36
 
2956
37
  // src/react/components/plan/phases/PlanTree.tsx
2957
38
  import {
2958
39
  CheckSquare,
2959
- ChevronRight as ChevronRight3,
40
+ ChevronRight as ChevronRight2,
2960
41
  GitBranch,
2961
42
  List,
2962
43
  Workflow as Workflow2
2963
44
  } from "lucide-react";
2964
- import { useCallback, useMemo as useMemo5, useState as useState5 } from "react";
45
+ import { useCallback, useMemo, useState } from "react";
2965
46
 
2966
47
  // src/react/components/plan/phases/PlanMindMap.tsx
2967
- import { ChevronRight as ChevronRight2, Workflow } from "lucide-react";
48
+ import { ChevronRight, Workflow } from "lucide-react";
2968
49
 
2969
50
  // src/react/components/plan/phases/PlanStatusIcon.tsx
2970
- import { CheckCircle2 as CheckCircle22, Circle, Loader2 as Loader22, XCircle } from "lucide-react";
2971
- import { jsx as jsx7 } from "react/jsx-runtime";
51
+ import { CheckCircle2, Circle, Loader2, XCircle } from "lucide-react";
52
+ import { jsx } from "react/jsx-runtime";
2972
53
  function PlanStatusIcon({
2973
54
  status,
2974
55
  size = 16
2975
56
  }) {
2976
57
  if (status === "pending") {
2977
- return /* @__PURE__ */ jsx7(
58
+ return /* @__PURE__ */ jsx(
2978
59
  Circle,
2979
60
  {
2980
61
  size,
@@ -2983,8 +64,8 @@ function PlanStatusIcon({
2983
64
  );
2984
65
  }
2985
66
  if (status === "running") {
2986
- return /* @__PURE__ */ jsx7(
2987
- Loader22,
67
+ return /* @__PURE__ */ jsx(
68
+ Loader2,
2988
69
  {
2989
70
  size,
2990
71
  className: "shrink-0 animate-spin text-[hsl(var(--primary))] transition-transform duration-300"
@@ -2992,15 +73,15 @@ function PlanStatusIcon({
2992
73
  );
2993
74
  }
2994
75
  if (status === "done") {
2995
- return /* @__PURE__ */ jsx7(
2996
- CheckCircle22,
76
+ return /* @__PURE__ */ jsx(
77
+ CheckCircle2,
2997
78
  {
2998
79
  size,
2999
80
  className: "shrink-0 scale-105 text-green-500 transition-transform duration-300"
3000
81
  }
3001
82
  );
3002
83
  }
3003
- return /* @__PURE__ */ jsx7(
84
+ return /* @__PURE__ */ jsx(
3004
85
  XCircle,
3005
86
  {
3006
87
  size,
@@ -3010,9 +91,9 @@ function PlanStatusIcon({
3010
91
  }
3011
92
 
3012
93
  // src/react/components/plan/phases/PlanMindMap.tsx
3013
- import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
94
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
3014
95
  function PlanMindMap({ root, expandedIds, onToggle }) {
3015
- return /* @__PURE__ */ jsx8("div", { className: "overflow-x-auto py-2", children: /* @__PURE__ */ jsx8(MindMapSubtree, { node: root, expandedIds, onToggle, isRoot: true }) });
96
+ return /* @__PURE__ */ jsx2("div", { className: "overflow-x-auto py-2", children: /* @__PURE__ */ jsx2(MindMapSubtree, { node: root, expandedIds, onToggle, isRoot: true }) });
3016
97
  }
3017
98
  function MindMapSubtree({
3018
99
  node,
@@ -3024,8 +105,8 @@ function MindMapSubtree({
3024
105
  const hasChildren = children.length > 0;
3025
106
  const isExpanded = expandedIds.has(node.id);
3026
107
  const visibleChildren = hasChildren && isExpanded ? children : [];
3027
- return /* @__PURE__ */ jsxs6("div", { className: "flex items-center", children: [
3028
- /* @__PURE__ */ jsx8(
108
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
109
+ /* @__PURE__ */ jsx2(
3029
110
  "div",
3030
111
  {
3031
112
  role: hasChildren ? "button" : void 0,
@@ -3043,12 +124,12 @@ function MindMapSubtree({
3043
124
  hasChildren && "cursor-pointer",
3044
125
  isRoot ? "border-[hsl(var(--primary))] bg-[hsl(var(--primary)/0.15)] text-[hsl(var(--primary))]" : node.skillRef ? "border-[hsl(var(--primary)/0.4)] bg-[hsl(var(--primary)/0.08)] text-[hsl(var(--foreground))]" : "border-[hsl(var(--border))] bg-[hsl(var(--card))] text-[hsl(var(--foreground))]"
3045
126
  ),
3046
- children: /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-1.5", children: [
3047
- /* @__PURE__ */ jsx8(PlanStatusIcon, { status: node.status, size: 14 }),
3048
- node.skillRef && /* @__PURE__ */ jsx8(Workflow, { size: 12, className: "text-[hsl(var(--primary))]" }),
127
+ children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
128
+ /* @__PURE__ */ jsx2(PlanStatusIcon, { status: node.status, size: 14 }),
129
+ node.skillRef && /* @__PURE__ */ jsx2(Workflow, { size: 12, className: "text-[hsl(var(--primary))]" }),
3049
130
  node.label,
3050
- hasChildren && /* @__PURE__ */ jsx8(
3051
- ChevronRight2,
131
+ hasChildren && /* @__PURE__ */ jsx2(
132
+ ChevronRight,
3052
133
  {
3053
134
  size: 14,
3054
135
  className: cn(
@@ -3057,28 +138,28 @@ function MindMapSubtree({
3057
138
  )
3058
139
  }
3059
140
  ),
3060
- hasChildren && !isExpanded && /* @__PURE__ */ jsxs6("span", { className: "ml-0.5 rounded-full bg-[hsl(var(--muted))] px-1.5 py-px text-[10px] text-[hsl(var(--muted-foreground))]", children: [
141
+ hasChildren && !isExpanded && /* @__PURE__ */ jsxs("span", { className: "ml-0.5 rounded-full bg-[hsl(var(--muted))] px-1.5 py-px text-[10px] text-[hsl(var(--muted-foreground))]", children: [
3061
142
  "+",
3062
143
  children.length
3063
144
  ] })
3064
145
  ] })
3065
146
  }
3066
147
  ),
3067
- visibleChildren.length > 0 && /* @__PURE__ */ jsxs6(Fragment3, { children: [
3068
- /* @__PURE__ */ jsx8("div", { className: "h-px w-6 shrink-0 bg-[hsl(var(--border))]" }),
3069
- /* @__PURE__ */ jsx8(VerticalRail, { count: visibleChildren.length, children: visibleChildren.map((child) => /* @__PURE__ */ jsxs6("div", { className: "flex items-center", children: [
3070
- /* @__PURE__ */ jsx8("div", { className: "h-px w-4 shrink-0 bg-[hsl(var(--border))]" }),
3071
- /* @__PURE__ */ jsx8(MindMapSubtree, { node: child, expandedIds, onToggle })
148
+ visibleChildren.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
149
+ /* @__PURE__ */ jsx2("div", { className: "h-px w-6 shrink-0 bg-[hsl(var(--border))]" }),
150
+ /* @__PURE__ */ jsx2(VerticalRail, { count: visibleChildren.length, children: visibleChildren.map((child) => /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
151
+ /* @__PURE__ */ jsx2("div", { className: "h-px w-4 shrink-0 bg-[hsl(var(--border))]" }),
152
+ /* @__PURE__ */ jsx2(MindMapSubtree, { node: child, expandedIds, onToggle })
3072
153
  ] }, child.id)) })
3073
154
  ] })
3074
155
  ] });
3075
156
  }
3076
157
  function VerticalRail({ count, children }) {
3077
158
  if (count <= 1) {
3078
- return /* @__PURE__ */ jsx8("div", { className: "flex flex-col", children });
159
+ return /* @__PURE__ */ jsx2("div", { className: "flex flex-col", children });
3079
160
  }
3080
- return /* @__PURE__ */ jsx8("div", { className: "flex flex-col", children: children.map((child, i) => /* @__PURE__ */ jsxs6("div", { className: cn("relative", i > 0 && "pt-1.5"), children: [
3081
- /* @__PURE__ */ jsx8(
161
+ return /* @__PURE__ */ jsx2("div", { className: "flex flex-col", children: children.map((child, i) => /* @__PURE__ */ jsxs("div", { className: cn("relative", i > 0 && "pt-1.5"), children: [
162
+ /* @__PURE__ */ jsx2(
3082
163
  "div",
3083
164
  {
3084
165
  className: "absolute left-0 w-px bg-[hsl(var(--border))]",
@@ -3093,7 +174,7 @@ function VerticalRail({ count, children }) {
3093
174
  }
3094
175
 
3095
176
  // src/react/components/plan/phases/PlanTree.tsx
3096
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
177
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
3097
178
  function collectIdsToDepth(node, maxDepth, out) {
3098
179
  if (node.depth > maxDepth) return;
3099
180
  out.add(node.id);
@@ -3105,16 +186,16 @@ function treeFinger(node) {
3105
186
  return `${node.label}[${children.map(treeFinger).join(",")}]`;
3106
187
  }
3107
188
  function PlanTree({ root, notes, active }) {
3108
- return /* @__PURE__ */ jsx9(PlanTreeContent, { root, notes: notes ?? [], active }, treeFinger(root));
189
+ return /* @__PURE__ */ jsx3(PlanTreeContent, { root, notes: notes ?? [], active }, treeFinger(root));
3109
190
  }
3110
191
  function PlanTreeContent({ root, notes, active }) {
3111
- const [viewMode, setViewMode] = useState5("mindmap");
3112
- const defaultExpanded = useMemo5(() => {
192
+ const [viewMode, setViewMode] = useState("mindmap");
193
+ const defaultExpanded = useMemo(() => {
3113
194
  const ids = /* @__PURE__ */ new Set();
3114
195
  collectIdsToDepth(root, 1, ids);
3115
196
  return ids;
3116
197
  }, [root]);
3117
- const [expandedIds, setExpandedIds] = useState5(defaultExpanded);
198
+ const [expandedIds, setExpandedIds] = useState(defaultExpanded);
3118
199
  const toggle = useCallback((id) => {
3119
200
  setExpandedIds((prev) => {
3120
201
  const next = new Set(prev);
@@ -3123,9 +204,9 @@ function PlanTreeContent({ root, notes, active }) {
3123
204
  return next;
3124
205
  });
3125
206
  }, []);
3126
- return /* @__PURE__ */ jsx9("div", { className: cn(!active && "pointer-events-none opacity-0"), children: /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-3", children: [
3127
- /* @__PURE__ */ jsx9("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-0.5 rounded-lg border border-[hsl(var(--border))] p-0.5", children: [
3128
- /* @__PURE__ */ jsx9(
207
+ return /* @__PURE__ */ jsx3("div", { className: cn(!active && "pointer-events-none opacity-0"), children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-3", children: [
208
+ /* @__PURE__ */ jsx3("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-0.5 rounded-lg border border-[hsl(var(--border))] p-0.5", children: [
209
+ /* @__PURE__ */ jsx3(
3129
210
  "button",
3130
211
  {
3131
212
  type: "button",
@@ -3135,10 +216,10 @@ function PlanTreeContent({ root, notes, active }) {
3135
216
  viewMode === "mindmap" ? "bg-[hsl(var(--accent))] text-[hsl(var(--foreground))]" : "text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]"
3136
217
  ),
3137
218
  title: "\u601D\u7EF4\u5BFC\u56FE",
3138
- children: /* @__PURE__ */ jsx9(GitBranch, { size: 14 })
219
+ children: /* @__PURE__ */ jsx3(GitBranch, { size: 14 })
3139
220
  }
3140
221
  ),
3141
- /* @__PURE__ */ jsx9(
222
+ /* @__PURE__ */ jsx3(
3142
223
  "button",
3143
224
  {
3144
225
  type: "button",
@@ -3148,13 +229,13 @@ function PlanTreeContent({ root, notes, active }) {
3148
229
  viewMode === "tree" ? "bg-[hsl(var(--accent))] text-[hsl(var(--foreground))]" : "text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]"
3149
230
  ),
3150
231
  title: "\u5217\u8868\u89C6\u56FE",
3151
- children: /* @__PURE__ */ jsx9(List, { size: 14 })
232
+ children: /* @__PURE__ */ jsx3(List, { size: 14 })
3152
233
  }
3153
234
  )
3154
235
  ] }) }),
3155
- /* @__PURE__ */ jsx9("div", { className: "rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.5)] px-3 py-3", children: viewMode === "mindmap" ? /* @__PURE__ */ jsx9(PlanMindMap, { root, expandedIds, onToggle: toggle }) : /* @__PURE__ */ jsx9(TreeNode, { node: root }) }),
3156
- notes.length > 0 && /* @__PURE__ */ jsx9("div", { className: "rounded-xl border border-[hsl(var(--border)/0.5)] bg-[hsl(var(--card)/0.5)] px-4 py-3 text-sm text-[hsl(var(--muted-foreground))]", children: notes.map((note, i) => /* @__PURE__ */ jsxs7("p", { className: "py-0.5", children: [
3157
- /* @__PURE__ */ jsxs7("span", { className: "mr-1.5 text-[hsl(var(--primary)/0.6)]", children: [
236
+ /* @__PURE__ */ jsx3("div", { className: "rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.5)] px-3 py-3", children: viewMode === "mindmap" ? /* @__PURE__ */ jsx3(PlanMindMap, { root, expandedIds, onToggle: toggle }) : /* @__PURE__ */ jsx3(TreeNode, { node: root }) }),
237
+ notes.length > 0 && /* @__PURE__ */ jsx3("div", { className: "rounded-xl border border-[hsl(var(--border)/0.5)] bg-[hsl(var(--card)/0.5)] px-4 py-3 text-sm text-[hsl(var(--muted-foreground))]", children: notes.map((note, i) => /* @__PURE__ */ jsxs2("p", { className: "py-0.5", children: [
238
+ /* @__PURE__ */ jsxs2("span", { className: "mr-1.5 text-[hsl(var(--primary)/0.6)]", children: [
3158
239
  i + 1,
3159
240
  "."
3160
241
  ] }),
@@ -3165,43 +246,43 @@ function PlanTreeContent({ root, notes, active }) {
3165
246
  function TreeNode({ node }) {
3166
247
  const children = node.children ?? [];
3167
248
  const hasChildren = children.length > 0;
3168
- return /* @__PURE__ */ jsxs7("div", { children: [
3169
- /* @__PURE__ */ jsxs7(
249
+ return /* @__PURE__ */ jsxs2("div", { children: [
250
+ /* @__PURE__ */ jsxs2(
3170
251
  "div",
3171
252
  {
3172
253
  className: "group flex min-w-0 items-center gap-2 rounded-md px-2 py-2 hover:bg-[hsl(var(--accent)/0.5)]",
3173
254
  style: { paddingLeft: `${node.depth * 24 + 10}px` },
3174
255
  children: [
3175
- hasChildren ? /* @__PURE__ */ jsx9(
3176
- ChevronRight3,
256
+ hasChildren ? /* @__PURE__ */ jsx3(
257
+ ChevronRight2,
3177
258
  {
3178
259
  size: 16,
3179
260
  className: "shrink-0 rotate-90 text-[hsl(var(--muted-foreground)/0.6)]"
3180
261
  }
3181
- ) : /* @__PURE__ */ jsx9("span", { className: "w-4 shrink-0" }),
3182
- /* @__PURE__ */ jsx9(PlanStatusIcon, { status: node.status }),
3183
- node.skillRef ? /* @__PURE__ */ jsx9(Workflow2, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }) : /* @__PURE__ */ jsx9(CheckSquare, { size: 15, className: "shrink-0 text-[hsl(var(--muted-foreground))]" }),
3184
- /* @__PURE__ */ jsx9("span", { className: "min-w-0 flex-1 truncate text-[15px] font-medium text-[hsl(var(--foreground))]", children: node.label }),
3185
- node.skillRef && /* @__PURE__ */ jsx9("span", { className: "ml-auto max-w-[160px] shrink-0 truncate rounded bg-[hsl(var(--primary)/0.1)] px-2 py-0.5 text-sm font-medium text-[hsl(var(--primary)/0.8)]", children: node.skillRef })
262
+ ) : /* @__PURE__ */ jsx3("span", { className: "w-4 shrink-0" }),
263
+ /* @__PURE__ */ jsx3(PlanStatusIcon, { status: node.status }),
264
+ node.skillRef ? /* @__PURE__ */ jsx3(Workflow2, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }) : /* @__PURE__ */ jsx3(CheckSquare, { size: 15, className: "shrink-0 text-[hsl(var(--muted-foreground))]" }),
265
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 flex-1 truncate text-[15px] font-medium text-[hsl(var(--foreground))]", children: node.label }),
266
+ node.skillRef && /* @__PURE__ */ jsx3("span", { className: "ml-auto max-w-[160px] shrink-0 truncate rounded bg-[hsl(var(--primary)/0.1)] px-2 py-0.5 text-sm font-medium text-[hsl(var(--primary)/0.8)]", children: node.skillRef })
3186
267
  ]
3187
268
  }
3188
269
  ),
3189
- hasChildren && /* @__PURE__ */ jsxs7("div", { className: "relative", children: [
3190
- /* @__PURE__ */ jsx9(
270
+ hasChildren && /* @__PURE__ */ jsxs2("div", { className: "relative", children: [
271
+ /* @__PURE__ */ jsx3(
3191
272
  "div",
3192
273
  {
3193
274
  className: "absolute bottom-1 top-0 w-px bg-[hsl(var(--border)/0.4)]",
3194
275
  style: { left: `${node.depth * 24 + 18}px` }
3195
276
  }
3196
277
  ),
3197
- children.map((child) => /* @__PURE__ */ jsx9(TreeNode, { node: child }, child.id))
278
+ children.map((child) => /* @__PURE__ */ jsx3(TreeNode, { node: child }, child.id))
3198
279
  ] })
3199
280
  ] });
3200
281
  }
3201
282
 
3202
283
  // src/react/components/plan/phases/SkillAnalysis.tsx
3203
284
  import { BookOpen, Link2 } from "lucide-react";
3204
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
285
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
3205
286
  function planSkillDisplayName(skill) {
3206
287
  return skill.displayName?.trim() || skill.skillId;
3207
288
  }
@@ -3210,38 +291,38 @@ function extractSteps(content) {
3210
291
  }
3211
292
  function SkillAnalysis({ skills: rawSkills, active }) {
3212
293
  const skills = Array.isArray(rawSkills) ? rawSkills : [];
3213
- return /* @__PURE__ */ jsx10(
294
+ return /* @__PURE__ */ jsx4(
3214
295
  "div",
3215
296
  {
3216
297
  className: cn(
3217
298
  "transition-opacity duration-500",
3218
299
  active ? "opacity-100" : "pointer-events-none opacity-0"
3219
300
  ),
3220
- children: /* @__PURE__ */ jsx10("div", { className: "columns-2 gap-4", children: skills.map((skill) => {
301
+ children: /* @__PURE__ */ jsx4("div", { className: "columns-2 gap-4", children: skills.map((skill) => {
3221
302
  const steps = skill.content ? extractSteps(skill.content) : [];
3222
- return /* @__PURE__ */ jsxs8(
303
+ return /* @__PURE__ */ jsxs3(
3223
304
  "div",
3224
305
  {
3225
306
  className: "mb-4 break-inside-avoid overflow-hidden rounded-xl border border-[hsl(var(--primary)/0.4)] bg-[hsl(var(--card))] shadow-lg shadow-[hsl(var(--primary)/0.05)] transition-all duration-500",
3226
307
  children: [
3227
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 px-4 py-3", children: [
3228
- /* @__PURE__ */ jsx10(BookOpen, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }),
3229
- /* @__PURE__ */ jsx10("span", { className: "min-w-0 truncate text-[15px] font-semibold text-[hsl(var(--foreground))]", children: planSkillDisplayName(skill) })
308
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-4 py-3", children: [
309
+ /* @__PURE__ */ jsx4(BookOpen, { size: 15, className: "shrink-0 text-[hsl(var(--primary))]" }),
310
+ /* @__PURE__ */ jsx4("span", { className: "min-w-0 truncate text-[15px] font-semibold text-[hsl(var(--foreground))]", children: planSkillDisplayName(skill) })
3230
311
  ] }),
3231
- /* @__PURE__ */ jsx10("div", { className: "border-t border-[hsl(var(--border)/0.5)] px-4 py-2.5", children: /* @__PURE__ */ jsx10("p", { className: "text-sm leading-relaxed text-[hsl(var(--muted-foreground))]", children: skill.description }) }),
3232
- /* @__PURE__ */ jsxs8("div", { className: "border-t border-[hsl(var(--border)/0.5)] px-4 py-2.5", children: [
3233
- skill.references && skill.references.length > 0 && /* @__PURE__ */ jsx10("div", { className: "mb-2 flex flex-wrap gap-1.5", children: skill.references.map((ref, refIdx) => /* @__PURE__ */ jsxs8(
312
+ /* @__PURE__ */ jsx4("div", { className: "border-t border-[hsl(var(--border)/0.5)] px-4 py-2.5", children: /* @__PURE__ */ jsx4("p", { className: "text-sm leading-relaxed text-[hsl(var(--muted-foreground))]", children: skill.description }) }),
313
+ /* @__PURE__ */ jsxs3("div", { className: "border-t border-[hsl(var(--border)/0.5)] px-4 py-2.5", children: [
314
+ skill.references && skill.references.length > 0 && /* @__PURE__ */ jsx4("div", { className: "mb-2 flex flex-wrap gap-1.5", children: skill.references.map((ref, refIdx) => /* @__PURE__ */ jsxs3(
3234
315
  "span",
3235
316
  {
3236
317
  className: "inline-flex items-center gap-1 rounded-md bg-[hsl(var(--primary)/0.1)] px-2 py-0.5 text-xs text-[hsl(var(--primary))]",
3237
318
  children: [
3238
- /* @__PURE__ */ jsx10(Link2, { size: 10 }),
319
+ /* @__PURE__ */ jsx4(Link2, { size: 10 }),
3239
320
  ref
3240
321
  ]
3241
322
  },
3242
323
  `${refIdx}-${ref}`
3243
324
  )) }),
3244
- steps.length > 0 && /* @__PURE__ */ jsx10("ol", { className: "list-inside list-decimal space-y-0.5 text-sm leading-relaxed text-[hsl(var(--muted-foreground)/0.8)]", children: steps.map((step, idx) => /* @__PURE__ */ jsx10("li", { children: step }, idx)) })
325
+ steps.length > 0 && /* @__PURE__ */ jsx4("ol", { className: "list-inside list-decimal space-y-0.5 text-sm leading-relaxed text-[hsl(var(--muted-foreground)/0.8)]", children: steps.map((step, idx) => /* @__PURE__ */ jsx4("li", { children: step }, idx)) })
3245
326
  ] })
3246
327
  ]
3247
328
  },
@@ -3253,9 +334,9 @@ function SkillAnalysis({ skills: rawSkills, active }) {
3253
334
  }
3254
335
 
3255
336
  // src/react/components/plan/phases/SkillDiscovery.tsx
3256
- import { CheckCircle2 as CheckCircle23, Search, Sparkles as Sparkles2 } from "lucide-react";
3257
- import { useMemo as useMemo6 } from "react";
3258
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
337
+ import { CheckCircle2 as CheckCircle22, Search, Sparkles } from "lucide-react";
338
+ import { useMemo as useMemo2 } from "react";
339
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
3259
340
  function sizeClass(name) {
3260
341
  const hash = name.split("").reduce((acc, c) => acc + c.charCodeAt(0), 0);
3261
342
  const sizes = ["text-xs", "text-sm", "text-[15px]"];
@@ -3274,12 +355,12 @@ function SkillDiscovery({
3274
355
  const searchResults = Array.isArray(rawSearchResults) ? rawSearchResults : [];
3275
356
  const selectedSkills = Array.isArray(rawSelectedSkills) ? rawSelectedSkills : [];
3276
357
  const allSkillNames = Array.isArray(rawAllSkillNames) ? rawAllSkillNames : [];
3277
- const searchNames = useMemo6(() => new Set(searchResults.map((s) => s.skillId)), [searchResults]);
3278
- const selectedNames = useMemo6(
358
+ const searchNames = useMemo2(() => new Set(searchResults.map((s) => s.skillId)), [searchResults]);
359
+ const selectedNames = useMemo2(
3279
360
  () => new Set(selectedSkills.map((s) => s.skillId)),
3280
361
  [selectedSkills]
3281
362
  );
3282
- const cloudItems = useMemo6(() => {
363
+ const cloudItems = useMemo2(() => {
3283
364
  const bgItems = allSkillNames.filter((skill) => !searchNames.has(skill.skillId)).map((skill) => ({
3284
365
  name: planSkillDisplayName2(skill),
3285
366
  key: `bg:${skill.skillId}`,
@@ -3299,7 +380,7 @@ function SkillDiscovery({
3299
380
  }
3300
381
  return result;
3301
382
  }, [allSkillNames, searchNames, searchResults, selectedNames]);
3302
- return /* @__PURE__ */ jsxs9(
383
+ return /* @__PURE__ */ jsxs4(
3303
384
  "div",
3304
385
  {
3305
386
  className: cn(
@@ -3307,18 +388,18 @@ function SkillDiscovery({
3307
388
  active ? "opacity-100" : "pointer-events-none opacity-0"
3308
389
  ),
3309
390
  children: [
3310
- /* @__PURE__ */ jsxs9("div", { className: "flex shrink-0 max-w-md self-center flex-col items-center gap-2.5 rounded-2xl border border-[hsl(var(--primary)/0.4)] bg-[hsl(var(--primary)/0.08)] px-6 py-5 text-center shadow-lg shadow-[hsl(var(--primary)/0.1)]", children: [
3311
- /* @__PURE__ */ jsx11(Sparkles2, { size: 20, className: "text-[hsl(var(--primary))]" }),
3312
- /* @__PURE__ */ jsx11("p", { className: "break-words text-[15px] leading-relaxed text-[hsl(var(--foreground))]", children: intent })
391
+ /* @__PURE__ */ jsxs4("div", { className: "flex shrink-0 max-w-md self-center flex-col items-center gap-2.5 rounded-2xl border border-[hsl(var(--primary)/0.4)] bg-[hsl(var(--primary)/0.08)] px-6 py-5 text-center shadow-lg shadow-[hsl(var(--primary)/0.1)]", children: [
392
+ /* @__PURE__ */ jsx5(Sparkles, { size: 20, className: "text-[hsl(var(--primary))]" }),
393
+ /* @__PURE__ */ jsx5("p", { className: "break-words text-[15px] leading-relaxed text-[hsl(var(--foreground))]", children: intent })
3313
394
  ] }),
3314
- /* @__PURE__ */ jsx11("div", { className: "flex min-h-0 flex-1 flex-wrap content-start items-start justify-center gap-x-4 gap-y-3 overflow-y-auto px-6 pb-6", children: cloudItems.map((item) => {
395
+ /* @__PURE__ */ jsx5("div", { className: "flex min-h-0 flex-1 flex-wrap content-start items-start justify-center gap-x-4 gap-y-3 overflow-y-auto px-6 pb-6", children: cloudItems.map((item) => {
3315
396
  if (item.isSearch && item.isSelected) {
3316
- return /* @__PURE__ */ jsxs9(
397
+ return /* @__PURE__ */ jsxs4(
3317
398
  "span",
3318
399
  {
3319
400
  className: "inline-flex items-center gap-1.5 rounded-lg border border-[hsl(var(--primary)/0.5)] bg-[hsl(var(--primary)/0.12)] px-3 py-1.5 text-[15px] font-medium text-[hsl(var(--primary))] shadow-md shadow-[hsl(var(--primary)/0.15)] transition-all duration-500",
3320
401
  children: [
3321
- /* @__PURE__ */ jsx11(CheckCircle23, { size: 14, className: "shrink-0" }),
402
+ /* @__PURE__ */ jsx5(CheckCircle22, { size: 14, className: "shrink-0" }),
3322
403
  item.name
3323
404
  ]
3324
405
  },
@@ -3326,19 +407,19 @@ function SkillDiscovery({
3326
407
  );
3327
408
  }
3328
409
  if (item.isSearch) {
3329
- return /* @__PURE__ */ jsxs9(
410
+ return /* @__PURE__ */ jsxs4(
3330
411
  "span",
3331
412
  {
3332
413
  className: "inline-flex items-center gap-1.5 rounded-lg border border-[hsl(var(--foreground)/0.3)] bg-[hsl(var(--foreground)/0.08)] px-3 py-1.5 text-[15px] font-medium text-[hsl(var(--foreground))] transition-all duration-500",
3333
414
  children: [
3334
- /* @__PURE__ */ jsx11(Search, { size: 14, className: "shrink-0" }),
415
+ /* @__PURE__ */ jsx5(Search, { size: 14, className: "shrink-0" }),
3335
416
  item.name
3336
417
  ]
3337
418
  },
3338
419
  item.key
3339
420
  );
3340
421
  }
3341
- return /* @__PURE__ */ jsx11(
422
+ return /* @__PURE__ */ jsx5(
3342
423
  "span",
3343
424
  {
3344
425
  className: cn(
@@ -3356,7 +437,7 @@ function SkillDiscovery({
3356
437
  }
3357
438
 
3358
439
  // src/react/components/plan/PlanVisualization.tsx
3359
- import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
440
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
3360
441
  var PHASE_LABELS = [
3361
442
  { key: "discovering", label: "\u6280\u80FD\u53D1\u73B0", icon: Search2 },
3362
443
  { key: "analyzing", label: "\u6280\u80FD\u5206\u6790", icon: BookOpen2 },
@@ -3377,7 +458,7 @@ function PlanVisualization({
3377
458
  }) {
3378
459
  const messages = Array.isArray(rawMessages) ? rawMessages : [];
3379
460
  const allSkillNames = Array.isArray(rawAllSkillNames) ? rawAllSkillNames : [];
3380
- const data = useMemo7(() => parsePlanMessages(messages), [messages]);
461
+ const data = useMemo3(() => parsePlanMessages(messages), [messages]);
3381
462
  const latestIdx = getLatestPhaseIndex(data);
3382
463
  const isWaitingForInput = sessionStatus === "waiting_for_input";
3383
464
  const hasError = sessionStatus === "failed";
@@ -3387,26 +468,26 @@ function PlanVisualization({
3387
468
  const latestAskQuestion = data.askQuestions[data.askQuestions.length - 1];
3388
469
  const hasPhaseData = latestIdx >= 0;
3389
470
  const showAskQuestion = latestAskQuestion && isWaitingForInput && data.lastPauseTool === "AskUserQuestion" && onAnswer;
3390
- const [selectedTab, setSelectedTab] = useState6(null);
3391
- const prevLatestRef = useRef2(latestIdx);
471
+ const [selectedTab, setSelectedTab] = useState2(null);
472
+ const prevLatestRef = useRef(latestIdx);
3392
473
  if (latestIdx < prevLatestRef.current) {
3393
474
  setSelectedTab(null);
3394
475
  }
3395
476
  prevLatestRef.current = latestIdx;
3396
477
  const activeSelectedTab = selectedTab != null && selectedTab <= latestIdx ? selectedTab : null;
3397
478
  const viewIdx = activeSelectedTab ?? latestIdx;
3398
- return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.4)] p-5", children: [
3399
- hasPhaseData && /* @__PURE__ */ jsxs10(Fragment4, { children: [
3400
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between", children: [
3401
- /* @__PURE__ */ jsx12("div", { className: "flex items-center gap-1", children: PHASE_LABELS.map((p, i) => {
479
+ return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card)/0.4)] p-5", children: [
480
+ hasPhaseData && /* @__PURE__ */ jsxs5(Fragment2, { children: [
481
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between", children: [
482
+ /* @__PURE__ */ jsx6("div", { className: "flex items-center gap-1", children: PHASE_LABELS.map((p, i) => {
3402
483
  const Icon = p.icon;
3403
484
  const isViewing = viewIdx === i;
3404
485
  const isDone = latestIdx > i;
3405
486
  const isStatusPhase = i === activeStatusIdx && (hasError || isInterrupted);
3406
487
  const tabHasData = i === 0 && data.searchResults.length > 0 || i === 1 && data.selectedSkills.length > 0 || i === 2 && (data.plan != null || data.hasPlanContent);
3407
488
  const isReachable = i <= latestIdx || tabHasData;
3408
- return /* @__PURE__ */ jsxs10("div", { className: "flex items-center", children: [
3409
- i > 0 && /* @__PURE__ */ jsx12(
489
+ return /* @__PURE__ */ jsxs5("div", { className: "flex items-center", children: [
490
+ i > 0 && /* @__PURE__ */ jsx6(
3410
491
  "div",
3411
492
  {
3412
493
  className: cn(
@@ -3415,7 +496,7 @@ function PlanVisualization({
3415
496
  )
3416
497
  }
3417
498
  ),
3418
- /* @__PURE__ */ jsxs10(
499
+ /* @__PURE__ */ jsxs5(
3419
500
  "button",
3420
501
  {
3421
502
  type: "button",
@@ -3430,9 +511,9 @@ function PlanVisualization({
3430
511
  isReachable && !isViewing && !isDone && !tabHasData && "text-[hsl(var(--muted-foreground))]"
3431
512
  ),
3432
513
  children: [
3433
- /* @__PURE__ */ jsx12(Icon, { size: 12 }),
514
+ /* @__PURE__ */ jsx6(Icon, { size: 12 }),
3434
515
  p.label,
3435
- latestIdx === i && isSessionActive && activeSelectedTab === null && /* @__PURE__ */ jsx12(
516
+ latestIdx === i && isSessionActive && activeSelectedTab === null && /* @__PURE__ */ jsx6(
3436
517
  "span",
3437
518
  {
3438
519
  className: cn(
@@ -3441,7 +522,7 @@ function PlanVisualization({
3441
522
  )
3442
523
  }
3443
524
  ),
3444
- isStatusPhase && latestIdx !== i && /* @__PURE__ */ jsx12(
525
+ isStatusPhase && latestIdx !== i && /* @__PURE__ */ jsx6(
3445
526
  "span",
3446
527
  {
3447
528
  className: cn(
@@ -3455,13 +536,13 @@ function PlanVisualization({
3455
536
  )
3456
537
  ] }, p.key);
3457
538
  }) }),
3458
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1", children: [
3459
- hasError && /* @__PURE__ */ jsx12("span", { className: "rounded-full bg-[hsl(var(--destructive)/0.12)] px-2.5 py-1 text-xs font-medium text-[hsl(var(--destructive))]", children: "\u51FA\u9519" }),
3460
- isInterrupted && /* @__PURE__ */ jsx12("span", { className: "rounded-full bg-orange-500/10 px-2.5 py-1 text-xs font-medium text-orange-300", children: "\u5DF2\u4E2D\u65AD" })
539
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1", children: [
540
+ hasError && /* @__PURE__ */ jsx6("span", { className: "rounded-full bg-[hsl(var(--destructive)/0.12)] px-2.5 py-1 text-xs font-medium text-[hsl(var(--destructive))]", children: "\u51FA\u9519" }),
541
+ isInterrupted && /* @__PURE__ */ jsx6("span", { className: "rounded-full bg-orange-500/10 px-2.5 py-1 text-xs font-medium text-orange-300", children: "\u5DF2\u4E2D\u65AD" })
3461
542
  ] })
3462
543
  ] }),
3463
- /* @__PURE__ */ jsxs10("div", { className: "min-h-0", children: [
3464
- viewIdx === 0 && /* @__PURE__ */ jsx12(
544
+ /* @__PURE__ */ jsxs5("div", { className: "min-h-0", children: [
545
+ viewIdx === 0 && /* @__PURE__ */ jsx6(
3465
546
  SkillDiscovery,
3466
547
  {
3467
548
  intent: data.intent,
@@ -3471,12 +552,12 @@ function PlanVisualization({
3471
552
  active: true
3472
553
  }
3473
554
  ),
3474
- viewIdx === 1 && /* @__PURE__ */ jsx12(SkillAnalysis, { skills: data.selectedSkills, active: true }),
3475
- viewIdx === 2 && (data.plan != null ? /* @__PURE__ */ jsx12(PlanTree, { root: data.plan.root, notes: data.plan.notes, active: true }) : data.parseError ? /* @__PURE__ */ jsx12("div", { className: "flex min-h-[240px] items-center justify-center rounded-xl border border-[hsl(var(--destructive)/0.35)] bg-[hsl(var(--destructive)/0.08)] px-6 text-sm text-[hsl(var(--destructive))]", children: data.parseError }) : data.hasPlanContent ? /* @__PURE__ */ jsx12("div", { className: "flex min-h-[240px] items-center justify-center rounded-xl border border-dashed border-[hsl(var(--border))] bg-[hsl(var(--card)/0.3)] px-6 text-sm text-[hsl(var(--muted-foreground))]", children: "\u8BA1\u5212\u89E3\u6790\u4E2D..." }) : null)
555
+ viewIdx === 1 && /* @__PURE__ */ jsx6(SkillAnalysis, { skills: data.selectedSkills, active: true }),
556
+ viewIdx === 2 && (data.plan != null ? /* @__PURE__ */ jsx6(PlanTree, { root: data.plan.root, notes: data.plan.notes, active: true }) : data.parseError ? /* @__PURE__ */ jsx6("div", { className: "flex min-h-[240px] items-center justify-center rounded-xl border border-[hsl(var(--destructive)/0.35)] bg-[hsl(var(--destructive)/0.08)] px-6 text-sm text-[hsl(var(--destructive))]", children: data.parseError }) : data.hasPlanContent ? /* @__PURE__ */ jsx6("div", { className: "flex min-h-[240px] items-center justify-center rounded-xl border border-dashed border-[hsl(var(--border))] bg-[hsl(var(--card)/0.3)] px-6 text-sm text-[hsl(var(--muted-foreground))]", children: "\u8BA1\u5212\u89E3\u6790\u4E2D..." }) : null)
3476
557
  ] })
3477
558
  ] }),
3478
- !hasPhaseData && showAskQuestion && /* @__PURE__ */ jsx12(AskUserQuestionBlock, { data: latestAskQuestion.data, answered: false, toolCallId: latestAskQuestion.toolCallId, sessionStatus: sessionStatus ?? "", onAnswer }),
3479
- hasPhaseData && showAskQuestion && /* @__PURE__ */ jsx12(AskUserQuestionBlock, { data: latestAskQuestion.data, answered: false, toolCallId: latestAskQuestion.toolCallId, sessionStatus: sessionStatus ?? "", onAnswer })
559
+ !hasPhaseData && showAskQuestion && /* @__PURE__ */ jsx6(AskUserQuestionBlock, { data: latestAskQuestion.data, answered: false, toolCallId: latestAskQuestion.toolCallId, sessionStatus: sessionStatus ?? "", onAnswer }),
560
+ hasPhaseData && showAskQuestion && /* @__PURE__ */ jsx6(AskUserQuestionBlock, { data: latestAskQuestion.data, answered: false, toolCallId: latestAskQuestion.toolCallId, sessionStatus: sessionStatus ?? "", onAnswer })
3480
561
  ] });
3481
562
  }
3482
563
  export {