techunter 1.0.0 → 1.0.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 (4) hide show
  1. package/README.md +237 -237
  2. package/dist/index.js +328 -149
  3. package/dist/mcp.js +221 -62
  4. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -46,11 +46,13 @@ __export(github_exports, {
46
46
  extractTargetBranch: () => extractTargetBranch,
47
47
  formatGuideAsMarkdown: () => formatGuideAsMarkdown,
48
48
  getAuthenticatedUser: () => getAuthenticatedUser,
49
+ getBranchHeadSha: () => getBranchHeadSha,
49
50
  getDefaultBranch: () => getDefaultBranch,
50
51
  getIssueNumberFromBranch: () => getIssueNumberFromBranch,
51
52
  getOpenSubtasks: () => getOpenSubtasks,
52
53
  getRepoFile: () => getRepoFile,
53
54
  getTask: () => getTask,
55
+ getTaskBranch: () => getTaskBranch,
54
56
  getTaskPR: () => getTaskPR,
55
57
  getTaskPRDiff: () => getTaskPRDiff,
56
58
  isCollaborator: () => isCollaborator,
@@ -60,6 +62,7 @@ __export(github_exports, {
60
62
  listTasksForReview: () => listTasksForReview,
61
63
  markInReview: () => markInReview,
62
64
  mergeWorkerIntoBase: () => mergeWorkerIntoBase,
65
+ moveTask: () => moveTask,
63
66
  postComment: () => postComment,
64
67
  postGuideComment: () => postGuideComment,
65
68
  rejectTask: () => rejectTask,
@@ -437,6 +440,37 @@ async function getDefaultBranch(config) {
437
440
  const { data } = await octokit.repos.get({ owner, repo });
438
441
  return data.default_branch;
439
442
  }
443
+ async function getTaskBranch(config, issueNumber) {
444
+ const octokit = createOctokit(config.githubToken);
445
+ const { owner, repo } = config.github;
446
+ const { data: prs } = await octokit.pulls.list({ owner, repo, state: "open", per_page: 100 });
447
+ const pr = prs.find((p) => new RegExp(`Closes #${issueNumber}\\b`, "i").test(p.body ?? ""));
448
+ if (pr) return pr.head.ref;
449
+ const { data: branches } = await octokit.repos.listBranches({ owner, repo, per_page: 100 });
450
+ const taskBranch = branches.find((b) => new RegExp(`^task-${issueNumber}-`).test(b.name));
451
+ return taskBranch?.name ?? null;
452
+ }
453
+ async function getBranchHeadSha(config, branchName) {
454
+ const octokit = createOctokit(config.githubToken);
455
+ const { owner, repo } = config.github;
456
+ try {
457
+ const { data } = await octokit.repos.getBranch({ owner, repo, branch: branchName });
458
+ return data.commit.sha;
459
+ } catch {
460
+ return null;
461
+ }
462
+ }
463
+ async function moveTask(config, issueNumber, newTargetBranch, newBaseCommit) {
464
+ const octokit = createOctokit(config.githubToken);
465
+ const { owner, repo } = config.github;
466
+ const { data } = await octokit.issues.get({ owner, repo, issue_number: issueNumber });
467
+ let body = data.body ?? "";
468
+ body = body.replace(/\n*<!-- techunter-base:[a-f0-9]{7,40} -->/g, "");
469
+ body = body.replace(/\n*<!-- techunter-target:[^\s>]+ -->/g, "");
470
+ body = embedBaseCommit(body, newBaseCommit);
471
+ body = embedTargetBranch(body, newTargetBranch);
472
+ await octokit.issues.update({ owner, repo, issue_number: issueNumber, body });
473
+ }
440
474
  async function getTaskPR(config, issueNumber) {
441
475
  const octokit = createOctokit(config.githubToken);
442
476
  const { owner, repo } = config.github;
@@ -527,14 +561,14 @@ var init_github = __esm({
527
561
  });
528
562
 
529
563
  // src/index.ts
530
- import chalk17 from "chalk";
564
+ import chalk18 from "chalk";
531
565
  import readline from "readline";
532
566
  import { createRequire } from "module";
533
567
 
534
568
  // src/commands/init.ts
535
- import { input, password, select as select11 } from "@inquirer/prompts";
536
- import chalk13 from "chalk";
537
- import ora14 from "ora";
569
+ import { input, password, select as select12 } from "@inquirer/prompts";
570
+ import chalk14 from "chalk";
571
+ import ora15 from "ora";
538
572
  import open2 from "open";
539
573
  import { createOAuthDeviceAuth } from "@octokit/auth-oauth-device";
540
574
 
@@ -2601,21 +2635,145 @@ async function execute11(input3, config) {
2601
2635
  }
2602
2636
  var terminal11 = true;
2603
2637
 
2604
- // src/tools/wiki/index.ts
2605
- var wiki_exports = {};
2606
- __export(wiki_exports, {
2638
+ // src/tools/move-task/index.ts
2639
+ var move_task_exports = {};
2640
+ __export(move_task_exports, {
2607
2641
  definition: () => definition12,
2608
2642
  execute: () => execute12,
2609
2643
  run: () => run12,
2610
2644
  terminal: () => terminal12
2611
2645
  });
2646
+ init_github();
2647
+ import { select as select9 } from "@inquirer/prompts";
2612
2648
  import ora10 from "ora";
2613
2649
  import chalk10 from "chalk";
2650
+ var definition12 = {
2651
+ type: "function",
2652
+ function: {
2653
+ name: "move_task",
2654
+ description: "Move one of your own published tasks to be a sub-task of another task. Updates the target branch and base commit so executors sync from the new parent HEAD. Equivalent to /move.",
2655
+ parameters: {
2656
+ type: "object",
2657
+ properties: {
2658
+ issue_number: { type: "number", description: "Issue number of the task to move." },
2659
+ parent_issue_number: { type: "number", description: "Issue number of the new parent task." }
2660
+ },
2661
+ required: ["issue_number", "parent_issue_number"]
2662
+ }
2663
+ }
2664
+ };
2665
+ async function run12(input3, config) {
2666
+ const me = await getAuthenticatedUser(config);
2667
+ const allTasks = await listTasks(config);
2668
+ let issueNumber = input3["issue_number"];
2669
+ let taskToMove;
2670
+ if (issueNumber) {
2671
+ try {
2672
+ taskToMove = await getTask(config, issueNumber);
2673
+ } catch (err) {
2674
+ return `Error loading task #${issueNumber}: ${err.message}`;
2675
+ }
2676
+ if (taskToMove.author !== me) {
2677
+ return `Task #${issueNumber} was not authored by you \u2014 you can only move your own tasks.`;
2678
+ }
2679
+ } else {
2680
+ const myTasks = allTasks.filter((t) => t.author === me);
2681
+ if (myTasks.length === 0) return "No tasks you authored are available to move.";
2682
+ try {
2683
+ issueNumber = await select9({
2684
+ message: "Select task to move:",
2685
+ choices: myTasks.map((t) => ({
2686
+ name: `#${t.number} [${getStatus(t)}] ${t.title}`,
2687
+ value: t.number
2688
+ }))
2689
+ });
2690
+ } catch {
2691
+ return "Cancelled.";
2692
+ }
2693
+ taskToMove = myTasks.find((t) => t.number === issueNumber);
2694
+ }
2695
+ const candidates = allTasks.filter((t) => t.number !== taskToMove.number);
2696
+ const resolveSpinner = ora10("Finding parent task branches\u2026").start();
2697
+ const parents = [];
2698
+ for (const t of candidates) {
2699
+ const branch = await getTaskBranch(config, t.number);
2700
+ if (branch) parents.push({ task: t, branch });
2701
+ }
2702
+ resolveSpinner.stop();
2703
+ if (parents.length === 0) {
2704
+ return "No other tasks with known branches are available as a parent.";
2705
+ }
2706
+ let parentIssueNumber = input3["parent_issue_number"];
2707
+ let chosen;
2708
+ if (parentIssueNumber) {
2709
+ const found = parents.find((p) => p.task.number === parentIssueNumber);
2710
+ if (!found) {
2711
+ return `Task #${parentIssueNumber} is not available as a parent (no branch found or not open).`;
2712
+ }
2713
+ chosen = found;
2714
+ } else {
2715
+ try {
2716
+ const selectedBranch = await select9({
2717
+ message: `Move #${taskToMove.number} under which task?`,
2718
+ choices: parents.map((p) => ({
2719
+ name: `#${p.task.number} [${getStatus(p.task)}] ${p.task.title} ${chalk10.dim("\u2192 " + p.branch)}`,
2720
+ value: p.branch
2721
+ }))
2722
+ });
2723
+ chosen = parents.find((p) => p.branch === selectedBranch);
2724
+ } catch {
2725
+ return "Cancelled.";
2726
+ }
2727
+ }
2728
+ const sha = await getBranchHeadSha(config, chosen.branch);
2729
+ if (!sha) {
2730
+ return `Could not resolve HEAD of branch ${chosen.branch} \u2014 does it exist on the remote?`;
2731
+ }
2732
+ const spinner = ora10(`Moving #${taskToMove.number} under #${chosen.task.number}\u2026`).start();
2733
+ try {
2734
+ await moveTask(config, taskToMove.number, chosen.branch, sha);
2735
+ spinner.succeed(
2736
+ `Task #${taskToMove.number} moved under #${chosen.task.number} "${chosen.task.title}"
2737
+ target: ${chalk10.cyan(chosen.branch)} base: ${chalk10.dim(sha.slice(0, 7))}`
2738
+ );
2739
+ return `Task #${taskToMove.number} moved under #${chosen.task.number} (branch: ${chosen.branch}, base: ${sha.slice(0, 7)})`;
2740
+ } catch (err) {
2741
+ spinner.fail(`Failed: ${err.message}`);
2742
+ return `Error: ${err.message}`;
2743
+ }
2744
+ }
2745
+ async function execute12(input3, config) {
2746
+ const me = await getAuthenticatedUser(config);
2747
+ const issueNumber = input3["issue_number"];
2748
+ const parentIssueNumber = input3["parent_issue_number"];
2749
+ const task = await getTask(config, issueNumber);
2750
+ if (task.author !== me) {
2751
+ return `Task #${issueNumber} was not authored by you \u2014 you can only move your own tasks.`;
2752
+ }
2753
+ const branch = await getTaskBranch(config, parentIssueNumber);
2754
+ if (!branch) return `No branch found for parent task #${parentIssueNumber}.`;
2755
+ const sha = await getBranchHeadSha(config, branch);
2756
+ if (!sha) return `Could not resolve HEAD of branch ${branch}.`;
2757
+ await moveTask(config, issueNumber, branch, sha);
2758
+ return `Task #${issueNumber} moved under #${parentIssueNumber} (branch: ${branch}, base: ${sha.slice(0, 7)})`;
2759
+ }
2760
+ var terminal12 = true;
2761
+
2762
+ // src/tools/wiki/index.ts
2763
+ var wiki_exports = {};
2764
+ __export(wiki_exports, {
2765
+ definition: () => definition13,
2766
+ execute: () => execute13,
2767
+ run: () => run13,
2768
+ terminal: () => terminal13
2769
+ });
2770
+ import ora11 from "ora";
2771
+ import chalk11 from "chalk";
2614
2772
  import { readFile as readFile2 } from "fs/promises";
2615
- import { select as select9 } from "@inquirer/prompts";
2773
+ import { select as select10 } from "@inquirer/prompts";
2616
2774
  init_github();
2617
2775
  var WIKI_PATH = "TECHUNTER.md";
2618
- var definition12 = {
2776
+ var definition13 = {
2619
2777
  type: "function",
2620
2778
  function: {
2621
2779
  name: "update_wiki",
@@ -2635,20 +2793,20 @@ async function readWikiContent(config) {
2635
2793
  return getRepoFile(config, WIKI_PATH);
2636
2794
  }
2637
2795
  function printWiki(content) {
2638
- const divider = chalk10.dim("\u2500".repeat(70));
2796
+ const divider = chalk11.dim("\u2500".repeat(70));
2639
2797
  console.log("\n" + divider);
2640
- console.log(chalk10.bold(" TECHUNTER.md"));
2798
+ console.log(chalk11.bold(" TECHUNTER.md"));
2641
2799
  console.log(divider);
2642
2800
  console.log(renderMarkdown(content));
2643
2801
  console.log(divider + "\n");
2644
2802
  }
2645
- async function run12(_input, config) {
2646
- const fetchSpinner = ora10("Checking for existing wiki\u2026").start();
2803
+ async function run13(_input, config) {
2804
+ const fetchSpinner = ora11("Checking for existing wiki\u2026").start();
2647
2805
  const existing = await readWikiContent(config).catch(() => null);
2648
2806
  fetchSpinner.stop();
2649
2807
  let action;
2650
2808
  try {
2651
- action = await select9({
2809
+ action = await select10({
2652
2810
  message: "TECHUNTER.md \u2014 what would you like to do?",
2653
2811
  choices: [
2654
2812
  ...existing ? [{ name: "View current wiki", value: "view" }] : [],
@@ -2664,7 +2822,7 @@ async function run12(_input, config) {
2664
2822
  printWiki(existing);
2665
2823
  return "Displayed TECHUNTER.md.";
2666
2824
  }
2667
- const authSpinner = ora10("Checking permissions\u2026").start();
2825
+ const authSpinner = ora11("Checking permissions\u2026").start();
2668
2826
  let me;
2669
2827
  let allowed;
2670
2828
  try {
@@ -2678,7 +2836,7 @@ async function run12(_input, config) {
2678
2836
  if (!allowed) {
2679
2837
  return `Permission denied: only repository collaborators can update the project wiki.`;
2680
2838
  }
2681
- const genSpinner = ora10("Analyzing project and generating overview\u2026").start();
2839
+ const genSpinner = ora11("Analyzing project and generating overview\u2026").start();
2682
2840
  let content;
2683
2841
  try {
2684
2842
  content = await generateWiki(config);
@@ -2690,7 +2848,7 @@ async function run12(_input, config) {
2690
2848
  printWiki(content);
2691
2849
  let confirm;
2692
2850
  try {
2693
- confirm = await select9({
2851
+ confirm = await select10({
2694
2852
  message: `Publish to repository as ${WIKI_PATH}?`,
2695
2853
  choices: [
2696
2854
  { name: "Yes, commit to repo", value: "publish" },
@@ -2701,7 +2859,7 @@ async function run12(_input, config) {
2701
2859
  return "Cancelled.";
2702
2860
  }
2703
2861
  if (confirm === "cancel") return "Cancelled.";
2704
- const writeSpinner = ora10(`Writing ${WIKI_PATH}\u2026`).start();
2862
+ const writeSpinner = ora11(`Writing ${WIKI_PATH}\u2026`).start();
2705
2863
  try {
2706
2864
  const url = await upsertRepoFile(config, WIKI_PATH, content, "docs: update TECHUNTER.md project overview");
2707
2865
  writeSpinner.succeed(`Written: ${url}`);
@@ -2712,7 +2870,7 @@ async function run12(_input, config) {
2712
2870
  return `Error: ${err.message}`;
2713
2871
  }
2714
2872
  }
2715
- async function execute12(_input, config) {
2873
+ async function execute13(_input, config) {
2716
2874
  const me = await getAuthenticatedUser(config);
2717
2875
  if (!await isCollaborator(config, me)) {
2718
2876
  return `Permission denied: only repository collaborators can update the project wiki.`;
@@ -2725,16 +2883,16 @@ async function execute12(_input, config) {
2725
2883
  return `Error: ${err.message}`;
2726
2884
  }
2727
2885
  }
2728
- var terminal12 = true;
2886
+ var terminal13 = true;
2729
2887
 
2730
2888
  // src/tools/list-tasks/index.ts
2731
2889
  var list_tasks_exports = {};
2732
2890
  __export(list_tasks_exports, {
2733
- definition: () => definition13,
2734
- execute: () => execute13
2891
+ definition: () => definition14,
2892
+ execute: () => execute14
2735
2893
  });
2736
2894
  init_github();
2737
- var definition13 = {
2895
+ var definition14 = {
2738
2896
  type: "function",
2739
2897
  function: {
2740
2898
  name: "list_tasks",
@@ -2746,7 +2904,7 @@ var definition13 = {
2746
2904
  }
2747
2905
  }
2748
2906
  };
2749
- async function execute13(_input, config) {
2907
+ async function execute14(_input, config) {
2750
2908
  const tasks = await listTasks(config);
2751
2909
  if (tasks.length === 0) return "No open tasks.";
2752
2910
  return tasks.map((t) => {
@@ -2759,11 +2917,11 @@ async function execute13(_input, config) {
2759
2917
  // src/tools/get-task/index.ts
2760
2918
  var get_task_exports = {};
2761
2919
  __export(get_task_exports, {
2762
- definition: () => definition14,
2763
- execute: () => execute14
2920
+ definition: () => definition15,
2921
+ execute: () => execute15
2764
2922
  });
2765
2923
  init_github();
2766
- var definition14 = {
2924
+ var definition15 = {
2767
2925
  type: "function",
2768
2926
  function: {
2769
2927
  name: "get_task",
@@ -2777,7 +2935,7 @@ var definition14 = {
2777
2935
  }
2778
2936
  }
2779
2937
  };
2780
- async function execute14(input3, config) {
2938
+ async function execute15(input3, config) {
2781
2939
  const issue = await getTask(config, input3["issue_number"]);
2782
2940
  const status = issue.labels.find((l) => l.startsWith("techunter:"))?.replace("techunter:", "") ?? "unknown";
2783
2941
  const assignee = issue.assignee ? `@${issue.assignee}` : "\u2014";
@@ -2794,12 +2952,12 @@ ${issue.body}`);
2794
2952
  // src/tools/get-comments/index.ts
2795
2953
  var get_comments_exports = {};
2796
2954
  __export(get_comments_exports, {
2797
- definition: () => definition15,
2798
- execute: () => execute15
2955
+ definition: () => definition16,
2956
+ execute: () => execute16
2799
2957
  });
2800
2958
  init_github();
2801
- import ora11 from "ora";
2802
- var definition15 = {
2959
+ import ora12 from "ora";
2960
+ var definition16 = {
2803
2961
  type: "function",
2804
2962
  function: {
2805
2963
  name: "get_comments",
@@ -2814,10 +2972,10 @@ var definition15 = {
2814
2972
  }
2815
2973
  }
2816
2974
  };
2817
- async function execute15(input3, config) {
2975
+ async function execute16(input3, config) {
2818
2976
  const issueNumber = input3["issue_number"];
2819
2977
  const limit = input3["limit"] ?? 5;
2820
- const spinner = ora11(`Loading comments for #${issueNumber}...`).start();
2978
+ const spinner = ora12(`Loading comments for #${issueNumber}...`).start();
2821
2979
  try {
2822
2980
  const comments = await listComments(config, issueNumber, limit);
2823
2981
  spinner.stop();
@@ -2836,11 +2994,11 @@ ${lines.join("\n\n")}`;
2836
2994
  // src/tools/get-diff/index.ts
2837
2995
  var get_diff_exports = {};
2838
2996
  __export(get_diff_exports, {
2839
- definition: () => definition16,
2840
- execute: () => execute16
2997
+ definition: () => definition17,
2998
+ execute: () => execute17
2841
2999
  });
2842
- import ora12 from "ora";
2843
- var definition16 = {
3000
+ import ora13 from "ora";
3001
+ var definition17 = {
2844
3002
  type: "function",
2845
3003
  function: {
2846
3004
  name: "get_diff",
@@ -2848,8 +3006,8 @@ var definition16 = {
2848
3006
  parameters: { type: "object", properties: {}, required: [] }
2849
3007
  }
2850
3008
  };
2851
- async function execute16(_input, _config) {
2852
- const spinner = ora12("Reading git diff...").start();
3009
+ async function execute17(_input, _config) {
3010
+ const spinner = ora13("Reading git diff...").start();
2853
3011
  try {
2854
3012
  const diff = await getDiff();
2855
3013
  spinner.stop();
@@ -2863,14 +3021,14 @@ async function execute16(_input, _config) {
2863
3021
  // src/tools/run-command/index.ts
2864
3022
  var run_command_exports = {};
2865
3023
  __export(run_command_exports, {
2866
- definition: () => definition17,
2867
- execute: () => execute17
3024
+ definition: () => definition18,
3025
+ execute: () => execute18
2868
3026
  });
2869
3027
  import { exec } from "child_process";
2870
3028
  import { promisify } from "util";
2871
- import ora13 from "ora";
3029
+ import ora14 from "ora";
2872
3030
  var execAsync = promisify(exec);
2873
- var definition17 = {
3031
+ var definition18 = {
2874
3032
  type: "function",
2875
3033
  function: {
2876
3034
  name: "run_command",
@@ -2884,10 +3042,10 @@ var definition17 = {
2884
3042
  }
2885
3043
  }
2886
3044
  };
2887
- async function execute17(input3, _config) {
3045
+ async function execute18(input3, _config) {
2888
3046
  const command = input3["command"];
2889
3047
  const cwd = process.cwd();
2890
- const spinner = ora13(`$ ${command}`).start();
3048
+ const spinner = ora14(`$ ${command}`).start();
2891
3049
  try {
2892
3050
  const { stdout, stderr } = await execAsync(command, { cwd, timeout: 6e4, maxBuffer: 1024 * 1024 });
2893
3051
  spinner.stop();
@@ -2906,15 +3064,15 @@ ${out || e.message}`;
2906
3064
  // src/tools/list-files/index.ts
2907
3065
  var list_files_exports = {};
2908
3066
  __export(list_files_exports, {
2909
- definition: () => definition18,
2910
- execute: () => execute18
3067
+ definition: () => definition19,
3068
+ execute: () => execute19
2911
3069
  });
2912
3070
  import { readFile as readFile3 } from "fs/promises";
2913
3071
  import { existsSync } from "fs";
2914
3072
  import path2 from "path";
2915
3073
  import { globby } from "globby";
2916
3074
  import ignore from "ignore";
2917
- var definition18 = {
3075
+ var definition19 = {
2918
3076
  type: "function",
2919
3077
  function: {
2920
3078
  name: "list_files",
@@ -2954,7 +3112,7 @@ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
2954
3112
  ".sqlite",
2955
3113
  ".lock"
2956
3114
  ]);
2957
- async function execute18(input3, _config) {
3115
+ async function execute19(input3, _config) {
2958
3116
  const glob = input3["glob"] ?? "**/*";
2959
3117
  const cwd = process.cwd();
2960
3118
  const ig = ignore();
@@ -2973,15 +3131,15 @@ ${filtered.join("\n")}`;
2973
3131
  // src/tools/grep-code/index.ts
2974
3132
  var grep_code_exports = {};
2975
3133
  __export(grep_code_exports, {
2976
- definition: () => definition19,
2977
- execute: () => execute19
3134
+ definition: () => definition20,
3135
+ execute: () => execute20
2978
3136
  });
2979
3137
  import { readFile as readFile4 } from "fs/promises";
2980
3138
  import { existsSync as existsSync2 } from "fs";
2981
3139
  import path3 from "path";
2982
3140
  import { globby as globby2 } from "globby";
2983
3141
  import ignore2 from "ignore";
2984
- var definition19 = {
3142
+ var definition20 = {
2985
3143
  type: "function",
2986
3144
  function: {
2987
3145
  name: "grep_code",
@@ -3054,7 +3212,7 @@ function isText(f) {
3054
3212
  return !BINARY_EXTENSIONS2.has(path3.extname(f).toLowerCase());
3055
3213
  }
3056
3214
  var MAX_RANGE_LINES = 300;
3057
- async function execute19(input3, _config) {
3215
+ async function execute20(input3, _config) {
3058
3216
  const pattern = input3["pattern"] ?? "";
3059
3217
  const fileGlob = input3["file_glob"] ?? "**/*";
3060
3218
  const contextLines = Math.min(input3["context_lines"] ?? 2, 5);
@@ -3141,12 +3299,12 @@ ${snippets.join("\n---\n")}
3141
3299
  // src/tools/ask-user/index.ts
3142
3300
  var ask_user_exports = {};
3143
3301
  __export(ask_user_exports, {
3144
- definition: () => definition20,
3145
- execute: () => execute20
3302
+ definition: () => definition21,
3303
+ execute: () => execute21
3146
3304
  });
3147
- import chalk11 from "chalk";
3148
- import { select as select10, input as promptInput5 } from "@inquirer/prompts";
3149
- var definition20 = {
3305
+ import chalk12 from "chalk";
3306
+ import { select as select11, input as promptInput5 } from "@inquirer/prompts";
3307
+ var definition21 = {
3150
3308
  type: "function",
3151
3309
  function: {
3152
3310
  name: "ask_user",
@@ -3165,24 +3323,24 @@ var definition20 = {
3165
3323
  }
3166
3324
  }
3167
3325
  };
3168
- async function execute20(input3, _config) {
3326
+ async function execute21(input3, _config) {
3169
3327
  const question = input3["question"];
3170
3328
  const options = input3["options"];
3171
3329
  const OTHER = "__other__";
3172
3330
  console.log("");
3173
- console.log(chalk11.dim(" \u250C\u2500 Agent question " + "\u2500".repeat(51)));
3174
- console.log(chalk11.dim(" \u2502"));
3331
+ console.log(chalk12.dim(" \u250C\u2500 Agent question " + "\u2500".repeat(51)));
3332
+ console.log(chalk12.dim(" \u2502"));
3175
3333
  for (const line of question.split("\n")) {
3176
- console.log(chalk11.dim(" \u2502 ") + line);
3334
+ console.log(chalk12.dim(" \u2502 ") + line);
3177
3335
  }
3178
- console.log(chalk11.dim(" \u2514" + "\u2500".repeat(67)));
3336
+ console.log(chalk12.dim(" \u2514" + "\u2500".repeat(67)));
3179
3337
  let answer;
3180
3338
  try {
3181
- const chosen = await select10({
3339
+ const chosen = await select11({
3182
3340
  message: " ",
3183
3341
  choices: [
3184
3342
  ...options.map((o) => ({ name: o, value: o })),
3185
- { name: chalk11.dim("Other (describe below)"), value: OTHER }
3343
+ { name: chalk12.dim("Other (describe below)"), value: OTHER }
3186
3344
  ]
3187
3345
  });
3188
3346
  answer = chosen === OTHER ? await promptInput5({ message: "Your answer:" }) : chosen;
@@ -3207,6 +3365,7 @@ var toolModules = [
3207
3365
  reject_exports,
3208
3366
  accept_exports,
3209
3367
  edit_task_exports,
3368
+ move_task_exports,
3210
3369
  wiki_exports,
3211
3370
  // Low-level tools
3212
3371
  list_tasks_exports,
@@ -3220,7 +3379,7 @@ var toolModules = [
3220
3379
  ];
3221
3380
 
3222
3381
  // src/lib/agent-ui.ts
3223
- import chalk12 from "chalk";
3382
+ import chalk13 from "chalk";
3224
3383
  function formatInput(input3) {
3225
3384
  return Object.entries(input3).map(([k, v]) => {
3226
3385
  if (typeof v === "number") return `${k}=${v}`;
@@ -3237,12 +3396,12 @@ function summarize(result) {
3237
3396
  }
3238
3397
  function printToolCall(name, input3) {
3239
3398
  const params = formatInput(input3);
3240
- console.log(` ${chalk12.cyan("\u2192")} ${chalk12.bold(name)}${params ? " " + chalk12.dim(params) : ""}`);
3399
+ console.log(` ${chalk13.cyan("\u2192")} ${chalk13.bold(name)}${params ? " " + chalk13.dim(params) : ""}`);
3241
3400
  }
3242
3401
  function printToolResult(result) {
3243
3402
  const ok = !result.startsWith("Error:");
3244
- const icon = ok ? chalk12.green("\u2713") : chalk12.red("\u2717");
3245
- console.log(` ${icon} ${chalk12.dim(summarize(result))}`);
3403
+ const icon = ok ? chalk13.green("\u2713") : chalk13.red("\u2717");
3404
+ console.log(` ${icon} ${chalk13.dim(summarize(result))}`);
3246
3405
  }
3247
3406
 
3248
3407
  // src/lib/sub-agent.ts
@@ -3345,8 +3504,8 @@ async function generateWiki(config) {
3345
3504
 
3346
3505
  // src/commands/init.ts
3347
3506
  async function getGitHubTokenViaPAT() {
3348
- console.log(chalk13.dim("\n Create a token at: https://github.com/settings/tokens/new"));
3349
- console.log(chalk13.dim(" Required scopes: repo, read:user\n"));
3507
+ console.log(chalk14.dim("\n Create a token at: https://github.com/settings/tokens/new"));
3508
+ console.log(chalk14.dim(" Required scopes: repo, read:user\n"));
3350
3509
  const token = await password({
3351
3510
  message: "GitHub Personal Access Token:",
3352
3511
  mask: "*"
@@ -3365,17 +3524,17 @@ async function getGitHubTokenViaDeviceFlow() {
3365
3524
  verificationUri = verification.verification_uri;
3366
3525
  userCode = verification.user_code;
3367
3526
  console.log("");
3368
- console.log(chalk13.bold(" 1. Open this URL in your browser:"));
3369
- console.log(" " + chalk13.cyan(verificationUri));
3527
+ console.log(chalk14.bold(" 1. Open this URL in your browser:"));
3528
+ console.log(" " + chalk14.cyan(verificationUri));
3370
3529
  console.log("");
3371
- console.log(chalk13.bold(" 2. Enter this code:"));
3372
- console.log(" " + chalk13.yellow.bold(userCode));
3530
+ console.log(chalk14.bold(" 2. Enter this code:"));
3531
+ console.log(" " + chalk14.yellow.bold(userCode));
3373
3532
  console.log("");
3374
3533
  open2(verificationUri).catch(() => {
3375
3534
  });
3376
3535
  }
3377
3536
  });
3378
- const spinner = ora14("Waiting for authorization in browser...").start();
3537
+ const spinner = ora15("Waiting for authorization in browser...").start();
3379
3538
  let token;
3380
3539
  try {
3381
3540
  const result = await auth({ type: "oauth" });
@@ -3388,7 +3547,7 @@ async function getGitHubTokenViaDeviceFlow() {
3388
3547
  return { token, clientId: OAUTH_CLIENT_ID };
3389
3548
  }
3390
3549
  async function initCommand() {
3391
- console.log(chalk13.bold.cyan("\nTechunter \u2014 Initial Setup\n"));
3550
+ console.log(chalk14.bold.cyan("\nTechunter \u2014 Initial Setup\n"));
3392
3551
  let detectedOwner = "";
3393
3552
  let detectedRepo = "";
3394
3553
  const remoteUrl = await getRemoteUrl();
@@ -3397,11 +3556,11 @@ async function initCommand() {
3397
3556
  if (parsed) {
3398
3557
  detectedOwner = parsed.owner;
3399
3558
  detectedRepo = parsed.repo;
3400
- console.log(chalk13.dim(`Detected GitHub repo: ${detectedOwner}/${detectedRepo}
3559
+ console.log(chalk14.dim(`Detected GitHub repo: ${detectedOwner}/${detectedRepo}
3401
3560
  `));
3402
3561
  }
3403
3562
  }
3404
- const authMethod = await select11({
3563
+ const authMethod = await select12({
3405
3564
  message: "How would you like to authenticate with GitHub?",
3406
3565
  choices: [
3407
3566
  {
@@ -3424,10 +3583,10 @@ async function initCommand() {
3424
3583
  const result = await getGitHubTokenViaPAT();
3425
3584
  githubToken = result.token;
3426
3585
  }
3427
- const providerChoice = await select11({
3586
+ const providerChoice = await select12({
3428
3587
  message: "AI provider:",
3429
3588
  choices: [
3430
- { name: `OpenRouter (recommended) ${chalk13.dim(`${DEFAULT_BASE_URL} \xB7 ${DEFAULT_MODEL}`)}`, value: "openrouter" },
3589
+ { name: `OpenRouter (recommended) ${chalk14.dim(`${DEFAULT_BASE_URL} \xB7 ${DEFAULT_MODEL}`)}`, value: "openrouter" },
3431
3590
  { name: "Custom (specify base URL and model)", value: "custom" }
3432
3591
  ]
3433
3592
  });
@@ -3437,7 +3596,7 @@ async function initCommand() {
3437
3596
  aiBaseUrl = (await input({ message: "API base URL:", default: DEFAULT_BASE_URL })).trim();
3438
3597
  aiModel = (await input({ message: "Model name:", default: DEFAULT_MODEL })).trim();
3439
3598
  }
3440
- const apiKeyHint = providerChoice === "openrouter" ? chalk13.dim(" Get a key at: https://openrouter.ai/settings/keys\n") : chalk13.dim(" API key for your provider\n");
3599
+ const apiKeyHint = providerChoice === "openrouter" ? chalk14.dim(" Get a key at: https://openrouter.ai/settings/keys\n") : chalk14.dim(" API key for your provider\n");
3441
3600
  console.log(apiKeyHint);
3442
3601
  const aiApiKey = await password({
3443
3602
  message: "API Key:",
@@ -3467,20 +3626,20 @@ async function initCommand() {
3467
3626
  }
3468
3627
  };
3469
3628
  setConfig(config);
3470
- const spinner = ora14("Setting up GitHub labels...").start();
3629
+ const spinner = ora15("Setting up GitHub labels...").start();
3471
3630
  try {
3472
3631
  await ensureLabels(config);
3473
3632
  spinner.succeed("GitHub labels created");
3474
3633
  } catch (err) {
3475
3634
  spinner.fail("Failed to create labels (check token permissions)");
3476
- console.error(chalk13.red(String(err)));
3635
+ console.error(chalk14.red(String(err)));
3477
3636
  }
3478
- console.log(chalk13.green("\nSetup complete!"));
3479
- console.log(chalk13.dim(`Config saved to: ${getConfigPath()}
3637
+ console.log(chalk14.green("\nSetup complete!"));
3638
+ console.log(chalk14.dim(`Config saved to: ${getConfigPath()}
3480
3639
  `));
3481
3640
  let genWiki = false;
3482
3641
  try {
3483
- genWiki = await select11({
3642
+ genWiki = await select12({
3484
3643
  message: "Generate TECHUNTER.md project overview for new team members?",
3485
3644
  choices: [
3486
3645
  { name: "Yes, generate now", value: true },
@@ -3490,7 +3649,7 @@ async function initCommand() {
3490
3649
  } catch {
3491
3650
  }
3492
3651
  if (genWiki) {
3493
- const wikiSpinner = ora14("Analyzing project and generating TECHUNTER.md\u2026").start();
3652
+ const wikiSpinner = ora15("Analyzing project and generating TECHUNTER.md\u2026").start();
3494
3653
  try {
3495
3654
  const content = await generateWiki(config);
3496
3655
  await upsertRepoFile(config, "TECHUNTER.md", content, "docs: add TECHUNTER.md project overview");
@@ -3503,31 +3662,31 @@ async function initCommand() {
3503
3662
  }
3504
3663
 
3505
3664
  // src/commands/config.ts
3506
- import { input as input2, password as password2, select as select12 } from "@inquirer/prompts";
3507
- import chalk14 from "chalk";
3665
+ import { input as input2, password as password2, select as select13 } from "@inquirer/prompts";
3666
+ import chalk15 from "chalk";
3508
3667
  async function configCommand() {
3509
3668
  let config;
3510
3669
  try {
3511
3670
  config = getConfig();
3512
3671
  } catch {
3513
- console.error(chalk14.red("No config found. Run `tch init` first."));
3672
+ console.error(chalk15.red("No config found. Run `tch init` first."));
3514
3673
  process.exit(1);
3515
3674
  }
3516
- console.log(chalk14.bold.cyan("\nTechunter \u2014 Settings\n"));
3517
- console.log(chalk14.dim(`Config file: ${getConfigPath()}
3675
+ console.log(chalk15.bold.cyan("\nTechunter \u2014 Settings\n"));
3676
+ console.log(chalk15.dim(`Config file: ${getConfigPath()}
3518
3677
  `));
3519
3678
  const currentBaseUrl = config.aiBaseUrl ?? DEFAULT_BASE_URL;
3520
3679
  const currentModel = config.aiModel ?? DEFAULT_MODEL;
3521
3680
  const currentBaseBranch = config.baseBranch ?? "main";
3522
- const field = await select12({
3681
+ const field = await select13({
3523
3682
  message: "Which setting to change?",
3524
3683
  choices: [
3525
- { name: `GitHub repo ${chalk14.dim(`${config.github.owner}/${config.github.repo}`)}`, value: "repo" },
3526
- { name: `Base branch ${chalk14.dim(currentBaseBranch)}`, value: "baseBranch" },
3527
- { name: `AI base URL ${chalk14.dim(currentBaseUrl)}`, value: "aiBaseUrl" },
3528
- { name: `AI model ${chalk14.dim(currentModel)}`, value: "aiModel" },
3529
- { name: `AI API Key ${chalk14.dim("(hidden)")}`, value: "aiApiKey" },
3530
- { name: `GitHub Token ${chalk14.dim("(hidden)")}`, value: "githubToken" },
3684
+ { name: `GitHub repo ${chalk15.dim(`${config.github.owner}/${config.github.repo}`)}`, value: "repo" },
3685
+ { name: `Base branch ${chalk15.dim(currentBaseBranch)}`, value: "baseBranch" },
3686
+ { name: `AI base URL ${chalk15.dim(currentBaseUrl)}`, value: "aiBaseUrl" },
3687
+ { name: `AI model ${chalk15.dim(currentModel)}`, value: "aiModel" },
3688
+ { name: `AI API Key ${chalk15.dim("(hidden)")}`, value: "aiApiKey" },
3689
+ { name: `GitHub Token ${chalk15.dim("(hidden)")}`, value: "githubToken" },
3531
3690
  { name: "Cancel", value: "cancel" }
3532
3691
  ]
3533
3692
  });
@@ -3536,7 +3695,7 @@ async function configCommand() {
3536
3695
  const val = await input2({ message: "Base branch name:", default: currentBaseBranch });
3537
3696
  if (val.trim()) {
3538
3697
  setConfig({ baseBranch: val.trim() });
3539
- console.log(chalk14.green(`
3698
+ console.log(chalk15.green(`
3540
3699
  Base branch set to: ${val.trim()}
3541
3700
  `));
3542
3701
  }
@@ -3544,14 +3703,14 @@ Base branch set to: ${val.trim()}
3544
3703
  const owner = await input2({ message: "GitHub repo owner:", default: config.github.owner });
3545
3704
  const repo = await input2({ message: "GitHub repo name:", default: config.github.repo });
3546
3705
  setConfig({ github: { ...config.github, owner: owner.trim(), repo: repo.trim() } });
3547
- console.log(chalk14.green(`
3706
+ console.log(chalk15.green(`
3548
3707
  Repo set to: ${owner.trim()}/${repo.trim()}
3549
3708
  `));
3550
3709
  } else if (field === "aiBaseUrl") {
3551
3710
  const val = await input2({ message: "AI base URL:", default: currentBaseUrl });
3552
3711
  if (val.trim()) {
3553
3712
  setConfig({ aiBaseUrl: val.trim() });
3554
- console.log(chalk14.green(`
3713
+ console.log(chalk15.green(`
3555
3714
  AI base URL set to: ${val.trim()}
3556
3715
  `));
3557
3716
  }
@@ -3559,7 +3718,7 @@ AI base URL set to: ${val.trim()}
3559
3718
  const val = await input2({ message: "AI model name:", default: currentModel });
3560
3719
  if (val.trim()) {
3561
3720
  setConfig({ aiModel: val.trim() });
3562
- console.log(chalk14.green(`
3721
+ console.log(chalk15.green(`
3563
3722
  AI model set to: ${val.trim()}
3564
3723
  `));
3565
3724
  }
@@ -3567,13 +3726,13 @@ AI model set to: ${val.trim()}
3567
3726
  const val = await password2({ message: "New AI API Key:", mask: "*" });
3568
3727
  if (val.trim()) {
3569
3728
  setConfig({ aiApiKey: val.trim() });
3570
- console.log(chalk14.green("\nAI API Key updated.\n"));
3729
+ console.log(chalk15.green("\nAI API Key updated.\n"));
3571
3730
  }
3572
3731
  } else if (field === "githubToken") {
3573
3732
  const val = await password2({ message: "New GitHub Token:", mask: "*" });
3574
3733
  if (val.trim()) {
3575
3734
  setConfig({ githubToken: val.trim() });
3576
- console.log(chalk14.green("\nGitHub Token updated.\n"));
3735
+ console.log(chalk15.green("\nGitHub Token updated.\n"));
3577
3736
  }
3578
3737
  }
3579
3738
  }
@@ -3582,8 +3741,8 @@ AI model set to: ${val.trim()}
3582
3741
  init_github();
3583
3742
 
3584
3743
  // src/lib/agent.ts
3585
- import ora15 from "ora";
3586
- import chalk15 from "chalk";
3744
+ import ora16 from "ora";
3745
+ import chalk16 from "chalk";
3587
3746
  var tools = toolModules.map((m) => m.definition);
3588
3747
  var HISTORY_KEEP_TURNS = 8;
3589
3748
  function trimHistory(messages) {
@@ -3669,7 +3828,7 @@ async function runAgentLoop(config, messages) {
3669
3828
  throw new Error(`Agent exceeded ${MAX_ITERATIONS} iterations without finishing.`);
3670
3829
  }
3671
3830
  trimHistory(messages);
3672
- const spinner = ora15({ text: chalk15.dim("Thinking\u2026"), color: "cyan" }).start();
3831
+ const spinner = ora16({ text: chalk16.dim("Thinking\u2026"), color: "cyan" }).start();
3673
3832
  let response;
3674
3833
  try {
3675
3834
  response = await client.chat.completions.create({
@@ -3714,7 +3873,7 @@ async function runAgentLoop(config, messages) {
3714
3873
  return executeTool(tc.function.name, parsed, config);
3715
3874
  })
3716
3875
  );
3717
- let terminal13 = false;
3876
+ let terminal14 = false;
3718
3877
  for (let i = 0; i < toolCalls.length; i++) {
3719
3878
  printToolResult(results[i]);
3720
3879
  messages.push({
@@ -3723,10 +3882,10 @@ async function runAgentLoop(config, messages) {
3723
3882
  content: results[i]
3724
3883
  });
3725
3884
  if (toolModules.find((m) => m.definition.function.name === toolCalls[i].function.name)?.terminal) {
3726
- terminal13 = true;
3885
+ terminal14 = true;
3727
3886
  }
3728
3887
  }
3729
- if (terminal13) return results[results.length - 1];
3888
+ if (terminal14) return results[results.length - 1];
3730
3889
  } else {
3731
3890
  return choice.message.content ?? "";
3732
3891
  }
@@ -3735,7 +3894,7 @@ async function runAgentLoop(config, messages) {
3735
3894
 
3736
3895
  // src/lib/update-check.ts
3737
3896
  import Conf2 from "conf";
3738
- import chalk16 from "chalk";
3897
+ import chalk17 from "chalk";
3739
3898
  import { execFile } from "child_process";
3740
3899
  var PACKAGE_NAME = "techunter";
3741
3900
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
@@ -3796,16 +3955,16 @@ async function startAutoUpdate(currentVersion) {
3796
3955
  ]);
3797
3956
  if (!latest) return;
3798
3957
  console.log(
3799
- chalk16.cyan("\n \u2191 Auto-updating to v" + latest + "\u2026") + chalk16.dim(" (running in background)\n")
3958
+ chalk17.cyan("\n \u2191 Auto-updating to v" + latest + "\u2026") + chalk17.dim(" (running in background)\n")
3800
3959
  );
3801
3960
  installUpdate().then((installedVersion) => {
3802
3961
  console.log(
3803
- "\n" + chalk16.green(" \u2714 Updated to v" + (installedVersion || latest)) + chalk16.dim(" \u2014 restart tch to use the new version\n") + chalk16.cyan(" You \u203A ")
3962
+ "\n" + chalk17.green(" \u2714 Updated to v" + (installedVersion || latest)) + chalk17.dim(" \u2014 restart tch to use the new version\n") + chalk17.cyan(" You \u203A ")
3804
3963
  // redraw the prompt hint
3805
3964
  );
3806
3965
  }).catch((err) => {
3807
3966
  console.log(
3808
- "\n" + chalk16.red(" \u2718 Auto-update failed: ") + chalk16.dim(err.message) + "\n" + chalk16.dim(" Run manually: npm install -g techunter\n") + chalk16.cyan(" You \u203A ")
3967
+ "\n" + chalk17.red(" \u2718 Auto-update failed: ") + chalk17.dim(err.message) + "\n" + chalk17.dim(" Run manually: npm install -g techunter\n") + chalk17.cyan(" You \u203A ")
3809
3968
  );
3810
3969
  });
3811
3970
  }
@@ -3828,6 +3987,8 @@ var SLASH_NAMES = [
3828
3987
  "/d",
3829
3988
  "/edit",
3830
3989
  "/e",
3990
+ "/move",
3991
+ "/mv",
3831
3992
  "/review",
3832
3993
  "/rv",
3833
3994
  "/accept",
@@ -3853,8 +4014,14 @@ var _rl = null;
3853
4014
  function promptUser() {
3854
4015
  return new Promise((resolve) => {
3855
4016
  if (process.stdin.isPaused()) process.stdin.resume();
4017
+ if (process.stdin.isTTY) {
4018
+ try {
4019
+ process.stdin.setRawMode(true);
4020
+ } catch {
4021
+ }
4022
+ }
3856
4023
  _rl.resume();
3857
- _rl.question(chalk17.cyan("You") + chalk17.dim(" \u203A "), resolve);
4024
+ _rl.question(chalk18.cyan("You") + chalk18.dim(" \u203A "), resolve);
3858
4025
  });
3859
4026
  }
3860
4027
  var COMMANDS = [
@@ -3864,6 +4031,7 @@ var COMMANDS = [
3864
4031
  { cmd: "/new", alias: "/n", desc: "Create a new task interactively" },
3865
4032
  { cmd: "/close", alias: "/d", desc: "Close (delete) a task" },
3866
4033
  { cmd: "/edit", alias: "/e", desc: "Edit the title or description of a task" },
4034
+ { cmd: "/move", alias: "/mv", desc: "Move your task under another task as a sub-task" },
3867
4035
  { cmd: "/submit", alias: "/s", desc: "Commit, create PR, and mark in-review" },
3868
4036
  { cmd: "/review", alias: "/rv", desc: "List tasks waiting for your approval" },
3869
4037
  { cmd: "/accept", alias: "/ac", desc: "Accept a reviewed task: merge PR and close issue" },
@@ -3875,40 +4043,40 @@ var COMMANDS = [
3875
4043
  ];
3876
4044
  function cmdHelp() {
3877
4045
  console.log("");
3878
- console.log(chalk17.bold(" Commands"));
3879
- console.log(chalk17.dim(" \u2500".repeat(35)));
4046
+ console.log(chalk18.bold(" Commands"));
4047
+ console.log(chalk18.dim(" \u2500".repeat(35)));
3880
4048
  for (const { cmd, alias, desc } of COMMANDS) {
3881
- const left = (cmd + (alias ? ` ${chalk17.dim(alias)}` : "")).padEnd(22);
3882
- console.log(` ${chalk17.cyan(cmd)}${alias ? " " + chalk17.dim(alias) : ""}`.padEnd(30) + chalk17.dim(desc));
4049
+ const left = (cmd + (alias ? ` ${chalk18.dim(alias)}` : "")).padEnd(22);
4050
+ console.log(` ${chalk18.cyan(cmd)}${alias ? " " + chalk18.dim(alias) : ""}`.padEnd(30) + chalk18.dim(desc));
3883
4051
  }
3884
- console.log(chalk17.dim("\n Anything else is sent to the AI agent.\n"));
4052
+ console.log(chalk18.dim("\n Anything else is sent to the AI agent.\n"));
3885
4053
  }
3886
4054
  function printBanner(config) {
3887
4055
  const { owner, repo } = config.github;
3888
- const g = chalk17.cyan;
3889
- const b = chalk17.bold.white;
3890
- const p = chalk17.yellow.bold;
4056
+ const g = chalk18.cyan;
4057
+ const b = chalk18.bold.white;
4058
+ const p = chalk18.yellow.bold;
3891
4059
  console.log("");
3892
4060
  console.log(" " + g("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
3893
4061
  console.log(p("\u25C6") + b("\u2550\u2550\u2550") + g("\u256C") + b(" TECHUNTER ") + g("\u256C") + b("\u2550\u2550\u2550\u25B6"));
3894
4062
  console.log(" " + g("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
3895
4063
  console.log("");
3896
4064
  console.log(
3897
- " " + chalk17.bold("Techunter") + chalk17.dim(` v${version}`) + chalk17.dim(" \xB7 ") + chalk17.cyan(getModel(config)) + chalk17.dim(" \xB7 ") + chalk17.dim(`${owner}/${repo}`)
4065
+ " " + chalk18.bold("Techunter") + chalk18.dim(` v${version}`) + chalk18.dim(" \xB7 ") + chalk18.cyan(getModel(config)) + chalk18.dim(" \xB7 ") + chalk18.dim(`${owner}/${repo}`)
3898
4066
  );
3899
4067
  console.log("");
3900
4068
  }
3901
4069
  async function initNewRepo(config, owner, repo) {
3902
4070
  console.log("");
3903
- console.log(chalk17.bold.cyan(` New repo detected: ${owner}/${repo}`));
3904
- console.log(chalk17.dim(" Setting up Techunter for this repository...\n"));
4071
+ console.log(chalk18.bold.cyan(` New repo detected: ${owner}/${repo}`));
4072
+ console.log(chalk18.dim(" Setting up Techunter for this repository...\n"));
3905
4073
  const newConfig = {
3906
4074
  ...config,
3907
4075
  github: { owner, repo }
3908
4076
  };
3909
4077
  setConfig({ github: newConfig.github });
3910
- const ora16 = (await import("ora")).default;
3911
- const spinner = ora16("Creating Techunter labels...").start();
4078
+ const ora17 = (await import("ora")).default;
4079
+ const spinner = ora17("Creating Techunter labels...").start();
3912
4080
  try {
3913
4081
  await ensureLabels(newConfig);
3914
4082
  spinner.succeed("Labels ready");
@@ -3924,7 +4092,7 @@ async function main() {
3924
4092
  try {
3925
4093
  await configCommand();
3926
4094
  } catch (err) {
3927
- console.error(chalk17.red(`
4095
+ console.error(chalk18.red(`
3928
4096
  Error: ${err.message}`));
3929
4097
  process.exit(1);
3930
4098
  }
@@ -3938,7 +4106,7 @@ Error: ${err.message}`));
3938
4106
  await initCommand();
3939
4107
  config = getConfig();
3940
4108
  } catch (err) {
3941
- console.error(chalk17.red(`
4109
+ console.error(chalk18.red(`
3942
4110
  Setup failed: ${err.message}`));
3943
4111
  process.exit(1);
3944
4112
  return;
@@ -3956,11 +4124,11 @@ Setup failed: ${err.message}`));
3956
4124
  }
3957
4125
  }
3958
4126
  } else if (!config.github.owner) {
3959
- console.error(chalk17.red("\nNo git remote found and no repo configured. Run tch init."));
4127
+ console.error(chalk18.red("\nNo git remote found and no repo configured. Run tch init."));
3960
4128
  process.exit(1);
3961
4129
  }
3962
4130
  printBanner(config);
3963
- console.log(chalk17.dim(" Type /help for commands, or describe what you want.\n"));
4131
+ console.log(chalk18.dim(" Type /help for commands, or describe what you want.\n"));
3964
4132
  startAutoUpdate(version).catch(() => {
3965
4133
  });
3966
4134
  await printTaskList(config);
@@ -3972,11 +4140,11 @@ Setup failed: ${err.message}`));
3972
4140
  terminal: true
3973
4141
  });
3974
4142
  _rl.on("close", () => {
3975
- console.log(chalk17.gray("\nGoodbye!"));
4143
+ console.log(chalk18.gray("\nGoodbye!"));
3976
4144
  process.exit(0);
3977
4145
  });
3978
4146
  _rl.on("SIGINT", () => {
3979
- console.log(chalk17.gray("\nGoodbye!"));
4147
+ console.log(chalk18.gray("\nGoodbye!"));
3980
4148
  process.exit(0);
3981
4149
  });
3982
4150
  const messages = [];
@@ -4001,7 +4169,7 @@ Setup failed: ${err.message}`));
4001
4169
  const preselected = arg ? parseInt(arg, 10) : void 0;
4002
4170
  const result = await run3({ issue_number: Number.isNaN(preselected) ? void 0 : preselected }, config);
4003
4171
  if (result && result !== "Cancelled.") {
4004
- console.log(chalk17.green(`
4172
+ console.log(chalk18.green(`
4005
4173
  ${result}
4006
4174
  `));
4007
4175
  }
@@ -4011,7 +4179,7 @@ Setup failed: ${err.message}`));
4011
4179
  case "/new":
4012
4180
  case "/n": {
4013
4181
  const result = await run4({}, config);
4014
- console.log(chalk17.green(`
4182
+ console.log(chalk18.green(`
4015
4183
  ${result}
4016
4184
  `));
4017
4185
  await printTaskList(config);
@@ -4029,7 +4197,18 @@ Setup failed: ${err.message}`));
4029
4197
  const arg = userInput.slice(cmd.length).trim().replace(/^#/, "");
4030
4198
  const preselected = arg ? parseInt(arg, 10) : void 0;
4031
4199
  const result = await run11({ issue_number: Number.isNaN(preselected) ? void 0 : preselected }, config);
4032
- console.log(chalk17.green(`
4200
+ console.log(chalk18.green(`
4201
+ ${result}
4202
+ `));
4203
+ await printTaskList(config);
4204
+ break;
4205
+ }
4206
+ case "/move":
4207
+ case "/mv": {
4208
+ const arg = userInput.slice(cmd.length).trim().replace(/^#/, "");
4209
+ const preselected = arg ? parseInt(arg, 10) : void 0;
4210
+ const result = await run12({ issue_number: Number.isNaN(preselected) ? void 0 : preselected }, config);
4211
+ console.log(chalk18.green(`
4033
4212
  ${result}
4034
4213
  `));
4035
4214
  await printTaskList(config);
@@ -4038,7 +4217,7 @@ Setup failed: ${err.message}`));
4038
4217
  case "/close":
4039
4218
  case "/d": {
4040
4219
  const result = await run2({}, config);
4041
- console.log(chalk17.green(`
4220
+ console.log(chalk18.green(`
4042
4221
  ${result}
4043
4222
  `));
4044
4223
  await printTaskList(config);
@@ -4061,7 +4240,7 @@ Setup failed: ${err.message}`));
4061
4240
  const arg = userInput.slice(cmd.length).trim().replace(/^#/, "");
4062
4241
  const preselected = arg ? parseInt(arg, 10) : void 0;
4063
4242
  const result = await run6({ issue_number: Number.isNaN(preselected) ? void 0 : preselected }, config);
4064
- console.log(chalk17.green(`
4243
+ console.log(chalk18.green(`
4065
4244
  ${result}
4066
4245
  `));
4067
4246
  await printTaskList(config);
@@ -4077,7 +4256,7 @@ Setup failed: ${err.message}`));
4077
4256
  config = getConfig();
4078
4257
  await printTaskList(config);
4079
4258
  } catch (err) {
4080
- console.error(chalk17.red(`
4259
+ console.error(chalk18.red(`
4081
4260
  Init failed: ${err.message}
4082
4261
  `));
4083
4262
  }
@@ -4088,14 +4267,14 @@ Init failed: ${err.message}
4088
4267
  break;
4089
4268
  case "/wiki":
4090
4269
  case "/w": {
4091
- const result = await run12({}, config);
4092
- console.log(chalk17.green(`
4270
+ const result = await run13({}, config);
4271
+ console.log(chalk18.green(`
4093
4272
  ${result}
4094
4273
  `));
4095
4274
  break;
4096
4275
  }
4097
4276
  default:
4098
- console.log(chalk17.yellow(` Unknown command: ${cmd} (try /help)`));
4277
+ console.log(chalk18.yellow(` Unknown command: ${cmd} (try /help)`));
4099
4278
  }
4100
4279
  continue;
4101
4280
  }
@@ -4103,10 +4282,10 @@ Init failed: ${err.message}
4103
4282
  messages.push({ role: "user", content: userInput });
4104
4283
  try {
4105
4284
  const response = await runAgentLoop(config, messages);
4106
- console.log("\n" + chalk17.green("Techunter:") + "\n" + renderMarkdown(response));
4285
+ console.log("\n" + chalk18.green("Techunter:") + "\n" + renderMarkdown(response));
4107
4286
  } catch (err) {
4108
4287
  messages.splice(prevLength);
4109
- console.error(chalk17.red(`
4288
+ console.error(chalk18.red(`
4110
4289
  Error: ${err.message}
4111
4290
  `));
4112
4291
  }
@@ -4114,6 +4293,6 @@ Error: ${err.message}
4114
4293
  }
4115
4294
  }
4116
4295
  main().catch((err) => {
4117
- console.error(chalk17.red(`Fatal: ${err.message}`));
4296
+ console.error(chalk18.red(`Fatal: ${err.message}`));
4118
4297
  process.exit(1);
4119
4298
  });