@industry-theme/backlogmd-kanban-panel 1.0.14 → 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.
@@ -4419,9 +4419,9 @@ function parseArrayValue(value) {
4419
4419
  function parseAcceptanceCriteria(content2) {
4420
4420
  const criteria = [];
4421
4421
  const checkboxPattern = /^-\s*\[([ xX])\]\s*(.+)$/gm;
4422
- let match;
4422
+ const matches = content2.matchAll(checkboxPattern);
4423
4423
  let index2 = 1;
4424
- while ((match = checkboxPattern.exec(content2)) !== null) {
4424
+ for (const match of matches) {
4425
4425
  criteria.push({
4426
4426
  index: index2++,
4427
4427
  checked: match[1].toLowerCase() === "x",
@@ -4435,9 +4435,9 @@ function extractDescription(content2, title) {
4435
4435
  if (title) {
4436
4436
  body = body.replace(new RegExp(`^#\\s+${escapeRegex(title)}\\s*$`, "m"), "");
4437
4437
  }
4438
- body = body.replace(/^##\s+Acceptance Criteria[\s\S]*?(?=^##|\z)/m, "");
4439
- body = body.replace(/^##\s+Implementation Plan[\s\S]*?(?=^##|\z)/m, "");
4440
- 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, "");
4441
4441
  return body.trim();
4442
4442
  }
4443
4443
  function extractIdFromPath(filePath) {
@@ -4546,6 +4546,184 @@ function extractMilestoneIdFromFilename(filename) {
4546
4546
  const match = filename.match(/^(m-\d+)/);
4547
4547
  return match ? match[1] : null;
4548
4548
  }
4549
+ const NO_MILESTONE_KEY = "__none";
4550
+ function normalizeMilestoneName(name2) {
4551
+ return name2.trim();
4552
+ }
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";
4563
+ }
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);
4582
+ }
4583
+ for (const task of tasks) {
4584
+ addMilestone(task.milestone ?? "");
4585
+ }
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);
4603
+ }
4604
+ for (const task of tasks) {
4605
+ addMilestone(task.milestone ?? "");
4606
+ }
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;
4618
+ }
4619
+ for (const task of bucketTasks) {
4620
+ const status = task.status ?? "";
4621
+ counts[status] = (counts[status] ?? 0) + 1;
4622
+ }
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
+ };
4666
+ }
4667
+ const PRIORITY_ORDER = {
4668
+ high: 0,
4669
+ medium: 1,
4670
+ low: 2
4671
+ };
4672
+ function sortTasksByTitle(tasks, direction = "asc") {
4673
+ return [...tasks].sort((a, b) => {
4674
+ const cmp = a.title.localeCompare(b.title);
4675
+ return direction === "asc" ? cmp : -cmp;
4676
+ });
4677
+ }
4678
+ function sortTasksBy(tasks, sortBy = "title", direction = "asc") {
4679
+ switch (sortBy) {
4680
+ case "title":
4681
+ return sortTasksByTitle(tasks, direction);
4682
+ case "createdDate":
4683
+ return [...tasks].sort((a, b) => {
4684
+ const cmp = a.createdDate.localeCompare(b.createdDate);
4685
+ return direction === "asc" ? cmp : -cmp;
4686
+ });
4687
+ default: {
4688
+ const sorted = sortTasks(tasks);
4689
+ return direction === "desc" ? sorted.reverse() : sorted;
4690
+ }
4691
+ }
4692
+ }
4693
+ function sortTasks(tasks) {
4694
+ return [...tasks].sort((a, b) => {
4695
+ if (a.ordinal !== void 0 && b.ordinal !== void 0) {
4696
+ return a.ordinal - b.ordinal;
4697
+ }
4698
+ if (a.ordinal !== void 0)
4699
+ return -1;
4700
+ if (b.ordinal !== void 0)
4701
+ return 1;
4702
+ const aPri = a.priority ? PRIORITY_ORDER[a.priority] : 3;
4703
+ const bPri = b.priority ? PRIORITY_ORDER[b.priority] : 3;
4704
+ if (aPri !== bPri)
4705
+ return aPri - bPri;
4706
+ return b.createdDate.localeCompare(a.createdDate);
4707
+ });
4708
+ }
4709
+ function groupTasksByStatus(tasks, statuses) {
4710
+ const grouped = /* @__PURE__ */ new Map();
4711
+ for (const status of statuses) {
4712
+ grouped.set(status, []);
4713
+ }
4714
+ for (const task of tasks) {
4715
+ const list2 = grouped.get(task.status);
4716
+ if (list2) {
4717
+ list2.push(task);
4718
+ } else {
4719
+ grouped.set(task.status, [task]);
4720
+ }
4721
+ }
4722
+ for (const [status, statusTasks] of grouped) {
4723
+ grouped.set(status, sortTasks(statusTasks));
4724
+ }
4725
+ return grouped;
4726
+ }
4549
4727
  const DEFAULT_STATUSES = ["To Do", "In Progress", "Done"];
4550
4728
  function parseBacklogConfig(content2) {
4551
4729
  const config = {};
@@ -4696,185 +4874,6 @@ function serializeBacklogConfig(config) {
4696
4874
  return `${lines.join("\n")}
4697
4875
  `;
4698
4876
  }
4699
- const PRIORITY_ORDER = {
4700
- high: 0,
4701
- medium: 1,
4702
- low: 2
4703
- };
4704
- function sortTasksByTitle(tasks, direction = "asc") {
4705
- return [...tasks].sort((a, b) => {
4706
- const cmp = a.title.localeCompare(b.title);
4707
- return direction === "asc" ? cmp : -cmp;
4708
- });
4709
- }
4710
- function sortTasksBy(tasks, sortBy = "title", direction = "asc") {
4711
- switch (sortBy) {
4712
- case "title":
4713
- return sortTasksByTitle(tasks, direction);
4714
- case "createdDate":
4715
- return [...tasks].sort((a, b) => {
4716
- const cmp = a.createdDate.localeCompare(b.createdDate);
4717
- return direction === "asc" ? cmp : -cmp;
4718
- });
4719
- case "priority":
4720
- case "ordinal":
4721
- default:
4722
- const sorted = sortTasks(tasks);
4723
- return direction === "desc" ? sorted.reverse() : sorted;
4724
- }
4725
- }
4726
- function sortTasks(tasks) {
4727
- return [...tasks].sort((a, b) => {
4728
- if (a.ordinal !== void 0 && b.ordinal !== void 0) {
4729
- return a.ordinal - b.ordinal;
4730
- }
4731
- if (a.ordinal !== void 0)
4732
- return -1;
4733
- if (b.ordinal !== void 0)
4734
- return 1;
4735
- const aPri = a.priority ? PRIORITY_ORDER[a.priority] : 3;
4736
- const bPri = b.priority ? PRIORITY_ORDER[b.priority] : 3;
4737
- if (aPri !== bPri)
4738
- return aPri - bPri;
4739
- return b.createdDate.localeCompare(a.createdDate);
4740
- });
4741
- }
4742
- function groupTasksByStatus(tasks, statuses) {
4743
- const grouped = /* @__PURE__ */ new Map();
4744
- for (const status of statuses) {
4745
- grouped.set(status, []);
4746
- }
4747
- for (const task of tasks) {
4748
- const list2 = grouped.get(task.status);
4749
- if (list2) {
4750
- list2.push(task);
4751
- } else {
4752
- grouped.set(task.status, [task]);
4753
- }
4754
- }
4755
- for (const [status, statusTasks] of grouped) {
4756
- grouped.set(status, sortTasks(statusTasks));
4757
- }
4758
- return grouped;
4759
- }
4760
- const NO_MILESTONE_KEY = "__none";
4761
- function normalizeMilestoneName(name2) {
4762
- return name2.trim();
4763
- }
4764
- function milestoneKey(name2) {
4765
- return normalizeMilestoneName(name2 ?? "").toLowerCase();
4766
- }
4767
- function isDoneStatus(status) {
4768
- const normalized = (status ?? "").toLowerCase();
4769
- return normalized.includes("done") || normalized.includes("complete");
4770
- }
4771
- function getMilestoneLabel(milestoneId, milestoneEntities) {
4772
- if (!milestoneId) {
4773
- return "Tasks without milestone";
4774
- }
4775
- const entity = milestoneEntities.find((m) => milestoneKey(m.id) === milestoneKey(milestoneId));
4776
- return (entity == null ? void 0 : entity.title) || milestoneId;
4777
- }
4778
- function collectMilestoneIds(tasks, milestoneEntities) {
4779
- const merged = [];
4780
- const seen = /* @__PURE__ */ new Set();
4781
- const addMilestone = (value) => {
4782
- const normalized = normalizeMilestoneName(value);
4783
- if (!normalized)
4784
- return;
4785
- const key2 = milestoneKey(normalized);
4786
- if (seen.has(key2))
4787
- return;
4788
- seen.add(key2);
4789
- merged.push(normalized);
4790
- };
4791
- for (const entity of milestoneEntities) {
4792
- addMilestone(entity.id);
4793
- }
4794
- for (const task of tasks) {
4795
- addMilestone(task.milestone ?? "");
4796
- }
4797
- return merged;
4798
- }
4799
- function collectMilestones(tasks, configMilestones) {
4800
- const merged = [];
4801
- const seen = /* @__PURE__ */ new Set();
4802
- const addMilestone = (value) => {
4803
- const normalized = normalizeMilestoneName(value);
4804
- if (!normalized)
4805
- return;
4806
- const key2 = milestoneKey(normalized);
4807
- if (seen.has(key2))
4808
- return;
4809
- seen.add(key2);
4810
- merged.push(normalized);
4811
- };
4812
- for (const m of configMilestones) {
4813
- addMilestone(m);
4814
- }
4815
- for (const task of tasks) {
4816
- addMilestone(task.milestone ?? "");
4817
- }
4818
- return merged;
4819
- }
4820
- function createBucket(milestoneId, tasks, statuses, milestoneEntities, isNoMilestone) {
4821
- const bucketMilestoneKey = milestoneKey(milestoneId);
4822
- const bucketTasks = tasks.filter((task) => {
4823
- const taskMilestoneKey = milestoneKey(task.milestone);
4824
- return bucketMilestoneKey ? taskMilestoneKey === bucketMilestoneKey : !taskMilestoneKey;
4825
- });
4826
- const counts = {};
4827
- for (const status of statuses) {
4828
- counts[status] = 0;
4829
- }
4830
- for (const task of bucketTasks) {
4831
- const status = task.status ?? "";
4832
- counts[status] = (counts[status] ?? 0) + 1;
4833
- }
4834
- const doneCount = bucketTasks.filter((t) => isDoneStatus(t.status)).length;
4835
- const progress = bucketTasks.length > 0 ? Math.round(doneCount / bucketTasks.length * 100) : 0;
4836
- const key2 = bucketMilestoneKey ? bucketMilestoneKey : NO_MILESTONE_KEY;
4837
- const label = getMilestoneLabel(milestoneId, milestoneEntities);
4838
- return {
4839
- key: key2,
4840
- label,
4841
- milestone: milestoneId,
4842
- isNoMilestone,
4843
- tasks: bucketTasks,
4844
- statusCounts: counts,
4845
- total: bucketTasks.length,
4846
- doneCount,
4847
- progress
4848
- };
4849
- }
4850
- function buildMilestoneBuckets(tasks, milestoneEntities, statuses) {
4851
- const allMilestoneIds = collectMilestoneIds(tasks, milestoneEntities);
4852
- const buckets = [
4853
- // "No milestone" bucket first
4854
- createBucket(void 0, tasks, statuses, milestoneEntities, true),
4855
- // Then each milestone bucket
4856
- ...allMilestoneIds.map((m) => createBucket(m, tasks, statuses, milestoneEntities, false))
4857
- ];
4858
- return buckets;
4859
- }
4860
- function buildMilestoneBucketsFromConfig(tasks, configMilestones, statuses) {
4861
- const milestoneEntities = configMilestones.map((id) => ({
4862
- id,
4863
- title: id,
4864
- description: "",
4865
- rawContent: "",
4866
- tasks: []
4867
- }));
4868
- return buildMilestoneBuckets(tasks, milestoneEntities, statuses);
4869
- }
4870
- function groupTasksByMilestone(tasks, configMilestones, statuses) {
4871
- const milestones = collectMilestones(tasks, configMilestones);
4872
- const buckets = buildMilestoneBucketsFromConfig(tasks, configMilestones, statuses);
4873
- return {
4874
- milestones,
4875
- buckets
4876
- };
4877
- }
4878
4877
  class Core {
4879
4878
  constructor(options) {
4880
4879
  __publicField(this, "projectRoot");
@@ -5067,7 +5066,7 @@ class Core {
5067
5066
  const tasksLimit = (options == null ? void 0 : options.tasksLimit) ?? 10;
5068
5067
  const completedLimit = (options == null ? void 0 : options.completedLimit) ?? 10;
5069
5068
  const offset = (options == null ? void 0 : options.offset) ?? 0;
5070
- (options == null ? void 0 : options.tasksSortDirection) ?? "asc";
5069
+ const tasksSortDirection = (options == null ? void 0 : options.tasksSortDirection) ?? "asc";
5071
5070
  const completedSortByIdDesc = (options == null ? void 0 : options.completedSortByIdDesc) ?? true;
5072
5071
  const sources = ["tasks", "completed"];
5073
5072
  const bySource = /* @__PURE__ */ new Map();
@@ -5077,7 +5076,11 @@ class Core {
5077
5076
  entries = entries.sort((a, b) => {
5078
5077
  const aNum = parseInt(a.id.replace(/\D/g, ""), 10) || 0;
5079
5078
  const bNum = parseInt(b.id.replace(/\D/g, ""), 10) || 0;
5080
- 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
+ }
5081
5084
  });
5082
5085
  const total = entries.length;
5083
5086
  const pageEntries = entries.slice(offset, offset + limit);
@@ -5108,13 +5111,17 @@ class Core {
5108
5111
  throw new Error("Core not lazy initialized. Call initializeLazy() first.");
5109
5112
  }
5110
5113
  const limit = (options == null ? void 0 : options.limit) ?? 10;
5111
- (options == null ? void 0 : options.sortDirection) ?? "asc";
5114
+ const sortDirection = (options == null ? void 0 : options.sortDirection) ?? "asc";
5112
5115
  const completedSortByIdDesc = (options == null ? void 0 : options.completedSortByIdDesc) ?? true;
5113
5116
  let entries = Array.from(this.taskIndex.values()).filter((e) => e.source === source2);
5114
5117
  entries = entries.sort((a, b) => {
5115
5118
  const aNum = parseInt(a.id.replace(/\D/g, ""), 10) || 0;
5116
5119
  const bNum = parseInt(b.id.replace(/\D/g, ""), 10) || 0;
5117
- 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
+ }
5118
5125
  });
5119
5126
  const total = entries.length;
5120
5127
  const pageEntries = entries.slice(currentOffset, currentOffset + limit);
@@ -5134,7 +5141,7 @@ class Core {
5134
5141
  */
5135
5142
  getConfig() {
5136
5143
  this.ensureInitialized();
5137
- return this.config;
5144
+ return this.safeConfig;
5138
5145
  }
5139
5146
  /**
5140
5147
  * List all tasks, optionally filtered
@@ -5149,7 +5156,8 @@ class Core {
5149
5156
  tasks = tasks.filter((t) => t.status === filter.status);
5150
5157
  }
5151
5158
  if (filter == null ? void 0 : filter.assignee) {
5152
- tasks = tasks.filter((t) => t.assignee.includes(filter.assignee));
5159
+ const assignee = filter.assignee;
5160
+ tasks = tasks.filter((t) => t.assignee.includes(assignee));
5153
5161
  }
5154
5162
  if (filter == null ? void 0 : filter.priority) {
5155
5163
  tasks = tasks.filter((t) => t.priority === filter.priority);
@@ -5159,7 +5167,10 @@ class Core {
5159
5167
  tasks = tasks.filter((t) => milestoneKey(t.milestone) === filterKey);
5160
5168
  }
5161
5169
  if ((filter == null ? void 0 : filter.labels) && filter.labels.length > 0) {
5162
- 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
+ });
5163
5174
  }
5164
5175
  if (filter == null ? void 0 : filter.parentTaskId) {
5165
5176
  tasks = tasks.filter((t) => t.parentTaskId === filter.parentTaskId);
@@ -5176,7 +5187,7 @@ class Core {
5176
5187
  getTasksByStatus() {
5177
5188
  this.ensureInitialized();
5178
5189
  const tasks = Array.from(this.tasks.values());
5179
- return groupTasksByStatus(tasks, this.config.statuses);
5190
+ return groupTasksByStatus(tasks, this.safeConfig.statuses);
5180
5191
  }
5181
5192
  /**
5182
5193
  * Get tasks grouped by milestone
@@ -5200,7 +5211,7 @@ class Core {
5200
5211
  getTasksByMilestone() {
5201
5212
  this.ensureInitialized();
5202
5213
  const tasks = Array.from(this.tasks.values());
5203
- return groupTasksByMilestone(tasks, this.config.milestones, this.config.statuses);
5214
+ return groupTasksByMilestone(tasks, this.safeConfig.milestones, this.safeConfig.statuses);
5204
5215
  }
5205
5216
  // =========================================================================
5206
5217
  // Milestone CRUD Operations
@@ -5426,7 +5437,7 @@ class Core {
5426
5437
  const sortDirection = (pagination == null ? void 0 : pagination.sortDirection) ?? "asc";
5427
5438
  const byStatus = /* @__PURE__ */ new Map();
5428
5439
  const allGrouped = /* @__PURE__ */ new Map();
5429
- for (const status of this.config.statuses) {
5440
+ for (const status of this.safeConfig.statuses) {
5430
5441
  allGrouped.set(status, []);
5431
5442
  }
5432
5443
  for (const task of this.tasks.values()) {
@@ -5437,7 +5448,7 @@ class Core {
5437
5448
  allGrouped.set(task.status, [task]);
5438
5449
  }
5439
5450
  }
5440
- for (const status of this.config.statuses) {
5451
+ for (const status of this.safeConfig.statuses) {
5441
5452
  let tasks = allGrouped.get(status) ?? [];
5442
5453
  tasks = sortTasksBy(tasks, sortBy, sortDirection);
5443
5454
  const total = tasks.length;
@@ -5452,7 +5463,7 @@ class Core {
5452
5463
  }
5453
5464
  return {
5454
5465
  byStatus,
5455
- statuses: this.config.statuses
5466
+ statuses: this.safeConfig.statuses
5456
5467
  };
5457
5468
  }
5458
5469
  /**
@@ -5492,10 +5503,16 @@ class Core {
5492
5503
  }
5493
5504
  // --- Private methods ---
5494
5505
  ensureInitialized() {
5495
- if (!this.initialized) {
5496
- 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.");
5497
5508
  }
5498
5509
  }
5510
+ /**
5511
+ * Get config with type safety (use after ensureInitialized)
5512
+ */
5513
+ get safeConfig() {
5514
+ return this.config;
5515
+ }
5499
5516
  applyFilters(tasks, filter) {
5500
5517
  if (!filter)
5501
5518
  return tasks;
@@ -5504,7 +5521,8 @@ class Core {
5504
5521
  result = result.filter((t) => t.status === filter.status);
5505
5522
  }
5506
5523
  if (filter.assignee) {
5507
- result = result.filter((t) => t.assignee.includes(filter.assignee));
5524
+ const assignee = filter.assignee;
5525
+ result = result.filter((t) => t.assignee.includes(assignee));
5508
5526
  }
5509
5527
  if (filter.priority) {
5510
5528
  result = result.filter((t) => t.priority === filter.priority);
@@ -5514,7 +5532,10 @@ class Core {
5514
5532
  result = result.filter((t) => milestoneKey(t.milestone) === filterKey);
5515
5533
  }
5516
5534
  if (filter.labels && filter.labels.length > 0) {
5517
- 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
+ });
5518
5539
  }
5519
5540
  if (filter.parentTaskId) {
5520
5541
  result = result.filter((t) => t.parentTaskId === filter.parentTaskId);
@@ -5611,6 +5632,12 @@ class Core {
5611
5632
  getTasksDir() {
5612
5633
  return this.fs.join(this.projectRoot, "backlog", "tasks");
5613
5634
  }
5635
+ /**
5636
+ * Get the completed directory path
5637
+ */
5638
+ getCompletedDir() {
5639
+ return this.fs.join(this.projectRoot, "backlog", "completed");
5640
+ }
5614
5641
  // =========================================================================
5615
5642
  // Task CRUD Operations
5616
5643
  // =========================================================================
@@ -5621,18 +5648,18 @@ class Core {
5621
5648
  * @returns Created task
5622
5649
  */
5623
5650
  async createTask(input) {
5624
- var _a;
5651
+ var _a, _b;
5625
5652
  this.ensureInitialized();
5626
5653
  const tasksDir = this.getTasksDir();
5627
5654
  await this.fs.createDir(tasksDir, { recursive: true });
5628
- 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));
5629
5656
  const nextId = existingIds.length > 0 ? Math.max(...existingIds) + 1 : 1;
5630
5657
  const taskId = String(nextId);
5631
5658
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
5632
5659
  const task = {
5633
5660
  id: taskId,
5634
5661
  title: input.title,
5635
- status: input.status || this.config.defaultStatus || "To Do",
5662
+ status: input.status || ((_a = this.config) == null ? void 0 : _a.defaultStatus) || "To Do",
5636
5663
  priority: input.priority,
5637
5664
  assignee: input.assignee || [],
5638
5665
  createdDate: now,
@@ -5643,7 +5670,7 @@ class Core {
5643
5670
  description: input.description,
5644
5671
  implementationPlan: input.implementationPlan,
5645
5672
  implementationNotes: input.implementationNotes,
5646
- acceptanceCriteriaItems: (_a = input.acceptanceCriteria) == null ? void 0 : _a.map((ac, i) => ({
5673
+ acceptanceCriteriaItems: (_b = input.acceptanceCriteria) == null ? void 0 : _b.map((ac, i) => ({
5647
5674
  index: i + 1,
5648
5675
  text: ac.text,
5649
5676
  checked: ac.checked || false
@@ -5699,19 +5726,23 @@ class Core {
5699
5726
  updated.labels = [.../* @__PURE__ */ new Set([...updated.labels, ...input.addLabels])];
5700
5727
  }
5701
5728
  if (input.removeLabels) {
5702
- 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
+ });
5703
5733
  }
5704
5734
  }
5705
5735
  if (input.assignee) {
5706
5736
  updated.assignee = input.assignee;
5707
5737
  }
5708
5738
  if (input.addDependencies) {
5709
- updated.dependencies = [
5710
- .../* @__PURE__ */ new Set([...updated.dependencies, ...input.addDependencies])
5711
- ];
5739
+ updated.dependencies = [.../* @__PURE__ */ new Set([...updated.dependencies, ...input.addDependencies])];
5712
5740
  }
5713
5741
  if (input.removeDependencies) {
5714
- 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
+ });
5715
5746
  }
5716
5747
  if (input.acceptanceCriteria) {
5717
5748
  updated.acceptanceCriteriaItems = input.acceptanceCriteria.map((ac, i) => ({
@@ -5767,6 +5798,92 @@ class Core {
5767
5798
  this.tasks.delete(id);
5768
5799
  return true;
5769
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
+ }
5770
5887
  /**
5771
5888
  * Load specific tasks by their IDs (for lazy loading milestone tasks)
5772
5889
  *