aitasks 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +216 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1890,7 +1890,7 @@ var require_commander = __commonJS((exports) => {
1890
1890
  var require_package = __commonJS((exports, module) => {
1891
1891
  module.exports = {
1892
1892
  name: "aitasks",
1893
- version: "1.1.1",
1893
+ version: "1.2.1",
1894
1894
  description: "CLI task management tool built for AI agents",
1895
1895
  type: "module",
1896
1896
  bin: {
@@ -41438,8 +41438,9 @@ function buildTree(tasks) {
41438
41438
  push(sub, 1, i === subs.length - 1, "middle", false);
41439
41439
  });
41440
41440
  }
41441
+ const doneSorted = sorted.filter((t) => t.status === "done").sort((a2, b2) => (b2.completed_at ?? b2.created_at) - (a2.completed_at ?? a2.created_at));
41441
41442
  let firstDone = true;
41442
- for (const task of sorted.filter((t) => t.status === "done")) {
41443
+ for (const task of doneSorted) {
41443
41444
  if (shownIds.has(task.id))
41444
41445
  continue;
41445
41446
  push(task, 0, false, "done", firstDone);
@@ -41663,6 +41664,70 @@ var RightPane = ({ task, width, height, scrollOffset }) => {
41663
41664
  }, i, true, undefined, this))
41664
41665
  }, undefined, false, undefined, this);
41665
41666
  };
41667
+ var PICKER_STATUSES = ["backlog", "ready", "in_progress", "blocked", "needs_review", "done"];
41668
+ var StatusPicker = ({ task }) => /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
41669
+ flexDirection: "column",
41670
+ paddingLeft: 2,
41671
+ paddingTop: 1,
41672
+ children: [
41673
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41674
+ children: [
41675
+ "Change status for ",
41676
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41677
+ bold: true,
41678
+ color: "cyan",
41679
+ children: task.id
41680
+ }, undefined, false, undefined, this)
41681
+ ]
41682
+ }, undefined, true, undefined, this),
41683
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41684
+ dimColor: true,
41685
+ children: "\u2500".repeat(36)
41686
+ }, undefined, false, undefined, this),
41687
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
41688
+ marginTop: 1,
41689
+ flexDirection: "column",
41690
+ children: PICKER_STATUSES.map((status, i) => {
41691
+ const isCurrent = task.status === status;
41692
+ const sc = STATUS_COLORS3[status];
41693
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
41694
+ children: [
41695
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41696
+ color: isCurrent ? "cyan" : "gray",
41697
+ children: [
41698
+ i + 1,
41699
+ " "
41700
+ ]
41701
+ }, undefined, true, undefined, this),
41702
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41703
+ color: sc,
41704
+ children: [
41705
+ STATUS_ICON[status],
41706
+ " "
41707
+ ]
41708
+ }, undefined, true, undefined, this),
41709
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41710
+ color: isCurrent ? "cyan" : undefined,
41711
+ bold: isCurrent,
41712
+ children: status
41713
+ }, undefined, false, undefined, this),
41714
+ isCurrent && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41715
+ dimColor: true,
41716
+ children: " \u2190 current"
41717
+ }, undefined, false, undefined, this)
41718
+ ]
41719
+ }, status, true, undefined, this);
41720
+ })
41721
+ }, undefined, false, undefined, this),
41722
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
41723
+ marginTop: 1,
41724
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41725
+ dimColor: true,
41726
+ children: "1\u20136 select \xB7 Esc cancel"
41727
+ }, undefined, false, undefined, this)
41728
+ }, undefined, false, undefined, this)
41729
+ ]
41730
+ }, undefined, true, undefined, this);
41666
41731
  function wrapText2(text, maxW) {
41667
41732
  const words2 = text.split(/\s+/);
41668
41733
  const result2 = [];
@@ -41685,6 +41750,8 @@ var TreeBoardComponent = ({ getTasks }) => {
41685
41750
  const [selectedIdx, setSelectedIdx] = import_react29.useState(0);
41686
41751
  const [scrollOffset, setScrollOffset] = import_react29.useState(0);
41687
41752
  const [leftScrollOffset, setLeftScrollOffset] = import_react29.useState(0);
41753
+ const [mode, setMode] = import_react29.useState("normal");
41754
+ const [searchQuery, setSearchQuery] = import_react29.useState("");
41688
41755
  const { exit } = use_app_default();
41689
41756
  const { stdout } = use_stdout_default();
41690
41757
  import_react29.useEffect(() => {
@@ -41693,8 +41760,17 @@ var TreeBoardComponent = ({ getTasks }) => {
41693
41760
  }, 1500);
41694
41761
  return () => clearInterval(id);
41695
41762
  }, [getTasks]);
41696
- const items = import_react29.useMemo(() => buildTree(tasks), [tasks]);
41763
+ const filteredTasks = import_react29.useMemo(() => {
41764
+ if (!searchQuery.trim())
41765
+ return tasks;
41766
+ const q2 = searchQuery.toLowerCase();
41767
+ return tasks.filter((t) => t.id.toLowerCase().includes(q2) || t.title.toLowerCase().includes(q2) || t.description.toLowerCase().includes(q2) || t.acceptance_criteria.some((ac) => ac.toLowerCase().includes(q2)) || t.implementation_notes.some((n) => n.note.toLowerCase().includes(q2)));
41768
+ }, [tasks, searchQuery]);
41769
+ const items = import_react29.useMemo(() => buildTree(filteredTasks), [filteredTasks]);
41697
41770
  const clampIdx = Math.min(selectedIdx, Math.max(0, items.length - 1));
41771
+ import_react29.useEffect(() => {
41772
+ setSelectedIdx(0);
41773
+ }, [searchQuery]);
41698
41774
  const leftRows = import_react29.useMemo(() => {
41699
41775
  const ipCnt = items.filter((i) => i.section === "in_progress").length;
41700
41776
  const ipTotal = items.filter((i) => i.section === "in_progress" || i.section === "middle").length;
@@ -41734,20 +41810,77 @@ var TreeBoardComponent = ({ getTasks }) => {
41734
41810
  return o;
41735
41811
  });
41736
41812
  }, [selectedRowIdx, stdout]);
41813
+ const selectedTask = items[clampIdx]?.task;
41737
41814
  use_input_default((input, key) => {
41738
- if (input === "q" || key.escape)
41815
+ if (mode === "search") {
41816
+ if (key.escape) {
41817
+ setSearchQuery("");
41818
+ setMode("normal");
41819
+ return;
41820
+ }
41821
+ if (key.return) {
41822
+ setMode("normal");
41823
+ return;
41824
+ }
41825
+ if (key.upArrow) {
41826
+ setSelectedIdx((i) => Math.max(0, i - 1));
41827
+ return;
41828
+ }
41829
+ if (key.downArrow) {
41830
+ setSelectedIdx((i) => Math.min(items.length - 1, i + 1));
41831
+ return;
41832
+ }
41833
+ if (key.backspace || key.delete) {
41834
+ setSearchQuery((q2) => q2.slice(0, -1));
41835
+ return;
41836
+ }
41837
+ if (input && !key.ctrl && !key.meta) {
41838
+ setSearchQuery((q2) => q2 + input);
41839
+ return;
41840
+ }
41841
+ return;
41842
+ }
41843
+ if (mode === "move") {
41844
+ if (key.escape || input === "q") {
41845
+ setMode("normal");
41846
+ return;
41847
+ }
41848
+ const statusMap = {
41849
+ "1": "backlog",
41850
+ "2": "ready",
41851
+ "3": "in_progress",
41852
+ "4": "blocked",
41853
+ "5": "needs_review",
41854
+ "6": "done"
41855
+ };
41856
+ const newStatus = statusMap[input];
41857
+ if (newStatus && selectedTask) {
41858
+ updateTask(selectedTask.id, { status: newStatus });
41859
+ setTasks(getTasks());
41860
+ setMode("normal");
41861
+ }
41862
+ return;
41863
+ }
41864
+ if (input === "q")
41739
41865
  exit();
41866
+ if (key.escape) {
41867
+ searchQuery ? setSearchQuery("") : exit();
41868
+ return;
41869
+ }
41740
41870
  if (key.upArrow)
41741
41871
  setSelectedIdx((i) => Math.max(0, i - 1));
41742
41872
  if (key.downArrow)
41743
41873
  setSelectedIdx((i) => Math.min(items.length - 1, i + 1));
41874
+ if (input === "s")
41875
+ setMode("search");
41876
+ if (input === "m" && selectedTask)
41877
+ setMode("move");
41744
41878
  });
41745
41879
  const cols = stdout.columns ?? 120;
41746
41880
  const rows = stdout.rows ?? 30;
41747
41881
  const leftWidth = Math.max(44, Math.floor(cols * 0.37));
41748
41882
  const rightWidth = cols - leftWidth - 2;
41749
41883
  const rightHeight = rows - 2;
41750
- const selectedTask = items[clampIdx]?.task;
41751
41884
  const itemsLenRef = import_react29.useRef(items.length);
41752
41885
  itemsLenRef.current = items.length;
41753
41886
  const leftWidthRef = import_react29.useRef(leftWidth);
@@ -41819,6 +41952,8 @@ var TreeBoardComponent = ({ getTasks }) => {
41819
41952
  }
41820
41953
  return bar;
41821
41954
  })();
41955
+ const taskCountLabel = searchQuery ? `${filteredTasks.length} of ${tasks.length}` : `${tasks.length}`;
41956
+ const searchMode = mode === "search";
41822
41957
  return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
41823
41958
  flexDirection: "column",
41824
41959
  width: cols,
@@ -41845,17 +41980,85 @@ var TreeBoardComponent = ({ getTasks }) => {
41845
41980
  color: "#AAAAAA",
41846
41981
  children: [
41847
41982
  "(",
41848
- tasks.length,
41983
+ taskCountLabel,
41849
41984
  ")"
41850
41985
  ]
41851
41986
  }, undefined, true, undefined, this),
41852
41987
  /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41853
41988
  dimColor: true,
41854
- children: " \u2191\u2193 navigate \xB7 q quit"
41855
- }, undefined, false, undefined, this)
41989
+ children: " "
41990
+ }, undefined, false, undefined, this),
41991
+ searchMode ? /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(jsx_dev_runtime3.Fragment, {
41992
+ children: [
41993
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41994
+ dimColor: true,
41995
+ children: "type to filter \xB7 "
41996
+ }, undefined, false, undefined, this),
41997
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41998
+ color: "cyan",
41999
+ children: "Enter"
42000
+ }, undefined, false, undefined, this),
42001
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42002
+ dimColor: true,
42003
+ children: " done \xB7 "
42004
+ }, undefined, false, undefined, this),
42005
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42006
+ color: "cyan",
42007
+ children: "Esc"
42008
+ }, undefined, false, undefined, this),
42009
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42010
+ dimColor: true,
42011
+ children: " clear"
42012
+ }, undefined, false, undefined, this)
42013
+ ]
42014
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(jsx_dev_runtime3.Fragment, {
42015
+ children: [
42016
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42017
+ color: "cyan",
42018
+ children: "s"
42019
+ }, undefined, false, undefined, this),
42020
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42021
+ dimColor: true,
42022
+ children: " search \xB7 "
42023
+ }, undefined, false, undefined, this),
42024
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42025
+ color: "cyan",
42026
+ children: "m"
42027
+ }, undefined, false, undefined, this),
42028
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42029
+ dimColor: true,
42030
+ children: " status \xB7 "
42031
+ }, undefined, false, undefined, this),
42032
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42033
+ color: "cyan",
42034
+ children: "q"
42035
+ }, undefined, false, undefined, this),
42036
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42037
+ dimColor: true,
42038
+ children: " quit"
42039
+ }, undefined, false, undefined, this)
42040
+ ]
42041
+ }, undefined, true, undefined, this)
41856
42042
  ]
41857
42043
  }, undefined, true, undefined, this),
41858
- /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42044
+ mode === "search" || searchQuery ? /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
42045
+ paddingLeft: 1,
42046
+ children: [
42047
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42048
+ color: "cyan",
42049
+ children: "/ "
42050
+ }, undefined, false, undefined, this),
42051
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42052
+ color: "white",
42053
+ children: searchQuery
42054
+ }, undefined, false, undefined, this),
42055
+ mode === "search" && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
42056
+ color: "cyan",
42057
+ bold: true,
42058
+ children: "\u2588"
42059
+ }, undefined, false, undefined, this)
42060
+ ]
42061
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
41859
42062
  dimColor: true,
41860
42063
  children: "\u2500".repeat(leftInner)
41861
42064
  }, undefined, false, undefined, this),
@@ -41930,7 +42133,9 @@ var TreeBoardComponent = ({ getTasks }) => {
41930
42133
  flexDirection: "column",
41931
42134
  borderStyle: "round",
41932
42135
  borderColor: "gray",
41933
- children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(RightPane, {
42136
+ children: mode === "move" && selectedTask ? /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(StatusPicker, {
42137
+ task: selectedTask
42138
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(RightPane, {
41934
42139
  task: selectedTask,
41935
42140
  width: rightInner,
41936
42141
  height: rightHeight,
@@ -42780,4 +42985,4 @@ program2.parseAsync(process.argv).catch((err) => {
42780
42985
  process.exit(1);
42781
42986
  });
42782
42987
 
42783
- //# debugId=DB5FBA0C117EB46464756E2164756E21
42988
+ //# debugId=758BC15FE9C3042464756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aitasks",
3
- "version": "1.1.1",
3
+ "version": "1.2.1",
4
4
  "description": "CLI task management tool built for AI agents",
5
5
  "type": "module",
6
6
  "bin": {