@nextop-os/workspace-issue-manager 0.0.16 → 0.0.17

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.
@@ -0,0 +1,3316 @@
1
+ import {
2
+ appendIssueManagerWorkspaceFileLinksToContent,
3
+ extractIssueManagerPlainTextFromContent,
4
+ extractIssueManagerWorkspaceFileLinksFromContent,
5
+ normalizeIssueManagerContent,
6
+ normalizeIssueManagerNodeState
7
+ } from "./chunk-LYYOPZIJ.js";
8
+
9
+ // src/react/internal/useIssueManagerController.ts
10
+ import { useDeferredValue, useEffect, useState } from "react";
11
+
12
+ // src/react/internal/controllerUtils.ts
13
+ var defaultTaskPriority = "medium";
14
+ function resolveIssueManagerSelectedIssueId(currentSelectedIssueId, issues) {
15
+ if (currentSelectedIssueId && issues.some((issue) => issue.issueId === currentSelectedIssueId)) {
16
+ return currentSelectedIssueId;
17
+ }
18
+ return issues[0]?.issueId ?? null;
19
+ }
20
+ function resolveIssueManagerSelectedTaskId(currentSelectedTaskId, tasks) {
21
+ if (currentSelectedTaskId && tasks.some((task) => task.taskId === currentSelectedTaskId)) {
22
+ return currentSelectedTaskId;
23
+ }
24
+ return tasks[0]?.taskId ?? null;
25
+ }
26
+ function toContextRefInput(ref) {
27
+ return {
28
+ displayName: ref.displayName,
29
+ path: ref.path,
30
+ refType: ref.kind === "folder" ? "folder" : "file"
31
+ };
32
+ }
33
+ function toIssueManagerWorkspaceFileLinkInput(ref) {
34
+ return {
35
+ kind: ref.kind === "folder" ? "folder" : "file",
36
+ name: ref.displayName,
37
+ path: ref.path
38
+ };
39
+ }
40
+ function confirmIssueManagerMessage(message) {
41
+ try {
42
+ return globalThis.confirm?.(message) ?? true;
43
+ } catch {
44
+ return true;
45
+ }
46
+ }
47
+ function resolveIssueManagerErrorMessage(error, copy) {
48
+ const raw = error instanceof Error ? error.message : typeof error === "string" ? error : String(error);
49
+ if (!copy) {
50
+ return raw;
51
+ }
52
+ if (raw === "issue_manager.upload_type_conflict") {
53
+ return copy.t("messages.uploadTypeConflict");
54
+ }
55
+ if (raw === "issue_manager.workspace_path_unavailable") {
56
+ return copy.t("messages.workspacePathUnavailable");
57
+ }
58
+ if (raw === "issue_manager.run_status_missing") {
59
+ return copy.t("messages.runStatusMissing");
60
+ }
61
+ if (raw === "issue_manager.run_timed_out") {
62
+ return copy.t("messages.runTimedOut");
63
+ }
64
+ if (raw.startsWith("issue_manager.run_exit_code:")) {
65
+ return copy.t("messages.runExitCode", {
66
+ code: raw.slice("issue_manager.run_exit_code:".length)
67
+ });
68
+ }
69
+ return raw;
70
+ }
71
+
72
+ // src/react/internal/controllerActions.ts
73
+ function createIssueManagerControllerActions(input) {
74
+ const {
75
+ copy,
76
+ feature,
77
+ issueDetail,
78
+ issueDraft,
79
+ issueEditorMode,
80
+ nodeState,
81
+ referenceTarget,
82
+ refreshAll,
83
+ refreshDetails,
84
+ setIsRunningTask,
85
+ setIssueDraftInternal,
86
+ setIssueEditorModeState,
87
+ setNotice,
88
+ setReferenceTarget,
89
+ setTaskDraftInternal,
90
+ setTaskEditorModeState,
91
+ taskDetail,
92
+ taskDraft,
93
+ taskEditorMode,
94
+ updateNodeState,
95
+ workspaceId
96
+ } = input;
97
+ const submitReferences = async (refs, target = referenceTarget) => {
98
+ const dedupedRefs = refs.filter((ref) => ref.path.trim().length > 0);
99
+ if (!target || dedupedRefs.length === 0) {
100
+ setReferenceTarget(null);
101
+ return;
102
+ }
103
+ if (target.mode === "insert") {
104
+ if (target.parentKind === "issue") {
105
+ setIssueDraftInternal((current) => ({
106
+ ...current,
107
+ content: appendIssueManagerWorkspaceFileLinksToContent(
108
+ current.content,
109
+ dedupedRefs.map(toIssueManagerWorkspaceFileLinkInput)
110
+ )
111
+ }));
112
+ } else {
113
+ setTaskDraftInternal((current) => ({
114
+ ...current,
115
+ content: appendIssueManagerWorkspaceFileLinksToContent(
116
+ current.content,
117
+ dedupedRefs.map(toIssueManagerWorkspaceFileLinkInput)
118
+ )
119
+ }));
120
+ }
121
+ setReferenceTarget(null);
122
+ return;
123
+ }
124
+ const selectedIssueId = nodeState.selectedIssueId;
125
+ if (!selectedIssueId) {
126
+ setReferenceTarget(null);
127
+ return;
128
+ }
129
+ await feature.backend.addContextRefs(
130
+ target.parentKind === "task" ? {
131
+ issueId: selectedIssueId,
132
+ parentKind: "task",
133
+ refs: dedupedRefs.map(toContextRefInput),
134
+ taskId: target.taskId,
135
+ workspaceId
136
+ } : {
137
+ issueId: selectedIssueId,
138
+ parentKind: "issue",
139
+ refs: dedupedRefs.map(toContextRefInput),
140
+ workspaceId
141
+ }
142
+ );
143
+ setReferenceTarget(null);
144
+ refreshDetails();
145
+ };
146
+ const createInsertReferenceTarget = (parentKind) => parentKind === "task" ? {
147
+ mode: "insert",
148
+ parentKind: "task",
149
+ taskId: nodeState.selectedTaskId ?? ""
150
+ } : {
151
+ mode: "insert",
152
+ parentKind: "issue"
153
+ };
154
+ const syncContentReferences = async (payload) => {
155
+ const existingPaths = new Set(payload.existingRefs.map((ref) => ref.path));
156
+ const missingRefs = extractIssueManagerWorkspaceFileLinksFromContent(
157
+ payload.content
158
+ ).filter((ref) => !existingPaths.has(ref.path)).map((ref) => ({
159
+ displayName: ref.name,
160
+ path: ref.path,
161
+ refType: ref.kind
162
+ }));
163
+ if (missingRefs.length === 0) {
164
+ return;
165
+ }
166
+ await feature.backend.addContextRefs(
167
+ payload.parentKind === "task" ? {
168
+ issueId: payload.issueId,
169
+ parentKind: "task",
170
+ refs: missingRefs,
171
+ taskId: payload.taskId ?? "",
172
+ workspaceId
173
+ } : {
174
+ issueId: payload.issueId,
175
+ parentKind: "issue",
176
+ refs: missingRefs,
177
+ workspaceId
178
+ }
179
+ );
180
+ };
181
+ return {
182
+ async attachReferences(parentKind) {
183
+ if (!feature.fileAdapter) {
184
+ return;
185
+ }
186
+ if (parentKind === "task" && !nodeState.selectedTaskId) {
187
+ return;
188
+ }
189
+ if (feature.fileAdapter.requestReferences && !feature.fileAdapter.listDirectory && !feature.fileAdapter.searchReferences) {
190
+ const refs = await feature.fileAdapter.requestReferences({
191
+ workspaceId
192
+ });
193
+ await submitReferences(
194
+ refs,
195
+ parentKind === "task" ? {
196
+ mode: "attach",
197
+ parentKind: "task",
198
+ taskId: nodeState.selectedTaskId ?? ""
199
+ } : {
200
+ mode: "attach",
201
+ parentKind: "issue"
202
+ }
203
+ );
204
+ return;
205
+ }
206
+ setReferenceTarget(
207
+ parentKind === "task" ? { mode: "attach", parentKind, taskId: nodeState.selectedTaskId } : { mode: "attach", parentKind }
208
+ );
209
+ },
210
+ createTaskDraft() {
211
+ setTaskEditorModeState("create");
212
+ setTaskDraftInternal({
213
+ content: nodeState.taskDraftContent ?? "",
214
+ priority: defaultTaskPriority,
215
+ title: nodeState.taskDraftTitle ?? ""
216
+ });
217
+ updateNodeState((current) => ({
218
+ ...current,
219
+ selectedTaskId: null
220
+ }));
221
+ },
222
+ async deleteIssue() {
223
+ const selectedIssueId = nodeState.selectedIssueId;
224
+ if (!selectedIssueId || !confirmIssueManagerMessage(copy.t("confirmations.deleteIssue"))) {
225
+ return;
226
+ }
227
+ try {
228
+ await feature.backend.deleteIssue({
229
+ issueId: selectedIssueId,
230
+ workspaceId
231
+ });
232
+ setNotice({
233
+ kind: "success",
234
+ message: copy.t("messages.issueDeleted")
235
+ });
236
+ setIssueEditorModeState("read");
237
+ setTaskEditorModeState("read");
238
+ updateNodeState((current) => ({
239
+ ...current,
240
+ selectedIssueId: null,
241
+ selectedTaskId: null
242
+ }));
243
+ refreshAll();
244
+ } catch (error) {
245
+ setNotice({
246
+ kind: "error",
247
+ message: resolveIssueManagerErrorMessage(error, copy)
248
+ });
249
+ }
250
+ },
251
+ async deleteTask() {
252
+ const selectedIssueId = nodeState.selectedIssueId;
253
+ const selectedTaskId = nodeState.selectedTaskId;
254
+ if (!selectedIssueId || !selectedTaskId || !confirmIssueManagerMessage(copy.t("confirmations.deleteTask"))) {
255
+ return;
256
+ }
257
+ try {
258
+ await feature.backend.deleteTask({
259
+ issueId: selectedIssueId,
260
+ taskId: selectedTaskId,
261
+ workspaceId
262
+ });
263
+ setNotice({
264
+ kind: "success",
265
+ message: copy.t("messages.taskDeleted")
266
+ });
267
+ setTaskEditorModeState("read");
268
+ updateNodeState((current) => ({
269
+ ...current,
270
+ selectedTaskId: null
271
+ }));
272
+ refreshAll();
273
+ } catch (error) {
274
+ setNotice({
275
+ kind: "error",
276
+ message: resolveIssueManagerErrorMessage(error, copy)
277
+ });
278
+ }
279
+ },
280
+ async insertReferences(parentKind) {
281
+ if (!feature.fileAdapter) {
282
+ return;
283
+ }
284
+ if (parentKind === "task" && !nodeState.selectedTaskId && taskEditorMode !== "create") {
285
+ return;
286
+ }
287
+ if (feature.fileAdapter.requestReferences && !feature.fileAdapter.listDirectory && !feature.fileAdapter.searchReferences) {
288
+ const refs = await feature.fileAdapter.requestReferences({
289
+ workspaceId
290
+ });
291
+ await submitReferences(refs, createInsertReferenceTarget(parentKind));
292
+ return;
293
+ }
294
+ setReferenceTarget(createInsertReferenceTarget(parentKind));
295
+ },
296
+ async uploadReferences(parentKind, mode) {
297
+ if (!feature.fileAdapter?.requestUpload) {
298
+ return;
299
+ }
300
+ const refs = await feature.fileAdapter.requestUpload({
301
+ mode,
302
+ targetDirectoryPath: "/",
303
+ workspaceId
304
+ });
305
+ if (refs.length === 0) {
306
+ return;
307
+ }
308
+ await feature.fileAdapter.refreshTree?.({
309
+ depth: 1,
310
+ paths: refs.map((ref) => ref.path),
311
+ workspaceId
312
+ });
313
+ await submitReferences(refs, createInsertReferenceTarget(parentKind));
314
+ },
315
+ async openReference(reference) {
316
+ await feature.fileAdapter?.openReference?.(reference);
317
+ },
318
+ async removeContextRef(ref) {
319
+ try {
320
+ await feature.backend.removeContextRef(
321
+ ref.parentKind === "task" ? {
322
+ contextRefId: ref.contextRefId,
323
+ issueId: ref.issueId,
324
+ parentKind: "task",
325
+ taskId: ref.taskId,
326
+ workspaceId
327
+ } : {
328
+ contextRefId: ref.contextRefId,
329
+ issueId: ref.issueId,
330
+ parentKind: "issue",
331
+ workspaceId
332
+ }
333
+ );
334
+ refreshDetails();
335
+ } catch (error) {
336
+ setNotice({
337
+ kind: "error",
338
+ message: resolveIssueManagerErrorMessage(error, copy)
339
+ });
340
+ }
341
+ },
342
+ async runTask(providerOverride) {
343
+ if (!issueDetail.value || !taskDetail.value) {
344
+ return;
345
+ }
346
+ const provider = providerOverride?.trim() || nodeState.selectedAgentProvider.trim();
347
+ if (!provider) {
348
+ return;
349
+ }
350
+ if (provider !== nodeState.selectedAgentProvider) {
351
+ updateNodeState((current) => ({
352
+ ...current,
353
+ selectedAgentProvider: provider
354
+ }));
355
+ }
356
+ setIsRunningTask(true);
357
+ let createdRun = null;
358
+ try {
359
+ const currentUser = await Promise.resolve(
360
+ feature.identityAdapter.currentUser()
361
+ );
362
+ createdRun = await feature.backend.createRun({
363
+ agentProvider: provider,
364
+ agentUserId: currentUser?.userId ?? void 0,
365
+ issueId: issueDetail.value.issue.issueId,
366
+ taskId: taskDetail.value.task.taskId,
367
+ workspaceId
368
+ });
369
+ setNotice({
370
+ kind: "success",
371
+ message: copy.t("messages.runStarted")
372
+ });
373
+ refreshDetails();
374
+ const result = await feature.agentRunner.runTask({
375
+ issue: issueDetail.value.issue,
376
+ provider,
377
+ run: createdRun,
378
+ task: taskDetail.value.task,
379
+ workspaceId
380
+ });
381
+ await feature.backend.completeRun({
382
+ errorMessage: result.errorMessage,
383
+ issueId: issueDetail.value.issue.issueId,
384
+ outputs: result.outputs ?? [],
385
+ runId: createdRun.runId,
386
+ status: result.status,
387
+ summary: result.summary,
388
+ taskId: taskDetail.value.task.taskId,
389
+ workspaceId
390
+ });
391
+ setNotice({
392
+ kind: result.status === "completed" ? "success" : "error",
393
+ message: result.status === "completed" ? copy.t("messages.runCompleted") : copy.t("messages.runFailed")
394
+ });
395
+ } catch (error) {
396
+ const message = resolveIssueManagerErrorMessage(error, copy);
397
+ if (createdRun && issueDetail.value && taskDetail.value) {
398
+ try {
399
+ await feature.backend.completeRun({
400
+ errorMessage: message,
401
+ issueId: issueDetail.value.issue.issueId,
402
+ outputs: [],
403
+ runId: createdRun.runId,
404
+ status: "failed",
405
+ summary: copy.t("run.failedSummaryFallback"),
406
+ taskId: taskDetail.value.task.taskId,
407
+ workspaceId
408
+ });
409
+ } catch {
410
+ }
411
+ }
412
+ setNotice({
413
+ kind: "error",
414
+ message
415
+ });
416
+ } finally {
417
+ setIsRunningTask(false);
418
+ refreshDetails();
419
+ }
420
+ },
421
+ async saveIssue() {
422
+ const title = issueDraft.title.trim();
423
+ if (!title) {
424
+ return;
425
+ }
426
+ try {
427
+ const content = normalizeIssueManagerContent(issueDraft.content);
428
+ const savedIssue = issueEditorMode === "create" ? await feature.backend.createIssue({
429
+ content,
430
+ title,
431
+ workspaceId
432
+ }) : await feature.backend.updateIssue({
433
+ content,
434
+ issueId: nodeState.selectedIssueId ?? "",
435
+ title,
436
+ workspaceId
437
+ });
438
+ await syncContentReferences({
439
+ content,
440
+ existingRefs: issueEditorMode === "create" ? [] : issueDetail.value?.contextRefs.filter(
441
+ (ref) => ref.parentKind === "issue"
442
+ ) ?? [],
443
+ issueId: savedIssue.issueId,
444
+ parentKind: "issue"
445
+ });
446
+ setIssueEditorModeState("read");
447
+ setNotice({
448
+ kind: "success",
449
+ message: copy.t("messages.issueSaved")
450
+ });
451
+ updateNodeState((current) => ({
452
+ ...current,
453
+ issueDraftContent: null,
454
+ issueDraftTitle: null,
455
+ selectedIssueId: savedIssue.issueId
456
+ }));
457
+ refreshAll();
458
+ } catch (error) {
459
+ setNotice({
460
+ kind: "error",
461
+ message: resolveIssueManagerErrorMessage(error, copy)
462
+ });
463
+ }
464
+ },
465
+ async saveTask() {
466
+ const selectedIssueId = nodeState.selectedIssueId;
467
+ if (!selectedIssueId) {
468
+ return;
469
+ }
470
+ const title = taskDraft.title.trim();
471
+ if (!title) {
472
+ return;
473
+ }
474
+ try {
475
+ const content = normalizeIssueManagerContent(taskDraft.content);
476
+ const savedTask = taskEditorMode === "create" ? await feature.backend.createTask({
477
+ content,
478
+ issueId: selectedIssueId,
479
+ priority: taskDraft.priority,
480
+ title,
481
+ workspaceId
482
+ }) : await feature.backend.updateTask({
483
+ content,
484
+ issueId: selectedIssueId,
485
+ priority: taskDraft.priority,
486
+ taskId: nodeState.selectedTaskId ?? "",
487
+ title,
488
+ workspaceId
489
+ });
490
+ await syncContentReferences({
491
+ content,
492
+ existingRefs: taskEditorMode === "create" ? [] : taskDetail.value?.contextRefs.filter(
493
+ (ref) => ref.parentKind === "task"
494
+ ) ?? [],
495
+ issueId: selectedIssueId,
496
+ parentKind: "task",
497
+ taskId: savedTask.taskId
498
+ });
499
+ setTaskEditorModeState("read");
500
+ setNotice({
501
+ kind: "success",
502
+ message: copy.t("messages.taskSaved")
503
+ });
504
+ updateNodeState((current) => ({
505
+ ...current,
506
+ selectedTaskId: savedTask.taskId,
507
+ taskDraftContent: null,
508
+ taskDraftTitle: null
509
+ }));
510
+ refreshAll();
511
+ } catch (error) {
512
+ setNotice({
513
+ kind: "error",
514
+ message: resolveIssueManagerErrorMessage(error, copy)
515
+ });
516
+ }
517
+ },
518
+ async shareSelection() {
519
+ const selectedIssueId = nodeState.selectedIssueId;
520
+ if (!feature.shareAdapter?.createIssueLink || !selectedIssueId) {
521
+ return;
522
+ }
523
+ try {
524
+ const link = await feature.shareAdapter.createIssueLink({
525
+ issueId: selectedIssueId,
526
+ taskId: nodeState.selectedTaskId ?? void 0,
527
+ workspaceId
528
+ });
529
+ if (typeof navigator === "undefined" || !navigator.clipboard?.writeText) {
530
+ throw new Error(copy.t("messages.clipboardUnavailable"));
531
+ }
532
+ await navigator.clipboard.writeText(link);
533
+ setNotice({
534
+ kind: "success",
535
+ message: copy.t("messages.copiedShareLink")
536
+ });
537
+ } catch (error) {
538
+ setNotice({
539
+ kind: "error",
540
+ message: resolveIssueManagerErrorMessage(error, copy)
541
+ });
542
+ }
543
+ },
544
+ async submitReferenceSelection(refs) {
545
+ await submitReferences(refs);
546
+ }
547
+ };
548
+ }
549
+
550
+ // src/react/internal/controllerState.ts
551
+ function createIssueManagerIssueDraftFromNodeState(state) {
552
+ return {
553
+ content: state?.issueDraftContent ?? "",
554
+ title: state?.issueDraftTitle ?? ""
555
+ };
556
+ }
557
+ function createIssueManagerTaskDraftFromNodeState(state, priority = defaultTaskPriority) {
558
+ return {
559
+ content: state?.taskDraftContent ?? "",
560
+ priority,
561
+ title: state?.taskDraftTitle ?? ""
562
+ };
563
+ }
564
+ function applyIssueManagerIssueSelection(current, issueId) {
565
+ return {
566
+ ...current,
567
+ selectedIssueId: issueId,
568
+ selectedTaskId: null
569
+ };
570
+ }
571
+ function applyIssueManagerTaskSelection(current, taskId) {
572
+ return {
573
+ ...current,
574
+ selectedTaskId: taskId
575
+ };
576
+ }
577
+ function applyIssueManagerIssueListResultToNodeState(current, result) {
578
+ return {
579
+ ...current,
580
+ issueListNextPageToken: result.nextPageToken ?? null,
581
+ selectedIssueId: resolveIssueManagerSelectedIssueId(
582
+ current.selectedIssueId,
583
+ result.issues
584
+ )
585
+ };
586
+ }
587
+ function applyIssueManagerIssueDetailResultToNodeState(current, detail) {
588
+ return {
589
+ ...current,
590
+ selectedTaskId: resolveIssueManagerSelectedTaskId(
591
+ current.selectedTaskId,
592
+ detail.tasks
593
+ )
594
+ };
595
+ }
596
+ function syncIssueManagerIssueDraftFromDetail(current, detail, editorMode) {
597
+ if (editorMode !== "read") {
598
+ return current;
599
+ }
600
+ return {
601
+ content: normalizeIssueManagerContent(detail?.issue.content ?? ""),
602
+ title: detail?.issue.title ?? ""
603
+ };
604
+ }
605
+ function syncIssueManagerTaskDraftFromDetail(current, detail, editorMode) {
606
+ if (editorMode !== "read") {
607
+ return current;
608
+ }
609
+ return {
610
+ content: normalizeIssueManagerContent(detail?.task.content ?? ""),
611
+ priority: detail?.task.priority ?? defaultTaskPriority,
612
+ title: detail?.task.title ?? ""
613
+ };
614
+ }
615
+ function applyIssueManagerIssueEditorModeToNodeState(current, editorMode) {
616
+ if (editorMode === "create") {
617
+ return current;
618
+ }
619
+ return {
620
+ ...current,
621
+ issueDraftContent: null,
622
+ issueDraftTitle: null
623
+ };
624
+ }
625
+ function applyIssueManagerTaskEditorModeToNodeState(current, editorMode) {
626
+ if (editorMode === "create") {
627
+ return current;
628
+ }
629
+ return {
630
+ ...current,
631
+ taskDraftContent: null,
632
+ taskDraftTitle: null
633
+ };
634
+ }
635
+ function persistIssueManagerIssueDraftContent(current, editorMode, content) {
636
+ if (editorMode !== "create") {
637
+ return current;
638
+ }
639
+ return {
640
+ ...current,
641
+ issueDraftContent: content
642
+ };
643
+ }
644
+ function persistIssueManagerIssueDraftTitle(current, editorMode, title) {
645
+ if (editorMode !== "create") {
646
+ return current;
647
+ }
648
+ return {
649
+ ...current,
650
+ issueDraftTitle: title
651
+ };
652
+ }
653
+ function persistIssueManagerTaskDraftContent(current, editorMode, content) {
654
+ if (editorMode !== "create") {
655
+ return current;
656
+ }
657
+ return {
658
+ ...current,
659
+ taskDraftContent: content
660
+ };
661
+ }
662
+ function persistIssueManagerTaskDraftTitle(current, editorMode, title) {
663
+ if (editorMode !== "create") {
664
+ return current;
665
+ }
666
+ return {
667
+ ...current,
668
+ taskDraftTitle: title
669
+ };
670
+ }
671
+
672
+ // src/react/internal/useIssueManagerController.ts
673
+ var issueManagerProviderOptions = ["codex"];
674
+ function useIssueManagerController({
675
+ feature,
676
+ onStateChange,
677
+ state,
678
+ workspaceId
679
+ }) {
680
+ const copy = feature.i18n;
681
+ const [nodeState, setNodeStateInternal] = useState(
682
+ () => normalizeIssueManagerNodeState(state)
683
+ );
684
+ const [issueEditorMode, setIssueEditorModeState] = useState("read");
685
+ const [taskEditorMode, setTaskEditorModeState] = useState("read");
686
+ const [issueDraft, setIssueDraftInternal] = useState(
687
+ () => createIssueManagerIssueDraftFromNodeState(nodeState)
688
+ );
689
+ const [taskDraft, setTaskDraftInternal] = useState(
690
+ () => createIssueManagerTaskDraftFromNodeState(nodeState)
691
+ );
692
+ const [issueReloadToken, setIssueReloadToken] = useState(0);
693
+ const [detailReloadToken, setDetailReloadToken] = useState(0);
694
+ const [notice, setNotice] = useState(null);
695
+ const [isRunningTask, setIsRunningTask] = useState(false);
696
+ const [referenceTarget, setReferenceTarget] = useState(null);
697
+ const [issues, setIssues] = useState({
698
+ error: null,
699
+ isLoading: false,
700
+ value: []
701
+ });
702
+ const [issueDetail, setIssueDetail] = useState({
703
+ error: null,
704
+ isLoading: false,
705
+ value: null
706
+ });
707
+ const [taskDetail, setTaskDetail] = useState({
708
+ error: null,
709
+ isLoading: false,
710
+ value: null
711
+ });
712
+ const deferredIssueSearch = useDeferredValue(nodeState.issueSearchQuery);
713
+ const canReferenceWorkspaceFiles = hasFileAdapterMethod(feature.fileAdapter, "requestReferences") || hasFileAdapterMethod(feature.fileAdapter, "listDirectory") || hasFileAdapterMethod(feature.fileAdapter, "searchReferences");
714
+ const canUploadWorkspaceFiles = hasFileAdapterMethod(
715
+ feature.fileAdapter,
716
+ "requestUpload"
717
+ );
718
+ const updateNodeState = (updater) => {
719
+ setNodeStateInternal((current) => {
720
+ const next = typeof updater === "function" ? updater(current) : {
721
+ ...current,
722
+ ...updater
723
+ };
724
+ onStateChange?.(next);
725
+ return next;
726
+ });
727
+ };
728
+ const refreshIssues = () => {
729
+ setIssueReloadToken((current) => current + 1);
730
+ };
731
+ const refreshDetails = () => {
732
+ setDetailReloadToken((current) => current + 1);
733
+ };
734
+ const refreshAll = () => {
735
+ refreshIssues();
736
+ refreshDetails();
737
+ };
738
+ useEffect(() => {
739
+ const normalized = normalizeIssueManagerNodeState(state);
740
+ setNodeStateInternal(normalized);
741
+ setIssueDraftInternal(
742
+ createIssueManagerIssueDraftFromNodeState(normalized)
743
+ );
744
+ setTaskDraftInternal((current) => ({
745
+ ...createIssueManagerTaskDraftFromNodeState(normalized, current.priority)
746
+ }));
747
+ }, [workspaceId]);
748
+ useEffect(() => {
749
+ let canceled = false;
750
+ setIssues((current) => ({
751
+ ...current,
752
+ error: null,
753
+ isLoading: true
754
+ }));
755
+ void feature.backend.listIssues({
756
+ searchQuery: deferredIssueSearch || void 0,
757
+ statusFilter: nodeState.issueStatusFilter,
758
+ workspaceId
759
+ }).then((result) => {
760
+ if (canceled) {
761
+ return;
762
+ }
763
+ setIssues({
764
+ error: null,
765
+ isLoading: false,
766
+ value: result.issues
767
+ });
768
+ updateNodeState(
769
+ (current) => applyIssueManagerIssueListResultToNodeState(current, result)
770
+ );
771
+ }).catch((error) => {
772
+ if (canceled) {
773
+ return;
774
+ }
775
+ setIssues({
776
+ error: resolveIssueManagerErrorMessage(error, copy),
777
+ isLoading: false,
778
+ value: []
779
+ });
780
+ });
781
+ return () => {
782
+ canceled = true;
783
+ };
784
+ }, [
785
+ copy,
786
+ deferredIssueSearch,
787
+ feature.backend,
788
+ issueReloadToken,
789
+ nodeState.issueStatusFilter,
790
+ workspaceId
791
+ ]);
792
+ useEffect(() => {
793
+ const selectedIssueId = nodeState.selectedIssueId;
794
+ if (!selectedIssueId) {
795
+ setIssueDetail({
796
+ error: null,
797
+ isLoading: false,
798
+ value: null
799
+ });
800
+ return;
801
+ }
802
+ let canceled = false;
803
+ setIssueDetail((current) => ({
804
+ ...current,
805
+ error: null,
806
+ isLoading: true
807
+ }));
808
+ void feature.backend.getIssueDetail({
809
+ issueId: selectedIssueId,
810
+ workspaceId
811
+ }).then((result) => {
812
+ if (canceled) {
813
+ return;
814
+ }
815
+ setIssueDetail({
816
+ error: null,
817
+ isLoading: false,
818
+ value: result
819
+ });
820
+ updateNodeState(
821
+ (current) => applyIssueManagerIssueDetailResultToNodeState(current, result)
822
+ );
823
+ }).catch((error) => {
824
+ if (canceled) {
825
+ return;
826
+ }
827
+ setIssueDetail({
828
+ error: resolveIssueManagerErrorMessage(error, copy),
829
+ isLoading: false,
830
+ value: null
831
+ });
832
+ });
833
+ return () => {
834
+ canceled = true;
835
+ };
836
+ }, [
837
+ copy,
838
+ detailReloadToken,
839
+ feature.backend,
840
+ nodeState.selectedIssueId,
841
+ workspaceId
842
+ ]);
843
+ useEffect(() => {
844
+ const selectedIssueId = nodeState.selectedIssueId;
845
+ const selectedTaskId = nodeState.selectedTaskId;
846
+ if (!selectedIssueId || !selectedTaskId) {
847
+ setTaskDetail({
848
+ error: null,
849
+ isLoading: false,
850
+ value: null
851
+ });
852
+ return;
853
+ }
854
+ let canceled = false;
855
+ setTaskDetail((current) => ({
856
+ ...current,
857
+ error: null,
858
+ isLoading: true
859
+ }));
860
+ void feature.backend.getTaskDetail({
861
+ issueId: selectedIssueId,
862
+ taskId: selectedTaskId,
863
+ workspaceId
864
+ }).then((result) => {
865
+ if (canceled) {
866
+ return;
867
+ }
868
+ setTaskDetail({
869
+ error: null,
870
+ isLoading: false,
871
+ value: result
872
+ });
873
+ }).catch((error) => {
874
+ if (canceled) {
875
+ return;
876
+ }
877
+ setTaskDetail({
878
+ error: resolveIssueManagerErrorMessage(error, copy),
879
+ isLoading: false,
880
+ value: null
881
+ });
882
+ });
883
+ return () => {
884
+ canceled = true;
885
+ };
886
+ }, [
887
+ copy,
888
+ detailReloadToken,
889
+ feature.backend,
890
+ nodeState.selectedIssueId,
891
+ nodeState.selectedTaskId,
892
+ workspaceId
893
+ ]);
894
+ useEffect(() => {
895
+ setIssueDraftInternal(
896
+ (current) => syncIssueManagerIssueDraftFromDetail(
897
+ current,
898
+ issueDetail.value,
899
+ issueEditorMode
900
+ )
901
+ );
902
+ }, [
903
+ issueDetail.value?.issue.content,
904
+ issueDetail.value?.issue.title,
905
+ issueEditorMode
906
+ ]);
907
+ useEffect(() => {
908
+ setTaskDraftInternal(
909
+ (current) => syncIssueManagerTaskDraftFromDetail(
910
+ current,
911
+ taskDetail.value,
912
+ taskEditorMode
913
+ )
914
+ );
915
+ }, [
916
+ taskDetail.value?.task.content,
917
+ taskDetail.value?.task.priority,
918
+ taskDetail.value?.task.title,
919
+ taskEditorMode
920
+ ]);
921
+ const actions = createIssueManagerControllerActions({
922
+ copy,
923
+ feature,
924
+ issueDetail,
925
+ issueDraft,
926
+ issueEditorMode,
927
+ nodeState,
928
+ referenceTarget,
929
+ refreshAll,
930
+ refreshDetails,
931
+ setIsRunningTask,
932
+ setIssueDraftInternal,
933
+ setIssueEditorModeState,
934
+ setNotice,
935
+ setReferenceTarget,
936
+ setTaskDraftInternal,
937
+ setTaskEditorModeState,
938
+ taskDetail,
939
+ taskDraft,
940
+ taskEditorMode,
941
+ updateNodeState,
942
+ workspaceId
943
+ });
944
+ return {
945
+ ...actions,
946
+ canReferenceWorkspaceFiles,
947
+ canUploadWorkspaceFiles,
948
+ clearNotice() {
949
+ setNotice(null);
950
+ },
951
+ copy,
952
+ issueDetail,
953
+ issueDraft,
954
+ issueEditorMode,
955
+ issues,
956
+ isRunningTask,
957
+ nodeState,
958
+ notice,
959
+ providerOptions: issueManagerProviderOptions,
960
+ refreshAll,
961
+ referenceTarget,
962
+ selectIssue(issueId) {
963
+ updateNodeState(
964
+ (current) => applyIssueManagerIssueSelection(current, issueId)
965
+ );
966
+ setIssueEditorModeState("read");
967
+ setTaskEditorModeState("read");
968
+ },
969
+ selectTask(taskId) {
970
+ updateNodeState(
971
+ (current) => applyIssueManagerTaskSelection(current, taskId)
972
+ );
973
+ setTaskEditorModeState("read");
974
+ },
975
+ setIssueContent(content) {
976
+ setIssueDraftInternal((current) => ({
977
+ ...current,
978
+ content
979
+ }));
980
+ updateNodeState(
981
+ (current) => persistIssueManagerIssueDraftContent(current, issueEditorMode, content)
982
+ );
983
+ },
984
+ setIssueDraft(patch) {
985
+ setIssueDraftInternal((current) => ({
986
+ ...current,
987
+ ...patch
988
+ }));
989
+ },
990
+ setIssueEditorMode(mode) {
991
+ setIssueEditorModeState(mode);
992
+ if (mode === "create") {
993
+ setIssueDraftInternal(
994
+ createIssueManagerIssueDraftFromNodeState(nodeState)
995
+ );
996
+ }
997
+ updateNodeState(
998
+ (current) => applyIssueManagerIssueEditorModeToNodeState(current, mode)
999
+ );
1000
+ },
1001
+ setIssueSearchQuery(query) {
1002
+ updateNodeState((current) => ({
1003
+ ...current,
1004
+ issueSearchQuery: query
1005
+ }));
1006
+ },
1007
+ setIssueStatusFilter(value) {
1008
+ updateNodeState((current) => ({
1009
+ ...current,
1010
+ issueStatusFilter: value
1011
+ }));
1012
+ },
1013
+ setIssueTitle(title) {
1014
+ setIssueDraftInternal((current) => ({
1015
+ ...current,
1016
+ title
1017
+ }));
1018
+ updateNodeState(
1019
+ (current) => persistIssueManagerIssueDraftTitle(current, issueEditorMode, title)
1020
+ );
1021
+ },
1022
+ setReferenceTarget,
1023
+ setSelectedAgentProvider(provider) {
1024
+ updateNodeState((current) => ({
1025
+ ...current,
1026
+ selectedAgentProvider: provider
1027
+ }));
1028
+ },
1029
+ setTaskContent(content) {
1030
+ setTaskDraftInternal((current) => ({
1031
+ ...current,
1032
+ content
1033
+ }));
1034
+ updateNodeState(
1035
+ (current) => persistIssueManagerTaskDraftContent(current, taskEditorMode, content)
1036
+ );
1037
+ },
1038
+ setTaskDraft(patch) {
1039
+ setTaskDraftInternal((current) => ({
1040
+ ...current,
1041
+ ...patch
1042
+ }));
1043
+ },
1044
+ setTaskEditorMode(mode) {
1045
+ setTaskEditorModeState(mode);
1046
+ if (mode === "create") {
1047
+ setTaskDraftInternal(
1048
+ createIssueManagerTaskDraftFromNodeState(nodeState)
1049
+ );
1050
+ }
1051
+ updateNodeState(
1052
+ (current) => applyIssueManagerTaskEditorModeToNodeState(current, mode)
1053
+ );
1054
+ },
1055
+ setTaskPriority(priority) {
1056
+ setTaskDraftInternal((current) => ({
1057
+ ...current,
1058
+ priority
1059
+ }));
1060
+ },
1061
+ setTaskTitle(title) {
1062
+ setTaskDraftInternal((current) => ({
1063
+ ...current,
1064
+ title
1065
+ }));
1066
+ updateNodeState(
1067
+ (current) => persistIssueManagerTaskDraftTitle(current, taskEditorMode, title)
1068
+ );
1069
+ },
1070
+ taskDetail,
1071
+ taskDraft,
1072
+ taskEditorMode
1073
+ };
1074
+ }
1075
+ function hasFileAdapterMethod(fileAdapter, methodName) {
1076
+ return typeof Reflect.get(fileAdapter ?? {}, methodName) === "function";
1077
+ }
1078
+
1079
+ // src/react/internal/IssueManagerReferencePicker.tsx
1080
+ import { useEffect as useEffect2, useMemo, useState as useState2 } from "react";
1081
+ import { createPortal } from "react-dom";
1082
+ import {
1083
+ Badge,
1084
+ Button,
1085
+ Card,
1086
+ CardContent,
1087
+ CardDescription,
1088
+ CardHeader,
1089
+ CardTitle,
1090
+ DirectoryIcon,
1091
+ FileIcon,
1092
+ Input,
1093
+ LoadingIcon,
1094
+ ScrollArea,
1095
+ SearchIcon,
1096
+ UploadIcon,
1097
+ cn
1098
+ } from "@nextop-os/ui-system";
1099
+
1100
+ // src/react/internal/model.ts
1101
+ function createIssueManagerDate(value) {
1102
+ if (!value || !Number.isFinite(value)) {
1103
+ return null;
1104
+ }
1105
+ const normalized = value < 1e12 ? value * 1e3 : value;
1106
+ const date = new Date(normalized);
1107
+ return Number.isNaN(date.getTime()) ? null : date;
1108
+ }
1109
+ function formatIssueManagerTimestamp(value) {
1110
+ return createIssueManagerDate(value)?.toLocaleString() ?? null;
1111
+ }
1112
+ function formatIssueManagerDate(value) {
1113
+ return createIssueManagerDate(value)?.toLocaleDateString() ?? "";
1114
+ }
1115
+ function resolveIssueManagerStatusLabel(copy, status) {
1116
+ switch (status) {
1117
+ case "not_started":
1118
+ return copy.t("status.notStarted");
1119
+ case "running":
1120
+ return copy.t("status.running");
1121
+ case "pending_acceptance":
1122
+ return copy.t("status.pendingAcceptance");
1123
+ case "completed":
1124
+ return copy.t("status.completed");
1125
+ case "failed":
1126
+ return copy.t("status.failed");
1127
+ case "canceled":
1128
+ return copy.t("status.canceled");
1129
+ default:
1130
+ return copy.t("status.unknown");
1131
+ }
1132
+ }
1133
+ function resolveIssueManagerPriorityLabel(copy, priority) {
1134
+ switch (priority) {
1135
+ case "high":
1136
+ return copy.t("priority.high");
1137
+ case "low":
1138
+ return copy.t("priority.low");
1139
+ default:
1140
+ return copy.t("priority.medium");
1141
+ }
1142
+ }
1143
+ function uniqueIssueManagerFileReferences(refs) {
1144
+ const unique = /* @__PURE__ */ new Map();
1145
+ for (const ref of refs) {
1146
+ const normalizedPath = ref.path.trim();
1147
+ if (!normalizedPath || unique.has(normalizedPath)) {
1148
+ continue;
1149
+ }
1150
+ unique.set(normalizedPath, {
1151
+ displayName: ref.displayName?.trim() || void 0,
1152
+ kind: ref.kind === "folder" ? "folder" : "file",
1153
+ path: normalizedPath
1154
+ });
1155
+ }
1156
+ return [...unique.values()];
1157
+ }
1158
+ function parentDirectoryPath(path) {
1159
+ const trimmed = path.trim();
1160
+ if (!trimmed || trimmed === "/") {
1161
+ return null;
1162
+ }
1163
+ const normalized = trimmed.endsWith("/") && trimmed.length > 1 ? trimmed.slice(0, -1) : trimmed;
1164
+ const index = normalized.lastIndexOf("/");
1165
+ if (index <= 0) {
1166
+ return "/";
1167
+ }
1168
+ return normalized.slice(0, index) || "/";
1169
+ }
1170
+
1171
+ // src/react/internal/IssueManagerReferencePicker.tsx
1172
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1173
+ var defaultDirectoryPath = "/";
1174
+ function IssueManagerReferencePicker({
1175
+ copy,
1176
+ fileAdapter,
1177
+ onClose,
1178
+ onConfirm,
1179
+ open,
1180
+ workspaceId
1181
+ }) {
1182
+ const [currentPath, setCurrentPath] = useState2(defaultDirectoryPath);
1183
+ const [searchQuery, setSearchQuery] = useState2("");
1184
+ const [entries, setEntries] = useState2([]);
1185
+ const [isLoading, setIsLoading] = useState2(false);
1186
+ const [selectedRefs, setSelectedRefs] = useState2(
1187
+ []
1188
+ );
1189
+ const supportsSearch = hasFileAdapterMethod2(fileAdapter, "searchReferences");
1190
+ const supportsBrowse = hasFileAdapterMethod2(fileAdapter, "listDirectory");
1191
+ const mode = searchQuery.trim().length > 0 && supportsSearch ? "search" : "browse";
1192
+ const canUpload = hasFileAdapterMethod2(fileAdapter, "requestUpload");
1193
+ const parentPath = useMemo(
1194
+ () => parentDirectoryPath(currentPath),
1195
+ [currentPath]
1196
+ );
1197
+ useEffect2(() => {
1198
+ if (!open) {
1199
+ return;
1200
+ }
1201
+ setSearchQuery("");
1202
+ setCurrentPath(defaultDirectoryPath);
1203
+ setSelectedRefs([]);
1204
+ }, [open]);
1205
+ useEffect2(() => {
1206
+ if (!open || !fileAdapter) {
1207
+ return;
1208
+ }
1209
+ let canceled = false;
1210
+ const load = async () => {
1211
+ setIsLoading(true);
1212
+ try {
1213
+ if (mode === "search" && fileAdapter.searchReferences) {
1214
+ const refs = await fileAdapter.searchReferences({
1215
+ query: searchQuery.trim(),
1216
+ workspaceId
1217
+ });
1218
+ if (!canceled) {
1219
+ setEntries(uniqueIssueManagerFileReferences(refs));
1220
+ }
1221
+ return;
1222
+ }
1223
+ if (mode === "browse" && fileAdapter.listDirectory) {
1224
+ const listing = await fileAdapter.listDirectory({
1225
+ path: currentPath,
1226
+ workspaceId
1227
+ });
1228
+ if (!canceled) {
1229
+ setCurrentPath(listing.directoryPath || defaultDirectoryPath);
1230
+ setEntries(uniqueIssueManagerFileReferences(listing.entries));
1231
+ }
1232
+ return;
1233
+ }
1234
+ if (fileAdapter.requestReferences) {
1235
+ const refs = await fileAdapter.requestReferences({ workspaceId });
1236
+ if (!canceled) {
1237
+ onConfirm(uniqueIssueManagerFileReferences(refs));
1238
+ onClose();
1239
+ }
1240
+ return;
1241
+ }
1242
+ if (!canceled) {
1243
+ setEntries([]);
1244
+ }
1245
+ } finally {
1246
+ if (!canceled) {
1247
+ setIsLoading(false);
1248
+ }
1249
+ }
1250
+ };
1251
+ void load();
1252
+ return () => {
1253
+ canceled = true;
1254
+ };
1255
+ }, [
1256
+ currentPath,
1257
+ fileAdapter,
1258
+ mode,
1259
+ onClose,
1260
+ onConfirm,
1261
+ open,
1262
+ searchQuery,
1263
+ workspaceId
1264
+ ]);
1265
+ if (!open) {
1266
+ return null;
1267
+ }
1268
+ const toggleRef = (ref) => {
1269
+ setSelectedRefs((current) => {
1270
+ const existing = current.some((item) => item.path === ref.path);
1271
+ return existing ? current.filter((item) => item.path !== ref.path) : uniqueIssueManagerFileReferences([...current, ref]);
1272
+ });
1273
+ };
1274
+ const upload = async (mode2) => {
1275
+ if (!fileAdapter?.requestUpload) {
1276
+ return;
1277
+ }
1278
+ const refs = await fileAdapter.requestUpload({
1279
+ mode: mode2,
1280
+ targetDirectoryPath: currentPath,
1281
+ workspaceId
1282
+ });
1283
+ setSelectedRefs(
1284
+ (current) => uniqueIssueManagerFileReferences([...current, ...refs])
1285
+ );
1286
+ };
1287
+ const dialog = /* @__PURE__ */ jsx(
1288
+ "div",
1289
+ {
1290
+ className: "fixed inset-0 grid place-items-center bg-black/26 px-4 backdrop-blur-sm",
1291
+ style: { zIndex: "var(--z-panel)" },
1292
+ onClick: onClose,
1293
+ children: /* @__PURE__ */ jsxs(
1294
+ Card,
1295
+ {
1296
+ "aria-modal": "true",
1297
+ className: "w-full max-w-4xl border-border/70 bg-popover/96 shadow-[var(--workbench-window-elevation)]",
1298
+ role: "dialog",
1299
+ onClick: (event) => event.stopPropagation(),
1300
+ children: [
1301
+ /* @__PURE__ */ jsxs(CardHeader, { className: "gap-3 border-b border-border/70", children: [
1302
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
1303
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1304
+ /* @__PURE__ */ jsx(CardTitle, { children: copy.t("referencePicker.title") }),
1305
+ /* @__PURE__ */ jsx(CardDescription, { children: copy.t("referencePicker.selectedCount", {
1306
+ count: selectedRefs.length
1307
+ }) })
1308
+ ] }),
1309
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1310
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: onClose, children: copy.t("actions.cancel") }),
1311
+ /* @__PURE__ */ jsx(
1312
+ Button,
1313
+ {
1314
+ disabled: selectedRefs.length === 0,
1315
+ type: "button",
1316
+ onClick: () => onConfirm(selectedRefs),
1317
+ children: copy.t("referencePicker.confirm")
1318
+ }
1319
+ )
1320
+ ] })
1321
+ ] }),
1322
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
1323
+ /* @__PURE__ */ jsxs("div", { className: "relative min-w-[16rem] flex-1", children: [
1324
+ /* @__PURE__ */ jsx(SearchIcon, { className: "pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-foreground" }),
1325
+ /* @__PURE__ */ jsx(
1326
+ Input,
1327
+ {
1328
+ className: "pl-8",
1329
+ placeholder: copy.t("referencePicker.searchPlaceholder"),
1330
+ value: searchQuery,
1331
+ onChange: (event) => setSearchQuery(event.target.value)
1332
+ }
1333
+ )
1334
+ ] }),
1335
+ mode === "browse" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1336
+ /* @__PURE__ */ jsx(Badge, { className: "border-border/70 bg-background/80 text-muted-foreground", children: currentPath }),
1337
+ parentPath ? /* @__PURE__ */ jsx(
1338
+ Button,
1339
+ {
1340
+ size: "sm",
1341
+ type: "button",
1342
+ variant: "outline",
1343
+ onClick: () => setCurrentPath(parentPath),
1344
+ children: ".."
1345
+ }
1346
+ ) : null
1347
+ ] }) : null,
1348
+ canUpload ? /* @__PURE__ */ jsxs(Fragment, { children: [
1349
+ /* @__PURE__ */ jsxs(
1350
+ Button,
1351
+ {
1352
+ size: "sm",
1353
+ type: "button",
1354
+ variant: "outline",
1355
+ onClick: () => {
1356
+ void upload("files");
1357
+ },
1358
+ children: [
1359
+ /* @__PURE__ */ jsx(UploadIcon, { className: "size-3.5" }),
1360
+ copy.t("actions.uploadFiles")
1361
+ ]
1362
+ }
1363
+ ),
1364
+ /* @__PURE__ */ jsxs(
1365
+ Button,
1366
+ {
1367
+ size: "sm",
1368
+ type: "button",
1369
+ variant: "outline",
1370
+ onClick: () => {
1371
+ void upload("folder");
1372
+ },
1373
+ children: [
1374
+ /* @__PURE__ */ jsx(UploadIcon, { className: "size-3.5" }),
1375
+ copy.t("actions.uploadFolder")
1376
+ ]
1377
+ }
1378
+ )
1379
+ ] }) : null
1380
+ ] })
1381
+ ] }),
1382
+ /* @__PURE__ */ jsxs(CardContent, { className: "grid min-h-[26rem] gap-4 pt-4 lg:grid-cols-[minmax(0,1fr)_18rem]", children: [
1383
+ /* @__PURE__ */ jsx(ScrollArea, { className: "min-h-0 rounded-xl border border-border/70 bg-background/72", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col p-2", children: isLoading ? /* @__PURE__ */ jsx(PickerFeedback, { children: /* @__PURE__ */ jsx(LoadingIcon, { className: "size-4 animate-spin" }) }) : entries.length === 0 ? /* @__PURE__ */ jsx(PickerFeedback, { children: mode === "search" ? copy.t("referencePicker.emptySearch") : copy.t("referencePicker.emptyDirectory") }) : entries.map((entry) => {
1384
+ const selected = selectedRefs.some(
1385
+ (item) => item.path === entry.path
1386
+ );
1387
+ const isFolder = entry.kind === "folder";
1388
+ return /* @__PURE__ */ jsxs(
1389
+ "div",
1390
+ {
1391
+ className: cn(
1392
+ "grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2 rounded-lg px-2 py-1.5",
1393
+ selected && "bg-primary/[0.08]"
1394
+ ),
1395
+ children: [
1396
+ /* @__PURE__ */ jsxs(
1397
+ "button",
1398
+ {
1399
+ className: "flex min-w-0 items-center gap-2 rounded-md px-2 py-1 text-left text-sm text-foreground hover:bg-accent/75",
1400
+ type: "button",
1401
+ onClick: () => {
1402
+ if (isFolder && mode === "browse" && supportsBrowse) {
1403
+ setCurrentPath(entry.path);
1404
+ return;
1405
+ }
1406
+ toggleRef(entry);
1407
+ },
1408
+ children: [
1409
+ isFolder ? /* @__PURE__ */ jsx(DirectoryIcon, { className: "size-4 text-muted-foreground" }) : /* @__PURE__ */ jsx(FileIcon, { className: "size-4 text-muted-foreground" }),
1410
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: entry.displayName || entry.path.split("/").filter(Boolean).at(-1) || entry.path })
1411
+ ]
1412
+ }
1413
+ ),
1414
+ /* @__PURE__ */ jsx(
1415
+ Button,
1416
+ {
1417
+ size: "xs",
1418
+ type: "button",
1419
+ variant: selected ? "secondary" : "outline",
1420
+ onClick: () => toggleRef(entry),
1421
+ children: selected ? "\u2713" : "+"
1422
+ }
1423
+ )
1424
+ ]
1425
+ },
1426
+ entry.path
1427
+ );
1428
+ }) }) }),
1429
+ /* @__PURE__ */ jsxs("aside", { className: "flex min-h-0 flex-col gap-3 rounded-xl border border-border/70 bg-panel/72 p-3", children: [
1430
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1431
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: copy.t("referencePicker.confirm") }),
1432
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: copy.t("referencePicker.selectedCount", {
1433
+ count: selectedRefs.length
1434
+ }) })
1435
+ ] }),
1436
+ /* @__PURE__ */ jsx(ScrollArea, { className: "min-h-0 flex-1 rounded-lg border border-border/70 bg-background/75", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1.5 p-2", children: selectedRefs.length === 0 ? /* @__PURE__ */ jsx(PickerFeedback, { children: copy.t("referencePicker.emptySearch") }) : selectedRefs.map((ref) => /* @__PURE__ */ jsxs(
1437
+ "div",
1438
+ {
1439
+ className: "flex items-center justify-between gap-2 rounded-md border border-border/60 bg-background/92 px-2.5 py-2 text-sm",
1440
+ children: [
1441
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
1442
+ /* @__PURE__ */ jsx("p", { className: "truncate font-medium text-foreground", children: ref.displayName || ref.path.split("/").filter(Boolean).at(-1) || ref.path }),
1443
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-muted-foreground", children: ref.path })
1444
+ ] }),
1445
+ /* @__PURE__ */ jsx(
1446
+ Button,
1447
+ {
1448
+ size: "icon-xs",
1449
+ type: "button",
1450
+ variant: "ghost",
1451
+ onClick: () => setSelectedRefs(
1452
+ (current) => current.filter((item) => item.path !== ref.path)
1453
+ ),
1454
+ children: "x"
1455
+ }
1456
+ )
1457
+ ]
1458
+ },
1459
+ ref.path
1460
+ )) }) })
1461
+ ] })
1462
+ ] })
1463
+ ]
1464
+ }
1465
+ )
1466
+ }
1467
+ );
1468
+ if (typeof document === "undefined") {
1469
+ return dialog;
1470
+ }
1471
+ return createPortal(dialog, document.body);
1472
+ }
1473
+ function hasFileAdapterMethod2(fileAdapter, methodName) {
1474
+ return typeof Reflect.get(fileAdapter ?? {}, methodName) === "function";
1475
+ }
1476
+ function PickerFeedback({ children }) {
1477
+ return /* @__PURE__ */ jsx("div", { className: "grid min-h-[10rem] place-items-center px-4 text-center text-sm text-muted-foreground", children });
1478
+ }
1479
+
1480
+ // src/react/internal/IssueManagerShell.tsx
1481
+ import {
1482
+ useEffect as useEffect4,
1483
+ useRef as useRef2,
1484
+ useState as useState4
1485
+ } from "react";
1486
+ import {
1487
+ ArrowLeftIcon,
1488
+ ArrowRightIcon,
1489
+ Badge as Badge5,
1490
+ Button as Button6,
1491
+ CloseIcon as CloseIcon2,
1492
+ FileCreateIcon as FileCreateIcon3,
1493
+ Input as Input5,
1494
+ RefreshIcon,
1495
+ ScrollArea as ScrollArea4,
1496
+ SearchIcon as SearchIcon2,
1497
+ cn as cn4
1498
+ } from "@nextop-os/ui-system";
1499
+
1500
+ // src/react/internal/IssueManagerPanels.tsx
1501
+ import {
1502
+ Badge as Badge3,
1503
+ Button as Button3,
1504
+ FileCreateIcon as FileCreateIcon2,
1505
+ Input as Input2,
1506
+ ScrollArea as ScrollArea2,
1507
+ cn as cn3
1508
+ } from "@nextop-os/ui-system";
1509
+
1510
+ // src/react/internal/IssueManagerPanelParts.tsx
1511
+ import { useEffect as useEffect3, useRef, useState as useState3 } from "react";
1512
+ import {
1513
+ Badge as Badge2,
1514
+ Button as Button2,
1515
+ DirectoryIcon as DirectoryIcon2,
1516
+ FileCreateIcon,
1517
+ FileIcon as FileIcon2,
1518
+ Select,
1519
+ SelectContent,
1520
+ SelectItem,
1521
+ SelectTrigger,
1522
+ SparkIcon,
1523
+ cn as cn2
1524
+ } from "@nextop-os/ui-system";
1525
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1526
+ var workspaceDockTaskImage = new URL(
1527
+ "../../assets/workspace-dock-task.png",
1528
+ import.meta.url
1529
+ ).href;
1530
+ function IssueManagerEmptyIllustration() {
1531
+ return /* @__PURE__ */ jsx2(
1532
+ "img",
1533
+ {
1534
+ alt: "",
1535
+ "aria-hidden": "true",
1536
+ className: "h-[84px] w-[84px] object-contain",
1537
+ decoding: "async",
1538
+ draggable: false,
1539
+ src: workspaceDockTaskImage
1540
+ }
1541
+ );
1542
+ }
1543
+ function IssueManagerDescriptionSection({
1544
+ content,
1545
+ emptyLabel,
1546
+ label,
1547
+ minHeightClass = "min-h-[14rem]",
1548
+ onOpen,
1549
+ variant = "card"
1550
+ }) {
1551
+ const contentRef = useRef(null);
1552
+ const [isOverflowing, setIsOverflowing] = useState3(false);
1553
+ const normalizedContent = normalizeIssueManagerContent(content).trim();
1554
+ useEffect3(() => {
1555
+ if (variant === "plain") {
1556
+ setIsOverflowing(false);
1557
+ return;
1558
+ }
1559
+ if (!normalizedContent) {
1560
+ setIsOverflowing(false);
1561
+ return;
1562
+ }
1563
+ const contentElement = contentRef.current;
1564
+ if (!contentElement) {
1565
+ return;
1566
+ }
1567
+ const measure = () => {
1568
+ setIsOverflowing(
1569
+ contentElement.scrollHeight > contentElement.clientHeight + 1
1570
+ );
1571
+ };
1572
+ measure();
1573
+ if (typeof ResizeObserver === "undefined") {
1574
+ return;
1575
+ }
1576
+ const observer = new ResizeObserver(() => {
1577
+ measure();
1578
+ });
1579
+ observer.observe(contentElement);
1580
+ return () => {
1581
+ observer.disconnect();
1582
+ };
1583
+ }, [normalizedContent, variant]);
1584
+ if (variant === "plain") {
1585
+ return /* @__PURE__ */ jsxs2("section", { className: "grid gap-2.5", children: [
1586
+ /* @__PURE__ */ jsx2("span", { className: "text-sm font-semibold text-foreground", children: label }),
1587
+ normalizedContent ? /* @__PURE__ */ jsx2("div", { className: "max-w-3xl text-sm leading-6 text-muted-foreground", children: /* @__PURE__ */ jsx2(
1588
+ IssueManagerDescriptionContent,
1589
+ {
1590
+ content: normalizedContent,
1591
+ onOpen
1592
+ }
1593
+ ) }) : /* @__PURE__ */ jsx2("p", { className: "text-sm leading-6 text-muted-foreground", children: emptyLabel })
1594
+ ] });
1595
+ }
1596
+ return /* @__PURE__ */ jsxs2("section", { className: "grid gap-2", children: [
1597
+ /* @__PURE__ */ jsx2("span", { className: "text-sm font-semibold text-foreground", children: label }),
1598
+ /* @__PURE__ */ jsxs2(
1599
+ "div",
1600
+ {
1601
+ className: cn2(
1602
+ "relative min-w-0 rounded-[24px] border border-border/70 bg-transparent px-5 py-4",
1603
+ minHeightClass
1604
+ ),
1605
+ children: [
1606
+ /* @__PURE__ */ jsx2(
1607
+ "div",
1608
+ {
1609
+ className: cn2(
1610
+ "max-h-[18rem] overflow-y-auto pr-2 text-sm leading-6 text-muted-foreground",
1611
+ isOverflowing && "pb-8"
1612
+ ),
1613
+ ref: contentRef,
1614
+ children: normalizedContent ? /* @__PURE__ */ jsx2(
1615
+ IssueManagerDescriptionContent,
1616
+ {
1617
+ content: normalizedContent,
1618
+ onOpen
1619
+ }
1620
+ ) : /* @__PURE__ */ jsx2("p", { className: "text-muted-foreground", children: emptyLabel })
1621
+ }
1622
+ ),
1623
+ isOverflowing ? /* @__PURE__ */ jsx2(
1624
+ "div",
1625
+ {
1626
+ className: "pointer-events-none absolute right-0 bottom-1 left-0 h-10",
1627
+ style: {
1628
+ background: "linear-gradient(to top, var(--workbench-node-surface), color-mix(in srgb, var(--workbench-node-surface) 80%, transparent), transparent)"
1629
+ }
1630
+ }
1631
+ ) : null
1632
+ ]
1633
+ }
1634
+ )
1635
+ ] });
1636
+ }
1637
+ function IssueManagerRunActionTrigger({
1638
+ controller,
1639
+ disabled = false,
1640
+ iconSize = 16,
1641
+ triggerClassName
1642
+ }) {
1643
+ const [resetToken, setResetToken] = useState3(0);
1644
+ return /* @__PURE__ */ jsxs2(
1645
+ Select,
1646
+ {
1647
+ disabled: controller.isRunningTask || disabled,
1648
+ onValueChange: (provider) => {
1649
+ setResetToken((current) => current + 1);
1650
+ void controller.runTask(provider);
1651
+ },
1652
+ children: [
1653
+ /* @__PURE__ */ jsx2(
1654
+ SelectTrigger,
1655
+ {
1656
+ "aria-label": controller.copy.t("actions.askAgentToRun"),
1657
+ className: triggerClassName,
1658
+ children: /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
1659
+ /* @__PURE__ */ jsx2(SparkIcon, { size: iconSize }),
1660
+ /* @__PURE__ */ jsx2("span", { className: "truncate", children: controller.copy.t("actions.askAgentToRun") })
1661
+ ] })
1662
+ }
1663
+ ),
1664
+ /* @__PURE__ */ jsx2(SelectContent, { style: { zIndex: "var(--z-panel-popover)" }, children: controller.providerOptions.map((provider) => /* @__PURE__ */ jsx2(SelectItem, { value: provider, children: provider }, provider)) })
1665
+ ]
1666
+ },
1667
+ `${controller.nodeState.selectedAgentProvider}:${resetToken}`
1668
+ );
1669
+ }
1670
+ function IssueManagerDescriptionContent({
1671
+ content,
1672
+ onOpen
1673
+ }) {
1674
+ const paragraphs = content.split(/\n{2,}/).map((paragraph) => paragraph.trim()).filter(Boolean);
1675
+ return /* @__PURE__ */ jsx2("div", { className: "space-y-4", children: paragraphs.map((paragraph, paragraphIndex) => /* @__PURE__ */ jsx2(
1676
+ "p",
1677
+ {
1678
+ className: "whitespace-pre-wrap",
1679
+ children: renderIssueManagerInlineMarkdown(paragraph, onOpen)
1680
+ },
1681
+ `${paragraphIndex}:${paragraph}`
1682
+ )) });
1683
+ }
1684
+ function renderIssueManagerInlineMarkdown(content, onOpen) {
1685
+ const markdownLinkPattern = /\[([^\]]+)\]\(([^)\s]+)\)/g;
1686
+ const parts = [];
1687
+ let match;
1688
+ let cursor = 0;
1689
+ let index = 0;
1690
+ while ((match = markdownLinkPattern.exec(content)) !== null) {
1691
+ const [source, label = "", href = ""] = match;
1692
+ const start = match.index;
1693
+ if (start > cursor) {
1694
+ parts.push(
1695
+ /* @__PURE__ */ jsx2("span", { children: content.slice(cursor, start) }, `text:${index}:${cursor}`)
1696
+ );
1697
+ index += 1;
1698
+ }
1699
+ parts.push(
1700
+ /* @__PURE__ */ jsx2(
1701
+ IssueManagerInlineLink,
1702
+ {
1703
+ href,
1704
+ label: label || href,
1705
+ onOpen
1706
+ },
1707
+ `link:${index}:${href}`
1708
+ )
1709
+ );
1710
+ index += 1;
1711
+ cursor = start + source.length;
1712
+ }
1713
+ if (cursor < content.length) {
1714
+ parts.push(
1715
+ /* @__PURE__ */ jsx2("span", { children: content.slice(cursor) }, `text:${index}:${cursor}`)
1716
+ );
1717
+ }
1718
+ return parts;
1719
+ }
1720
+ function IssueManagerInlineLink({
1721
+ href,
1722
+ label,
1723
+ onOpen
1724
+ }) {
1725
+ const trimmedHref = href.trim();
1726
+ const isExternal = /^(?:[a-z]+:)?\/\//i.test(trimmedHref);
1727
+ if (!trimmedHref || isExternal || !onOpen) {
1728
+ return /* @__PURE__ */ jsx2(
1729
+ "a",
1730
+ {
1731
+ className: "font-medium text-foreground underline decoration-border underline-offset-4 hover:text-primary",
1732
+ href: trimmedHref || void 0,
1733
+ rel: "noreferrer",
1734
+ target: "_blank",
1735
+ children: label
1736
+ }
1737
+ );
1738
+ }
1739
+ return /* @__PURE__ */ jsx2(
1740
+ "button",
1741
+ {
1742
+ className: "font-medium text-foreground underline decoration-border underline-offset-4 hover:text-primary",
1743
+ type: "button",
1744
+ onClick: () => {
1745
+ void onOpen({
1746
+ displayName: label,
1747
+ kind: trimmedHref.endsWith("/") ? "folder" : "file",
1748
+ path: trimmedHref
1749
+ });
1750
+ },
1751
+ children: label
1752
+ }
1753
+ );
1754
+ }
1755
+ function IssueManagerContextSection({
1756
+ copy,
1757
+ emptyLabel,
1758
+ onAdd,
1759
+ onOpen,
1760
+ onRemove,
1761
+ refs
1762
+ }) {
1763
+ return /* @__PURE__ */ jsxs2("section", { className: "rounded-2xl border border-border/70 bg-transparent px-5 py-4", children: [
1764
+ /* @__PURE__ */ jsxs2("div", { className: "mb-3 flex items-center justify-between gap-3", children: [
1765
+ /* @__PURE__ */ jsx2("h4", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.contextReferences") }),
1766
+ /* @__PURE__ */ jsx2(
1767
+ Button2,
1768
+ {
1769
+ className: "h-8 rounded-lg border-border/70 px-3 text-[13px] font-semibold",
1770
+ size: "sm",
1771
+ type: "button",
1772
+ variant: "outline",
1773
+ onClick: onAdd,
1774
+ children: copy.t("actions.addReferences")
1775
+ }
1776
+ )
1777
+ ] }),
1778
+ refs.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "text-sm leading-6 text-muted-foreground", children: emptyLabel }) : /* @__PURE__ */ jsx2("div", { className: "grid gap-2.5", children: refs.map((ref) => /* @__PURE__ */ jsxs2(
1779
+ "div",
1780
+ {
1781
+ className: "flex items-center justify-between gap-3 rounded-xl border border-border/65 bg-transparent px-3.5 py-3",
1782
+ children: [
1783
+ /* @__PURE__ */ jsxs2(
1784
+ "button",
1785
+ {
1786
+ className: "flex min-w-0 flex-1 items-center gap-3 text-left",
1787
+ type: "button",
1788
+ onClick: () => {
1789
+ void onOpen({
1790
+ displayName: ref.displayName,
1791
+ kind: ref.path.endsWith("/") ? "folder" : "file",
1792
+ path: ref.path
1793
+ });
1794
+ },
1795
+ children: [
1796
+ ref.path.endsWith("/") ? /* @__PURE__ */ jsx2(
1797
+ DirectoryIcon2,
1798
+ {
1799
+ className: "shrink-0 text-muted-foreground",
1800
+ size: 16
1801
+ }
1802
+ ) : /* @__PURE__ */ jsx2(
1803
+ FileIcon2,
1804
+ {
1805
+ className: "shrink-0 text-muted-foreground",
1806
+ size: 16
1807
+ }
1808
+ ),
1809
+ /* @__PURE__ */ jsxs2("span", { className: "min-w-0", children: [
1810
+ /* @__PURE__ */ jsx2("span", { className: "block truncate text-sm font-semibold text-foreground", children: ref.displayName }),
1811
+ /* @__PURE__ */ jsx2("span", { className: "block truncate text-xs text-muted-foreground", children: ref.path })
1812
+ ] })
1813
+ ]
1814
+ }
1815
+ ),
1816
+ /* @__PURE__ */ jsx2(
1817
+ Button2,
1818
+ {
1819
+ className: "h-7 px-2 text-[13px] font-semibold text-muted-foreground hover:text-foreground",
1820
+ size: "sm",
1821
+ type: "button",
1822
+ variant: "ghost",
1823
+ onClick: () => {
1824
+ void onRemove(ref);
1825
+ },
1826
+ children: copy.t("actions.removeReference")
1827
+ }
1828
+ )
1829
+ ]
1830
+ },
1831
+ ref.contextRefId
1832
+ )) })
1833
+ ] });
1834
+ }
1835
+ function IssueManagerRunPanels({
1836
+ copy,
1837
+ onOpen,
1838
+ outputs,
1839
+ recentRuns
1840
+ }) {
1841
+ return /* @__PURE__ */ jsxs2("div", { className: "grid gap-4", children: [
1842
+ /* @__PURE__ */ jsxs2("section", { className: "rounded-2xl border border-border/70 bg-transparent px-5 py-4", children: [
1843
+ /* @__PURE__ */ jsx2("h4", { className: "mb-3 text-sm font-semibold text-foreground", children: copy.t("labels.recentRuns") }),
1844
+ recentRuns.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "text-sm leading-6 text-muted-foreground", children: copy.t("messages.noRecentRuns") }) : /* @__PURE__ */ jsx2("div", { className: "grid gap-2.5", children: recentRuns.map((run) => /* @__PURE__ */ jsxs2(
1845
+ "div",
1846
+ {
1847
+ className: "rounded-xl border border-border/65 bg-transparent px-3.5 py-3",
1848
+ children: [
1849
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between gap-3", children: [
1850
+ /* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
1851
+ /* @__PURE__ */ jsx2("p", { className: "truncate text-sm font-semibold text-foreground", children: run.summary || run.runId }),
1852
+ /* @__PURE__ */ jsx2("p", { className: "mt-1 text-xs text-muted-foreground", children: formatIssueManagerTimestamp(
1853
+ run.updatedAtUnix ?? run.createdAtUnix
1854
+ ) })
1855
+ ] }),
1856
+ /* @__PURE__ */ jsx2(Badge2, { className: "rounded-full border-transparent bg-muted px-2.5 py-1 text-[11px] text-muted-foreground", children: resolveIssueManagerStatusLabel(copy, run.status) })
1857
+ ] }),
1858
+ run.errorMessage ? /* @__PURE__ */ jsx2("p", { className: "mt-2 text-xs text-destructive", children: run.errorMessage }) : null
1859
+ ]
1860
+ },
1861
+ run.runId
1862
+ )) })
1863
+ ] }),
1864
+ /* @__PURE__ */ jsxs2("section", { className: "rounded-2xl border border-border/70 bg-transparent px-5 py-4", children: [
1865
+ /* @__PURE__ */ jsx2("h4", { className: "mb-3 text-sm font-semibold text-foreground", children: copy.t("labels.outputs") }),
1866
+ outputs.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "text-sm leading-6 text-muted-foreground", children: copy.t("messages.noOutputs") }) : /* @__PURE__ */ jsx2("div", { className: "grid gap-2.5", children: outputs.map((output) => /* @__PURE__ */ jsxs2(
1867
+ "button",
1868
+ {
1869
+ className: "rounded-xl border border-border/65 bg-transparent px-3.5 py-3 text-left transition-colors hover:bg-accent/25",
1870
+ type: "button",
1871
+ onClick: () => {
1872
+ void onOpen({
1873
+ displayName: output.displayName,
1874
+ kind: "file",
1875
+ path: output.path
1876
+ });
1877
+ },
1878
+ children: [
1879
+ /* @__PURE__ */ jsx2("p", { className: "truncate text-sm font-semibold text-foreground", children: output.displayName }),
1880
+ /* @__PURE__ */ jsx2("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: output.path })
1881
+ ]
1882
+ },
1883
+ output.outputId
1884
+ )) })
1885
+ ] })
1886
+ ] });
1887
+ }
1888
+ function IssueManagerPaneLoadingState() {
1889
+ return /* @__PURE__ */ jsxs2(
1890
+ "div",
1891
+ {
1892
+ className: "mx-auto flex w-full max-w-4xl flex-col gap-6",
1893
+ "aria-hidden": "true",
1894
+ children: [
1895
+ /* @__PURE__ */ jsx2("div", { className: "h-6 w-28 rounded-full bg-muted" }),
1896
+ /* @__PURE__ */ jsx2("div", { className: "h-12 w-2/3 rounded-full bg-muted" }),
1897
+ /* @__PURE__ */ jsxs2("div", { className: "rounded-[28px] border border-border/70 bg-transparent px-5 py-5", children: [
1898
+ /* @__PURE__ */ jsx2("div", { className: "h-4 w-24 rounded-full bg-muted" }),
1899
+ /* @__PURE__ */ jsx2("div", { className: "mt-5 h-4 w-full rounded-full bg-muted" }),
1900
+ /* @__PURE__ */ jsx2("div", { className: "mt-3 h-4 w-11/12 rounded-full bg-muted" }),
1901
+ /* @__PURE__ */ jsx2("div", { className: "mt-3 h-4 w-10/12 rounded-full bg-muted" })
1902
+ ] }),
1903
+ /* @__PURE__ */ jsxs2("div", { className: "rounded-[24px] border border-border/70 bg-transparent px-5 py-5", children: [
1904
+ /* @__PURE__ */ jsx2("div", { className: "h-4 w-32 rounded-full bg-muted" }),
1905
+ /* @__PURE__ */ jsx2("div", { className: "mt-5 h-4 w-full rounded-full bg-muted" }),
1906
+ /* @__PURE__ */ jsx2("div", { className: "mt-3 h-4 w-9/12 rounded-full bg-muted" })
1907
+ ] })
1908
+ ]
1909
+ }
1910
+ );
1911
+ }
1912
+ function IssueManagerTaskDrawerLoadingState() {
1913
+ return /* @__PURE__ */ jsxs2("div", { className: "grid gap-5", "aria-hidden": "true", children: [
1914
+ /* @__PURE__ */ jsx2("div", { className: "h-12 w-full rounded-2xl bg-muted" }),
1915
+ /* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-2 gap-3", children: [
1916
+ /* @__PURE__ */ jsx2("div", { className: "h-10 rounded-xl bg-muted" }),
1917
+ /* @__PURE__ */ jsx2("div", { className: "h-10 rounded-xl bg-muted" })
1918
+ ] }),
1919
+ /* @__PURE__ */ jsxs2("div", { className: "rounded-[24px] border border-border/70 bg-transparent px-4 py-4", children: [
1920
+ /* @__PURE__ */ jsx2("div", { className: "h-4 w-24 rounded-full bg-muted" }),
1921
+ /* @__PURE__ */ jsx2("div", { className: "mt-4 h-4 w-full rounded-full bg-muted" }),
1922
+ /* @__PURE__ */ jsx2("div", { className: "mt-3 h-4 w-11/12 rounded-full bg-muted" }),
1923
+ /* @__PURE__ */ jsx2("div", { className: "mt-3 h-4 w-9/12 rounded-full bg-muted" })
1924
+ ] })
1925
+ ] });
1926
+ }
1927
+
1928
+ // src/react/internal/IssueManagerPanelText.ts
1929
+ function summarizeIssueManagerContent(content, fallback) {
1930
+ const plainText = extractIssueManagerPlainTextFromContent(
1931
+ content ?? ""
1932
+ ).trim();
1933
+ if (!plainText) {
1934
+ return fallback;
1935
+ }
1936
+ if (plainText.length <= 120) {
1937
+ return plainText;
1938
+ }
1939
+ return `${plainText.slice(0, 117)}...`;
1940
+ }
1941
+ function resolveTaskCreatorLabel(task) {
1942
+ return resolveIssueManagerCreatorLabel(task);
1943
+ }
1944
+ function resolveIssueManagerCreatorLabel(entity) {
1945
+ return entity.creatorDisplayName?.trim() || entity.creatorUserId;
1946
+ }
1947
+
1948
+ // src/react/internal/IssueManagerPanels.tsx
1949
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1950
+ function IssueManagerIssuePane({
1951
+ controller,
1952
+ selectedIssue,
1953
+ onDismissCreate
1954
+ }) {
1955
+ const copy = controller.copy;
1956
+ const issueRefs = controller.issueDetail.value?.contextRefs.filter(
1957
+ (ref) => ref.parentKind === "issue"
1958
+ ) ?? [];
1959
+ const isCreatingIssue = controller.issueEditorMode === "create";
1960
+ const isEditingIssue = controller.issueEditorMode === "edit";
1961
+ const issueContent = selectedIssue?.content ?? "";
1962
+ const tasks = controller.issueDetail.value?.tasks ?? [];
1963
+ const selectedTaskId = controller.nodeState.selectedTaskId;
1964
+ const selectedTask = selectedTaskId ? (controller.taskDetail.value?.task?.taskId === selectedTaskId ? controller.taskDetail.value.task : tasks.find((task) => task.taskId === selectedTaskId)) ?? null : null;
1965
+ const latestRun = selectedTask ? controller.taskDetail.value?.latestRun ?? controller.taskDetail.value?.recentRuns[0] ?? null : null;
1966
+ const latestOutputs = selectedTask ? controller.taskDetail.value?.latestOutputs ?? [] : [];
1967
+ if (isCreatingIssue || isEditingIssue) {
1968
+ return /* @__PURE__ */ jsxs3("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: [
1969
+ /* @__PURE__ */ jsx3("div", { className: "min-h-0 flex-1 overflow-y-auto px-7 py-8", children: /* @__PURE__ */ jsxs3("div", { className: "flex w-full flex-col gap-5", children: [
1970
+ /* @__PURE__ */ jsx3("div", { className: "grid gap-3", children: /* @__PURE__ */ jsx3("h2", { className: "text-[1.65rem] font-semibold tracking-tight text-foreground", children: isCreatingIssue ? copy.t("actions.createIssue") : copy.t("actions.editIssue") }) }),
1971
+ /* @__PURE__ */ jsxs3("div", { className: "grid gap-5", children: [
1972
+ /* @__PURE__ */ jsxs3("label", { className: "grid gap-2.5", children: [
1973
+ /* @__PURE__ */ jsx3("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.title") }),
1974
+ /* @__PURE__ */ jsx3(
1975
+ Input2,
1976
+ {
1977
+ className: "h-10 rounded-xl border-border/80 text-base font-semibold shadow-none",
1978
+ placeholder: copy.t("composer.issueTitlePlaceholder"),
1979
+ value: controller.issueDraft.title,
1980
+ onChange: (event) => controller.setIssueTitle(event.target.value)
1981
+ }
1982
+ )
1983
+ ] }),
1984
+ /* @__PURE__ */ jsxs3("div", { className: "grid min-h-0 gap-2.5", children: [
1985
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-3", children: [
1986
+ /* @__PURE__ */ jsx3("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.content") }),
1987
+ /* @__PURE__ */ jsx3(
1988
+ Button3,
1989
+ {
1990
+ className: "h-8 rounded-lg border-border/70 px-3 text-[13px] font-semibold",
1991
+ size: "sm",
1992
+ type: "button",
1993
+ variant: "outline",
1994
+ onClick: () => {
1995
+ void controller.insertReferences("issue");
1996
+ },
1997
+ children: copy.t("actions.insertReferences")
1998
+ }
1999
+ )
2000
+ ] }),
2001
+ /* @__PURE__ */ jsx3(
2002
+ "textarea",
2003
+ {
2004
+ className: "min-h-[12rem] w-full resize-none rounded-2xl border border-border/70 bg-transparent px-4 py-3 text-sm leading-6 text-foreground outline-none",
2005
+ placeholder: copy.t("composer.issueContentPlaceholder"),
2006
+ value: controller.issueDraft.content,
2007
+ onChange: (event) => controller.setIssueContent(event.target.value)
2008
+ }
2009
+ )
2010
+ ] })
2011
+ ] })
2012
+ ] }) }),
2013
+ /* @__PURE__ */ jsx3("div", { className: "border-t border-border/70 px-7 py-4", children: /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-end gap-3", children: [
2014
+ /* @__PURE__ */ jsx3(
2015
+ Button3,
2016
+ {
2017
+ size: "default",
2018
+ type: "button",
2019
+ variant: "secondary",
2020
+ onClick: onDismissCreate,
2021
+ children: copy.t("actions.cancel")
2022
+ }
2023
+ ),
2024
+ /* @__PURE__ */ jsx3(
2025
+ Button3,
2026
+ {
2027
+ size: "default",
2028
+ type: "button",
2029
+ onClick: () => void controller.saveIssue(),
2030
+ children: copy.t("actions.saveIssue")
2031
+ }
2032
+ )
2033
+ ] }) })
2034
+ ] });
2035
+ }
2036
+ if (!selectedIssue) {
2037
+ return /* @__PURE__ */ jsx3("div", { className: "h-full min-h-0" });
2038
+ }
2039
+ return /* @__PURE__ */ jsx3("div", { className: "flex min-h-0 flex-col", children: /* @__PURE__ */ jsx3("div", { className: "min-h-0 flex-1 overflow-y-auto px-8 py-7", children: controller.issueDetail.isLoading && controller.issueDetail.value === null ? /* @__PURE__ */ jsx3(IssueManagerPaneLoadingState, {}) : /* @__PURE__ */ jsxs3("div", { className: "flex w-full max-w-[44rem] flex-col gap-9", children: [
2040
+ /* @__PURE__ */ jsxs3("header", { className: "flex items-start justify-between gap-6", children: [
2041
+ /* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
2042
+ /* @__PURE__ */ jsx3("h2", { className: "line-clamp-2 text-base font-semibold leading-6 text-foreground", children: selectedIssue.title }),
2043
+ /* @__PURE__ */ jsxs3("div", { className: "mt-3 flex flex-wrap items-center gap-x-5 gap-y-2 text-sm text-muted-foreground", children: [
2044
+ /* @__PURE__ */ jsx3(Badge3, { className: "rounded-full border-transparent bg-muted px-2 py-1 text-[11px] text-muted-foreground", children: resolveIssueManagerStatusLabel(copy, selectedIssue.status) }),
2045
+ /* @__PURE__ */ jsxs3("span", { children: [
2046
+ copy.t("labels.creator"),
2047
+ " ",
2048
+ resolveIssueManagerCreatorLabel(selectedIssue)
2049
+ ] }),
2050
+ /* @__PURE__ */ jsxs3("span", { children: [
2051
+ copy.t("labels.createdAt"),
2052
+ " ",
2053
+ formatIssueManagerTimestamp(selectedIssue.createdAtUnix) || "-"
2054
+ ] })
2055
+ ] })
2056
+ ] }),
2057
+ /* @__PURE__ */ jsxs3("div", { className: "flex shrink-0 items-center gap-5 pt-1", children: [
2058
+ /* @__PURE__ */ jsx3(
2059
+ Button3,
2060
+ {
2061
+ className: "h-auto px-0 text-sm font-semibold text-muted-foreground hover:text-foreground",
2062
+ size: "sm",
2063
+ type: "button",
2064
+ variant: "ghost",
2065
+ onClick: () => controller.setIssueEditorMode("edit"),
2066
+ children: copy.t("actions.edit")
2067
+ }
2068
+ ),
2069
+ /* @__PURE__ */ jsx3(
2070
+ Button3,
2071
+ {
2072
+ className: "h-auto px-0 text-sm font-semibold text-destructive hover:text-destructive",
2073
+ size: "sm",
2074
+ type: "button",
2075
+ variant: "ghost",
2076
+ onClick: () => {
2077
+ void controller.deleteIssue();
2078
+ },
2079
+ children: copy.t("actions.delete")
2080
+ }
2081
+ )
2082
+ ] })
2083
+ ] }),
2084
+ /* @__PURE__ */ jsx3(
2085
+ IssueManagerDescriptionSection,
2086
+ {
2087
+ content: issueContent,
2088
+ emptyLabel: copy.t("messages.issueContentEmpty"),
2089
+ label: copy.t("labels.description"),
2090
+ onOpen: controller.openReference,
2091
+ variant: "plain"
2092
+ }
2093
+ ),
2094
+ /* @__PURE__ */ jsx3(
2095
+ IssueManagerDetailTextSection,
2096
+ {
2097
+ body: latestRun ? latestRun.summary?.trim() || resolveIssueManagerStatusLabel(copy, latestRun.status) : copy.t("messages.noExecutionStatus"),
2098
+ label: copy.t("labels.latestRunStatus"),
2099
+ meta: latestRun ? formatIssueManagerTimestamp(
2100
+ latestRun.updatedAtUnix ?? latestRun.createdAtUnix
2101
+ ) || void 0 : void 0,
2102
+ tone: latestRun?.status === "failed" ? "destructive" : "muted"
2103
+ }
2104
+ ),
2105
+ /* @__PURE__ */ jsx3(
2106
+ IssueManagerOutputSection,
2107
+ {
2108
+ copy,
2109
+ outputs: latestOutputs,
2110
+ onOpen: controller.openReference
2111
+ }
2112
+ ),
2113
+ issueRefs.length > 0 ? /* @__PURE__ */ jsx3(
2114
+ IssueManagerContextSection,
2115
+ {
2116
+ copy,
2117
+ emptyLabel: copy.t("messages.noIssueReferences"),
2118
+ refs: issueRefs,
2119
+ onAdd: () => {
2120
+ void controller.attachReferences("issue");
2121
+ },
2122
+ onOpen: controller.openReference,
2123
+ onRemove: controller.removeContextRef
2124
+ }
2125
+ ) : null,
2126
+ /* @__PURE__ */ jsx3(
2127
+ IssueManagerSubtaskSection,
2128
+ {
2129
+ copy,
2130
+ onCreate: controller.createTaskDraft,
2131
+ onSelectTask: controller.selectTask,
2132
+ selectedTaskId: selectedTask?.taskId ?? null,
2133
+ tasks
2134
+ }
2135
+ )
2136
+ ] }) }) });
2137
+ }
2138
+ function IssueManagerDetailTextSection({
2139
+ body,
2140
+ label,
2141
+ meta,
2142
+ tone = "muted"
2143
+ }) {
2144
+ return /* @__PURE__ */ jsxs3("section", { className: "grid gap-2.5", children: [
2145
+ /* @__PURE__ */ jsx3("h3", { className: "text-sm font-semibold text-foreground", children: label }),
2146
+ /* @__PURE__ */ jsxs3("div", { className: "grid gap-1.5", children: [
2147
+ /* @__PURE__ */ jsx3(
2148
+ "p",
2149
+ {
2150
+ className: cn3(
2151
+ "text-sm leading-6",
2152
+ tone === "destructive" ? "text-destructive" : "text-muted-foreground"
2153
+ ),
2154
+ children: body
2155
+ }
2156
+ ),
2157
+ meta ? /* @__PURE__ */ jsx3("p", { className: "text-xs leading-5 text-muted-foreground", children: meta }) : null
2158
+ ] })
2159
+ ] });
2160
+ }
2161
+ function IssueManagerOutputSection({
2162
+ copy,
2163
+ onOpen,
2164
+ outputs
2165
+ }) {
2166
+ return /* @__PURE__ */ jsxs3("section", { className: "grid gap-2.5", children: [
2167
+ /* @__PURE__ */ jsx3("h3", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.executionOutputs") }),
2168
+ outputs.length === 0 ? /* @__PURE__ */ jsx3("p", { className: "text-sm leading-6 text-muted-foreground", children: copy.t("messages.noExecutionOutputs") }) : /* @__PURE__ */ jsx3("div", { className: "grid gap-2", children: outputs.map((output) => /* @__PURE__ */ jsxs3(
2169
+ "button",
2170
+ {
2171
+ className: "flex items-start justify-between gap-4 rounded-xl border border-border/65 px-4 py-3 text-left transition-colors hover:bg-accent/18",
2172
+ type: "button",
2173
+ onClick: () => {
2174
+ void onOpen({
2175
+ displayName: output.displayName,
2176
+ kind: "file",
2177
+ path: output.path
2178
+ });
2179
+ },
2180
+ children: [
2181
+ /* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1", children: [
2182
+ /* @__PURE__ */ jsx3("span", { className: "block truncate text-sm font-semibold text-foreground", children: output.displayName }),
2183
+ /* @__PURE__ */ jsx3("span", { className: "mt-1 block truncate text-xs text-muted-foreground", children: output.path })
2184
+ ] }),
2185
+ /* @__PURE__ */ jsx3("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatIssueManagerTimestamp(output.createdAtUnix) || "" })
2186
+ ]
2187
+ },
2188
+ output.outputId
2189
+ )) })
2190
+ ] });
2191
+ }
2192
+ function IssueManagerSubtaskSection({
2193
+ copy,
2194
+ onCreate,
2195
+ onSelectTask,
2196
+ selectedTaskId,
2197
+ tasks
2198
+ }) {
2199
+ return /* @__PURE__ */ jsxs3("section", { className: "grid gap-2.5", children: [
2200
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-3", children: [
2201
+ /* @__PURE__ */ jsx3("h3", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.subtasks") }),
2202
+ /* @__PURE__ */ jsxs3(
2203
+ Button3,
2204
+ {
2205
+ className: "h-auto gap-1.5 px-0 text-sm font-semibold text-foreground hover:text-foreground",
2206
+ size: "sm",
2207
+ type: "button",
2208
+ variant: "ghost",
2209
+ onClick: onCreate,
2210
+ children: [
2211
+ /* @__PURE__ */ jsx3(FileCreateIcon2, { size: 14 }),
2212
+ copy.t("actions.add")
2213
+ ]
2214
+ }
2215
+ )
2216
+ ] }),
2217
+ tasks.length === 0 ? /* @__PURE__ */ jsx3("p", { className: "text-sm leading-6 text-muted-foreground", children: copy.t("messages.noSubtasksForIssue") }) : /* @__PURE__ */ jsx3("div", { className: "grid gap-2", children: tasks.map((task) => /* @__PURE__ */ jsxs3(
2218
+ "button",
2219
+ {
2220
+ className: cn3(
2221
+ "flex items-start justify-between gap-4 rounded-xl border px-4 py-3 text-left transition-colors",
2222
+ selectedTaskId === task.taskId ? "border-border/90 bg-background-fronted" : "border-border/65 hover:bg-accent/18"
2223
+ ),
2224
+ type: "button",
2225
+ onClick: () => onSelectTask(task.taskId),
2226
+ children: [
2227
+ /* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
2228
+ /* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 items-center gap-2.5", children: [
2229
+ /* @__PURE__ */ jsx3("span", { className: "truncate text-sm font-semibold text-foreground", children: task.title }),
2230
+ /* @__PURE__ */ jsx3(Badge3, { className: "rounded-md border-transparent bg-muted px-2 py-1 text-[11px] font-medium text-muted-foreground", children: resolveIssueManagerStatusLabel(copy, task.status) })
2231
+ ] }),
2232
+ /* @__PURE__ */ jsx3("p", { className: "mt-2 line-clamp-2 text-sm leading-6 text-muted-foreground", children: summarizeIssueManagerContent(
2233
+ task.content,
2234
+ copy.t("messages.taskContentEmpty")
2235
+ ) })
2236
+ ] }),
2237
+ /* @__PURE__ */ jsx3("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatIssueManagerTimestamp(
2238
+ task.createdAtUnix ?? task.updatedAtUnix
2239
+ ) || "" })
2240
+ ]
2241
+ },
2242
+ task.taskId
2243
+ )) })
2244
+ ] });
2245
+ }
2246
+
2247
+ // src/react/internal/IssueManagerTaskComposerPane.tsx
2248
+ import {
2249
+ Button as Button4,
2250
+ FileSearchIcon,
2251
+ Input as Input3,
2252
+ Select as Select2,
2253
+ SelectContent as SelectContent2,
2254
+ SelectItem as SelectItem2,
2255
+ SelectTrigger as SelectTrigger2,
2256
+ SelectValue,
2257
+ UploadIcon as UploadIcon2
2258
+ } from "@nextop-os/ui-system";
2259
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2260
+ var taskPriorityOptions = ["high", "medium", "low"];
2261
+ function IssueManagerTaskComposerPane({
2262
+ controller,
2263
+ onCancel,
2264
+ selectedIssue
2265
+ }) {
2266
+ const copy = controller.copy;
2267
+ const showAttachmentActions = controller.canUploadWorkspaceFiles || controller.canReferenceWorkspaceFiles;
2268
+ return /* @__PURE__ */ jsxs4("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: [
2269
+ /* @__PURE__ */ jsx4("div", { className: "min-h-0 flex-1 overflow-y-auto px-8 py-8", children: /* @__PURE__ */ jsxs4("div", { className: "flex w-full max-w-[76rem] flex-col gap-8", children: [
2270
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-start justify-between gap-4", children: [
2271
+ /* @__PURE__ */ jsx4("h2", { className: "text-base font-semibold leading-6 text-foreground", children: copy.t("actions.addSubtask") }),
2272
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-3", children: [
2273
+ /* @__PURE__ */ jsx4("span", { className: "text-sm text-muted-foreground", children: copy.t("labels.priority") }),
2274
+ /* @__PURE__ */ jsxs4(
2275
+ Select2,
2276
+ {
2277
+ value: controller.taskDraft.priority,
2278
+ onValueChange: (value) => controller.setTaskPriority(value),
2279
+ children: [
2280
+ /* @__PURE__ */ jsx4(
2281
+ SelectTrigger2,
2282
+ {
2283
+ "aria-label": copy.t("labels.priority"),
2284
+ className: "min-w-28 rounded-xl border-border/70 bg-muted/25",
2285
+ children: /* @__PURE__ */ jsx4(SelectValue, {})
2286
+ }
2287
+ ),
2288
+ /* @__PURE__ */ jsx4(SelectContent2, { style: { zIndex: "var(--z-panel-popover)" }, children: taskPriorityOptions.map((priority) => /* @__PURE__ */ jsx4(SelectItem2, { value: priority, children: resolveIssueManagerPriorityLabel(copy, priority) }, priority)) })
2289
+ ]
2290
+ }
2291
+ )
2292
+ ] })
2293
+ ] }),
2294
+ /* @__PURE__ */ jsxs4("label", { className: "grid gap-3", children: [
2295
+ /* @__PURE__ */ jsx4("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.title") }),
2296
+ /* @__PURE__ */ jsx4(
2297
+ Input3,
2298
+ {
2299
+ className: "h-14 rounded-2xl border-0 bg-muted/28 px-5 text-base font-medium shadow-none placeholder:text-muted-foreground",
2300
+ placeholder: copy.t("composer.subtaskTitlePlaceholder"),
2301
+ value: controller.taskDraft.title,
2302
+ onChange: (event) => controller.setTaskTitle(event.target.value)
2303
+ }
2304
+ )
2305
+ ] }),
2306
+ /* @__PURE__ */ jsxs4("section", { className: "grid gap-3", children: [
2307
+ /* @__PURE__ */ jsx4("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.requirementDescription") }),
2308
+ /* @__PURE__ */ jsxs4("div", { className: "overflow-hidden rounded-[28px] border border-border/70 bg-muted/18", children: [
2309
+ /* @__PURE__ */ jsx4(
2310
+ "textarea",
2311
+ {
2312
+ className: "min-h-[20rem] w-full resize-none border-0 bg-transparent px-5 py-5 text-sm leading-6 text-foreground outline-none placeholder:text-muted-foreground",
2313
+ placeholder: copy.t("composer.subtaskContentPlaceholder"),
2314
+ value: controller.taskDraft.content,
2315
+ onChange: (event) => controller.setTaskContent(event.target.value)
2316
+ }
2317
+ ),
2318
+ showAttachmentActions ? /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-3 border-t border-border/60 px-5 py-4", children: [
2319
+ controller.canUploadWorkspaceFiles ? /* @__PURE__ */ jsxs4(
2320
+ Button4,
2321
+ {
2322
+ className: "rounded-xl border-0 bg-background-fronted px-4 text-sm font-semibold text-foreground shadow-none hover:bg-background-fronted",
2323
+ size: "sm",
2324
+ type: "button",
2325
+ variant: "secondary",
2326
+ onClick: () => {
2327
+ void controller.uploadReferences("task", "files");
2328
+ },
2329
+ children: [
2330
+ /* @__PURE__ */ jsx4(UploadIcon2, { size: 16 }),
2331
+ copy.t("actions.uploadFiles")
2332
+ ]
2333
+ }
2334
+ ) : null,
2335
+ controller.canUploadWorkspaceFiles ? /* @__PURE__ */ jsxs4(
2336
+ Button4,
2337
+ {
2338
+ className: "rounded-xl border-0 bg-background-fronted px-4 text-sm font-semibold text-foreground shadow-none hover:bg-background-fronted",
2339
+ size: "sm",
2340
+ type: "button",
2341
+ variant: "secondary",
2342
+ onClick: () => {
2343
+ void controller.uploadReferences("task", "folder");
2344
+ },
2345
+ children: [
2346
+ /* @__PURE__ */ jsx4(UploadIcon2, { size: 16 }),
2347
+ copy.t("actions.uploadFolder")
2348
+ ]
2349
+ }
2350
+ ) : null,
2351
+ controller.canReferenceWorkspaceFiles ? /* @__PURE__ */ jsxs4(
2352
+ Button4,
2353
+ {
2354
+ className: "rounded-xl border-0 bg-background-fronted px-4 text-sm font-semibold text-foreground shadow-none hover:bg-background-fronted",
2355
+ size: "sm",
2356
+ type: "button",
2357
+ variant: "secondary",
2358
+ onClick: () => {
2359
+ void controller.insertReferences("task");
2360
+ },
2361
+ children: [
2362
+ /* @__PURE__ */ jsx4(FileSearchIcon, { size: 16 }),
2363
+ copy.t("actions.referenceWorkspaceFiles")
2364
+ ]
2365
+ }
2366
+ ) : null
2367
+ ] }) : null
2368
+ ] })
2369
+ ] })
2370
+ ] }) }),
2371
+ /* @__PURE__ */ jsx4("div", { className: "border-t border-border/70 px-8 py-4", children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-end gap-3", children: [
2372
+ /* @__PURE__ */ jsx4(
2373
+ Button4,
2374
+ {
2375
+ size: "default",
2376
+ type: "button",
2377
+ variant: "secondary",
2378
+ onClick: onCancel,
2379
+ children: copy.t("actions.cancel")
2380
+ }
2381
+ ),
2382
+ /* @__PURE__ */ jsx4(
2383
+ Button4,
2384
+ {
2385
+ disabled: !selectedIssue,
2386
+ size: "default",
2387
+ type: "button",
2388
+ onClick: () => void controller.saveTask(),
2389
+ children: copy.t("actions.saveSubtask")
2390
+ }
2391
+ )
2392
+ ] }) })
2393
+ ] });
2394
+ }
2395
+
2396
+ // src/react/internal/IssueManagerTaskDrawer.tsx
2397
+ import {
2398
+ Badge as Badge4,
2399
+ Button as Button5,
2400
+ CloseIcon,
2401
+ DropdownMenu,
2402
+ DropdownMenuContent,
2403
+ DropdownMenuItem,
2404
+ DropdownMenuTrigger,
2405
+ Input as Input4,
2406
+ ScrollArea as ScrollArea3,
2407
+ Select as Select3,
2408
+ SelectContent as SelectContent3,
2409
+ SelectItem as SelectItem3,
2410
+ SelectTrigger as SelectTrigger3,
2411
+ SelectValue as SelectValue2,
2412
+ SparkIcon as SparkIcon2
2413
+ } from "@nextop-os/ui-system";
2414
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2415
+ var taskPriorityOptions2 = ["high", "medium", "low"];
2416
+ function IssueManagerTaskDrawer({
2417
+ controller,
2418
+ selectedIssue,
2419
+ selectedTask,
2420
+ onClose
2421
+ }) {
2422
+ const copy = controller.copy;
2423
+ const isCreate = controller.taskEditorMode === "create";
2424
+ const isEdit = controller.taskEditorMode === "edit";
2425
+ const isRead = !isCreate && !isEdit;
2426
+ const taskRefs = controller.taskDetail.value?.contextRefs.filter(
2427
+ (ref) => ref.parentKind === "task"
2428
+ ) ?? [];
2429
+ const title = isCreate || isEdit ? isCreate ? copy.t("actions.createTask") : copy.t("actions.editTask") : selectedTask?.title || copy.t("labels.taskDetails");
2430
+ const taskContent = selectedTask?.content ?? "";
2431
+ return /* @__PURE__ */ jsx5(
2432
+ "div",
2433
+ {
2434
+ className: "absolute inset-0 z-20 flex justify-end bg-foreground/6 backdrop-blur-[1px]",
2435
+ onClick: onClose,
2436
+ children: /* @__PURE__ */ jsxs5(
2437
+ "aside",
2438
+ {
2439
+ className: "flex h-full w-[34rem] max-w-[92vw] flex-col border-l border-border/70 [background:var(--workbench-node-surface)] shadow-[-20px_0_60px_rgba(15,23,42,0.12)]",
2440
+ onClick: (event) => event.stopPropagation(),
2441
+ children: [
2442
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-start justify-between gap-4 border-b border-border/70 px-6 py-5", children: [
2443
+ /* @__PURE__ */ jsxs5("div", { className: "min-w-0 flex-1", children: [
2444
+ isRead && selectedTask ? /* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center gap-2", children: [
2445
+ /* @__PURE__ */ jsx5("h3", { className: "line-clamp-2 text-lg font-semibold leading-7 tracking-tight text-foreground", children: title }),
2446
+ /* @__PURE__ */ jsx5(Badge4, { className: "rounded-full border-transparent bg-primary/10 px-2.5 py-1 text-[11px] text-primary", children: resolveIssueManagerStatusLabel(copy, selectedTask.status) }),
2447
+ /* @__PURE__ */ jsx5(Badge4, { className: "rounded-full border-transparent bg-muted px-2.5 py-1 text-[11px] text-muted-foreground", children: resolveIssueManagerPriorityLabel(
2448
+ copy,
2449
+ selectedTask.priority
2450
+ ) })
2451
+ ] }) : /* @__PURE__ */ jsx5("h3", { className: "line-clamp-2 text-lg font-semibold leading-7 tracking-tight text-foreground", children: title }),
2452
+ isRead && selectedTask ? /* @__PURE__ */ jsxs5("div", { className: "mt-3 flex flex-wrap items-center gap-2 text-sm text-muted-foreground", children: [
2453
+ /* @__PURE__ */ jsxs5("span", { children: [
2454
+ copy.t("labels.updatedAt"),
2455
+ " ",
2456
+ formatIssueManagerTimestamp(
2457
+ selectedTask.updatedAtUnix ?? selectedTask.createdAtUnix
2458
+ ) || "-"
2459
+ ] }),
2460
+ /* @__PURE__ */ jsx5("span", { className: "h-1 w-1 rounded-full bg-border" }),
2461
+ /* @__PURE__ */ jsx5("span", { children: resolveTaskCreatorLabel(selectedTask) })
2462
+ ] }) : null
2463
+ ] }),
2464
+ /* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-2", children: [
2465
+ isRead && selectedTask ? /* @__PURE__ */ jsxs5(DropdownMenu, { children: [
2466
+ /* @__PURE__ */ jsx5(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx5(
2467
+ Button5,
2468
+ {
2469
+ "aria-label": copy.t("actions.moreActions"),
2470
+ size: "icon-sm",
2471
+ type: "button",
2472
+ variant: "ghost",
2473
+ children: /* @__PURE__ */ jsx5(
2474
+ "span",
2475
+ {
2476
+ "aria-hidden": "true",
2477
+ className: "text-base leading-none tracking-[0.18em] text-muted-foreground",
2478
+ children: "..."
2479
+ }
2480
+ )
2481
+ }
2482
+ ) }),
2483
+ /* @__PURE__ */ jsxs5(DropdownMenuContent, { align: "end", sideOffset: 8, children: [
2484
+ /* @__PURE__ */ jsx5(
2485
+ DropdownMenuItem,
2486
+ {
2487
+ onClick: () => controller.setTaskEditorMode("edit"),
2488
+ children: copy.t("actions.editTask")
2489
+ }
2490
+ ),
2491
+ /* @__PURE__ */ jsx5(
2492
+ DropdownMenuItem,
2493
+ {
2494
+ variant: "destructive",
2495
+ onClick: () => {
2496
+ void controller.deleteTask();
2497
+ },
2498
+ children: copy.t("actions.deleteTask")
2499
+ }
2500
+ )
2501
+ ] })
2502
+ ] }) : null,
2503
+ /* @__PURE__ */ jsx5(
2504
+ Button5,
2505
+ {
2506
+ "aria-label": copy.t("actions.cancel"),
2507
+ size: "icon-sm",
2508
+ type: "button",
2509
+ variant: "ghost",
2510
+ onClick: onClose,
2511
+ children: /* @__PURE__ */ jsx5(CloseIcon, { size: 16 })
2512
+ }
2513
+ )
2514
+ ] })
2515
+ ] }),
2516
+ /* @__PURE__ */ jsx5(ScrollArea3, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx5("div", { className: "flex flex-col gap-6 px-6 py-6", children: controller.taskDetail.isLoading && !isCreate && controller.taskDetail.value === null ? /* @__PURE__ */ jsx5(IssueManagerTaskDrawerLoadingState, {}) : isCreate || isEdit ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
2517
+ /* @__PURE__ */ jsxs5("div", { className: "grid gap-5", children: [
2518
+ /* @__PURE__ */ jsxs5("label", { className: "grid gap-2.5", children: [
2519
+ /* @__PURE__ */ jsx5("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.title") }),
2520
+ /* @__PURE__ */ jsx5(
2521
+ Input4,
2522
+ {
2523
+ className: "h-10 rounded-xl border-border/80 text-base font-semibold shadow-none",
2524
+ placeholder: copy.t("composer.taskTitlePlaceholder"),
2525
+ value: controller.taskDraft.title,
2526
+ onChange: (event) => controller.setTaskTitle(event.target.value)
2527
+ }
2528
+ )
2529
+ ] }),
2530
+ /* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
2531
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3", children: [
2532
+ /* @__PURE__ */ jsx5("span", { className: "text-sm font-medium text-muted-foreground", children: copy.t("labels.priority") }),
2533
+ /* @__PURE__ */ jsxs5(
2534
+ Select3,
2535
+ {
2536
+ value: controller.taskDraft.priority,
2537
+ onValueChange: (value) => controller.setTaskPriority(value),
2538
+ children: [
2539
+ /* @__PURE__ */ jsx5(
2540
+ SelectTrigger3,
2541
+ {
2542
+ "aria-label": copy.t("labels.priority"),
2543
+ className: "min-w-28 rounded-xl border-border/70 bg-muted/30",
2544
+ children: /* @__PURE__ */ jsx5(SelectValue2, {})
2545
+ }
2546
+ ),
2547
+ /* @__PURE__ */ jsx5(
2548
+ SelectContent3,
2549
+ {
2550
+ style: { zIndex: "var(--z-panel-popover)" },
2551
+ children: taskPriorityOptions2.map((priority) => /* @__PURE__ */ jsx5(SelectItem3, { value: priority, children: resolveIssueManagerPriorityLabel(copy, priority) }, priority))
2552
+ }
2553
+ )
2554
+ ]
2555
+ }
2556
+ )
2557
+ ] }),
2558
+ /* @__PURE__ */ jsx5(
2559
+ Button5,
2560
+ {
2561
+ className: "h-8 justify-center rounded-lg border-border/70 px-3 text-[13px] font-semibold",
2562
+ size: "sm",
2563
+ type: "button",
2564
+ variant: "outline",
2565
+ onClick: () => {
2566
+ void controller.insertReferences("task");
2567
+ },
2568
+ children: copy.t("actions.insertReferences")
2569
+ }
2570
+ )
2571
+ ] }),
2572
+ /* @__PURE__ */ jsxs5("div", { className: "grid gap-2.5", children: [
2573
+ /* @__PURE__ */ jsx5("span", { className: "text-sm font-semibold text-foreground", children: copy.t("labels.content") }),
2574
+ /* @__PURE__ */ jsx5(
2575
+ "textarea",
2576
+ {
2577
+ className: "min-h-[12rem] w-full resize-none rounded-2xl border border-border/70 bg-transparent px-4 py-3 text-sm leading-6 text-foreground outline-none",
2578
+ placeholder: copy.t("composer.taskContentPlaceholder"),
2579
+ value: controller.taskDraft.content,
2580
+ onChange: (event) => controller.setTaskContent(event.target.value)
2581
+ }
2582
+ )
2583
+ ] })
2584
+ ] }),
2585
+ /* @__PURE__ */ jsx5(
2586
+ IssueManagerContextSection,
2587
+ {
2588
+ copy,
2589
+ emptyLabel: copy.t("messages.noTaskReferences"),
2590
+ refs: taskRefs,
2591
+ onAdd: () => {
2592
+ void controller.attachReferences("task");
2593
+ },
2594
+ onOpen: controller.openReference,
2595
+ onRemove: controller.removeContextRef
2596
+ }
2597
+ ),
2598
+ !isCreate ? /* @__PURE__ */ jsx5(
2599
+ IssueManagerRunPanels,
2600
+ {
2601
+ copy,
2602
+ outputs: controller.taskDetail.value?.latestOutputs ?? [],
2603
+ recentRuns: controller.taskDetail.value?.recentRuns ?? [],
2604
+ onOpen: controller.openReference
2605
+ }
2606
+ ) : null
2607
+ ] }) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
2608
+ /* @__PURE__ */ jsx5(
2609
+ IssueManagerDescriptionSection,
2610
+ {
2611
+ content: taskContent,
2612
+ emptyLabel: copy.t("messages.taskContentEmpty"),
2613
+ label: copy.t("labels.content"),
2614
+ minHeightClass: "min-h-[8rem]",
2615
+ onOpen: controller.openReference
2616
+ }
2617
+ ),
2618
+ /* @__PURE__ */ jsx5(
2619
+ IssueManagerContextSection,
2620
+ {
2621
+ copy,
2622
+ emptyLabel: copy.t("messages.noTaskReferences"),
2623
+ refs: taskRefs,
2624
+ onAdd: () => {
2625
+ void controller.attachReferences("task");
2626
+ },
2627
+ onOpen: controller.openReference,
2628
+ onRemove: controller.removeContextRef
2629
+ }
2630
+ ),
2631
+ /* @__PURE__ */ jsx5(
2632
+ IssueManagerRunPanels,
2633
+ {
2634
+ copy,
2635
+ outputs: controller.taskDetail.value?.latestOutputs ?? [],
2636
+ recentRuns: controller.taskDetail.value?.recentRuns ?? [],
2637
+ onOpen: controller.openReference
2638
+ }
2639
+ )
2640
+ ] }) }) }),
2641
+ isRead && selectedTask ? /* @__PURE__ */ jsx5("div", { className: "border-t border-border/70 px-6 py-5", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between gap-3", children: [
2642
+ /* @__PURE__ */ jsx5(
2643
+ IssueManagerRunActionTrigger,
2644
+ {
2645
+ controller,
2646
+ iconSize: 15,
2647
+ triggerClassName: "min-w-[11rem] rounded-xl border-border/70 bg-secondary/90 px-3.5 py-2"
2648
+ }
2649
+ ),
2650
+ /* @__PURE__ */ jsx5(
2651
+ Button5,
2652
+ {
2653
+ className: "shrink-0 rounded-xl bg-foreground px-4 text-background hover:bg-foreground/92",
2654
+ size: "sm",
2655
+ type: "button",
2656
+ onClick: () => {
2657
+ void controller.shareSelection();
2658
+ },
2659
+ children: copy.t("actions.inviteCollaborator")
2660
+ }
2661
+ )
2662
+ ] }) }) : isCreate || isEdit ? /* @__PURE__ */ jsx5("div", { className: "border-t border-border/70 px-6 py-5", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between gap-3", children: [
2663
+ /* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2", children: !isCreate && selectedTask ? /* @__PURE__ */ jsx5(
2664
+ Button5,
2665
+ {
2666
+ size: "default",
2667
+ type: "button",
2668
+ variant: "destructive",
2669
+ onClick: () => {
2670
+ void controller.deleteTask();
2671
+ },
2672
+ children: copy.t("actions.deleteTask")
2673
+ }
2674
+ ) : null }),
2675
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3", children: [
2676
+ /* @__PURE__ */ jsx5(
2677
+ Button5,
2678
+ {
2679
+ size: "default",
2680
+ type: "button",
2681
+ variant: "secondary",
2682
+ onClick: () => controller.setTaskEditorMode("read"),
2683
+ children: copy.t("actions.cancel")
2684
+ }
2685
+ ),
2686
+ /* @__PURE__ */ jsxs5(
2687
+ Button5,
2688
+ {
2689
+ disabled: !selectedIssue,
2690
+ size: "default",
2691
+ type: "button",
2692
+ onClick: () => void controller.saveTask(),
2693
+ children: [
2694
+ /* @__PURE__ */ jsx5(SparkIcon2, { size: 16 }),
2695
+ copy.t("actions.saveTask")
2696
+ ]
2697
+ }
2698
+ )
2699
+ ] })
2700
+ ] }) }) : null
2701
+ ]
2702
+ }
2703
+ )
2704
+ }
2705
+ );
2706
+ }
2707
+
2708
+ // src/react/internal/IssueManagerShell.tsx
2709
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2710
+ var issueStatusFilters = [
2711
+ "all",
2712
+ "not_started",
2713
+ "running",
2714
+ "pending_acceptance",
2715
+ "completed",
2716
+ "failed",
2717
+ "canceled"
2718
+ ];
2719
+ var sidebarDefaultWidth = 352;
2720
+ var sidebarMinWidth = 248;
2721
+ var sidebarMaxWidth = 520;
2722
+ var mainMinWidth = 460;
2723
+ function IssueManagerShell({
2724
+ controller,
2725
+ onClearNotice,
2726
+ onCloseTaskDrawer,
2727
+ onDismissIssueCreate,
2728
+ selectedIssue,
2729
+ selectedTask
2730
+ }) {
2731
+ const isIssueEditing = controller.issueEditorMode !== "read";
2732
+ const isTaskCreating = !isIssueEditing && controller.taskEditorMode === "create";
2733
+ const isTaskDrawerOpen = !isIssueEditing && !isTaskCreating && (controller.taskEditorMode === "edit" || selectedTask !== null);
2734
+ const layoutRef = useRef2(null);
2735
+ const resizeRef = useRef2(null);
2736
+ const [sidebarWidth, setSidebarWidth] = useState4(sidebarDefaultWidth);
2737
+ useEffect4(() => {
2738
+ const clamp = () => {
2739
+ const width = layoutRef.current?.getBoundingClientRect().width ?? 0;
2740
+ if (!width) {
2741
+ return;
2742
+ }
2743
+ setSidebarWidth((current) => clampSidebarWidth(current, width));
2744
+ };
2745
+ const layout = layoutRef.current;
2746
+ const observer = layout && typeof ResizeObserver !== "undefined" ? new ResizeObserver(clamp) : null;
2747
+ if (observer && layout) {
2748
+ observer.observe(layout);
2749
+ }
2750
+ window.addEventListener("resize", clamp);
2751
+ return () => {
2752
+ observer?.disconnect();
2753
+ window.removeEventListener("resize", clamp);
2754
+ };
2755
+ }, []);
2756
+ const layoutStyle = {
2757
+ "--issue-manager-sidebar-width": `${sidebarWidth}px`
2758
+ };
2759
+ return /* @__PURE__ */ jsxs6(Fragment3, { children: [
2760
+ controller.notice ? /* @__PURE__ */ jsx6(
2761
+ IssueManagerNoticeBanner,
2762
+ {
2763
+ kind: controller.notice.kind,
2764
+ label: controller.notice.message,
2765
+ onClear: onClearNotice,
2766
+ copy: controller.copy
2767
+ }
2768
+ ) : null,
2769
+ /* @__PURE__ */ jsxs6(
2770
+ "div",
2771
+ {
2772
+ className: "grid min-h-0 flex-1 grid-cols-[var(--issue-manager-sidebar-width)_12px_minmax(0,1fr)] overflow-hidden bg-transparent",
2773
+ ref: layoutRef,
2774
+ style: layoutStyle,
2775
+ children: [
2776
+ /* @__PURE__ */ jsx6(IssueManagerSidebar, { controller }),
2777
+ /* @__PURE__ */ jsx6(
2778
+ "div",
2779
+ {
2780
+ "aria-label": controller.copy.t("labels.resizeIssueList"),
2781
+ "aria-orientation": "vertical",
2782
+ "aria-valuemax": sidebarMaxWidth,
2783
+ "aria-valuemin": sidebarMinWidth,
2784
+ "aria-valuenow": sidebarWidth,
2785
+ className: "group flex cursor-col-resize items-center justify-center",
2786
+ role: "separator",
2787
+ tabIndex: 0,
2788
+ onKeyDown: (event) => handleSidebarResizeKeyDown(event, layoutRef, setSidebarWidth),
2789
+ onPointerCancel: (event) => handleSidebarResizePointerEnd(event, resizeRef),
2790
+ onPointerDown: (event) => handleSidebarResizePointerDown(
2791
+ event,
2792
+ layoutRef,
2793
+ resizeRef,
2794
+ sidebarWidth,
2795
+ setSidebarWidth
2796
+ ),
2797
+ onPointerMove: (event) => handleSidebarResizePointerMove(event, resizeRef, setSidebarWidth),
2798
+ onPointerUp: (event) => handleSidebarResizePointerEnd(event, resizeRef),
2799
+ children: /* @__PURE__ */ jsx6("span", { className: "h-full w-px rounded-full bg-border/70 transition-colors group-hover:bg-primary/40" })
2800
+ }
2801
+ ),
2802
+ /* @__PURE__ */ jsxs6("div", { className: "relative min-h-0 overflow-hidden bg-transparent", children: [
2803
+ /* @__PURE__ */ jsxs6("div", { className: "flex h-full min-h-0 flex-col", children: [
2804
+ /* @__PURE__ */ jsx6("div", { className: "min-h-0 flex-1 overflow-hidden", children: isIssueEditing ? /* @__PURE__ */ jsx6(
2805
+ IssueManagerIssuePane,
2806
+ {
2807
+ controller,
2808
+ selectedIssue,
2809
+ onDismissCreate: onDismissIssueCreate
2810
+ }
2811
+ ) : isTaskCreating ? /* @__PURE__ */ jsx6(
2812
+ IssueManagerTaskComposerPane,
2813
+ {
2814
+ controller,
2815
+ selectedIssue,
2816
+ onCancel: () => controller.setTaskEditorMode("read")
2817
+ }
2818
+ ) : selectedIssue ? /* @__PURE__ */ jsx6(
2819
+ IssueManagerIssuePane,
2820
+ {
2821
+ controller,
2822
+ selectedIssue,
2823
+ onDismissCreate: onDismissIssueCreate
2824
+ }
2825
+ ) : /* @__PURE__ */ jsx6("div", { className: "flex h-full min-h-0 items-center justify-center px-10 py-10", children: /* @__PURE__ */ jsxs6("div", { className: "flex max-w-2xl flex-col items-center gap-5 text-center", children: [
2826
+ /* @__PURE__ */ jsx6(IssueManagerEmptyIllustration, {}),
2827
+ /* @__PURE__ */ jsxs6("div", { className: "space-y-3", children: [
2828
+ /* @__PURE__ */ jsx6("h2", { className: "text-[2.05rem] font-semibold tracking-tight text-foreground", children: controller.copy.t("messages.noIssues") }),
2829
+ /* @__PURE__ */ jsx6("p", { className: "max-w-xl text-[1.15rem] leading-8 text-muted-foreground", children: controller.copy.t("emptyState") })
2830
+ ] }),
2831
+ /* @__PURE__ */ jsxs6(
2832
+ Button6,
2833
+ {
2834
+ className: "h-12 rounded-xl bg-foreground px-6 text-base font-semibold text-background hover:bg-foreground/92",
2835
+ size: "lg",
2836
+ type: "button",
2837
+ onClick: () => controller.setIssueEditorMode("create"),
2838
+ children: [
2839
+ /* @__PURE__ */ jsx6(FileCreateIcon3, { size: 18 }),
2840
+ controller.copy.t("actions.createIssue")
2841
+ ]
2842
+ }
2843
+ )
2844
+ ] }) }) }),
2845
+ /* @__PURE__ */ jsx6(
2846
+ IssueManagerBottomBar,
2847
+ {
2848
+ controller,
2849
+ selectedIssue,
2850
+ selectedTask
2851
+ }
2852
+ )
2853
+ ] }),
2854
+ isTaskDrawerOpen ? /* @__PURE__ */ jsx6(
2855
+ IssueManagerTaskDrawer,
2856
+ {
2857
+ controller,
2858
+ selectedIssue,
2859
+ selectedTask,
2860
+ onClose: onCloseTaskDrawer
2861
+ }
2862
+ ) : null
2863
+ ] })
2864
+ ]
2865
+ }
2866
+ )
2867
+ ] });
2868
+ }
2869
+ function IssueManagerNoticeBanner({
2870
+ copy,
2871
+ kind,
2872
+ label,
2873
+ onClear
2874
+ }) {
2875
+ return /* @__PURE__ */ jsx6(
2876
+ "div",
2877
+ {
2878
+ className: cn4(
2879
+ "border-b px-4 py-2.5 text-sm",
2880
+ kind === "error" ? "border-destructive/20 bg-destructive/8 text-destructive" : "border-primary/15 bg-primary/[0.06] text-foreground"
2881
+ ),
2882
+ children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-3", children: [
2883
+ /* @__PURE__ */ jsx6("span", { children: label }),
2884
+ /* @__PURE__ */ jsx6(
2885
+ Button6,
2886
+ {
2887
+ "aria-label": copy.t("actions.cancel"),
2888
+ size: "icon-xs",
2889
+ type: "button",
2890
+ variant: "ghost",
2891
+ onClick: onClear,
2892
+ children: /* @__PURE__ */ jsx6(CloseIcon2, { size: 14 })
2893
+ }
2894
+ )
2895
+ ] })
2896
+ }
2897
+ );
2898
+ }
2899
+ function IssueManagerSidebar({
2900
+ controller
2901
+ }) {
2902
+ const copy = controller.copy;
2903
+ const counts = buildIssueManagerStatusCounts(controller.issues.value);
2904
+ const showRefreshAction = controller.issues.isLoading || controller.issues.error !== null;
2905
+ const tabsViewportRef = useRef2(null);
2906
+ const [canScrollTabsLeft, setCanScrollTabsLeft] = useState4(false);
2907
+ const [canScrollTabsRight, setCanScrollTabsRight] = useState4(false);
2908
+ useEffect4(() => {
2909
+ const viewport = tabsViewportRef.current;
2910
+ if (!viewport) {
2911
+ return;
2912
+ }
2913
+ const updateScrollState = () => {
2914
+ const maxScrollLeft = viewport.scrollWidth - viewport.clientWidth;
2915
+ setCanScrollTabsLeft(viewport.scrollLeft > 4);
2916
+ setCanScrollTabsRight(
2917
+ maxScrollLeft > 4 && viewport.scrollLeft < maxScrollLeft - 4
2918
+ );
2919
+ };
2920
+ updateScrollState();
2921
+ viewport.addEventListener("scroll", updateScrollState, { passive: true });
2922
+ const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(updateScrollState) : null;
2923
+ observer?.observe(viewport);
2924
+ if (viewport.parentElement) {
2925
+ observer?.observe(viewport.parentElement);
2926
+ }
2927
+ return () => {
2928
+ viewport.removeEventListener("scroll", updateScrollState);
2929
+ observer?.disconnect();
2930
+ };
2931
+ }, [controller.issues.value.length]);
2932
+ return /* @__PURE__ */ jsxs6("aside", { className: "flex min-h-0 flex-col border-r border-border/70 bg-transparent", children: [
2933
+ /* @__PURE__ */ jsx6("div", { className: "border-b border-border/70 px-4 py-4", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
2934
+ /* @__PURE__ */ jsxs6("div", { className: "relative flex-1", children: [
2935
+ /* @__PURE__ */ jsx6(SearchIcon2, { className: "pointer-events-none absolute top-1/2 left-3 -translate-y-1/2 text-muted-foreground" }),
2936
+ /* @__PURE__ */ jsx6(
2937
+ Input5,
2938
+ {
2939
+ className: "h-8 rounded-lg border-0 bg-muted/45 pr-3 pl-9 text-[14px] shadow-none placeholder:text-muted-foreground",
2940
+ placeholder: copy.t("labels.searchIssues"),
2941
+ value: controller.nodeState.issueSearchQuery,
2942
+ onChange: (event) => controller.setIssueSearchQuery(event.target.value)
2943
+ }
2944
+ )
2945
+ ] }),
2946
+ /* @__PURE__ */ jsxs6(
2947
+ Button6,
2948
+ {
2949
+ className: "h-8 rounded-lg border-0 bg-secondary px-3 text-[13px] font-semibold text-foreground shadow-none hover:bg-accent/35",
2950
+ size: "sm",
2951
+ type: "button",
2952
+ variant: "secondary",
2953
+ onClick: () => controller.setIssueEditorMode("create"),
2954
+ children: [
2955
+ /* @__PURE__ */ jsx6(FileCreateIcon3, { size: 16 }),
2956
+ copy.t("actions.createIssue")
2957
+ ]
2958
+ }
2959
+ )
2960
+ ] }) }),
2961
+ /* @__PURE__ */ jsxs6("div", { className: "relative border-b border-border/70 px-4 pt-3", children: [
2962
+ canScrollTabsLeft ? /* @__PURE__ */ jsx6(
2963
+ Button6,
2964
+ {
2965
+ "aria-label": copy.t("labels.scrollStatusTabsLeft"),
2966
+ className: "absolute top-1/2 left-4 z-10 h-6 w-6 -translate-y-1/2 rounded-full border-0 bg-background/96 p-0 shadow-sm",
2967
+ size: "icon-xs",
2968
+ type: "button",
2969
+ variant: "ghost",
2970
+ onClick: () => scrollIssueManagerStatusTabs(tabsViewportRef, -120),
2971
+ children: /* @__PURE__ */ jsx6(ArrowLeftIcon, { size: 14 })
2972
+ }
2973
+ ) : null,
2974
+ /* @__PURE__ */ jsx6(
2975
+ "div",
2976
+ {
2977
+ className: cn4(
2978
+ "flex h-8 items-center gap-[14px] overflow-x-auto pb-2 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
2979
+ canScrollTabsLeft ? "pl-8" : "",
2980
+ canScrollTabsRight ? "pr-8" : ""
2981
+ ),
2982
+ ref: tabsViewportRef,
2983
+ children: issueStatusFilters.map((status) => {
2984
+ const isActive = controller.nodeState.issueStatusFilter === status;
2985
+ return /* @__PURE__ */ jsxs6(
2986
+ "button",
2987
+ {
2988
+ className: cn4(
2989
+ "flex h-6 shrink-0 items-center gap-1.5 border-b-2 px-0 pb-2 text-[13px] font-semibold transition-colors",
2990
+ isActive ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"
2991
+ ),
2992
+ type: "button",
2993
+ onClick: () => controller.setIssueStatusFilter(status),
2994
+ children: [
2995
+ /* @__PURE__ */ jsx6("span", { children: status === "all" ? copy.t("labels.allStatus") : resolveIssueManagerStatusLabel(copy, status) }),
2996
+ /* @__PURE__ */ jsx6("span", { className: "text-[12px] text-muted-foreground/80", children: counts[status] ?? 0 })
2997
+ ]
2998
+ },
2999
+ status
3000
+ );
3001
+ })
3002
+ }
3003
+ ),
3004
+ canScrollTabsRight ? /* @__PURE__ */ jsx6(
3005
+ Button6,
3006
+ {
3007
+ "aria-label": copy.t("labels.scrollStatusTabsRight"),
3008
+ className: "absolute top-1/2 right-4 z-10 h-6 w-6 -translate-y-1/2 rounded-full border-0 bg-background/96 p-0 shadow-sm",
3009
+ size: "icon-xs",
3010
+ type: "button",
3011
+ variant: "ghost",
3012
+ onClick: () => scrollIssueManagerStatusTabs(tabsViewportRef, 120),
3013
+ children: /* @__PURE__ */ jsx6(ArrowRightIcon, { size: 14 })
3014
+ }
3015
+ ) : null
3016
+ ] }),
3017
+ /* @__PURE__ */ jsx6(ScrollArea4, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx6("div", { className: "flex min-h-full flex-col px-0 py-0", children: controller.issues.isLoading && controller.issues.value.length === 0 ? /* @__PURE__ */ jsx6(IssueManagerSidebarLoadingState, {}) : controller.issues.error ? /* @__PURE__ */ jsx6(
3018
+ IssueManagerSidebarEmptyState,
3019
+ {
3020
+ body: controller.issues.error,
3021
+ title: copy.t("messages.noIssues"),
3022
+ tone: "destructive"
3023
+ }
3024
+ ) : controller.issues.value.length === 0 ? /* @__PURE__ */ jsx6(
3025
+ IssueManagerSidebarEmptyState,
3026
+ {
3027
+ body: copy.t("messages.noIssuesForFilterBody"),
3028
+ title: copy.t("messages.noIssuesForFilterTitle")
3029
+ }
3030
+ ) : /* @__PURE__ */ jsx6("div", { className: "flex flex-col gap-2.5 px-4 pt-1.5 pb-4", children: controller.issues.value.map((issue) => /* @__PURE__ */ jsx6(
3031
+ IssueManagerSidebarItem,
3032
+ {
3033
+ copy,
3034
+ issue,
3035
+ selected: controller.nodeState.selectedIssueId === issue.issueId,
3036
+ onSelect: controller.selectIssue
3037
+ },
3038
+ issue.issueId
3039
+ )) }) }) }),
3040
+ showRefreshAction ? /* @__PURE__ */ jsx6("div", { className: "border-t border-border/70 px-6 py-4", children: /* @__PURE__ */ jsxs6(
3041
+ Button6,
3042
+ {
3043
+ className: "w-full justify-center",
3044
+ size: "sm",
3045
+ type: "button",
3046
+ variant: "ghost",
3047
+ onClick: controller.refreshAll,
3048
+ children: [
3049
+ /* @__PURE__ */ jsx6(RefreshIcon, { size: 14 }),
3050
+ copy.t("actions.refresh")
3051
+ ]
3052
+ }
3053
+ ) }) : null
3054
+ ] });
3055
+ }
3056
+ function IssueManagerBottomBar({
3057
+ controller,
3058
+ selectedIssue,
3059
+ selectedTask
3060
+ }) {
3061
+ const copy = controller.copy;
3062
+ if (!selectedIssue || controller.issueEditorMode !== "read" || controller.taskEditorMode !== "read") {
3063
+ return null;
3064
+ }
3065
+ return /* @__PURE__ */ jsx6("div", { className: "border-t border-border/70 bg-transparent px-6 py-4 backdrop-blur", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-end gap-3", children: [
3066
+ /* @__PURE__ */ jsx6(
3067
+ IssueManagerRunActionTrigger,
3068
+ {
3069
+ controller,
3070
+ disabled: !selectedTask,
3071
+ triggerClassName: "min-w-[14rem] rounded-xl border-border/70 bg-secondary/90 px-4 py-2"
3072
+ }
3073
+ ),
3074
+ /* @__PURE__ */ jsx6(
3075
+ Button6,
3076
+ {
3077
+ disabled: !selectedIssue,
3078
+ className: "rounded-xl bg-foreground px-4 text-background hover:bg-foreground/92",
3079
+ size: "sm",
3080
+ type: "button",
3081
+ onClick: () => {
3082
+ void controller.shareSelection();
3083
+ },
3084
+ children: copy.t("actions.inviteCollaborator")
3085
+ }
3086
+ )
3087
+ ] }) });
3088
+ }
3089
+ function IssueManagerSidebarItem({
3090
+ copy,
3091
+ issue,
3092
+ onSelect,
3093
+ selected
3094
+ }) {
3095
+ return /* @__PURE__ */ jsxs6(
3096
+ "button",
3097
+ {
3098
+ className: cn4(
3099
+ "w-full rounded-lg border px-3.5 py-3.5 text-left transition-colors",
3100
+ selected ? "border-border/90 bg-background-fronted" : "border-border/80 bg-transparent hover:bg-accent/18"
3101
+ ),
3102
+ type: "button",
3103
+ onClick: () => onSelect(issue.issueId),
3104
+ children: [
3105
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-start justify-between gap-3", children: [
3106
+ /* @__PURE__ */ jsxs6("div", { className: "min-w-0 flex-1 space-y-2", children: [
3107
+ /* @__PURE__ */ jsx6("p", { className: "text-[12px] leading-[1.55] text-muted-foreground", children: formatSidebarTimestamp(issue.updatedAtUnix ?? issue.createdAtUnix) }),
3108
+ /* @__PURE__ */ jsx6("p", { className: "line-clamp-4 text-[14px] font-semibold leading-[1.35rem] text-foreground", children: issue.title })
3109
+ ] }),
3110
+ /* @__PURE__ */ jsx6(Badge5, { className: "rounded-full border-transparent bg-muted px-2 py-1 text-[11px] text-muted-foreground", children: resolveIssueManagerStatusLabel(copy, issue.status) })
3111
+ ] }),
3112
+ /* @__PURE__ */ jsx6("div", { className: "mt-2 text-[12px] leading-[1.55] text-muted-foreground", children: copy.t("labels.taskCount", { count: issue.taskCount ?? 0 }) })
3113
+ ]
3114
+ }
3115
+ );
3116
+ }
3117
+ function IssueManagerSidebarLoadingState() {
3118
+ return /* @__PURE__ */ jsx6("div", { className: "grid gap-2.5 px-4 pt-1.5 pb-4", "aria-hidden": "true", children: Array.from({ length: 4 }, (_, index) => /* @__PURE__ */ jsxs6("div", { className: "rounded-lg bg-transparent px-3.5 py-3.5", children: [
3119
+ /* @__PURE__ */ jsx6("div", { className: "h-3.5 w-20 rounded-full bg-muted" }),
3120
+ /* @__PURE__ */ jsx6("div", { className: "mt-3 h-4 w-4/5 rounded-full bg-muted" }),
3121
+ /* @__PURE__ */ jsx6("div", { className: "mt-4 h-3.5 w-24 rounded-full bg-muted" })
3122
+ ] }, index)) });
3123
+ }
3124
+ function IssueManagerSidebarEmptyState({
3125
+ body,
3126
+ title,
3127
+ tone = "default"
3128
+ }) {
3129
+ return /* @__PURE__ */ jsxs6("div", { className: "relative flex min-h-[240px] flex-1 flex-col items-center justify-center gap-1.5 overflow-hidden px-6 py-8 text-center", children: [
3130
+ /* @__PURE__ */ jsx6(
3131
+ "div",
3132
+ {
3133
+ "aria-hidden": "true",
3134
+ className: "pointer-events-none absolute inset-0 flex flex-col gap-2.5 opacity-[0.72] [mask-image:linear-gradient(to_bottom,black_0%,black_30%,transparent_100%)]",
3135
+ children: Array.from({ length: 3 }, (_, index) => /* @__PURE__ */ jsx6("div", { className: "mx-4 h-24 rounded-lg bg-muted/45" }, index))
3136
+ }
3137
+ ),
3138
+ /* @__PURE__ */ jsx6(
3139
+ "p",
3140
+ {
3141
+ className: cn4(
3142
+ "relative z-[1] text-sm font-semibold leading-5 text-foreground",
3143
+ tone === "destructive" ? "text-destructive" : "text-foreground"
3144
+ ),
3145
+ children: title
3146
+ }
3147
+ ),
3148
+ /* @__PURE__ */ jsx6("p", { className: "relative z-[1] max-w-sm text-sm leading-5 text-muted-foreground", children: body })
3149
+ ] });
3150
+ }
3151
+ function buildIssueManagerStatusCounts(issues) {
3152
+ const counts = {
3153
+ all: issues.length,
3154
+ canceled: 0,
3155
+ completed: 0,
3156
+ failed: 0,
3157
+ not_started: 0,
3158
+ pending_acceptance: 0,
3159
+ running: 0
3160
+ };
3161
+ for (const issue of issues) {
3162
+ if (issue.status in counts) {
3163
+ counts[issue.status] += 1;
3164
+ }
3165
+ }
3166
+ return counts;
3167
+ }
3168
+ function formatSidebarTimestamp(value) {
3169
+ return formatIssueManagerDate(value);
3170
+ }
3171
+ function scrollIssueManagerStatusTabs(tabsViewportRef, delta) {
3172
+ tabsViewportRef.current?.scrollBy({
3173
+ behavior: "smooth",
3174
+ left: delta
3175
+ });
3176
+ }
3177
+ function clampSidebarWidth(width, layoutWidth) {
3178
+ const maxWidth = Math.max(
3179
+ sidebarMinWidth,
3180
+ Math.min(sidebarMaxWidth, layoutWidth - mainMinWidth - 12)
3181
+ );
3182
+ return Math.min(Math.max(width, sidebarMinWidth), maxWidth);
3183
+ }
3184
+ function handleSidebarResizePointerDown(event, layoutRef, resizeRef, sidebarWidth, setSidebarWidth) {
3185
+ if (event.button !== 0) {
3186
+ return;
3187
+ }
3188
+ const layoutWidth = layoutRef.current?.getBoundingClientRect().width ?? 0;
3189
+ if (!layoutWidth) {
3190
+ return;
3191
+ }
3192
+ const startWidth = clampSidebarWidth(sidebarWidth, layoutWidth);
3193
+ resizeRef.current = {
3194
+ maxWidth: clampSidebarWidth(sidebarMaxWidth, layoutWidth),
3195
+ pointerId: event.pointerId,
3196
+ startClientX: event.clientX,
3197
+ startWidth
3198
+ };
3199
+ setSidebarWidth(startWidth);
3200
+ event.currentTarget.setPointerCapture?.(event.pointerId);
3201
+ }
3202
+ function handleSidebarResizePointerMove(event, resizeRef, setSidebarWidth) {
3203
+ const state = resizeRef.current;
3204
+ if (!state || state.pointerId !== event.pointerId) {
3205
+ return;
3206
+ }
3207
+ setSidebarWidth(
3208
+ Math.min(
3209
+ Math.max(
3210
+ state.startWidth + event.clientX - state.startClientX,
3211
+ sidebarMinWidth
3212
+ ),
3213
+ state.maxWidth
3214
+ )
3215
+ );
3216
+ }
3217
+ function handleSidebarResizePointerEnd(event, resizeRef) {
3218
+ resizeRef.current = null;
3219
+ event.currentTarget.releasePointerCapture?.(event.pointerId);
3220
+ }
3221
+ function handleSidebarResizeKeyDown(event, layoutRef, setSidebarWidth) {
3222
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") {
3223
+ return;
3224
+ }
3225
+ const delta = event.key === "ArrowRight" ? 16 : -16;
3226
+ const layoutWidth = layoutRef.current?.getBoundingClientRect().width ?? 0;
3227
+ if (!layoutWidth) {
3228
+ return;
3229
+ }
3230
+ event.preventDefault();
3231
+ setSidebarWidth((current) => clampSidebarWidth(current + delta, layoutWidth));
3232
+ }
3233
+
3234
+ // src/react/IssueManagerNode.tsx
3235
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
3236
+ function IssueManagerNode({
3237
+ feature,
3238
+ nodeId,
3239
+ onStateChange,
3240
+ state,
3241
+ workspaceId
3242
+ }) {
3243
+ const controller = useIssueManagerController({
3244
+ feature,
3245
+ onStateChange,
3246
+ state,
3247
+ workspaceId
3248
+ });
3249
+ const selectedIssue = resolveSelectedIssue(controller);
3250
+ const selectedTask = resolveSelectedTask(controller);
3251
+ return /* @__PURE__ */ jsxs7(
3252
+ "section",
3253
+ {
3254
+ "aria-label": controller.copy.t("title"),
3255
+ className: "flex h-full min-h-0 w-full min-w-0 flex-col overflow-hidden text-foreground",
3256
+ "data-issue-manager-node-id": nodeId,
3257
+ "data-issue-manager-workspace-id": workspaceId,
3258
+ children: [
3259
+ /* @__PURE__ */ jsx7(
3260
+ IssueManagerShell,
3261
+ {
3262
+ controller,
3263
+ selectedIssue,
3264
+ selectedTask,
3265
+ onClearNotice: controller.clearNotice,
3266
+ onCloseTaskDrawer: () => {
3267
+ controller.setTaskEditorMode("read");
3268
+ controller.selectTask(null);
3269
+ },
3270
+ onDismissIssueCreate: () => {
3271
+ controller.setIssueEditorMode("read");
3272
+ }
3273
+ }
3274
+ ),
3275
+ /* @__PURE__ */ jsx7(
3276
+ IssueManagerReferencePicker,
3277
+ {
3278
+ copy: controller.copy,
3279
+ fileAdapter: feature.fileAdapter,
3280
+ open: controller.referenceTarget !== null,
3281
+ workspaceId,
3282
+ onClose: () => controller.setReferenceTarget(null),
3283
+ onConfirm: (refs) => {
3284
+ void controller.submitReferenceSelection(refs);
3285
+ }
3286
+ }
3287
+ )
3288
+ ]
3289
+ }
3290
+ );
3291
+ }
3292
+ function IssueManagerNodeHeader() {
3293
+ return null;
3294
+ }
3295
+ function resolveSelectedIssue(controller) {
3296
+ const issueId = controller.nodeState.selectedIssueId;
3297
+ if (!issueId) {
3298
+ return null;
3299
+ }
3300
+ return controller.issueDetail.value?.issue ?? controller.issues.value.find((issue) => issue.issueId === issueId) ?? null;
3301
+ }
3302
+ function resolveSelectedTask(controller) {
3303
+ const taskId = controller.nodeState.selectedTaskId;
3304
+ if (!taskId) {
3305
+ return null;
3306
+ }
3307
+ return controller.taskDetail.value?.task ?? controller.issueDetail.value?.tasks.find(
3308
+ (task) => task.taskId === taskId
3309
+ ) ?? null;
3310
+ }
3311
+
3312
+ export {
3313
+ IssueManagerNode,
3314
+ IssueManagerNodeHeader
3315
+ };
3316
+ //# sourceMappingURL=chunk-RX6P2DPR.js.map