@industry-theme/backlogmd-kanban-panel 1.0.12 → 1.0.15

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.
@@ -3740,89 +3740,89 @@ const createLucideIcon = (iconName, iconNode) => {
3740
3740
  * This source code is licensed under the ISC license.
3741
3741
  * See the LICENSE file in the root directory of this source tree.
3742
3742
  */
3743
- const __iconNode$m = [
3743
+ const __iconNode$o = [
3744
3744
  ["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
3745
3745
  ["path", { d: "M19 12H5", key: "x3x0zl" }]
3746
3746
  ];
3747
- const ArrowLeft = createLucideIcon("arrow-left", __iconNode$m);
3747
+ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$o);
3748
3748
  /**
3749
3749
  * @license lucide-react v0.552.0 - ISC
3750
3750
  *
3751
3751
  * This source code is licensed under the ISC license.
3752
3752
  * See the LICENSE file in the root directory of this source tree.
3753
3753
  */
3754
- const __iconNode$l = [
3754
+ const __iconNode$n = [
3755
3755
  ["path", { d: "M8 2v4", key: "1cmpym" }],
3756
3756
  ["path", { d: "M16 2v4", key: "4m81vk" }],
3757
3757
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
3758
3758
  ["path", { d: "M3 10h18", key: "8toen8" }]
3759
3759
  ];
3760
- const Calendar = createLucideIcon("calendar", __iconNode$l);
3760
+ const Calendar = createLucideIcon("calendar", __iconNode$n);
3761
3761
  /**
3762
3762
  * @license lucide-react v0.552.0 - ISC
3763
3763
  *
3764
3764
  * This source code is licensed under the ISC license.
3765
3765
  * See the LICENSE file in the root directory of this source tree.
3766
3766
  */
3767
- const __iconNode$k = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
3768
- const Check = createLucideIcon("check", __iconNode$k);
3767
+ const __iconNode$m = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
3768
+ const Check = createLucideIcon("check", __iconNode$m);
3769
3769
  /**
3770
3770
  * @license lucide-react v0.552.0 - ISC
3771
3771
  *
3772
3772
  * This source code is licensed under the ISC license.
3773
3773
  * See the LICENSE file in the root directory of this source tree.
3774
3774
  */
3775
- const __iconNode$j = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
3776
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$j);
3775
+ const __iconNode$l = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
3776
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$l);
3777
3777
  /**
3778
3778
  * @license lucide-react v0.552.0 - ISC
3779
3779
  *
3780
3780
  * This source code is licensed under the ISC license.
3781
3781
  * See the LICENSE file in the root directory of this source tree.
3782
3782
  */
3783
- const __iconNode$i = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
3784
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$i);
3783
+ const __iconNode$k = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
3784
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$k);
3785
3785
  /**
3786
3786
  * @license lucide-react v0.552.0 - ISC
3787
3787
  *
3788
3788
  * This source code is licensed under the ISC license.
3789
3789
  * See the LICENSE file in the root directory of this source tree.
3790
3790
  */
3791
- const __iconNode$h = [
3791
+ const __iconNode$j = [
3792
3792
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3793
3793
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
3794
3794
  ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
3795
3795
  ];
3796
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$h);
3796
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$j);
3797
3797
  /**
3798
3798
  * @license lucide-react v0.552.0 - ISC
3799
3799
  *
3800
3800
  * This source code is licensed under the ISC license.
3801
3801
  * See the LICENSE file in the root directory of this source tree.
3802
3802
  */
3803
- const __iconNode$g = [
3803
+ const __iconNode$i = [
3804
3804
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3805
3805
  ["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
3806
3806
  ];
3807
- const CircleCheck = createLucideIcon("circle-check", __iconNode$g);
3807
+ const CircleCheck = createLucideIcon("circle-check", __iconNode$i);
3808
3808
  /**
3809
3809
  * @license lucide-react v0.552.0 - ISC
3810
3810
  *
3811
3811
  * This source code is licensed under the ISC license.
3812
3812
  * See the LICENSE file in the root directory of this source tree.
3813
3813
  */
3814
- const __iconNode$f = [
3814
+ const __iconNode$h = [
3815
3815
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
3816
3816
  ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
3817
3817
  ];
3818
- const Copy = createLucideIcon("copy", __iconNode$f);
3818
+ const Copy = createLucideIcon("copy", __iconNode$h);
3819
3819
  /**
3820
3820
  * @license lucide-react v0.552.0 - ISC
3821
3821
  *
3822
3822
  * This source code is licensed under the ISC license.
3823
3823
  * See the LICENSE file in the root directory of this source tree.
3824
3824
  */
3825
- const __iconNode$e = [
3825
+ const __iconNode$g = [
3826
3826
  ["path", { d: "m15 15 6 6", key: "1s409w" }],
3827
3827
  ["path", { d: "m15 9 6-6", key: "ko1vev" }],
3828
3828
  ["path", { d: "M21 16v5h-5", key: "1ck2sf" }],
@@ -3832,26 +3832,26 @@ const __iconNode$e = [
3832
3832
  ["path", { d: "M3 8V3h5", key: "1ln10m" }],
3833
3833
  ["path", { d: "M9 9 3 3", key: "v551iv" }]
3834
3834
  ];
3835
- const Expand = createLucideIcon("expand", __iconNode$e);
3835
+ const Expand = createLucideIcon("expand", __iconNode$g);
3836
3836
  /**
3837
3837
  * @license lucide-react v0.552.0 - ISC
3838
3838
  *
3839
3839
  * This source code is licensed under the ISC license.
3840
3840
  * See the LICENSE file in the root directory of this source tree.
3841
3841
  */
3842
- const __iconNode$d = [
3842
+ const __iconNode$f = [
3843
3843
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
3844
3844
  ["path", { d: "M10 14 21 3", key: "gplh6r" }],
3845
3845
  ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
3846
3846
  ];
3847
- const ExternalLink = createLucideIcon("external-link", __iconNode$d);
3847
+ const ExternalLink = createLucideIcon("external-link", __iconNode$f);
3848
3848
  /**
3849
3849
  * @license lucide-react v0.552.0 - ISC
3850
3850
  *
3851
3851
  * This source code is licensed under the ISC license.
3852
3852
  * See the LICENSE file in the root directory of this source tree.
3853
3853
  */
3854
- const __iconNode$c = [
3854
+ const __iconNode$e = [
3855
3855
  [
3856
3856
  "path",
3857
3857
  {
@@ -3864,14 +3864,14 @@ const __iconNode$c = [
3864
3864
  ["path", { d: "M16 13H8", key: "t4e002" }],
3865
3865
  ["path", { d: "M16 17H8", key: "z1uh3a" }]
3866
3866
  ];
3867
- const FileText = createLucideIcon("file-text", __iconNode$c);
3867
+ const FileText = createLucideIcon("file-text", __iconNode$e);
3868
3868
  /**
3869
3869
  * @license lucide-react v0.552.0 - ISC
3870
3870
  *
3871
3871
  * This source code is licensed under the ISC license.
3872
3872
  * See the LICENSE file in the root directory of this source tree.
3873
3873
  */
3874
- const __iconNode$b = [
3874
+ const __iconNode$d = [
3875
3875
  [
3876
3876
  "path",
3877
3877
  {
@@ -3880,14 +3880,14 @@ const __iconNode$b = [
3880
3880
  }
3881
3881
  ]
3882
3882
  ];
3883
- const Flag = createLucideIcon("flag", __iconNode$b);
3883
+ const Flag = createLucideIcon("flag", __iconNode$d);
3884
3884
  /**
3885
3885
  * @license lucide-react v0.552.0 - ISC
3886
3886
  *
3887
3887
  * This source code is licensed under the ISC license.
3888
3888
  * See the LICENSE file in the root directory of this source tree.
3889
3889
  */
3890
- const __iconNode$a = [
3890
+ const __iconNode$c = [
3891
3891
  ["path", { d: "M12 10v6", key: "1bos4e" }],
3892
3892
  ["path", { d: "M9 13h6", key: "1uhe8q" }],
3893
3893
  [
@@ -3898,70 +3898,70 @@ const __iconNode$a = [
3898
3898
  }
3899
3899
  ]
3900
3900
  ];
3901
- const FolderPlus = createLucideIcon("folder-plus", __iconNode$a);
3901
+ const FolderPlus = createLucideIcon("folder-plus", __iconNode$c);
3902
3902
  /**
3903
3903
  * @license lucide-react v0.552.0 - ISC
3904
3904
  *
3905
3905
  * This source code is licensed under the ISC license.
3906
3906
  * See the LICENSE file in the root directory of this source tree.
3907
3907
  */
3908
- const __iconNode$9 = [
3908
+ const __iconNode$b = [
3909
3909
  ["line", { x1: "6", x2: "6", y1: "3", y2: "15", key: "17qcm7" }],
3910
3910
  ["circle", { cx: "18", cy: "6", r: "3", key: "1h7g24" }],
3911
3911
  ["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
3912
3912
  ["path", { d: "M18 9a9 9 0 0 1-9 9", key: "n2h4wq" }]
3913
3913
  ];
3914
- const GitBranch = createLucideIcon("git-branch", __iconNode$9);
3914
+ const GitBranch = createLucideIcon("git-branch", __iconNode$b);
3915
3915
  /**
3916
3916
  * @license lucide-react v0.552.0 - ISC
3917
3917
  *
3918
3918
  * This source code is licensed under the ISC license.
3919
3919
  * See the LICENSE file in the root directory of this source tree.
3920
3920
  */
3921
- const __iconNode$8 = [
3921
+ const __iconNode$a = [
3922
3922
  ["path", { d: "M5 3v14", key: "9nsxs2" }],
3923
3923
  ["path", { d: "M12 3v8", key: "1h2ygw" }],
3924
3924
  ["path", { d: "M19 3v18", key: "1sk56x" }]
3925
3925
  ];
3926
- const Kanban = createLucideIcon("kanban", __iconNode$8);
3926
+ const Kanban = createLucideIcon("kanban", __iconNode$a);
3927
3927
  /**
3928
3928
  * @license lucide-react v0.552.0 - ISC
3929
3929
  *
3930
3930
  * This source code is licensed under the ISC license.
3931
3931
  * See the LICENSE file in the root directory of this source tree.
3932
3932
  */
3933
- const __iconNode$7 = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
3934
- const LoaderCircle = createLucideIcon("loader-circle", __iconNode$7);
3933
+ const __iconNode$9 = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
3934
+ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$9);
3935
3935
  /**
3936
3936
  * @license lucide-react v0.552.0 - ISC
3937
3937
  *
3938
3938
  * This source code is licensed under the ISC license.
3939
3939
  * See the LICENSE file in the root directory of this source tree.
3940
3940
  */
3941
- const __iconNode$6 = [
3941
+ const __iconNode$8 = [
3942
3942
  ["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
3943
3943
  ["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
3944
3944
  ["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
3945
3945
  ];
3946
- const Monitor = createLucideIcon("monitor", __iconNode$6);
3946
+ const Monitor = createLucideIcon("monitor", __iconNode$8);
3947
3947
  /**
3948
3948
  * @license lucide-react v0.552.0 - ISC
3949
3949
  *
3950
3950
  * This source code is licensed under the ISC license.
3951
3951
  * See the LICENSE file in the root directory of this source tree.
3952
3952
  */
3953
- const __iconNode$5 = [
3953
+ const __iconNode$7 = [
3954
3954
  ["path", { d: "M18 8L22 12L18 16", key: "1r0oui" }],
3955
3955
  ["path", { d: "M2 12H22", key: "1m8cig" }]
3956
3956
  ];
3957
- const MoveRight = createLucideIcon("move-right", __iconNode$5);
3957
+ const MoveRight = createLucideIcon("move-right", __iconNode$7);
3958
3958
  /**
3959
3959
  * @license lucide-react v0.552.0 - ISC
3960
3960
  *
3961
3961
  * This source code is licensed under the ISC license.
3962
3962
  * See the LICENSE file in the root directory of this source tree.
3963
3963
  */
3964
- const __iconNode$4 = [
3964
+ const __iconNode$6 = [
3965
3965
  [
3966
3966
  "path",
3967
3967
  {
@@ -3970,27 +3970,38 @@ const __iconNode$4 = [
3970
3970
  }
3971
3971
  ]
3972
3972
  ];
3973
- const Play = createLucideIcon("play", __iconNode$4);
3973
+ const Play = createLucideIcon("play", __iconNode$6);
3974
3974
  /**
3975
3975
  * @license lucide-react v0.552.0 - ISC
3976
3976
  *
3977
3977
  * This source code is licensed under the ISC license.
3978
3978
  * See the LICENSE file in the root directory of this source tree.
3979
3979
  */
3980
- const __iconNode$3 = [
3980
+ const __iconNode$5 = [
3981
+ ["path", { d: "M5 12h14", key: "1ays0h" }],
3982
+ ["path", { d: "M12 5v14", key: "s699le" }]
3983
+ ];
3984
+ const Plus = createLucideIcon("plus", __iconNode$5);
3985
+ /**
3986
+ * @license lucide-react v0.552.0 - ISC
3987
+ *
3988
+ * This source code is licensed under the ISC license.
3989
+ * See the LICENSE file in the root directory of this source tree.
3990
+ */
3991
+ const __iconNode$4 = [
3981
3992
  ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
3982
3993
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
3983
3994
  ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
3984
3995
  ["path", { d: "M8 16H3v5", key: "1cv678" }]
3985
3996
  ];
3986
- const RefreshCw = createLucideIcon("refresh-cw", __iconNode$3);
3997
+ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$4);
3987
3998
  /**
3988
3999
  * @license lucide-react v0.552.0 - ISC
3989
4000
  *
3990
4001
  * This source code is licensed under the ISC license.
3991
4002
  * See the LICENSE file in the root directory of this source tree.
3992
4003
  */
3993
- const __iconNode$2 = [
4004
+ const __iconNode$3 = [
3994
4005
  [
3995
4006
  "path",
3996
4007
  {
@@ -4000,30 +4011,41 @@ const __iconNode$2 = [
4000
4011
  ],
4001
4012
  ["circle", { cx: "7.5", cy: "7.5", r: ".5", fill: "currentColor", key: "kqv944" }]
4002
4013
  ];
4003
- const Tag = createLucideIcon("tag", __iconNode$2);
4014
+ const Tag = createLucideIcon("tag", __iconNode$3);
4004
4015
  /**
4005
4016
  * @license lucide-react v0.552.0 - ISC
4006
4017
  *
4007
4018
  * This source code is licensed under the ISC license.
4008
4019
  * See the LICENSE file in the root directory of this source tree.
4009
4020
  */
4010
- const __iconNode$1 = [
4021
+ const __iconNode$2 = [
4011
4022
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
4012
4023
  ["circle", { cx: "12", cy: "12", r: "6", key: "1vlfrh" }],
4013
4024
  ["circle", { cx: "12", cy: "12", r: "2", key: "1c9p78" }]
4014
4025
  ];
4015
- const Target = createLucideIcon("target", __iconNode$1);
4026
+ const Target = createLucideIcon("target", __iconNode$2);
4016
4027
  /**
4017
4028
  * @license lucide-react v0.552.0 - ISC
4018
4029
  *
4019
4030
  * This source code is licensed under the ISC license.
4020
4031
  * See the LICENSE file in the root directory of this source tree.
4021
4032
  */
4022
- const __iconNode = [
4033
+ const __iconNode$1 = [
4023
4034
  ["path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2", key: "975kel" }],
4024
4035
  ["circle", { cx: "12", cy: "7", r: "4", key: "17ys0d" }]
4025
4036
  ];
4026
- const User = createLucideIcon("user", __iconNode);
4037
+ const User = createLucideIcon("user", __iconNode$1);
4038
+ /**
4039
+ * @license lucide-react v0.552.0 - ISC
4040
+ *
4041
+ * This source code is licensed under the ISC license.
4042
+ * See the LICENSE file in the root directory of this source tree.
4043
+ */
4044
+ const __iconNode = [
4045
+ ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
4046
+ ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
4047
+ ];
4048
+ const X = createLucideIcon("x", __iconNode);
4027
4049
  var terminalTheme$1 = {
4028
4050
  space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
4029
4051
  fonts: {
@@ -4397,9 +4419,9 @@ function parseArrayValue(value) {
4397
4419
  function parseAcceptanceCriteria(content2) {
4398
4420
  const criteria = [];
4399
4421
  const checkboxPattern = /^-\s*\[([ xX])\]\s*(.+)$/gm;
4400
- let match;
4422
+ const matches = content2.matchAll(checkboxPattern);
4401
4423
  let index2 = 1;
4402
- while ((match = checkboxPattern.exec(content2)) !== null) {
4424
+ for (const match of matches) {
4403
4425
  criteria.push({
4404
4426
  index: index2++,
4405
4427
  checked: match[1].toLowerCase() === "x",
@@ -4413,9 +4435,9 @@ function extractDescription(content2, title) {
4413
4435
  if (title) {
4414
4436
  body = body.replace(new RegExp(`^#\\s+${escapeRegex(title)}\\s*$`, "m"), "");
4415
4437
  }
4416
- body = body.replace(/^##\s+Acceptance Criteria[\s\S]*?(?=^##|\z)/m, "");
4417
- body = body.replace(/^##\s+Implementation Plan[\s\S]*?(?=^##|\z)/m, "");
4418
- body = body.replace(/^##\s+Implementation Notes[\s\S]*?(?=^##|\z)/m, "");
4438
+ body = body.replace(/^##\s+Acceptance Criteria[\s\S]*?(?=^##|$)/m, "");
4439
+ body = body.replace(/^##\s+Implementation Plan[\s\S]*?(?=^##|$)/m, "");
4440
+ body = body.replace(/^##\s+Implementation Notes[\s\S]*?(?=^##|$)/m, "");
4419
4441
  return body.trim();
4420
4442
  }
4421
4443
  function extractIdFromPath(filePath) {
@@ -4524,155 +4546,123 @@ function extractMilestoneIdFromFilename(filename) {
4524
4546
  const match = filename.match(/^(m-\d+)/);
4525
4547
  return match ? match[1] : null;
4526
4548
  }
4527
- const DEFAULT_STATUSES = ["To Do", "In Progress", "Done"];
4528
- function parseBacklogConfig(content2) {
4529
- const config = {};
4530
- const lines = content2.split("\n");
4531
- for (const line of lines) {
4532
- const trimmed = line.trim();
4533
- if (!trimmed || trimmed.startsWith("#"))
4534
- continue;
4535
- const colonIndex = trimmed.indexOf(":");
4536
- if (colonIndex === -1)
4537
- continue;
4538
- const key2 = trimmed.substring(0, colonIndex).trim();
4539
- const value = trimmed.substring(colonIndex + 1).trim();
4540
- switch (key2) {
4541
- case "project_name":
4542
- config.projectName = value.replace(/['"]/g, "");
4543
- break;
4544
- case "default_assignee":
4545
- config.defaultAssignee = value.replace(/['"]/g, "");
4546
- break;
4547
- case "default_reporter":
4548
- config.defaultReporter = value.replace(/['"]/g, "");
4549
- break;
4550
- case "default_status":
4551
- config.defaultStatus = value.replace(/['"]/g, "");
4552
- break;
4553
- case "statuses":
4554
- case "labels":
4555
- case "milestones":
4556
- if (value.startsWith("[") && value.endsWith("]")) {
4557
- const arrayContent = value.slice(1, -1);
4558
- config[key2] = arrayContent.split(",").map((item) => item.trim().replace(/['"]/g, "")).filter(Boolean);
4559
- }
4560
- break;
4561
- case "date_format":
4562
- config.dateFormat = value.replace(/['"]/g, "");
4563
- break;
4564
- case "max_column_width":
4565
- config.maxColumnWidth = parseInt(value, 10);
4566
- break;
4567
- case "task_resolution_strategy":
4568
- config.taskResolutionStrategy = value.replace(/['"]/g, "");
4569
- break;
4570
- case "default_editor":
4571
- config.defaultEditor = value.replace(/["']/g, "");
4572
- break;
4573
- case "auto_open_browser":
4574
- config.autoOpenBrowser = value.toLowerCase() === "true";
4575
- break;
4576
- case "default_port":
4577
- config.defaultPort = parseInt(value, 10);
4578
- break;
4579
- case "remote_operations":
4580
- config.remoteOperations = value.toLowerCase() === "true";
4581
- break;
4582
- case "auto_commit":
4583
- config.autoCommit = value.toLowerCase() === "true";
4584
- break;
4585
- case "zero_padded_ids":
4586
- config.zeroPaddedIds = parseInt(value, 10);
4587
- break;
4588
- case "timezone_preference":
4589
- config.timezonePreference = value.replace(/['"]/g, "");
4590
- break;
4591
- case "include_date_time_in_dates":
4592
- config.includeDateTimeInDates = value.toLowerCase() === "true";
4593
- break;
4594
- case "bypass_git_hooks":
4595
- config.bypassGitHooks = value.toLowerCase() === "true";
4596
- break;
4597
- case "check_active_branches":
4598
- config.checkActiveBranches = value.toLowerCase() === "true";
4599
- break;
4600
- case "active_branch_days":
4601
- config.activeBranchDays = parseInt(value, 10);
4602
- break;
4603
- }
4604
- }
4605
- return {
4606
- projectName: config.projectName || "Backlog",
4607
- statuses: config.statuses || [...DEFAULT_STATUSES],
4608
- labels: config.labels || [],
4609
- milestones: config.milestones || [],
4610
- defaultStatus: config.defaultStatus || DEFAULT_STATUSES[0],
4611
- dateFormat: config.dateFormat || "YYYY-MM-DD",
4612
- defaultAssignee: config.defaultAssignee,
4613
- defaultReporter: config.defaultReporter,
4614
- maxColumnWidth: config.maxColumnWidth,
4615
- taskResolutionStrategy: config.taskResolutionStrategy,
4616
- defaultEditor: config.defaultEditor,
4617
- autoOpenBrowser: config.autoOpenBrowser,
4618
- defaultPort: config.defaultPort,
4619
- remoteOperations: config.remoteOperations,
4620
- autoCommit: config.autoCommit,
4621
- zeroPaddedIds: config.zeroPaddedIds,
4622
- timezonePreference: config.timezonePreference,
4623
- includeDateTimeInDates: config.includeDateTimeInDates,
4624
- bypassGitHooks: config.bypassGitHooks,
4625
- checkActiveBranches: config.checkActiveBranches,
4626
- activeBranchDays: config.activeBranchDays
4627
- };
4549
+ const NO_MILESTONE_KEY = "__none";
4550
+ function normalizeMilestoneName(name2) {
4551
+ return name2.trim();
4628
4552
  }
4629
- function serializeBacklogConfig(config) {
4630
- const lines = [];
4631
- lines.push(`project_name: "${config.projectName}"`);
4632
- if (config.defaultStatus) {
4633
- lines.push(`default_status: "${config.defaultStatus}"`);
4634
- }
4635
- lines.push(`statuses: [${config.statuses.map((s2) => `"${s2}"`).join(", ")}]`);
4636
- lines.push(`labels: [${(config.labels || []).map((l) => `"${l}"`).join(", ")}]`);
4637
- lines.push(`milestones: [${(config.milestones || []).map((m) => `"${m}"`).join(", ")}]`);
4638
- if (config.dateFormat) {
4639
- lines.push(`date_format: "${config.dateFormat}"`);
4640
- }
4641
- if (config.defaultAssignee) {
4642
- lines.push(`default_assignee: "${config.defaultAssignee}"`);
4643
- }
4644
- if (config.defaultReporter) {
4645
- lines.push(`default_reporter: "${config.defaultReporter}"`);
4646
- }
4647
- if (config.defaultEditor) {
4648
- lines.push(`default_editor: "${config.defaultEditor}"`);
4649
- }
4650
- if (typeof config.autoCommit === "boolean") {
4651
- lines.push(`auto_commit: ${config.autoCommit}`);
4652
- }
4653
- if (typeof config.zeroPaddedIds === "number") {
4654
- lines.push(`zero_padded_ids: ${config.zeroPaddedIds}`);
4553
+ function milestoneKey(name2) {
4554
+ return normalizeMilestoneName(name2 ?? "").toLowerCase();
4555
+ }
4556
+ function isDoneStatus(status) {
4557
+ const normalized = (status ?? "").toLowerCase();
4558
+ return normalized.includes("done") || normalized.includes("complete");
4559
+ }
4560
+ function getMilestoneLabel(milestoneId, milestoneEntities) {
4561
+ if (!milestoneId) {
4562
+ return "Tasks without milestone";
4655
4563
  }
4656
- if (typeof config.autoOpenBrowser === "boolean") {
4657
- lines.push(`auto_open_browser: ${config.autoOpenBrowser}`);
4564
+ const entity = milestoneEntities.find((m) => milestoneKey(m.id) === milestoneKey(milestoneId));
4565
+ return (entity == null ? void 0 : entity.title) || milestoneId;
4566
+ }
4567
+ function collectMilestoneIds(tasks, milestoneEntities) {
4568
+ const merged = [];
4569
+ const seen = /* @__PURE__ */ new Set();
4570
+ const addMilestone = (value) => {
4571
+ const normalized = normalizeMilestoneName(value);
4572
+ if (!normalized)
4573
+ return;
4574
+ const key2 = milestoneKey(normalized);
4575
+ if (seen.has(key2))
4576
+ return;
4577
+ seen.add(key2);
4578
+ merged.push(normalized);
4579
+ };
4580
+ for (const entity of milestoneEntities) {
4581
+ addMilestone(entity.id);
4658
4582
  }
4659
- if (typeof config.defaultPort === "number") {
4660
- lines.push(`default_port: ${config.defaultPort}`);
4583
+ for (const task of tasks) {
4584
+ addMilestone(task.milestone ?? "");
4661
4585
  }
4662
- if (typeof config.remoteOperations === "boolean") {
4663
- lines.push(`remote_operations: ${config.remoteOperations}`);
4586
+ return merged;
4587
+ }
4588
+ function collectMilestones(tasks, configMilestones) {
4589
+ const merged = [];
4590
+ const seen = /* @__PURE__ */ new Set();
4591
+ const addMilestone = (value) => {
4592
+ const normalized = normalizeMilestoneName(value);
4593
+ if (!normalized)
4594
+ return;
4595
+ const key2 = milestoneKey(normalized);
4596
+ if (seen.has(key2))
4597
+ return;
4598
+ seen.add(key2);
4599
+ merged.push(normalized);
4600
+ };
4601
+ for (const m of configMilestones) {
4602
+ addMilestone(m);
4664
4603
  }
4665
- if (typeof config.bypassGitHooks === "boolean") {
4666
- lines.push(`bypass_git_hooks: ${config.bypassGitHooks}`);
4604
+ for (const task of tasks) {
4605
+ addMilestone(task.milestone ?? "");
4667
4606
  }
4668
- if (typeof config.checkActiveBranches === "boolean") {
4669
- lines.push(`check_active_branches: ${config.checkActiveBranches}`);
4607
+ return merged;
4608
+ }
4609
+ function createBucket(milestoneId, tasks, statuses, milestoneEntities, isNoMilestone) {
4610
+ const bucketMilestoneKey = milestoneKey(milestoneId);
4611
+ const bucketTasks = tasks.filter((task) => {
4612
+ const taskMilestoneKey = milestoneKey(task.milestone);
4613
+ return bucketMilestoneKey ? taskMilestoneKey === bucketMilestoneKey : !taskMilestoneKey;
4614
+ });
4615
+ const counts = {};
4616
+ for (const status of statuses) {
4617
+ counts[status] = 0;
4670
4618
  }
4671
- if (typeof config.activeBranchDays === "number") {
4672
- lines.push(`active_branch_days: ${config.activeBranchDays}`);
4619
+ for (const task of bucketTasks) {
4620
+ const status = task.status ?? "";
4621
+ counts[status] = (counts[status] ?? 0) + 1;
4673
4622
  }
4674
- return `${lines.join("\n")}
4675
- `;
4623
+ const doneCount = bucketTasks.filter((t) => isDoneStatus(t.status)).length;
4624
+ const progress = bucketTasks.length > 0 ? Math.round(doneCount / bucketTasks.length * 100) : 0;
4625
+ const key2 = bucketMilestoneKey ? bucketMilestoneKey : NO_MILESTONE_KEY;
4626
+ const label = getMilestoneLabel(milestoneId, milestoneEntities);
4627
+ return {
4628
+ key: key2,
4629
+ label,
4630
+ milestone: milestoneId,
4631
+ isNoMilestone,
4632
+ tasks: bucketTasks,
4633
+ statusCounts: counts,
4634
+ total: bucketTasks.length,
4635
+ doneCount,
4636
+ progress
4637
+ };
4638
+ }
4639
+ function buildMilestoneBuckets(tasks, milestoneEntities, statuses) {
4640
+ const allMilestoneIds = collectMilestoneIds(tasks, milestoneEntities);
4641
+ const buckets = [
4642
+ // "No milestone" bucket first
4643
+ createBucket(void 0, tasks, statuses, milestoneEntities, true),
4644
+ // Then each milestone bucket
4645
+ ...allMilestoneIds.map((m) => createBucket(m, tasks, statuses, milestoneEntities, false))
4646
+ ];
4647
+ return buckets;
4648
+ }
4649
+ function buildMilestoneBucketsFromConfig(tasks, configMilestones, statuses) {
4650
+ const milestoneEntities = configMilestones.map((id) => ({
4651
+ id,
4652
+ title: id,
4653
+ description: "",
4654
+ rawContent: "",
4655
+ tasks: []
4656
+ }));
4657
+ return buildMilestoneBuckets(tasks, milestoneEntities, statuses);
4658
+ }
4659
+ function groupTasksByMilestone(tasks, configMilestones, statuses) {
4660
+ const milestones = collectMilestones(tasks, configMilestones);
4661
+ const buckets = buildMilestoneBucketsFromConfig(tasks, configMilestones, statuses);
4662
+ return {
4663
+ milestones,
4664
+ buckets
4665
+ };
4676
4666
  }
4677
4667
  const PRIORITY_ORDER = {
4678
4668
  high: 0,
@@ -4694,11 +4684,10 @@ function sortTasksBy(tasks, sortBy = "title", direction = "asc") {
4694
4684
  const cmp = a.createdDate.localeCompare(b.createdDate);
4695
4685
  return direction === "asc" ? cmp : -cmp;
4696
4686
  });
4697
- case "priority":
4698
- case "ordinal":
4699
- default:
4687
+ default: {
4700
4688
  const sorted = sortTasks(tasks);
4701
4689
  return direction === "desc" ? sorted.reverse() : sorted;
4690
+ }
4702
4691
  }
4703
4692
  }
4704
4693
  function sortTasks(tasks) {
@@ -4735,123 +4724,155 @@ function groupTasksByStatus(tasks, statuses) {
4735
4724
  }
4736
4725
  return grouped;
4737
4726
  }
4738
- const NO_MILESTONE_KEY = "__none";
4739
- function normalizeMilestoneName(name2) {
4740
- return name2.trim();
4741
- }
4742
- function milestoneKey(name2) {
4743
- return normalizeMilestoneName(name2 ?? "").toLowerCase();
4744
- }
4745
- function isDoneStatus(status) {
4746
- const normalized = (status ?? "").toLowerCase();
4747
- return normalized.includes("done") || normalized.includes("complete");
4748
- }
4749
- function getMilestoneLabel(milestoneId, milestoneEntities) {
4750
- if (!milestoneId) {
4751
- return "Tasks without milestone";
4727
+ const DEFAULT_STATUSES = ["To Do", "In Progress", "Done"];
4728
+ function parseBacklogConfig(content2) {
4729
+ const config = {};
4730
+ const lines = content2.split("\n");
4731
+ for (const line of lines) {
4732
+ const trimmed = line.trim();
4733
+ if (!trimmed || trimmed.startsWith("#"))
4734
+ continue;
4735
+ const colonIndex = trimmed.indexOf(":");
4736
+ if (colonIndex === -1)
4737
+ continue;
4738
+ const key2 = trimmed.substring(0, colonIndex).trim();
4739
+ const value = trimmed.substring(colonIndex + 1).trim();
4740
+ switch (key2) {
4741
+ case "project_name":
4742
+ config.projectName = value.replace(/['"]/g, "");
4743
+ break;
4744
+ case "default_assignee":
4745
+ config.defaultAssignee = value.replace(/['"]/g, "");
4746
+ break;
4747
+ case "default_reporter":
4748
+ config.defaultReporter = value.replace(/['"]/g, "");
4749
+ break;
4750
+ case "default_status":
4751
+ config.defaultStatus = value.replace(/['"]/g, "");
4752
+ break;
4753
+ case "statuses":
4754
+ case "labels":
4755
+ case "milestones":
4756
+ if (value.startsWith("[") && value.endsWith("]")) {
4757
+ const arrayContent = value.slice(1, -1);
4758
+ config[key2] = arrayContent.split(",").map((item) => item.trim().replace(/['"]/g, "")).filter(Boolean);
4759
+ }
4760
+ break;
4761
+ case "date_format":
4762
+ config.dateFormat = value.replace(/['"]/g, "");
4763
+ break;
4764
+ case "max_column_width":
4765
+ config.maxColumnWidth = parseInt(value, 10);
4766
+ break;
4767
+ case "task_resolution_strategy":
4768
+ config.taskResolutionStrategy = value.replace(/['"]/g, "");
4769
+ break;
4770
+ case "default_editor":
4771
+ config.defaultEditor = value.replace(/["']/g, "");
4772
+ break;
4773
+ case "auto_open_browser":
4774
+ config.autoOpenBrowser = value.toLowerCase() === "true";
4775
+ break;
4776
+ case "default_port":
4777
+ config.defaultPort = parseInt(value, 10);
4778
+ break;
4779
+ case "remote_operations":
4780
+ config.remoteOperations = value.toLowerCase() === "true";
4781
+ break;
4782
+ case "auto_commit":
4783
+ config.autoCommit = value.toLowerCase() === "true";
4784
+ break;
4785
+ case "zero_padded_ids":
4786
+ config.zeroPaddedIds = parseInt(value, 10);
4787
+ break;
4788
+ case "timezone_preference":
4789
+ config.timezonePreference = value.replace(/['"]/g, "");
4790
+ break;
4791
+ case "include_date_time_in_dates":
4792
+ config.includeDateTimeInDates = value.toLowerCase() === "true";
4793
+ break;
4794
+ case "bypass_git_hooks":
4795
+ config.bypassGitHooks = value.toLowerCase() === "true";
4796
+ break;
4797
+ case "check_active_branches":
4798
+ config.checkActiveBranches = value.toLowerCase() === "true";
4799
+ break;
4800
+ case "active_branch_days":
4801
+ config.activeBranchDays = parseInt(value, 10);
4802
+ break;
4803
+ }
4752
4804
  }
4753
- const entity = milestoneEntities.find((m) => milestoneKey(m.id) === milestoneKey(milestoneId));
4754
- return (entity == null ? void 0 : entity.title) || milestoneId;
4755
- }
4756
- function collectMilestoneIds(tasks, milestoneEntities) {
4757
- const merged = [];
4758
- const seen = /* @__PURE__ */ new Set();
4759
- const addMilestone = (value) => {
4760
- const normalized = normalizeMilestoneName(value);
4761
- if (!normalized)
4762
- return;
4763
- const key2 = milestoneKey(normalized);
4764
- if (seen.has(key2))
4765
- return;
4766
- seen.add(key2);
4767
- merged.push(normalized);
4805
+ return {
4806
+ projectName: config.projectName || "Backlog",
4807
+ statuses: config.statuses || [...DEFAULT_STATUSES],
4808
+ labels: config.labels || [],
4809
+ milestones: config.milestones || [],
4810
+ defaultStatus: config.defaultStatus || DEFAULT_STATUSES[0],
4811
+ dateFormat: config.dateFormat || "YYYY-MM-DD",
4812
+ defaultAssignee: config.defaultAssignee,
4813
+ defaultReporter: config.defaultReporter,
4814
+ maxColumnWidth: config.maxColumnWidth,
4815
+ taskResolutionStrategy: config.taskResolutionStrategy,
4816
+ defaultEditor: config.defaultEditor,
4817
+ autoOpenBrowser: config.autoOpenBrowser,
4818
+ defaultPort: config.defaultPort,
4819
+ remoteOperations: config.remoteOperations,
4820
+ autoCommit: config.autoCommit,
4821
+ zeroPaddedIds: config.zeroPaddedIds,
4822
+ timezonePreference: config.timezonePreference,
4823
+ includeDateTimeInDates: config.includeDateTimeInDates,
4824
+ bypassGitHooks: config.bypassGitHooks,
4825
+ checkActiveBranches: config.checkActiveBranches,
4826
+ activeBranchDays: config.activeBranchDays
4768
4827
  };
4769
- for (const entity of milestoneEntities) {
4770
- addMilestone(entity.id);
4828
+ }
4829
+ function serializeBacklogConfig(config) {
4830
+ const lines = [];
4831
+ lines.push(`project_name: "${config.projectName}"`);
4832
+ if (config.defaultStatus) {
4833
+ lines.push(`default_status: "${config.defaultStatus}"`);
4771
4834
  }
4772
- for (const task of tasks) {
4773
- addMilestone(task.milestone ?? "");
4835
+ lines.push(`statuses: [${config.statuses.map((s2) => `"${s2}"`).join(", ")}]`);
4836
+ lines.push(`labels: [${(config.labels || []).map((l) => `"${l}"`).join(", ")}]`);
4837
+ lines.push(`milestones: [${(config.milestones || []).map((m) => `"${m}"`).join(", ")}]`);
4838
+ if (config.dateFormat) {
4839
+ lines.push(`date_format: "${config.dateFormat}"`);
4774
4840
  }
4775
- return merged;
4776
- }
4777
- function collectMilestones(tasks, configMilestones) {
4778
- const merged = [];
4779
- const seen = /* @__PURE__ */ new Set();
4780
- const addMilestone = (value) => {
4781
- const normalized = normalizeMilestoneName(value);
4782
- if (!normalized)
4783
- return;
4784
- const key2 = milestoneKey(normalized);
4785
- if (seen.has(key2))
4786
- return;
4787
- seen.add(key2);
4788
- merged.push(normalized);
4789
- };
4790
- for (const m of configMilestones) {
4791
- addMilestone(m);
4841
+ if (config.defaultAssignee) {
4842
+ lines.push(`default_assignee: "${config.defaultAssignee}"`);
4792
4843
  }
4793
- for (const task of tasks) {
4794
- addMilestone(task.milestone ?? "");
4844
+ if (config.defaultReporter) {
4845
+ lines.push(`default_reporter: "${config.defaultReporter}"`);
4795
4846
  }
4796
- return merged;
4797
- }
4798
- function createBucket(milestoneId, tasks, statuses, milestoneEntities, isNoMilestone) {
4799
- const bucketMilestoneKey = milestoneKey(milestoneId);
4800
- const bucketTasks = tasks.filter((task) => {
4801
- const taskMilestoneKey = milestoneKey(task.milestone);
4802
- return bucketMilestoneKey ? taskMilestoneKey === bucketMilestoneKey : !taskMilestoneKey;
4803
- });
4804
- const counts = {};
4805
- for (const status of statuses) {
4806
- counts[status] = 0;
4847
+ if (config.defaultEditor) {
4848
+ lines.push(`default_editor: "${config.defaultEditor}"`);
4807
4849
  }
4808
- for (const task of bucketTasks) {
4809
- const status = task.status ?? "";
4810
- counts[status] = (counts[status] ?? 0) + 1;
4850
+ if (typeof config.autoCommit === "boolean") {
4851
+ lines.push(`auto_commit: ${config.autoCommit}`);
4811
4852
  }
4812
- const doneCount = bucketTasks.filter((t) => isDoneStatus(t.status)).length;
4813
- const progress = bucketTasks.length > 0 ? Math.round(doneCount / bucketTasks.length * 100) : 0;
4814
- const key2 = bucketMilestoneKey ? bucketMilestoneKey : NO_MILESTONE_KEY;
4815
- const label = getMilestoneLabel(milestoneId, milestoneEntities);
4816
- return {
4817
- key: key2,
4818
- label,
4819
- milestone: milestoneId,
4820
- isNoMilestone,
4821
- tasks: bucketTasks,
4822
- statusCounts: counts,
4823
- total: bucketTasks.length,
4824
- doneCount,
4825
- progress
4826
- };
4827
- }
4828
- function buildMilestoneBuckets(tasks, milestoneEntities, statuses) {
4829
- const allMilestoneIds = collectMilestoneIds(tasks, milestoneEntities);
4830
- const buckets = [
4831
- // "No milestone" bucket first
4832
- createBucket(void 0, tasks, statuses, milestoneEntities, true),
4833
- // Then each milestone bucket
4834
- ...allMilestoneIds.map((m) => createBucket(m, tasks, statuses, milestoneEntities, false))
4835
- ];
4836
- return buckets;
4837
- }
4838
- function buildMilestoneBucketsFromConfig(tasks, configMilestones, statuses) {
4839
- const milestoneEntities = configMilestones.map((id) => ({
4840
- id,
4841
- title: id,
4842
- description: "",
4843
- rawContent: "",
4844
- tasks: []
4845
- }));
4846
- return buildMilestoneBuckets(tasks, milestoneEntities, statuses);
4847
- }
4848
- function groupTasksByMilestone(tasks, configMilestones, statuses) {
4849
- const milestones = collectMilestones(tasks, configMilestones);
4850
- const buckets = buildMilestoneBucketsFromConfig(tasks, configMilestones, statuses);
4851
- return {
4852
- milestones,
4853
- buckets
4854
- };
4853
+ if (typeof config.zeroPaddedIds === "number") {
4854
+ lines.push(`zero_padded_ids: ${config.zeroPaddedIds}`);
4855
+ }
4856
+ if (typeof config.autoOpenBrowser === "boolean") {
4857
+ lines.push(`auto_open_browser: ${config.autoOpenBrowser}`);
4858
+ }
4859
+ if (typeof config.defaultPort === "number") {
4860
+ lines.push(`default_port: ${config.defaultPort}`);
4861
+ }
4862
+ if (typeof config.remoteOperations === "boolean") {
4863
+ lines.push(`remote_operations: ${config.remoteOperations}`);
4864
+ }
4865
+ if (typeof config.bypassGitHooks === "boolean") {
4866
+ lines.push(`bypass_git_hooks: ${config.bypassGitHooks}`);
4867
+ }
4868
+ if (typeof config.checkActiveBranches === "boolean") {
4869
+ lines.push(`check_active_branches: ${config.checkActiveBranches}`);
4870
+ }
4871
+ if (typeof config.activeBranchDays === "number") {
4872
+ lines.push(`active_branch_days: ${config.activeBranchDays}`);
4873
+ }
4874
+ return `${lines.join("\n")}
4875
+ `;
4855
4876
  }
4856
4877
  class Core {
4857
4878
  constructor(options) {
@@ -5045,7 +5066,7 @@ class Core {
5045
5066
  const tasksLimit = (options == null ? void 0 : options.tasksLimit) ?? 10;
5046
5067
  const completedLimit = (options == null ? void 0 : options.completedLimit) ?? 10;
5047
5068
  const offset = (options == null ? void 0 : options.offset) ?? 0;
5048
- (options == null ? void 0 : options.tasksSortDirection) ?? "asc";
5069
+ const tasksSortDirection = (options == null ? void 0 : options.tasksSortDirection) ?? "asc";
5049
5070
  const completedSortByIdDesc = (options == null ? void 0 : options.completedSortByIdDesc) ?? true;
5050
5071
  const sources = ["tasks", "completed"];
5051
5072
  const bySource = /* @__PURE__ */ new Map();
@@ -5055,7 +5076,11 @@ class Core {
5055
5076
  entries = entries.sort((a, b) => {
5056
5077
  const aNum = parseInt(a.id.replace(/\D/g, ""), 10) || 0;
5057
5078
  const bNum = parseInt(b.id.replace(/\D/g, ""), 10) || 0;
5058
- return source2 === "completed" && completedSortByIdDesc ? bNum - aNum : aNum - bNum;
5079
+ if (source2 === "completed") {
5080
+ return completedSortByIdDesc ? bNum - aNum : aNum - bNum;
5081
+ } else {
5082
+ return tasksSortDirection === "desc" ? bNum - aNum : aNum - bNum;
5083
+ }
5059
5084
  });
5060
5085
  const total = entries.length;
5061
5086
  const pageEntries = entries.slice(offset, offset + limit);
@@ -5086,13 +5111,17 @@ class Core {
5086
5111
  throw new Error("Core not lazy initialized. Call initializeLazy() first.");
5087
5112
  }
5088
5113
  const limit = (options == null ? void 0 : options.limit) ?? 10;
5089
- (options == null ? void 0 : options.sortDirection) ?? "asc";
5114
+ const sortDirection = (options == null ? void 0 : options.sortDirection) ?? "asc";
5090
5115
  const completedSortByIdDesc = (options == null ? void 0 : options.completedSortByIdDesc) ?? true;
5091
5116
  let entries = Array.from(this.taskIndex.values()).filter((e) => e.source === source2);
5092
5117
  entries = entries.sort((a, b) => {
5093
5118
  const aNum = parseInt(a.id.replace(/\D/g, ""), 10) || 0;
5094
5119
  const bNum = parseInt(b.id.replace(/\D/g, ""), 10) || 0;
5095
- return source2 === "completed" && completedSortByIdDesc ? bNum - aNum : aNum - bNum;
5120
+ if (source2 === "completed") {
5121
+ return completedSortByIdDesc ? bNum - aNum : aNum - bNum;
5122
+ } else {
5123
+ return sortDirection === "desc" ? bNum - aNum : aNum - bNum;
5124
+ }
5096
5125
  });
5097
5126
  const total = entries.length;
5098
5127
  const pageEntries = entries.slice(currentOffset, currentOffset + limit);
@@ -5112,7 +5141,7 @@ class Core {
5112
5141
  */
5113
5142
  getConfig() {
5114
5143
  this.ensureInitialized();
5115
- return this.config;
5144
+ return this.safeConfig;
5116
5145
  }
5117
5146
  /**
5118
5147
  * List all tasks, optionally filtered
@@ -5127,7 +5156,8 @@ class Core {
5127
5156
  tasks = tasks.filter((t) => t.status === filter.status);
5128
5157
  }
5129
5158
  if (filter == null ? void 0 : filter.assignee) {
5130
- tasks = tasks.filter((t) => t.assignee.includes(filter.assignee));
5159
+ const assignee = filter.assignee;
5160
+ tasks = tasks.filter((t) => t.assignee.includes(assignee));
5131
5161
  }
5132
5162
  if (filter == null ? void 0 : filter.priority) {
5133
5163
  tasks = tasks.filter((t) => t.priority === filter.priority);
@@ -5137,7 +5167,10 @@ class Core {
5137
5167
  tasks = tasks.filter((t) => milestoneKey(t.milestone) === filterKey);
5138
5168
  }
5139
5169
  if ((filter == null ? void 0 : filter.labels) && filter.labels.length > 0) {
5140
- tasks = tasks.filter((t) => filter.labels.some((label) => t.labels.includes(label)));
5170
+ tasks = tasks.filter((t) => {
5171
+ var _a;
5172
+ return (_a = filter.labels) == null ? void 0 : _a.some((label) => t.labels.includes(label));
5173
+ });
5141
5174
  }
5142
5175
  if (filter == null ? void 0 : filter.parentTaskId) {
5143
5176
  tasks = tasks.filter((t) => t.parentTaskId === filter.parentTaskId);
@@ -5154,7 +5187,7 @@ class Core {
5154
5187
  getTasksByStatus() {
5155
5188
  this.ensureInitialized();
5156
5189
  const tasks = Array.from(this.tasks.values());
5157
- return groupTasksByStatus(tasks, this.config.statuses);
5190
+ return groupTasksByStatus(tasks, this.safeConfig.statuses);
5158
5191
  }
5159
5192
  /**
5160
5193
  * Get tasks grouped by milestone
@@ -5178,7 +5211,7 @@ class Core {
5178
5211
  getTasksByMilestone() {
5179
5212
  this.ensureInitialized();
5180
5213
  const tasks = Array.from(this.tasks.values());
5181
- return groupTasksByMilestone(tasks, this.config.milestones, this.config.statuses);
5214
+ return groupTasksByMilestone(tasks, this.safeConfig.milestones, this.safeConfig.statuses);
5182
5215
  }
5183
5216
  // =========================================================================
5184
5217
  // Milestone CRUD Operations
@@ -5404,7 +5437,7 @@ class Core {
5404
5437
  const sortDirection = (pagination == null ? void 0 : pagination.sortDirection) ?? "asc";
5405
5438
  const byStatus = /* @__PURE__ */ new Map();
5406
5439
  const allGrouped = /* @__PURE__ */ new Map();
5407
- for (const status of this.config.statuses) {
5440
+ for (const status of this.safeConfig.statuses) {
5408
5441
  allGrouped.set(status, []);
5409
5442
  }
5410
5443
  for (const task of this.tasks.values()) {
@@ -5415,7 +5448,7 @@ class Core {
5415
5448
  allGrouped.set(task.status, [task]);
5416
5449
  }
5417
5450
  }
5418
- for (const status of this.config.statuses) {
5451
+ for (const status of this.safeConfig.statuses) {
5419
5452
  let tasks = allGrouped.get(status) ?? [];
5420
5453
  tasks = sortTasksBy(tasks, sortBy, sortDirection);
5421
5454
  const total = tasks.length;
@@ -5430,7 +5463,7 @@ class Core {
5430
5463
  }
5431
5464
  return {
5432
5465
  byStatus,
5433
- statuses: this.config.statuses
5466
+ statuses: this.safeConfig.statuses
5434
5467
  };
5435
5468
  }
5436
5469
  /**
@@ -5470,10 +5503,16 @@ class Core {
5470
5503
  }
5471
5504
  // --- Private methods ---
5472
5505
  ensureInitialized() {
5473
- if (!this.initialized) {
5474
- throw new Error("Core not initialized. Call initialize() first.");
5506
+ if (!this.initialized && !this.lazyInitialized || !this.config) {
5507
+ throw new Error("Core not initialized. Call initialize() or initializeLazy() first.");
5475
5508
  }
5476
5509
  }
5510
+ /**
5511
+ * Get config with type safety (use after ensureInitialized)
5512
+ */
5513
+ get safeConfig() {
5514
+ return this.config;
5515
+ }
5477
5516
  applyFilters(tasks, filter) {
5478
5517
  if (!filter)
5479
5518
  return tasks;
@@ -5482,7 +5521,8 @@ class Core {
5482
5521
  result = result.filter((t) => t.status === filter.status);
5483
5522
  }
5484
5523
  if (filter.assignee) {
5485
- result = result.filter((t) => t.assignee.includes(filter.assignee));
5524
+ const assignee = filter.assignee;
5525
+ result = result.filter((t) => t.assignee.includes(assignee));
5486
5526
  }
5487
5527
  if (filter.priority) {
5488
5528
  result = result.filter((t) => t.priority === filter.priority);
@@ -5492,7 +5532,10 @@ class Core {
5492
5532
  result = result.filter((t) => milestoneKey(t.milestone) === filterKey);
5493
5533
  }
5494
5534
  if (filter.labels && filter.labels.length > 0) {
5495
- result = result.filter((t) => filter.labels.some((label) => t.labels.includes(label)));
5535
+ result = result.filter((t) => {
5536
+ var _a;
5537
+ return (_a = filter.labels) == null ? void 0 : _a.some((label) => t.labels.includes(label));
5538
+ });
5496
5539
  }
5497
5540
  if (filter.parentTaskId) {
5498
5541
  result = result.filter((t) => t.parentTaskId === filter.parentTaskId);
@@ -5589,6 +5632,12 @@ class Core {
5589
5632
  getTasksDir() {
5590
5633
  return this.fs.join(this.projectRoot, "backlog", "tasks");
5591
5634
  }
5635
+ /**
5636
+ * Get the completed directory path
5637
+ */
5638
+ getCompletedDir() {
5639
+ return this.fs.join(this.projectRoot, "backlog", "completed");
5640
+ }
5592
5641
  // =========================================================================
5593
5642
  // Task CRUD Operations
5594
5643
  // =========================================================================
@@ -5599,18 +5648,18 @@ class Core {
5599
5648
  * @returns Created task
5600
5649
  */
5601
5650
  async createTask(input) {
5602
- var _a;
5651
+ var _a, _b;
5603
5652
  this.ensureInitialized();
5604
5653
  const tasksDir = this.getTasksDir();
5605
5654
  await this.fs.createDir(tasksDir, { recursive: true });
5606
- const existingIds = Array.from(this.tasks.keys()).map((id) => parseInt(id.replace(/\D/g, ""), 10)).filter((n) => !isNaN(n));
5655
+ const existingIds = Array.from(this.tasks.keys()).map((id) => parseInt(id.replace(/\D/g, ""), 10)).filter((n) => !Number.isNaN(n));
5607
5656
  const nextId = existingIds.length > 0 ? Math.max(...existingIds) + 1 : 1;
5608
5657
  const taskId = String(nextId);
5609
5658
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
5610
5659
  const task = {
5611
5660
  id: taskId,
5612
5661
  title: input.title,
5613
- status: input.status || this.config.defaultStatus || "To Do",
5662
+ status: input.status || ((_a = this.config) == null ? void 0 : _a.defaultStatus) || "To Do",
5614
5663
  priority: input.priority,
5615
5664
  assignee: input.assignee || [],
5616
5665
  createdDate: now,
@@ -5621,7 +5670,7 @@ class Core {
5621
5670
  description: input.description,
5622
5671
  implementationPlan: input.implementationPlan,
5623
5672
  implementationNotes: input.implementationNotes,
5624
- acceptanceCriteriaItems: (_a = input.acceptanceCriteria) == null ? void 0 : _a.map((ac, i) => ({
5673
+ acceptanceCriteriaItems: (_b = input.acceptanceCriteria) == null ? void 0 : _b.map((ac, i) => ({
5625
5674
  index: i + 1,
5626
5675
  text: ac.text,
5627
5676
  checked: ac.checked || false
@@ -5677,19 +5726,23 @@ class Core {
5677
5726
  updated.labels = [.../* @__PURE__ */ new Set([...updated.labels, ...input.addLabels])];
5678
5727
  }
5679
5728
  if (input.removeLabels) {
5680
- updated.labels = updated.labels.filter((l) => !input.removeLabels.includes(l));
5729
+ updated.labels = updated.labels.filter((l) => {
5730
+ var _a;
5731
+ return !((_a = input.removeLabels) == null ? void 0 : _a.includes(l));
5732
+ });
5681
5733
  }
5682
5734
  }
5683
5735
  if (input.assignee) {
5684
5736
  updated.assignee = input.assignee;
5685
5737
  }
5686
5738
  if (input.addDependencies) {
5687
- updated.dependencies = [
5688
- .../* @__PURE__ */ new Set([...updated.dependencies, ...input.addDependencies])
5689
- ];
5739
+ updated.dependencies = [.../* @__PURE__ */ new Set([...updated.dependencies, ...input.addDependencies])];
5690
5740
  }
5691
5741
  if (input.removeDependencies) {
5692
- updated.dependencies = updated.dependencies.filter((d) => !input.removeDependencies.includes(d));
5742
+ updated.dependencies = updated.dependencies.filter((d) => {
5743
+ var _a;
5744
+ return !((_a = input.removeDependencies) == null ? void 0 : _a.includes(d));
5745
+ });
5693
5746
  }
5694
5747
  if (input.acceptanceCriteria) {
5695
5748
  updated.acceptanceCriteriaItems = input.acceptanceCriteria.map((ac, i) => ({
@@ -5745,6 +5798,92 @@ class Core {
5745
5798
  this.tasks.delete(id);
5746
5799
  return true;
5747
5800
  }
5801
+ /**
5802
+ * Archive a task (move from tasks/ to completed/)
5803
+ *
5804
+ * @param id - Task ID to archive
5805
+ * @returns Archived task or null if not found or already archived
5806
+ */
5807
+ async archiveTask(id) {
5808
+ this.ensureInitialized();
5809
+ const task = this.tasks.get(id);
5810
+ if (!task) {
5811
+ return null;
5812
+ }
5813
+ if (task.source === "completed") {
5814
+ return null;
5815
+ }
5816
+ const completedDir = this.getCompletedDir();
5817
+ await this.fs.createDir(completedDir, { recursive: true });
5818
+ const safeTitle = task.title.replace(/[<>:"/\\|?*]/g, "").replace(/\s+/g, " ").slice(0, 50);
5819
+ const filename = `${id} - ${safeTitle}.md`;
5820
+ const newFilepath = this.fs.join(completedDir, filename);
5821
+ if (task.filePath) {
5822
+ try {
5823
+ await this.fs.deleteFile(task.filePath);
5824
+ } catch {
5825
+ }
5826
+ }
5827
+ const archived = {
5828
+ ...task,
5829
+ source: "completed",
5830
+ filePath: newFilepath
5831
+ };
5832
+ const content2 = serializeTaskMarkdown(archived);
5833
+ await this.fs.writeFile(newFilepath, content2);
5834
+ this.tasks.set(id, archived);
5835
+ if (this.lazyInitialized) {
5836
+ const entry = this.taskIndex.get(id);
5837
+ if (entry) {
5838
+ entry.source = "completed";
5839
+ entry.filePath = newFilepath;
5840
+ }
5841
+ }
5842
+ return archived;
5843
+ }
5844
+ /**
5845
+ * Restore a task (move from completed/ to tasks/)
5846
+ *
5847
+ * @param id - Task ID to restore
5848
+ * @returns Restored task or null if not found or not archived
5849
+ */
5850
+ async restoreTask(id) {
5851
+ this.ensureInitialized();
5852
+ const task = this.tasks.get(id);
5853
+ if (!task) {
5854
+ return null;
5855
+ }
5856
+ if (task.source !== "completed") {
5857
+ return null;
5858
+ }
5859
+ const tasksDir = this.getTasksDir();
5860
+ await this.fs.createDir(tasksDir, { recursive: true });
5861
+ const safeTitle = task.title.replace(/[<>:"/\\|?*]/g, "").replace(/\s+/g, " ").slice(0, 50);
5862
+ const filename = `${id} - ${safeTitle}.md`;
5863
+ const newFilepath = this.fs.join(tasksDir, filename);
5864
+ if (task.filePath) {
5865
+ try {
5866
+ await this.fs.deleteFile(task.filePath);
5867
+ } catch {
5868
+ }
5869
+ }
5870
+ const restored = {
5871
+ ...task,
5872
+ source: "local",
5873
+ filePath: newFilepath
5874
+ };
5875
+ const content2 = serializeTaskMarkdown(restored);
5876
+ await this.fs.writeFile(newFilepath, content2);
5877
+ this.tasks.set(id, restored);
5878
+ if (this.lazyInitialized) {
5879
+ const entry = this.taskIndex.get(id);
5880
+ if (entry) {
5881
+ entry.source = "tasks";
5882
+ entry.filePath = newFilepath;
5883
+ }
5884
+ }
5885
+ return restored;
5886
+ }
5748
5887
  /**
5749
5888
  * Load specific tasks by their IDs (for lazy loading milestone tasks)
5750
5889
  *
@@ -5765,6 +5904,7 @@ class PanelFileSystemAdapter {
5765
5904
  constructor(access) {
5766
5905
  this.fetchFile = access.fetchFile;
5767
5906
  this.filePaths = new Set(access.filePaths);
5907
+ this.hostFileSystem = access.hostFileSystem;
5768
5908
  this.directories = /* @__PURE__ */ new Set();
5769
5909
  for (const filePath of access.filePaths) {
5770
5910
  const parts = filePath.split("/");
@@ -5774,6 +5914,13 @@ class PanelFileSystemAdapter {
5774
5914
  }
5775
5915
  this.directories.add("");
5776
5916
  }
5917
+ /**
5918
+ * Check if write operations are available
5919
+ */
5920
+ get canWrite() {
5921
+ var _a, _b;
5922
+ return !!(((_a = this.hostFileSystem) == null ? void 0 : _a.writeFile) && ((_b = this.hostFileSystem) == null ? void 0 : _b.createDir));
5923
+ }
5777
5924
  async exists(path2) {
5778
5925
  const normalized = this.normalizePath(path2);
5779
5926
  return this.filePaths.has(normalized) || this.directories.has(normalized);
@@ -5785,14 +5932,36 @@ class PanelFileSystemAdapter {
5785
5932
  }
5786
5933
  return this.fetchFile(normalized);
5787
5934
  }
5788
- async writeFile(_path, _content) {
5789
- throw new Error("Write operations not supported in panel context");
5935
+ async writeFile(path2, content2) {
5936
+ var _a;
5937
+ if (!((_a = this.hostFileSystem) == null ? void 0 : _a.writeFile)) {
5938
+ throw new Error("Write operations not available - host adapter not configured");
5939
+ }
5940
+ const normalized = this.normalizePath(path2);
5941
+ await this.hostFileSystem.writeFile(normalized, content2);
5942
+ this.filePaths.add(normalized);
5943
+ const parts = normalized.split("/");
5944
+ for (let i = 1; i < parts.length; i++) {
5945
+ this.directories.add(parts.slice(0, i).join("/"));
5946
+ }
5790
5947
  }
5791
- async deleteFile(_path) {
5792
- throw new Error("Delete operations not supported in panel context");
5948
+ async deleteFile(path2) {
5949
+ var _a;
5950
+ if (!((_a = this.hostFileSystem) == null ? void 0 : _a.deleteFile)) {
5951
+ throw new Error("Delete operations not available - host adapter not configured");
5952
+ }
5953
+ const normalized = this.normalizePath(path2);
5954
+ await this.hostFileSystem.deleteFile(normalized);
5955
+ this.filePaths.delete(normalized);
5793
5956
  }
5794
- async createDir(_path, _options) {
5795
- throw new Error("Directory creation not supported in panel context");
5957
+ async createDir(path2, _options) {
5958
+ var _a;
5959
+ if (!((_a = this.hostFileSystem) == null ? void 0 : _a.createDir)) {
5960
+ throw new Error("Directory creation not available - host adapter not configured");
5961
+ }
5962
+ const normalized = this.normalizePath(path2);
5963
+ await this.hostFileSystem.createDir(normalized);
5964
+ this.directories.add(normalized);
5796
5965
  }
5797
5966
  async readDir(path2) {
5798
5967
  const normalized = this.normalizePath(path2);
@@ -5905,6 +6074,7 @@ function useKanbanData(options) {
5905
6074
  const [isLoading, setIsLoading] = useState(true);
5906
6075
  const [error, setError] = useState(null);
5907
6076
  const [isBacklogProject, setIsBacklogProject] = useState(false);
6077
+ const [canWrite, setCanWrite] = useState(false);
5908
6078
  const [tasksBySource, setTasksBySource] = useState(
5909
6079
  /* @__PURE__ */ new Map()
5910
6080
  );
@@ -5950,7 +6120,7 @@ function useKanbanData(options) {
5950
6120
  }, []);
5951
6121
  const fileTreeVersionRef = useRef(null);
5952
6122
  const loadBacklogData = useCallback(async () => {
5953
- var _a, _b;
6123
+ var _a, _b, _c;
5954
6124
  if (!context || !actions) {
5955
6125
  console.log("[useKanbanData] No context provided");
5956
6126
  setIsBacklogProject(false);
@@ -5986,7 +6156,8 @@ function useKanbanData(options) {
5986
6156
  const filePaths = files.map((f) => f.path);
5987
6157
  const fs = new PanelFileSystemAdapter({
5988
6158
  fetchFile: fetchFileContent,
5989
- filePaths
6159
+ filePaths,
6160
+ hostFileSystem: (_c = context.adapters) == null ? void 0 : _c.fileSystem
5990
6161
  });
5991
6162
  const core2 = new Core({
5992
6163
  projectRoot: "",
@@ -6004,6 +6175,7 @@ function useKanbanData(options) {
6004
6175
  }
6005
6176
  console.log("[useKanbanData] Loading Backlog.md data with lazy loading...");
6006
6177
  setIsBacklogProject(true);
6178
+ setCanWrite(fs.canWrite);
6007
6179
  await core2.initializeLazy(filePaths);
6008
6180
  coreRef.current = core2;
6009
6181
  const paginatedResult = await core2.getTasksBySourcePaginated({
@@ -6138,14 +6310,28 @@ function useKanbanData(options) {
6138
6310
  await loadBacklogData();
6139
6311
  }, [loadBacklogData]);
6140
6312
  const updateTaskStatus = useCallback(
6141
- async (_taskId, _newStatus) => {
6313
+ async (taskId, newStatus) => {
6314
+ const core2 = coreRef.current;
6315
+ if (!core2) {
6316
+ console.warn("[useKanbanData] Core not available for updateTaskStatus");
6317
+ setError("Cannot update task - backlog not loaded");
6318
+ return;
6319
+ }
6142
6320
  setError(null);
6143
- console.warn(
6144
- "[useKanbanData] Task status updates not yet implemented for Backlog.md"
6145
- );
6146
- setError("Task editing is not yet supported");
6321
+ try {
6322
+ console.log(`[useKanbanData] Updating task ${taskId} status to "${newStatus}"`);
6323
+ const updatedTask = await core2.updateTask(taskId, { status: newStatus });
6324
+ if (!updatedTask) {
6325
+ throw new Error(`Task ${taskId} not found`);
6326
+ }
6327
+ console.log(`[useKanbanData] Task ${taskId} updated successfully`);
6328
+ await loadBacklogData();
6329
+ } catch (err) {
6330
+ console.error("[useKanbanData] Failed to update task status:", err);
6331
+ setError(err instanceof Error ? err.message : "Failed to update task");
6332
+ }
6147
6333
  },
6148
- []
6334
+ [loadBacklogData]
6149
6335
  );
6150
6336
  const moveTaskOptimistic = useCallback(
6151
6337
  (taskId, toColumn) => {
@@ -6237,7 +6423,10 @@ function useKanbanData(options) {
6237
6423
  loadMoreActive,
6238
6424
  // Drag-and-drop support
6239
6425
  moveTaskOptimistic,
6240
- getTaskById
6426
+ getTaskById,
6427
+ // Write support
6428
+ canWrite,
6429
+ core: coreRef.current
6241
6430
  };
6242
6431
  }
6243
6432
  const TaskCard = ({
@@ -6830,6 +7019,519 @@ const EmptyState = ({
6830
7019
  )
6831
7020
  ] });
6832
7021
  };
7022
+ const TaskModal = ({
7023
+ isOpen,
7024
+ onClose,
7025
+ onSave,
7026
+ task,
7027
+ defaultStatus = "To Do",
7028
+ availableStatuses = ["To Do", "In Progress", "Done"],
7029
+ availableMilestones = []
7030
+ }) => {
7031
+ const { theme: theme2 } = useTheme();
7032
+ const isEditing = !!task;
7033
+ const [title, setTitle] = useState("");
7034
+ const [description, setDescription] = useState("");
7035
+ const [status, setStatus] = useState(defaultStatus);
7036
+ const [priority, setPriority] = useState("medium");
7037
+ const [labels, setLabels] = useState("");
7038
+ const [assignee, setAssignee] = useState("");
7039
+ const [milestone, setMilestone] = useState("");
7040
+ const [isSaving, setIsSaving] = useState(false);
7041
+ const [error, setError] = useState(null);
7042
+ useEffect(() => {
7043
+ var _a, _b;
7044
+ if (isOpen) {
7045
+ if (task) {
7046
+ setTitle(task.title || "");
7047
+ setDescription(task.description || "");
7048
+ setStatus(task.status || defaultStatus);
7049
+ setPriority(task.priority || "medium");
7050
+ setLabels(((_a = task.labels) == null ? void 0 : _a.join(", ")) || "");
7051
+ setAssignee(((_b = task.assignee) == null ? void 0 : _b.join(", ")) || "");
7052
+ setMilestone(task.milestone || "");
7053
+ } else {
7054
+ setTitle("");
7055
+ setDescription("");
7056
+ setStatus(defaultStatus);
7057
+ setPriority("medium");
7058
+ setLabels("");
7059
+ setAssignee("");
7060
+ setMilestone("");
7061
+ }
7062
+ setError(null);
7063
+ }
7064
+ }, [isOpen, task, defaultStatus]);
7065
+ const handleSubmit = async (e) => {
7066
+ e.preventDefault();
7067
+ if (!title.trim()) {
7068
+ setError("Title is required");
7069
+ return;
7070
+ }
7071
+ setIsSaving(true);
7072
+ setError(null);
7073
+ try {
7074
+ const labelsArray = labels.split(",").map((l) => l.trim()).filter(Boolean);
7075
+ const assigneeArray = assignee.split(",").map((a) => a.trim()).filter(Boolean);
7076
+ if (isEditing) {
7077
+ const input = {
7078
+ title: title.trim(),
7079
+ description: description.trim() || void 0,
7080
+ status,
7081
+ priority,
7082
+ labels: labelsArray.length > 0 ? labelsArray : void 0,
7083
+ assignee: assigneeArray.length > 0 ? assigneeArray : void 0,
7084
+ milestone: milestone || void 0
7085
+ };
7086
+ await onSave(input);
7087
+ } else {
7088
+ const input = {
7089
+ title: title.trim(),
7090
+ description: description.trim() || void 0,
7091
+ status,
7092
+ priority,
7093
+ labels: labelsArray.length > 0 ? labelsArray : void 0,
7094
+ assignee: assigneeArray.length > 0 ? assigneeArray : void 0,
7095
+ milestone: milestone || void 0
7096
+ };
7097
+ await onSave(input);
7098
+ }
7099
+ onClose();
7100
+ } catch (err) {
7101
+ setError(err instanceof Error ? err.message : "Failed to save task");
7102
+ } finally {
7103
+ setIsSaving(false);
7104
+ }
7105
+ };
7106
+ if (!isOpen) return null;
7107
+ const modalContent = /* @__PURE__ */ jsxs(
7108
+ "div",
7109
+ {
7110
+ style: {
7111
+ position: "fixed",
7112
+ inset: 0,
7113
+ zIndex: 9999,
7114
+ display: "flex",
7115
+ alignItems: "center",
7116
+ justifyContent: "center",
7117
+ padding: "16px"
7118
+ },
7119
+ children: [
7120
+ /* @__PURE__ */ jsx(
7121
+ "div",
7122
+ {
7123
+ onClick: onClose,
7124
+ style: {
7125
+ position: "absolute",
7126
+ inset: 0,
7127
+ backgroundColor: "rgba(0, 0, 0, 0.5)"
7128
+ }
7129
+ }
7130
+ ),
7131
+ /* @__PURE__ */ jsxs(
7132
+ "div",
7133
+ {
7134
+ style: {
7135
+ position: "relative",
7136
+ width: "100%",
7137
+ maxWidth: "500px",
7138
+ maxHeight: "90vh",
7139
+ overflow: "auto",
7140
+ backgroundColor: theme2.colors.background,
7141
+ borderRadius: theme2.radii[3],
7142
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
7143
+ border: `1px solid ${theme2.colors.border}`
7144
+ },
7145
+ children: [
7146
+ /* @__PURE__ */ jsxs(
7147
+ "div",
7148
+ {
7149
+ style: {
7150
+ display: "flex",
7151
+ alignItems: "center",
7152
+ justifyContent: "space-between",
7153
+ padding: "16px 20px",
7154
+ borderBottom: `1px solid ${theme2.colors.border}`
7155
+ },
7156
+ children: [
7157
+ /* @__PURE__ */ jsx(
7158
+ "h2",
7159
+ {
7160
+ style: {
7161
+ margin: 0,
7162
+ fontSize: theme2.fontSizes[4],
7163
+ fontWeight: 600,
7164
+ color: theme2.colors.text
7165
+ },
7166
+ children: isEditing ? "Edit Task" : "New Task"
7167
+ }
7168
+ ),
7169
+ /* @__PURE__ */ jsx(
7170
+ "button",
7171
+ {
7172
+ onClick: onClose,
7173
+ style: {
7174
+ background: "none",
7175
+ border: "none",
7176
+ cursor: "pointer",
7177
+ padding: "4px",
7178
+ display: "flex",
7179
+ alignItems: "center",
7180
+ justifyContent: "center",
7181
+ borderRadius: theme2.radii[1],
7182
+ color: theme2.colors.textMuted
7183
+ },
7184
+ children: /* @__PURE__ */ jsx(X, { size: 20 })
7185
+ }
7186
+ )
7187
+ ]
7188
+ }
7189
+ ),
7190
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
7191
+ /* @__PURE__ */ jsxs("div", { style: { padding: "20px", display: "flex", flexDirection: "column", gap: "16px" }, children: [
7192
+ /* @__PURE__ */ jsxs("div", { children: [
7193
+ /* @__PURE__ */ jsx(
7194
+ "label",
7195
+ {
7196
+ style: {
7197
+ display: "block",
7198
+ marginBottom: "6px",
7199
+ fontSize: theme2.fontSizes[1],
7200
+ fontWeight: 500,
7201
+ color: theme2.colors.text
7202
+ },
7203
+ children: "Title *"
7204
+ }
7205
+ ),
7206
+ /* @__PURE__ */ jsx(
7207
+ "input",
7208
+ {
7209
+ type: "text",
7210
+ value: title,
7211
+ onChange: (e) => setTitle(e.target.value),
7212
+ placeholder: "Enter task title",
7213
+ autoFocus: true,
7214
+ style: {
7215
+ width: "100%",
7216
+ padding: "10px 12px",
7217
+ fontSize: theme2.fontSizes[2],
7218
+ border: `1px solid ${theme2.colors.border}`,
7219
+ borderRadius: theme2.radii[2],
7220
+ backgroundColor: theme2.colors.backgroundSecondary,
7221
+ color: theme2.colors.text,
7222
+ outline: "none",
7223
+ boxSizing: "border-box"
7224
+ }
7225
+ }
7226
+ )
7227
+ ] }),
7228
+ /* @__PURE__ */ jsxs("div", { children: [
7229
+ /* @__PURE__ */ jsx(
7230
+ "label",
7231
+ {
7232
+ style: {
7233
+ display: "block",
7234
+ marginBottom: "6px",
7235
+ fontSize: theme2.fontSizes[1],
7236
+ fontWeight: 500,
7237
+ color: theme2.colors.text
7238
+ },
7239
+ children: "Description"
7240
+ }
7241
+ ),
7242
+ /* @__PURE__ */ jsx(
7243
+ "textarea",
7244
+ {
7245
+ value: description,
7246
+ onChange: (e) => setDescription(e.target.value),
7247
+ placeholder: "Enter task description (markdown supported)",
7248
+ rows: 4,
7249
+ style: {
7250
+ width: "100%",
7251
+ padding: "10px 12px",
7252
+ fontSize: theme2.fontSizes[2],
7253
+ border: `1px solid ${theme2.colors.border}`,
7254
+ borderRadius: theme2.radii[2],
7255
+ backgroundColor: theme2.colors.backgroundSecondary,
7256
+ color: theme2.colors.text,
7257
+ outline: "none",
7258
+ resize: "vertical",
7259
+ fontFamily: theme2.fonts.body,
7260
+ boxSizing: "border-box"
7261
+ }
7262
+ }
7263
+ )
7264
+ ] }),
7265
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "12px" }, children: [
7266
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
7267
+ /* @__PURE__ */ jsx(
7268
+ "label",
7269
+ {
7270
+ style: {
7271
+ display: "block",
7272
+ marginBottom: "6px",
7273
+ fontSize: theme2.fontSizes[1],
7274
+ fontWeight: 500,
7275
+ color: theme2.colors.text
7276
+ },
7277
+ children: "Status"
7278
+ }
7279
+ ),
7280
+ /* @__PURE__ */ jsx(
7281
+ "select",
7282
+ {
7283
+ value: status,
7284
+ onChange: (e) => setStatus(e.target.value),
7285
+ style: {
7286
+ width: "100%",
7287
+ padding: "10px 12px",
7288
+ fontSize: theme2.fontSizes[2],
7289
+ border: `1px solid ${theme2.colors.border}`,
7290
+ borderRadius: theme2.radii[2],
7291
+ backgroundColor: theme2.colors.backgroundSecondary,
7292
+ color: theme2.colors.text,
7293
+ outline: "none",
7294
+ cursor: "pointer"
7295
+ },
7296
+ children: availableStatuses.map((s2) => /* @__PURE__ */ jsx("option", { value: s2, children: s2 }, s2))
7297
+ }
7298
+ )
7299
+ ] }),
7300
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
7301
+ /* @__PURE__ */ jsx(
7302
+ "label",
7303
+ {
7304
+ style: {
7305
+ display: "block",
7306
+ marginBottom: "6px",
7307
+ fontSize: theme2.fontSizes[1],
7308
+ fontWeight: 500,
7309
+ color: theme2.colors.text
7310
+ },
7311
+ children: "Priority"
7312
+ }
7313
+ ),
7314
+ /* @__PURE__ */ jsxs(
7315
+ "select",
7316
+ {
7317
+ value: priority,
7318
+ onChange: (e) => setPriority(e.target.value),
7319
+ style: {
7320
+ width: "100%",
7321
+ padding: "10px 12px",
7322
+ fontSize: theme2.fontSizes[2],
7323
+ border: `1px solid ${theme2.colors.border}`,
7324
+ borderRadius: theme2.radii[2],
7325
+ backgroundColor: theme2.colors.backgroundSecondary,
7326
+ color: theme2.colors.text,
7327
+ outline: "none",
7328
+ cursor: "pointer"
7329
+ },
7330
+ children: [
7331
+ /* @__PURE__ */ jsx("option", { value: "low", children: "Low" }),
7332
+ /* @__PURE__ */ jsx("option", { value: "medium", children: "Medium" }),
7333
+ /* @__PURE__ */ jsx("option", { value: "high", children: "High" })
7334
+ ]
7335
+ }
7336
+ )
7337
+ ] })
7338
+ ] }),
7339
+ /* @__PURE__ */ jsxs("div", { children: [
7340
+ /* @__PURE__ */ jsx(
7341
+ "label",
7342
+ {
7343
+ style: {
7344
+ display: "block",
7345
+ marginBottom: "6px",
7346
+ fontSize: theme2.fontSizes[1],
7347
+ fontWeight: 500,
7348
+ color: theme2.colors.text
7349
+ },
7350
+ children: "Labels"
7351
+ }
7352
+ ),
7353
+ /* @__PURE__ */ jsx(
7354
+ "input",
7355
+ {
7356
+ type: "text",
7357
+ value: labels,
7358
+ onChange: (e) => setLabels(e.target.value),
7359
+ placeholder: "bug, feature, enhancement (comma-separated)",
7360
+ style: {
7361
+ width: "100%",
7362
+ padding: "10px 12px",
7363
+ fontSize: theme2.fontSizes[2],
7364
+ border: `1px solid ${theme2.colors.border}`,
7365
+ borderRadius: theme2.radii[2],
7366
+ backgroundColor: theme2.colors.backgroundSecondary,
7367
+ color: theme2.colors.text,
7368
+ outline: "none",
7369
+ boxSizing: "border-box"
7370
+ }
7371
+ }
7372
+ )
7373
+ ] }),
7374
+ /* @__PURE__ */ jsxs("div", { children: [
7375
+ /* @__PURE__ */ jsx(
7376
+ "label",
7377
+ {
7378
+ style: {
7379
+ display: "block",
7380
+ marginBottom: "6px",
7381
+ fontSize: theme2.fontSizes[1],
7382
+ fontWeight: 500,
7383
+ color: theme2.colors.text
7384
+ },
7385
+ children: "Assignee"
7386
+ }
7387
+ ),
7388
+ /* @__PURE__ */ jsx(
7389
+ "input",
7390
+ {
7391
+ type: "text",
7392
+ value: assignee,
7393
+ onChange: (e) => setAssignee(e.target.value),
7394
+ placeholder: "user@example.com (comma-separated)",
7395
+ style: {
7396
+ width: "100%",
7397
+ padding: "10px 12px",
7398
+ fontSize: theme2.fontSizes[2],
7399
+ border: `1px solid ${theme2.colors.border}`,
7400
+ borderRadius: theme2.radii[2],
7401
+ backgroundColor: theme2.colors.backgroundSecondary,
7402
+ color: theme2.colors.text,
7403
+ outline: "none",
7404
+ boxSizing: "border-box"
7405
+ }
7406
+ }
7407
+ )
7408
+ ] }),
7409
+ availableMilestones.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
7410
+ /* @__PURE__ */ jsx(
7411
+ "label",
7412
+ {
7413
+ style: {
7414
+ display: "block",
7415
+ marginBottom: "6px",
7416
+ fontSize: theme2.fontSizes[1],
7417
+ fontWeight: 500,
7418
+ color: theme2.colors.text
7419
+ },
7420
+ children: "Milestone"
7421
+ }
7422
+ ),
7423
+ /* @__PURE__ */ jsxs(
7424
+ "select",
7425
+ {
7426
+ value: milestone,
7427
+ onChange: (e) => setMilestone(e.target.value),
7428
+ style: {
7429
+ width: "100%",
7430
+ padding: "10px 12px",
7431
+ fontSize: theme2.fontSizes[2],
7432
+ border: `1px solid ${theme2.colors.border}`,
7433
+ borderRadius: theme2.radii[2],
7434
+ backgroundColor: theme2.colors.backgroundSecondary,
7435
+ color: theme2.colors.text,
7436
+ outline: "none",
7437
+ cursor: "pointer"
7438
+ },
7439
+ children: [
7440
+ /* @__PURE__ */ jsx("option", { value: "", children: "None" }),
7441
+ availableMilestones.map((m) => /* @__PURE__ */ jsx("option", { value: m, children: m }, m))
7442
+ ]
7443
+ }
7444
+ )
7445
+ ] }),
7446
+ error && /* @__PURE__ */ jsx(
7447
+ "div",
7448
+ {
7449
+ style: {
7450
+ padding: "10px 12px",
7451
+ backgroundColor: `${theme2.colors.error}15`,
7452
+ border: `1px solid ${theme2.colors.error}`,
7453
+ borderRadius: theme2.radii[2],
7454
+ color: theme2.colors.error,
7455
+ fontSize: theme2.fontSizes[1]
7456
+ },
7457
+ children: error
7458
+ }
7459
+ )
7460
+ ] }),
7461
+ /* @__PURE__ */ jsxs(
7462
+ "div",
7463
+ {
7464
+ style: {
7465
+ display: "flex",
7466
+ justifyContent: "flex-end",
7467
+ gap: "12px",
7468
+ padding: "16px 20px",
7469
+ borderTop: `1px solid ${theme2.colors.border}`
7470
+ },
7471
+ children: [
7472
+ /* @__PURE__ */ jsx(
7473
+ "button",
7474
+ {
7475
+ type: "button",
7476
+ onClick: onClose,
7477
+ disabled: isSaving,
7478
+ style: {
7479
+ padding: "10px 20px",
7480
+ fontSize: theme2.fontSizes[2],
7481
+ fontWeight: 500,
7482
+ border: `1px solid ${theme2.colors.border}`,
7483
+ borderRadius: theme2.radii[2],
7484
+ backgroundColor: "transparent",
7485
+ color: theme2.colors.text,
7486
+ cursor: "pointer"
7487
+ },
7488
+ children: "Cancel"
7489
+ }
7490
+ ),
7491
+ /* @__PURE__ */ jsxs(
7492
+ "button",
7493
+ {
7494
+ type: "submit",
7495
+ disabled: isSaving,
7496
+ style: {
7497
+ display: "flex",
7498
+ alignItems: "center",
7499
+ gap: "8px",
7500
+ padding: "10px 20px",
7501
+ fontSize: theme2.fontSizes[2],
7502
+ fontWeight: 500,
7503
+ border: "none",
7504
+ borderRadius: theme2.radii[2],
7505
+ backgroundColor: theme2.colors.primary,
7506
+ color: "#fff",
7507
+ cursor: isSaving ? "wait" : "pointer",
7508
+ opacity: isSaving ? 0.7 : 1
7509
+ },
7510
+ children: [
7511
+ isSaving && /* @__PURE__ */ jsx(LoaderCircle, { size: 16, style: { animation: "spin 1s linear infinite" } }),
7512
+ isEditing ? "Save Changes" : "Create Task"
7513
+ ]
7514
+ }
7515
+ )
7516
+ ]
7517
+ }
7518
+ )
7519
+ ] })
7520
+ ]
7521
+ }
7522
+ ),
7523
+ /* @__PURE__ */ jsx("style", { children: `
7524
+ @keyframes spin {
7525
+ from { transform: rotate(0deg); }
7526
+ to { transform: rotate(360deg); }
7527
+ }
7528
+ ` })
7529
+ ]
7530
+ }
7531
+ );
7532
+ if (typeof document === "undefined") return null;
7533
+ return createPortal(modalContent, document.body);
7534
+ };
6833
7535
  const KanbanPanelContent = ({
6834
7536
  context,
6835
7537
  actions,
@@ -6842,6 +7544,8 @@ const KanbanPanelContent = ({
6842
7544
  const [isNarrowView, setIsNarrowView] = useState(false);
6843
7545
  const containerRef = useRef(null);
6844
7546
  const [activeTask, setActiveTask] = useState(null);
7547
+ const [isTaskModalOpen, setIsTaskModalOpen] = useState(false);
7548
+ const [editingTask, setEditingTask] = useState(void 0);
6845
7549
  const sensors = useSensors(
6846
7550
  useSensor(PointerSensor, {
6847
7551
  activationConstraint: {
@@ -6877,7 +7581,9 @@ const KanbanPanelContent = ({
6877
7581
  isBacklogProject,
6878
7582
  refreshData,
6879
7583
  moveTaskOptimistic,
6880
- getTaskById
7584
+ getTaskById,
7585
+ canWrite,
7586
+ core: core2
6881
7587
  } = useKanbanData({
6882
7588
  context,
6883
7589
  actions,
@@ -6972,14 +7678,38 @@ const KanbanPanelContent = ({
6972
7678
  normalize: (path2) => path2.replace(/\/+/g, "/"),
6973
7679
  homedir: () => "/"
6974
7680
  };
6975
- const core2 = new Core({
7681
+ const core22 = new Core({
6976
7682
  projectRoot: repoPath,
6977
7683
  adapters: { fs: fsAdapter }
6978
7684
  });
6979
7685
  const projectName = ((_b2 = context.currentScope.repository) == null ? void 0 : _b2.name) || "Backlog";
6980
- await core2.initProject({ projectName });
7686
+ await core22.initProject({ projectName });
6981
7687
  await refreshData();
6982
7688
  }, [fileSystem, context.currentScope.repository, refreshData]);
7689
+ const handleOpenNewTask = useCallback(() => {
7690
+ setEditingTask(void 0);
7691
+ setIsTaskModalOpen(true);
7692
+ }, []);
7693
+ useCallback((task) => {
7694
+ setEditingTask(task);
7695
+ setIsTaskModalOpen(true);
7696
+ }, []);
7697
+ const handleCloseTaskModal = useCallback(() => {
7698
+ setIsTaskModalOpen(false);
7699
+ setEditingTask(void 0);
7700
+ }, []);
7701
+ const handleSaveTask = useCallback(async (input) => {
7702
+ if (!core2) {
7703
+ throw new Error("Backlog not loaded");
7704
+ }
7705
+ if (editingTask) {
7706
+ await core2.updateTask(editingTask.id, input);
7707
+ } else {
7708
+ await core2.createTask(input);
7709
+ }
7710
+ await refreshData();
7711
+ }, [core2, editingTask, refreshData]);
7712
+ const availableStatuses = ["To Do", "In Progress", "Done"];
6983
7713
  return /* @__PURE__ */ jsxs(
6984
7714
  "div",
6985
7715
  {
@@ -7053,12 +7783,14 @@ const KanbanPanelContent = ({
7053
7783
  status
7054
7784
  );
7055
7785
  }) }),
7056
- activeTasksState.hasMore && /* @__PURE__ */ jsx(
7786
+ canWrite && /* @__PURE__ */ jsxs(
7057
7787
  "button",
7058
7788
  {
7059
- onClick: loadMoreActive,
7060
- disabled: activeTasksState.isLoadingMore,
7789
+ onClick: handleOpenNewTask,
7061
7790
  style: {
7791
+ display: "flex",
7792
+ alignItems: "center",
7793
+ gap: "6px",
7062
7794
  background: theme2.colors.primary,
7063
7795
  color: theme2.colors.background,
7064
7796
  border: "none",
@@ -7066,6 +7798,28 @@ const KanbanPanelContent = ({
7066
7798
  padding: "6px 12px",
7067
7799
  fontSize: theme2.fontSizes[1],
7068
7800
  fontWeight: theme2.fontWeights.medium,
7801
+ cursor: "pointer",
7802
+ transition: "opacity 0.2s ease"
7803
+ },
7804
+ children: [
7805
+ /* @__PURE__ */ jsx(Plus, { size: 14 }),
7806
+ "Add Task"
7807
+ ]
7808
+ }
7809
+ ),
7810
+ activeTasksState.hasMore && /* @__PURE__ */ jsx(
7811
+ "button",
7812
+ {
7813
+ onClick: loadMoreActive,
7814
+ disabled: activeTasksState.isLoadingMore,
7815
+ style: {
7816
+ background: theme2.colors.backgroundSecondary,
7817
+ color: theme2.colors.text,
7818
+ border: `1px solid ${theme2.colors.border}`,
7819
+ borderRadius: theme2.radii[2],
7820
+ padding: "6px 12px",
7821
+ fontSize: theme2.fontSizes[1],
7822
+ fontWeight: theme2.fontWeights.medium,
7069
7823
  cursor: activeTasksState.isLoadingMore ? "wait" : "pointer",
7070
7824
  opacity: activeTasksState.isLoadingMore ? 0.7 : 1,
7071
7825
  transition: "opacity 0.2s ease"
@@ -7247,6 +8001,17 @@ const KanbanPanelContent = ({
7247
8001
  )
7248
8002
  ]
7249
8003
  }
8004
+ ),
8005
+ /* @__PURE__ */ jsx(
8006
+ TaskModal,
8007
+ {
8008
+ isOpen: isTaskModalOpen,
8009
+ onClose: handleCloseTaskModal,
8010
+ onSave: handleSaveTask,
8011
+ task: editingTask,
8012
+ defaultStatus: "To Do",
8013
+ availableStatuses
8014
+ }
7250
8015
  )
7251
8016
  ]
7252
8017
  }
@@ -51590,6 +52355,7 @@ function useMilestoneData(options) {
51590
52355
  const [isLoading, setIsLoading] = useState(true);
51591
52356
  const [error, setError] = useState(null);
51592
52357
  const [isBacklogProject, setIsBacklogProject] = useState(false);
52358
+ const [canWrite, setCanWrite] = useState(false);
51593
52359
  const coreRef = useRef(null);
51594
52360
  const activeFilePathRef = useRef(null);
51595
52361
  const contextRef = useRef(context);
@@ -51629,7 +52395,7 @@ function useMilestoneData(options) {
51629
52395
  }, []);
51630
52396
  const fileTreeVersionRef = useRef(null);
51631
52397
  const loadMilestoneData = useCallback(async () => {
51632
- var _a, _b;
52398
+ var _a, _b, _c;
51633
52399
  if (!context || !actions) {
51634
52400
  console.log("[useMilestoneData] No context provided");
51635
52401
  setIsBacklogProject(false);
@@ -51661,7 +52427,8 @@ function useMilestoneData(options) {
51661
52427
  const filePaths = files.map((f) => f.path);
51662
52428
  const fs = new PanelFileSystemAdapter({
51663
52429
  fetchFile: fetchFileContent,
51664
- filePaths
52430
+ filePaths,
52431
+ hostFileSystem: (_c = context.adapters) == null ? void 0 : _c.fileSystem
51665
52432
  });
51666
52433
  const core2 = new Core({
51667
52434
  projectRoot: "",
@@ -51677,6 +52444,7 @@ function useMilestoneData(options) {
51677
52444
  }
51678
52445
  console.log("[useMilestoneData] Loading milestone data...");
51679
52446
  setIsBacklogProject(true);
52447
+ setCanWrite(fs.canWrite);
51680
52448
  await core2.initializeLazy(filePaths);
51681
52449
  coreRef.current = core2;
51682
52450
  console.log("[useMilestoneData] Core instance:", core2);
@@ -51784,7 +52552,10 @@ function useMilestoneData(options) {
51784
52552
  expandMilestone,
51785
52553
  collapseMilestone,
51786
52554
  toggleMilestone,
51787
- refreshData
52555
+ refreshData,
52556
+ // Write support
52557
+ canWrite,
52558
+ core: coreRef.current
51788
52559
  };
51789
52560
  }
51790
52561
  const MilestoneCard = ({
@@ -52137,6 +52908,307 @@ const MilestoneCard = ({
52137
52908
  }
52138
52909
  );
52139
52910
  };
52911
+ const MilestoneModal = ({
52912
+ isOpen,
52913
+ onClose,
52914
+ onSave,
52915
+ milestone
52916
+ }) => {
52917
+ const { theme: theme2 } = useTheme();
52918
+ const isEditing = !!milestone;
52919
+ const [title, setTitle] = useState("");
52920
+ const [description, setDescription] = useState("");
52921
+ const [isSaving, setIsSaving] = useState(false);
52922
+ const [error, setError] = useState(null);
52923
+ useEffect(() => {
52924
+ if (isOpen) {
52925
+ if (milestone) {
52926
+ setTitle(milestone.title || "");
52927
+ setDescription(milestone.description || "");
52928
+ } else {
52929
+ setTitle("");
52930
+ setDescription("");
52931
+ }
52932
+ setError(null);
52933
+ }
52934
+ }, [isOpen, milestone]);
52935
+ const handleSubmit = async (e) => {
52936
+ e.preventDefault();
52937
+ if (!title.trim()) {
52938
+ setError("Title is required");
52939
+ return;
52940
+ }
52941
+ setIsSaving(true);
52942
+ setError(null);
52943
+ try {
52944
+ if (isEditing) {
52945
+ const input = {
52946
+ title: title.trim(),
52947
+ description: description.trim() || void 0
52948
+ };
52949
+ await onSave(input);
52950
+ } else {
52951
+ const input = {
52952
+ title: title.trim(),
52953
+ description: description.trim() || void 0
52954
+ };
52955
+ await onSave(input);
52956
+ }
52957
+ onClose();
52958
+ } catch (err) {
52959
+ setError(err instanceof Error ? err.message : "Failed to save milestone");
52960
+ } finally {
52961
+ setIsSaving(false);
52962
+ }
52963
+ };
52964
+ if (!isOpen) return null;
52965
+ const modalContent = /* @__PURE__ */ jsxs(
52966
+ "div",
52967
+ {
52968
+ style: {
52969
+ position: "fixed",
52970
+ inset: 0,
52971
+ zIndex: 9999,
52972
+ display: "flex",
52973
+ alignItems: "center",
52974
+ justifyContent: "center",
52975
+ padding: "16px"
52976
+ },
52977
+ children: [
52978
+ /* @__PURE__ */ jsx(
52979
+ "div",
52980
+ {
52981
+ onClick: onClose,
52982
+ style: {
52983
+ position: "absolute",
52984
+ inset: 0,
52985
+ backgroundColor: "rgba(0, 0, 0, 0.5)"
52986
+ }
52987
+ }
52988
+ ),
52989
+ /* @__PURE__ */ jsxs(
52990
+ "div",
52991
+ {
52992
+ style: {
52993
+ position: "relative",
52994
+ width: "100%",
52995
+ maxWidth: "500px",
52996
+ maxHeight: "90vh",
52997
+ overflow: "auto",
52998
+ backgroundColor: theme2.colors.background,
52999
+ borderRadius: theme2.radii[3],
53000
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
53001
+ border: `1px solid ${theme2.colors.border}`
53002
+ },
53003
+ children: [
53004
+ /* @__PURE__ */ jsxs(
53005
+ "div",
53006
+ {
53007
+ style: {
53008
+ display: "flex",
53009
+ alignItems: "center",
53010
+ justifyContent: "space-between",
53011
+ padding: "16px 20px",
53012
+ borderBottom: `1px solid ${theme2.colors.border}`
53013
+ },
53014
+ children: [
53015
+ /* @__PURE__ */ jsx(
53016
+ "h2",
53017
+ {
53018
+ style: {
53019
+ margin: 0,
53020
+ fontSize: theme2.fontSizes[4],
53021
+ fontWeight: 600,
53022
+ color: theme2.colors.text
53023
+ },
53024
+ children: isEditing ? "Edit Milestone" : "New Milestone"
53025
+ }
53026
+ ),
53027
+ /* @__PURE__ */ jsx(
53028
+ "button",
53029
+ {
53030
+ onClick: onClose,
53031
+ style: {
53032
+ background: "none",
53033
+ border: "none",
53034
+ cursor: "pointer",
53035
+ padding: "4px",
53036
+ display: "flex",
53037
+ alignItems: "center",
53038
+ justifyContent: "center",
53039
+ borderRadius: theme2.radii[1],
53040
+ color: theme2.colors.textMuted
53041
+ },
53042
+ children: /* @__PURE__ */ jsx(X, { size: 20 })
53043
+ }
53044
+ )
53045
+ ]
53046
+ }
53047
+ ),
53048
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
53049
+ /* @__PURE__ */ jsxs("div", { style: { padding: "20px", display: "flex", flexDirection: "column", gap: "16px" }, children: [
53050
+ /* @__PURE__ */ jsxs("div", { children: [
53051
+ /* @__PURE__ */ jsx(
53052
+ "label",
53053
+ {
53054
+ style: {
53055
+ display: "block",
53056
+ marginBottom: "6px",
53057
+ fontSize: theme2.fontSizes[1],
53058
+ fontWeight: 500,
53059
+ color: theme2.colors.text
53060
+ },
53061
+ children: "Title *"
53062
+ }
53063
+ ),
53064
+ /* @__PURE__ */ jsx(
53065
+ "input",
53066
+ {
53067
+ type: "text",
53068
+ value: title,
53069
+ onChange: (e) => setTitle(e.target.value),
53070
+ placeholder: "Enter milestone title",
53071
+ autoFocus: true,
53072
+ style: {
53073
+ width: "100%",
53074
+ padding: "10px 12px",
53075
+ fontSize: theme2.fontSizes[2],
53076
+ border: `1px solid ${theme2.colors.border}`,
53077
+ borderRadius: theme2.radii[2],
53078
+ backgroundColor: theme2.colors.backgroundSecondary,
53079
+ color: theme2.colors.text,
53080
+ outline: "none",
53081
+ boxSizing: "border-box"
53082
+ }
53083
+ }
53084
+ )
53085
+ ] }),
53086
+ /* @__PURE__ */ jsxs("div", { children: [
53087
+ /* @__PURE__ */ jsx(
53088
+ "label",
53089
+ {
53090
+ style: {
53091
+ display: "block",
53092
+ marginBottom: "6px",
53093
+ fontSize: theme2.fontSizes[1],
53094
+ fontWeight: 500,
53095
+ color: theme2.colors.text
53096
+ },
53097
+ children: "Description"
53098
+ }
53099
+ ),
53100
+ /* @__PURE__ */ jsx(
53101
+ "textarea",
53102
+ {
53103
+ value: description,
53104
+ onChange: (e) => setDescription(e.target.value),
53105
+ placeholder: "Enter milestone description (markdown supported)",
53106
+ rows: 4,
53107
+ style: {
53108
+ width: "100%",
53109
+ padding: "10px 12px",
53110
+ fontSize: theme2.fontSizes[2],
53111
+ border: `1px solid ${theme2.colors.border}`,
53112
+ borderRadius: theme2.radii[2],
53113
+ backgroundColor: theme2.colors.backgroundSecondary,
53114
+ color: theme2.colors.text,
53115
+ outline: "none",
53116
+ resize: "vertical",
53117
+ fontFamily: theme2.fonts.body,
53118
+ boxSizing: "border-box"
53119
+ }
53120
+ }
53121
+ )
53122
+ ] }),
53123
+ error && /* @__PURE__ */ jsx(
53124
+ "div",
53125
+ {
53126
+ style: {
53127
+ padding: "10px 12px",
53128
+ backgroundColor: `${theme2.colors.error}15`,
53129
+ border: `1px solid ${theme2.colors.error}`,
53130
+ borderRadius: theme2.radii[2],
53131
+ color: theme2.colors.error,
53132
+ fontSize: theme2.fontSizes[1]
53133
+ },
53134
+ children: error
53135
+ }
53136
+ )
53137
+ ] }),
53138
+ /* @__PURE__ */ jsxs(
53139
+ "div",
53140
+ {
53141
+ style: {
53142
+ display: "flex",
53143
+ justifyContent: "flex-end",
53144
+ gap: "12px",
53145
+ padding: "16px 20px",
53146
+ borderTop: `1px solid ${theme2.colors.border}`
53147
+ },
53148
+ children: [
53149
+ /* @__PURE__ */ jsx(
53150
+ "button",
53151
+ {
53152
+ type: "button",
53153
+ onClick: onClose,
53154
+ disabled: isSaving,
53155
+ style: {
53156
+ padding: "10px 20px",
53157
+ fontSize: theme2.fontSizes[2],
53158
+ fontWeight: 500,
53159
+ border: `1px solid ${theme2.colors.border}`,
53160
+ borderRadius: theme2.radii[2],
53161
+ backgroundColor: "transparent",
53162
+ color: theme2.colors.text,
53163
+ cursor: "pointer"
53164
+ },
53165
+ children: "Cancel"
53166
+ }
53167
+ ),
53168
+ /* @__PURE__ */ jsxs(
53169
+ "button",
53170
+ {
53171
+ type: "submit",
53172
+ disabled: isSaving,
53173
+ style: {
53174
+ display: "flex",
53175
+ alignItems: "center",
53176
+ gap: "8px",
53177
+ padding: "10px 20px",
53178
+ fontSize: theme2.fontSizes[2],
53179
+ fontWeight: 500,
53180
+ border: "none",
53181
+ borderRadius: theme2.radii[2],
53182
+ backgroundColor: theme2.colors.primary,
53183
+ color: "#fff",
53184
+ cursor: isSaving ? "wait" : "pointer",
53185
+ opacity: isSaving ? 0.7 : 1
53186
+ },
53187
+ children: [
53188
+ isSaving && /* @__PURE__ */ jsx(LoaderCircle, { size: 16, style: { animation: "spin 1s linear infinite" } }),
53189
+ isEditing ? "Save Changes" : "Create Milestone"
53190
+ ]
53191
+ }
53192
+ )
53193
+ ]
53194
+ }
53195
+ )
53196
+ ] })
53197
+ ]
53198
+ }
53199
+ ),
53200
+ /* @__PURE__ */ jsx("style", { children: `
53201
+ @keyframes spin {
53202
+ from { transform: rotate(0deg); }
53203
+ to { transform: rotate(360deg); }
53204
+ }
53205
+ ` })
53206
+ ]
53207
+ }
53208
+ );
53209
+ if (typeof document === "undefined") return null;
53210
+ return createPortal(modalContent, document.body);
53211
+ };
52140
53212
  const MilestonePanelContent = ({
52141
53213
  context,
52142
53214
  actions,
@@ -52144,13 +53216,17 @@ const MilestonePanelContent = ({
52144
53216
  }) => {
52145
53217
  const { theme: theme2 } = useTheme();
52146
53218
  const [isRefreshing, setIsRefreshing] = useState(false);
53219
+ const [isMilestoneModalOpen, setIsMilestoneModalOpen] = useState(false);
53220
+ const [editingMilestone, setEditingMilestone] = useState(void 0);
52147
53221
  const {
52148
53222
  milestones,
52149
53223
  isLoading,
52150
53224
  error,
52151
53225
  isBacklogProject,
52152
53226
  toggleMilestone,
52153
- refreshData
53227
+ refreshData,
53228
+ canWrite,
53229
+ core: core2
52154
53230
  } = useMilestoneData({
52155
53231
  context,
52156
53232
  actions
@@ -52173,6 +53249,29 @@ const MilestonePanelContent = ({
52173
53249
  setIsRefreshing(false);
52174
53250
  }
52175
53251
  };
53252
+ const handleOpenNewMilestone = useCallback(() => {
53253
+ setEditingMilestone(void 0);
53254
+ setIsMilestoneModalOpen(true);
53255
+ }, []);
53256
+ useCallback((milestone) => {
53257
+ setEditingMilestone(milestone);
53258
+ setIsMilestoneModalOpen(true);
53259
+ }, []);
53260
+ const handleCloseMilestoneModal = useCallback(() => {
53261
+ setIsMilestoneModalOpen(false);
53262
+ setEditingMilestone(void 0);
53263
+ }, []);
53264
+ const handleSaveMilestone = useCallback(async (input) => {
53265
+ if (!core2) {
53266
+ throw new Error("Backlog not loaded");
53267
+ }
53268
+ if (editingMilestone) {
53269
+ await core2.updateMilestone(editingMilestone.id, input);
53270
+ } else {
53271
+ await core2.createMilestone(input);
53272
+ }
53273
+ await refreshData();
53274
+ }, [core2, editingMilestone, refreshData]);
52176
53275
  const totalMilestones = milestones.length;
52177
53276
  const totalTasks = milestones.reduce((sum, m) => sum + m.milestone.tasks.length, 0);
52178
53277
  return /* @__PURE__ */ jsxs(
@@ -52239,6 +53338,30 @@ const MilestonePanelContent = ({
52239
53338
  ]
52240
53339
  }
52241
53340
  ),
53341
+ canWrite && /* @__PURE__ */ jsxs(
53342
+ "button",
53343
+ {
53344
+ onClick: handleOpenNewMilestone,
53345
+ style: {
53346
+ display: "flex",
53347
+ alignItems: "center",
53348
+ gap: "6px",
53349
+ background: theme2.colors.primary,
53350
+ color: theme2.colors.background,
53351
+ border: "none",
53352
+ borderRadius: theme2.radii[2],
53353
+ padding: "6px 12px",
53354
+ fontSize: theme2.fontSizes[1],
53355
+ fontWeight: theme2.fontWeights.medium,
53356
+ cursor: "pointer",
53357
+ transition: "opacity 0.2s ease"
53358
+ },
53359
+ children: [
53360
+ /* @__PURE__ */ jsx(Plus, { size: 14 }),
53361
+ "Add Milestone"
53362
+ ]
53363
+ }
53364
+ ),
52242
53365
  /* @__PURE__ */ jsx(
52243
53366
  "button",
52244
53367
  {
@@ -52373,7 +53496,16 @@ const MilestonePanelContent = ({
52373
53496
  @keyframes spin {
52374
53497
  to { transform: rotate(360deg); }
52375
53498
  }
52376
- ` })
53499
+ ` }),
53500
+ /* @__PURE__ */ jsx(
53501
+ MilestoneModal,
53502
+ {
53503
+ isOpen: isMilestoneModalOpen,
53504
+ onClose: handleCloseMilestoneModal,
53505
+ onSave: handleSaveMilestone,
53506
+ milestone: editingMilestone
53507
+ }
53508
+ )
52377
53509
  ]
52378
53510
  }
52379
53511
  );