@krodak/clickup-cli 1.5.2 → 1.6.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.
package/dist/index.js CHANGED
@@ -100,6 +100,12 @@ var ClickUpClient = class {
100
100
  ...options.headers
101
101
  }
102
102
  });
103
+ if (res.status === 204 || res.headers.get("content-length") === "0") {
104
+ if (!res.ok) {
105
+ throw new Error(`ClickUp API error ${res.status}: ${res.statusText}`);
106
+ }
107
+ return {};
108
+ }
103
109
  let parsed;
104
110
  try {
105
111
  parsed = await res.json();
@@ -741,62 +747,243 @@ function migrateFromLegacy() {
741
747
  function configPath() {
742
748
  return join(configDir(), "config.json");
743
749
  }
744
- function loadConfig() {
750
+ function migrateToMultiProfile(parsed, filePath) {
751
+ if (typeof parsed.apiToken === "string" && !parsed.profiles) {
752
+ const profile = {};
753
+ const token = trimConfigValue(parsed.apiToken);
754
+ if (token) profile.apiToken = token;
755
+ const team = typeof parsed.teamId === "string" ? trimConfigValue(parsed.teamId) : void 0;
756
+ if (team) profile.teamId = team;
757
+ const sprint = typeof parsed.sprintFolderId === "string" ? trimConfigValue(parsed.sprintFolderId) : void 0;
758
+ if (sprint) profile.sprintFolderId = sprint;
759
+ const migrated = {
760
+ defaultProfile: "default",
761
+ profiles: { default: profile }
762
+ };
763
+ const dir = configDir();
764
+ if (!fs.existsSync(dir)) {
765
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
766
+ }
767
+ fs.writeFileSync(join(dir, "config.json"), JSON.stringify(migrated, null, 2) + "\n", {
768
+ encoding: "utf-8",
769
+ mode: 384
770
+ });
771
+ return migrated;
772
+ }
773
+ if (isRecord2(parsed.profiles)) {
774
+ const profiles = {};
775
+ for (const [name, value] of Object.entries(parsed.profiles)) {
776
+ if (isRecord2(value)) {
777
+ const p = {};
778
+ if (typeof value.apiToken === "string" && value.apiToken.trim())
779
+ p.apiToken = value.apiToken.trim();
780
+ if (typeof value.teamId === "string" && value.teamId.trim()) p.teamId = value.teamId.trim();
781
+ if (typeof value.sprintFolderId === "string" && value.sprintFolderId.trim())
782
+ p.sprintFolderId = value.sprintFolderId.trim();
783
+ profiles[name] = p;
784
+ }
785
+ }
786
+ return {
787
+ defaultProfile: typeof parsed.defaultProfile === "string" ? parsed.defaultProfile : "",
788
+ profiles
789
+ };
790
+ }
791
+ throw new Error(`Config file at ${filePath} has unrecognized format.`);
792
+ }
793
+ function parseRawConfig(filePath) {
794
+ const raw = fs.readFileSync(filePath, "utf-8");
795
+ let parsed;
796
+ try {
797
+ parsed = JSON.parse(raw);
798
+ } catch {
799
+ throw new Error(
800
+ `Config file at ${filePath} contains invalid JSON. Please check the file syntax.`
801
+ );
802
+ }
803
+ if (!isRecord2(parsed)) {
804
+ throw new Error(`Config file at ${filePath} must contain a JSON object.`);
805
+ }
806
+ return { parsed, raw };
807
+ }
808
+ function isOldFormat(parsed) {
809
+ return typeof parsed.apiToken === "string" && !parsed.profiles;
810
+ }
811
+ function loadConfig(profileName) {
745
812
  migrateFromLegacy();
746
813
  const envToken = process.env.CU_API_TOKEN?.trim();
747
814
  const envTeamId = process.env.CU_TEAM_ID?.trim();
748
- let fileToken;
749
- let fileTeamId;
750
- let fileSprintFolderId;
815
+ if (envToken && envTeamId) {
816
+ if (!envToken.startsWith("pk_")) {
817
+ throw new Error("CU_API_TOKEN must start with pk_.");
818
+ }
819
+ return { apiToken: envToken, teamId: envTeamId };
820
+ }
751
821
  const path = configPath();
752
- if (fs.existsSync(path)) {
753
- const raw = fs.readFileSync(path, "utf-8");
754
- const parsed = parseConfigFile(raw, path, true);
755
- fileToken = parsed.apiToken;
756
- fileTeamId = parsed.teamId;
757
- fileSprintFolderId = parsed.sprintFolderId;
822
+ if (!fs.existsSync(path)) {
823
+ if (envToken || envTeamId) {
824
+ throw new Error("Both CU_API_TOKEN and CU_TEAM_ID must be set, or run: cup init");
825
+ }
826
+ throw new Error("Config missing required field: apiToken.\nSet CU_API_TOKEN or run: cup init");
758
827
  }
759
- const apiToken = envToken || fileToken;
828
+ const { parsed } = parseRawConfig(path);
829
+ if (isOldFormat(parsed)) {
830
+ const fileConfig = parseConfigFile(JSON.stringify(parsed), path, true);
831
+ const apiToken2 = envToken ?? fileConfig.apiToken;
832
+ if (!apiToken2) {
833
+ throw new Error("Config missing required field: apiToken.\nSet CU_API_TOKEN or run: cup init");
834
+ }
835
+ if (!apiToken2.startsWith("pk_")) {
836
+ throw new Error("Config apiToken must start with pk_. The configured token does not.");
837
+ }
838
+ const teamId2 = envTeamId ?? fileConfig.teamId;
839
+ if (!teamId2) {
840
+ throw new Error("Config missing required field: teamId.\nSet CU_TEAM_ID or run: cup init");
841
+ }
842
+ migrateToMultiProfile(parsed, path);
843
+ return {
844
+ apiToken: apiToken2,
845
+ teamId: teamId2,
846
+ ...fileConfig.sprintFolderId ? { sprintFolderId: fileConfig.sprintFolderId } : {}
847
+ };
848
+ }
849
+ const multi = migrateToMultiProfile(parsed, path);
850
+ const resolvedProfile = profileName ?? process.env.CU_PROFILE?.trim() ?? multi.defaultProfile;
851
+ if (!resolvedProfile) {
852
+ throw new Error("No default profile set. Run: cup profile use <name>");
853
+ }
854
+ const profile = multi.profiles[resolvedProfile];
855
+ if (!profile) {
856
+ const available = Object.keys(multi.profiles).join(", ");
857
+ throw new Error(`Profile "${resolvedProfile}" not found. Available: ${available}`);
858
+ }
859
+ const apiToken = envToken ?? profile.apiToken?.trim();
760
860
  if (!apiToken) {
761
- throw new Error("Config missing required field: apiToken.\nSet CU_API_TOKEN or run: cup init");
861
+ throw new Error(
862
+ `Profile "${resolvedProfile}" missing apiToken. Run: cup profile add ${resolvedProfile}`
863
+ );
762
864
  }
763
865
  if (!apiToken.startsWith("pk_")) {
764
866
  throw new Error("Config apiToken must start with pk_. The configured token does not.");
765
867
  }
766
- const teamId = envTeamId || fileTeamId;
868
+ const teamId = envTeamId ?? profile.teamId?.trim();
767
869
  if (!teamId) {
768
- throw new Error("Config missing required field: teamId.\nSet CU_TEAM_ID or run: cup init");
870
+ throw new Error(`Profile "${resolvedProfile}" missing teamId.`);
769
871
  }
770
- return { apiToken, teamId, ...fileSprintFolderId ? { sprintFolderId: fileSprintFolderId } : {} };
872
+ return {
873
+ apiToken,
874
+ teamId,
875
+ ...profile.sprintFolderId ? { sprintFolderId: profile.sprintFolderId } : {}
876
+ };
771
877
  }
772
- function loadRawConfig() {
878
+ function loadMultiProfileConfig() {
879
+ migrateFromLegacy();
880
+ const path = configPath();
881
+ if (!fs.existsSync(path)) {
882
+ return { defaultProfile: "", profiles: {} };
883
+ }
884
+ let parsed;
885
+ try {
886
+ const raw = fs.readFileSync(path, "utf-8");
887
+ parsed = JSON.parse(raw);
888
+ } catch {
889
+ return { defaultProfile: "", profiles: {} };
890
+ }
891
+ if (!isRecord2(parsed)) return { defaultProfile: "", profiles: {} };
892
+ if (isOldFormat(parsed)) {
893
+ return migrateToMultiProfile(parsed, path);
894
+ }
895
+ return migrateToMultiProfile(parsed, path);
896
+ }
897
+ function saveMultiProfileConfig(config) {
898
+ const dir = configDir();
899
+ if (!fs.existsSync(dir)) {
900
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
901
+ }
902
+ fs.writeFileSync(join(dir, "config.json"), JSON.stringify(config, null, 2) + "\n", {
903
+ encoding: "utf-8",
904
+ mode: 384
905
+ });
906
+ }
907
+ function addProfile(name, profile) {
908
+ const multi = loadMultiProfileConfig();
909
+ multi.profiles[name] = profile;
910
+ if (!multi.defaultProfile) multi.defaultProfile = name;
911
+ saveMultiProfileConfig(multi);
912
+ }
913
+ function removeProfile(name) {
914
+ const multi = loadMultiProfileConfig();
915
+ if (!multi.profiles[name]) {
916
+ throw new Error(`Profile "${name}" not found.`);
917
+ }
918
+ const keys = Object.keys(multi.profiles);
919
+ if (keys.length <= 1) {
920
+ throw new Error("Cannot remove the last profile.");
921
+ }
922
+ delete multi.profiles[name];
923
+ if (multi.defaultProfile === name) {
924
+ multi.defaultProfile = Object.keys(multi.profiles)[0] ?? "";
925
+ }
926
+ saveMultiProfileConfig(multi);
927
+ }
928
+ function setDefaultProfile(name) {
929
+ const multi = loadMultiProfileConfig();
930
+ if (!multi.profiles[name]) {
931
+ const available = Object.keys(multi.profiles).join(", ");
932
+ throw new Error(`Profile "${name}" not found. Available: ${available}`);
933
+ }
934
+ multi.defaultProfile = name;
935
+ saveMultiProfileConfig(multi);
936
+ }
937
+ function listProfiles() {
938
+ const multi = loadMultiProfileConfig();
939
+ return Object.entries(multi.profiles).map(([name, profile]) => ({
940
+ name,
941
+ isDefault: name === multi.defaultProfile,
942
+ teamId: profile.teamId
943
+ }));
944
+ }
945
+ function loadRawConfig(profileName) {
773
946
  migrateFromLegacy();
774
947
  const path = configPath();
775
948
  if (!fs.existsSync(path)) return {};
776
- return parseConfigFile(fs.readFileSync(path, "utf-8"), path, false, true);
949
+ let parsed;
950
+ try {
951
+ const raw = fs.readFileSync(path, "utf-8");
952
+ parsed = JSON.parse(raw);
953
+ } catch {
954
+ return {};
955
+ }
956
+ if (!isRecord2(parsed)) {
957
+ throw new Error(`Config file at ${path} must contain a JSON object.`);
958
+ }
959
+ if (isOldFormat(parsed)) {
960
+ return parseConfigFile(JSON.stringify(parsed), path, false, true);
961
+ }
962
+ const multi = migrateToMultiProfile(parsed, path);
963
+ const name = profileName || multi.defaultProfile || "default";
964
+ return multi.profiles[name] ?? {};
777
965
  }
778
966
  function getConfigPath() {
779
967
  migrateFromLegacy();
780
968
  return configPath();
781
969
  }
782
- function writeConfig(config) {
783
- const dir = configDir();
784
- if (!fs.existsSync(dir)) {
785
- fs.mkdirSync(dir, { recursive: true, mode: 448 });
786
- }
787
- const filePath = join(dir, "config.json");
788
- const apiToken = trimConfigValue(config.apiToken) ?? "";
789
- const teamId = trimConfigValue(config.teamId) ?? "";
970
+ function writeConfig(config, profileName) {
971
+ const multi = loadMultiProfileConfig();
972
+ const name = profileName || multi.defaultProfile || "default";
973
+ const apiToken = trimConfigValue(config.apiToken) ?? void 0;
974
+ const teamId = trimConfigValue(config.teamId) ?? void 0;
790
975
  const sprintFolderId = trimConfigValue(config.sprintFolderId);
791
976
  const normalizedConfig = {
792
977
  ...apiToken ? { apiToken } : {},
793
978
  ...teamId ? { teamId } : {},
794
979
  ...sprintFolderId ? { sprintFolderId } : {}
795
980
  };
796
- fs.writeFileSync(filePath, JSON.stringify(normalizedConfig, null, 2) + "\n", {
797
- encoding: "utf-8",
798
- mode: 384
799
- });
981
+ multi.profiles[name] = {
982
+ ...multi.profiles[name],
983
+ ...normalizedConfig
984
+ };
985
+ if (!multi.defaultProfile) multi.defaultProfile = name;
986
+ saveMultiProfileConfig(multi);
800
987
  }
801
988
 
802
989
  // src/date.ts
@@ -1386,7 +1573,10 @@ function parseTimeEstimate(value) {
1386
1573
  }
1387
1574
  function buildUpdatePayload(opts) {
1388
1575
  const payload = {};
1389
- if (opts.name !== void 0) payload.name = opts.name;
1576
+ if (opts.name !== void 0) {
1577
+ if (!opts.name.trim()) throw new Error("Task name cannot be empty");
1578
+ payload.name = opts.name;
1579
+ }
1390
1580
  if (opts.description !== void 0) payload.markdown_content = opts.description;
1391
1581
  if (opts.status !== void 0) payload.status = opts.status;
1392
1582
  if (opts.priority !== void 0) payload.priority = parsePriority(opts.priority);
@@ -1435,6 +1625,7 @@ async function updateTask(config, taskId, options) {
1435
1625
 
1436
1626
  // src/commands/create.ts
1437
1627
  async function createTask(config, options) {
1628
+ if (!options.name.trim()) throw new Error("Task name cannot be empty");
1438
1629
  const client = new ClickUpClient(config);
1439
1630
  let listId = options.list;
1440
1631
  if (!listId && options.parent) {
@@ -2255,12 +2446,12 @@ function assertValidKey(key) {
2255
2446
  throw new Error(`Unknown config key: ${key}. Valid keys: ${[...VALID_KEYS].join(", ")}`);
2256
2447
  }
2257
2448
  }
2258
- function getConfigValue(key) {
2449
+ function getConfigValue(key, profileName) {
2259
2450
  assertValidKey(key);
2260
- const raw = loadRawConfig();
2451
+ const raw = loadRawConfig(profileName);
2261
2452
  return readStoredString(raw[key]);
2262
2453
  }
2263
- function setConfigValue(key, value) {
2454
+ function setConfigValue(key, value, profileName) {
2264
2455
  assertValidKey(key);
2265
2456
  const normalizedValue = readStoredString(value);
2266
2457
  if (key === "apiToken" && (!normalizedValue || !normalizedValue.startsWith("pk_"))) {
@@ -2269,7 +2460,7 @@ function setConfigValue(key, value) {
2269
2460
  if (key === "teamId" && !normalizedValue) {
2270
2461
  throw new Error("teamId must be non-empty");
2271
2462
  }
2272
- const raw = loadRawConfig();
2463
+ const raw = loadRawConfig(profileName);
2273
2464
  const sprintFolderId = readStoredString(raw.sprintFolderId);
2274
2465
  const merged = {
2275
2466
  ...readStoredString(raw.apiToken) ? { apiToken: readStoredString(raw.apiToken) } : {},
@@ -2285,7 +2476,7 @@ function setConfigValue(key, value) {
2285
2476
  } else {
2286
2477
  merged[key] = normalizedValue;
2287
2478
  }
2288
- writeConfig(merged);
2479
+ writeConfig(merged, profileName);
2289
2480
  }
2290
2481
  function configPath2() {
2291
2482
  return getConfigPath();
@@ -2960,6 +3151,13 @@ var commandMetadata = [
2960
3151
  flags: ["--json"],
2961
3152
  quickReference: [{ section: "read", usage: "templates", description: "List task templates" }]
2962
3153
  },
3154
+ {
3155
+ name: "profile",
3156
+ description: "Manage profiles",
3157
+ quickReference: [
3158
+ { section: "configuration", usage: "profile", description: "Manage profiles" }
3159
+ ]
3160
+ },
2963
3161
  {
2964
3162
  name: "config",
2965
3163
  description: "Manage CLI configuration",
@@ -3016,7 +3214,14 @@ function topLevelCommandNames() {
3016
3214
  }
3017
3215
 
3018
3216
  // src/commands/completion.ts
3019
- var bashSpecialCaseCommands = /* @__PURE__ */ new Set(["checklist", "time", "bulk", "config", "completion"]);
3217
+ var bashSpecialCaseCommands = /* @__PURE__ */ new Set([
3218
+ "checklist",
3219
+ "time",
3220
+ "bulk",
3221
+ "config",
3222
+ "profile",
3223
+ "completion"
3224
+ ]);
3020
3225
  function escapeSingleQuotes(value) {
3021
3226
  return value.replaceAll("'", "'\\''");
3022
3227
  }
@@ -3109,6 +3314,11 @@ ${renderBashCommandCases()}
3109
3314
  COMPREPLY=($(compgen -W "status" -- "$cur"))
3110
3315
  fi
3111
3316
  ;;
3317
+ profile)
3318
+ if [[ $cword -eq 2 ]]; then
3319
+ COMPREPLY=($(compgen -W "list add remove use" -- "$cur"))
3320
+ fi
3321
+ ;;
3112
3322
  config)
3113
3323
  if [[ $cword -eq 2 ]]; then
3114
3324
  COMPREPLY=($(compgen -W "get set path" -- "$cur"))
@@ -3646,6 +3856,33 @@ ${renderZshTopLevelCommands(name)}
3646
3856
  '(-c --content)'{-c,--content}'[New page content]:text:' \\
3647
3857
  '--json[Force JSON output]'
3648
3858
  ;;
3859
+ profile)
3860
+ local -a profile_cmds
3861
+ profile_cmds=(
3862
+ 'list:List all profiles'
3863
+ 'add:Add a new profile'
3864
+ 'remove:Remove a profile'
3865
+ 'use:Set the default profile'
3866
+ )
3867
+ _arguments -C \\
3868
+ '1:profile command:->profile_cmd' \\
3869
+ '*::profile_arg:->profile_args'
3870
+ case $state in
3871
+ profile_cmd)
3872
+ _describe 'profile command' profile_cmds
3873
+ ;;
3874
+ profile_args)
3875
+ case $words[1] in
3876
+ list)
3877
+ _arguments '--json[Force JSON output]'
3878
+ ;;
3879
+ add|remove|use)
3880
+ _arguments '1:name:'
3881
+ ;;
3882
+ esac
3883
+ ;;
3884
+ esac
3885
+ ;;
3649
3886
  config)
3650
3887
  local -a config_cmds
3651
3888
  config_cmds=(
@@ -3726,6 +3963,12 @@ complete -c ${name} -n '__fish_seen_subcommand_from attach' -F
3726
3963
  complete -c ${name} -n '__fish_seen_subcommand_from bulk; and not __fish_seen_subcommand_from status' -a status -d 'Update status of multiple tasks'
3727
3964
  complete -c ${name} -n '__fish_seen_subcommand_from status; and __fish_seen_subcommand_from bulk' -l json -d 'Force JSON output'
3728
3965
 
3966
+ complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a list -d 'List all profiles'
3967
+ complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a add -d 'Add a new profile'
3968
+ complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a remove -d 'Remove a profile'
3969
+ complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a use -d 'Set the default profile'
3970
+ complete -c ${name} -n '__fish_seen_subcommand_from list; and __fish_seen_subcommand_from profile' -l json -d 'Force JSON output'
3971
+
3729
3972
  complete -c ${name} -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a get -d 'Print a config value'
3730
3973
  complete -c ${name} -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a set -d 'Set a config value'
3731
3974
  complete -c ${name} -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a path -d 'Print config file path'
@@ -4539,7 +4782,7 @@ function wrapAction(fn) {
4539
4782
  return async (...args) => {
4540
4783
  await fn(...args).catch((err) => {
4541
4784
  console.error(err instanceof Error ? err.message : String(err));
4542
- process.exit(1);
4785
+ process.exitCode = 1;
4543
4786
  });
4544
4787
  };
4545
4788
  }
@@ -4552,7 +4795,10 @@ function parseOptionalNumberOption(value, optionName) {
4552
4795
  }
4553
4796
  function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4554
4797
  const program = new Command();
4555
- program.name(programName).description("ClickUp CLI for AI agents").version(version).allowExcessArguments(false);
4798
+ program.name(programName).description("ClickUp CLI for AI agents").version(version).allowExcessArguments(false).option("-p, --profile <name>", "Use a specific profile");
4799
+ function getProfileName() {
4800
+ return program.opts().profile;
4801
+ }
4556
4802
  program.command("init").description(`Set up ${programName} for the first time`).action(
4557
4803
  wrapAction(async () => {
4558
4804
  await runInitCommand();
@@ -4560,7 +4806,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4560
4806
  );
4561
4807
  program.command("auth").description("Validate API token and show current user").option("--json", "Force JSON output even in terminal").action(
4562
4808
  wrapAction(async (opts) => {
4563
- const config = loadConfig();
4809
+ const config = loadConfig(getProfileName());
4564
4810
  const result = await checkAuth(config);
4565
4811
  if (shouldOutputJson(opts.json ?? false)) {
4566
4812
  console.log(JSON.stringify(result, null, 2));
@@ -4576,7 +4822,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4576
4822
  'Filter by task type (e.g. "task", "initiative", or custom type name/ID)'
4577
4823
  ).option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
4578
4824
  wrapAction(async (opts) => {
4579
- const config = loadConfig();
4825
+ const config = loadConfig(getProfileName());
4580
4826
  const tasks = await fetchMyTasks(config, {
4581
4827
  typeFilter: opts.type,
4582
4828
  statuses: opts.status ? [opts.status] : void 0,
@@ -4590,7 +4836,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4590
4836
  );
4591
4837
  program.command("task <taskId>").description("Get task details").option("--json", "Force JSON output even in terminal").action(
4592
4838
  wrapAction(async (taskId, opts) => {
4593
- const config = loadConfig();
4839
+ const config = loadConfig(getProfileName());
4594
4840
  const result = await getTask(config, taskId);
4595
4841
  if (shouldOutputJson(opts.json ?? false)) {
4596
4842
  console.log(JSON.stringify(result, null, 2));
@@ -4603,7 +4849,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4603
4849
  );
4604
4850
  program.command("update <taskId>").description("Update a task").option("-n, --name <text>", "New task name").option("-d, --description <text>", "New description (markdown supported)").option("-s, --status <status>", 'New status (e.g. "in progress", "done")').option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--assignee <userId>", 'Add assignee by user ID or "me"').option("--parent <taskId>", "Set parent task (makes this a subtask)").option("--json", "Force JSON output even in terminal").action(
4605
4851
  wrapAction(async (taskId, opts) => {
4606
- const config = loadConfig();
4852
+ const config = loadConfig(getProfileName());
4607
4853
  if (opts.assignee === "me") {
4608
4854
  const client = new ClickUpClient(config);
4609
4855
  opts.assignee = String(await resolveAssigneeId(client, "me"));
@@ -4619,7 +4865,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4619
4865
  );
4620
4866
  program.command("create").description("Create a new task").option("-l, --list <listId>", "Target list ID (auto-detected from --parent if omitted)").requiredOption("-n, --name <name>", "Task name").option("-d, --description <text>", "Task description (markdown supported)").option("-p, --parent <taskId>", "Parent task ID (list auto-detected from parent)").option("-s, --status <status>", "Initial status").option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--assignee <userId>", 'Assignee user ID or "me"').option("--tags <tags>", "Comma-separated tag names").option("--custom-item-id <id>", "Custom task type ID (use to create initiatives)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--template <id>", "Create from a task template").option("--json", "Force JSON output even in terminal").action(
4621
4867
  wrapAction(async (opts) => {
4622
- const config = loadConfig();
4868
+ const config = loadConfig(getProfileName());
4623
4869
  if (opts.assignee === "me") {
4624
4870
  const client = new ClickUpClient(config);
4625
4871
  opts.assignee = String(await resolveAssigneeId(client, "me"));
@@ -4635,21 +4881,21 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4635
4881
  program.command("sprint").description("List my tasks in the current active sprint (auto-detected)").option("--status <status>", "Filter by status").option("--space <nameOrId>", "Narrow sprint search to a specific space (partial name or ID)").option("--folder <folderId>", "Sprint folder ID (overrides config and auto-detection)").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
4636
4882
  wrapAction(
4637
4883
  async (opts) => {
4638
- const config = loadConfig();
4884
+ const config = loadConfig(getProfileName());
4639
4885
  await runSprintCommand(config, opts);
4640
4886
  }
4641
4887
  )
4642
4888
  );
4643
4889
  program.command("sprints").description("List all sprints in sprint folders").option("--space <nameOrId>", "Filter by space (partial name or ID)").option("--json", "Force JSON output even in terminal").action(
4644
4890
  wrapAction(async (opts) => {
4645
- const config = loadConfig();
4891
+ const config = loadConfig(getProfileName());
4646
4892
  await listSprints(config, opts);
4647
4893
  })
4648
4894
  );
4649
4895
  program.command("subtasks <taskId>").description("List subtasks of a task or initiative").option("--status <status>", "Filter by status").option("--name <partial>", "Filter by name (case-insensitive contains)").option("--include-closed", "Include closed/done subtasks").option("--json", "Force JSON output even in terminal").action(
4650
4896
  wrapAction(
4651
4897
  async (taskId, opts) => {
4652
- const config = loadConfig();
4898
+ const config = loadConfig(getProfileName());
4653
4899
  let tasks = await fetchSubtasks(config, taskId, { includeClosed: opts.includeClosed });
4654
4900
  if (opts.status) {
4655
4901
  const lower = opts.status.toLowerCase();
@@ -4666,7 +4912,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4666
4912
  program.command("comment <taskId>").description("Post a comment on a task").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
4667
4913
  wrapAction(
4668
4914
  async (taskId, opts) => {
4669
- const config = loadConfig();
4915
+ const config = loadConfig(getProfileName());
4670
4916
  const result = await postComment(config, taskId, opts.message, opts.notifyAll);
4671
4917
  if (shouldOutputJson(opts.json ?? false)) {
4672
4918
  console.log(JSON.stringify(result, null, 2));
@@ -4678,7 +4924,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4678
4924
  );
4679
4925
  program.command("comments <taskId>").description("List comments on a task").option("--json", "Force JSON output even in terminal").action(
4680
4926
  wrapAction(async (taskId, opts) => {
4681
- const config = loadConfig();
4927
+ const config = loadConfig(getProfileName());
4682
4928
  const comments = await fetchComments(config, taskId);
4683
4929
  printComments(comments, opts.json ?? false);
4684
4930
  })
@@ -4686,7 +4932,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4686
4932
  program.command("comment-edit <commentId>").description("Edit an existing comment").requiredOption("-m, --message <text>", "New comment text").option("--resolved", "Mark comment as resolved").option("--unresolved", "Mark comment as unresolved").option("--json", "Force JSON output even in terminal").action(
4687
4933
  wrapAction(
4688
4934
  async (commentId, opts) => {
4689
- const config = loadConfig();
4935
+ const config = loadConfig(getProfileName());
4690
4936
  let resolved;
4691
4937
  if (opts.resolved) resolved = true;
4692
4938
  if (opts.unresolved) resolved = false;
@@ -4701,7 +4947,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4701
4947
  );
4702
4948
  program.command("comment-delete <commentId>").description("Delete a comment").option("--json", "Force JSON output even in terminal").action(
4703
4949
  wrapAction(async (commentId, opts) => {
4704
- const config = loadConfig();
4950
+ const config = loadConfig(getProfileName());
4705
4951
  await deleteComment(config, commentId);
4706
4952
  if (shouldOutputJson(opts.json ?? false)) {
4707
4953
  console.log(JSON.stringify({ success: true, commentId }, null, 2));
@@ -4712,7 +4958,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4712
4958
  );
4713
4959
  program.command("replies <commentId>").description("List threaded replies on a comment").option("--json", "Force JSON output even in terminal").action(
4714
4960
  wrapAction(async (commentId, opts) => {
4715
- const config = loadConfig();
4961
+ const config = loadConfig(getProfileName());
4716
4962
  const replies = await getReplies(config, commentId);
4717
4963
  if (shouldOutputJson(opts.json ?? false)) {
4718
4964
  console.log(JSON.stringify(replies, null, 2));
@@ -4726,7 +4972,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4726
4972
  program.command("reply <commentId>").description("Reply to a comment").requiredOption("-m, --message <text>", "Reply text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
4727
4973
  wrapAction(
4728
4974
  async (commentId, opts) => {
4729
- const config = loadConfig();
4975
+ const config = loadConfig(getProfileName());
4730
4976
  await createReply(config, commentId, opts.message, opts.notifyAll);
4731
4977
  if (shouldOutputJson(opts.json ?? false)) {
4732
4978
  console.log(JSON.stringify({ success: true, commentId }, null, 2));
@@ -4738,27 +4984,27 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4738
4984
  );
4739
4985
  program.command("activity <taskId>").description("Show task details and comments combined").option("--json", "Force JSON output even in terminal").action(
4740
4986
  wrapAction(async (taskId, opts) => {
4741
- const config = loadConfig();
4987
+ const config = loadConfig(getProfileName());
4742
4988
  const result = await fetchActivity(config, taskId);
4743
4989
  printActivity(result, opts.json ?? false);
4744
4990
  })
4745
4991
  );
4746
4992
  program.command("lists <spaceId>").description("List all lists in a space (including lists inside folders)").option("--name <partial>", "Filter by name (case-insensitive contains)").option("--json", "Force JSON output even in terminal").action(
4747
4993
  wrapAction(async (spaceId, opts) => {
4748
- const config = loadConfig();
4994
+ const config = loadConfig(getProfileName());
4749
4995
  const lists = await fetchLists(config, spaceId, { name: opts.name });
4750
4996
  printLists(lists, opts.json ?? false);
4751
4997
  })
4752
4998
  );
4753
4999
  program.command("spaces").description("List spaces in your workspace").option("--name <partial>", "Filter spaces by name (case-insensitive contains)").option("--my", "Show only spaces where I have assigned tasks").option("--json", "Force JSON output even in terminal").action(
4754
5000
  wrapAction(async (opts) => {
4755
- const config = loadConfig();
5001
+ const config = loadConfig(getProfileName());
4756
5002
  await listSpaces(config, opts);
4757
5003
  })
4758
5004
  );
4759
5005
  program.command("inbox").description("Recently updated tasks grouped by time period").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").option("--days <n>", "Lookback period in days", "30").action(
4760
5006
  wrapAction(async (opts) => {
4761
- const config = loadConfig();
5007
+ const config = loadConfig(getProfileName());
4762
5008
  const days = Number(opts.days ?? 30);
4763
5009
  if (!Number.isFinite(days) || days <= 0) {
4764
5010
  throw new Error("--days must be a positive number");
@@ -4769,20 +5015,20 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4769
5015
  );
4770
5016
  program.command("assigned").description("Show all tasks assigned to me, grouped by status").option("--status <status>", "Show only tasks with this status").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
4771
5017
  wrapAction(async (opts) => {
4772
- const config = loadConfig();
5018
+ const config = loadConfig(getProfileName());
4773
5019
  await runAssignedCommand(config, opts);
4774
5020
  })
4775
5021
  );
4776
5022
  program.command("open <query>").description("Open a task in the browser by ID or name").option("--json", "Output task JSON instead of opening").action(
4777
5023
  wrapAction(async (query, opts) => {
4778
- const config = loadConfig();
5024
+ const config = loadConfig(getProfileName());
4779
5025
  await openTask(config, query, opts);
4780
5026
  })
4781
5027
  );
4782
5028
  program.command("search <query>").description("Search my tasks by name").option("--status <status>", "Filter by status").option("--include-closed", "Include done/closed tasks in search").option("--json", "Force JSON output even in terminal").action(
4783
5029
  wrapAction(
4784
5030
  async (query, opts) => {
4785
- const config = loadConfig();
5031
+ const config = loadConfig(getProfileName());
4786
5032
  const tasks = await searchTasks(config, query, {
4787
5033
  status: opts.status,
4788
5034
  includeClosed: opts.includeClosed
@@ -4793,7 +5039,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4793
5039
  );
4794
5040
  program.command("summary").description("Daily standup summary: completed, in-progress, overdue").option("--hours <n>", "Completed-tasks lookback in hours", "24").option("--json", "Force JSON output even in terminal").action(
4795
5041
  wrapAction(async (opts) => {
4796
- const config = loadConfig();
5042
+ const config = loadConfig(getProfileName());
4797
5043
  const hours = Number(opts.hours ?? 24);
4798
5044
  if (!Number.isFinite(hours) || hours <= 0) {
4799
5045
  throw new Error("--hours must be a positive number");
@@ -4803,14 +5049,14 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4803
5049
  );
4804
5050
  program.command("overdue").description("List tasks that are past their due date").option("--include-closed", "Include done/closed overdue tasks").option("--json", "Force JSON output even in terminal").action(
4805
5051
  wrapAction(async (opts) => {
4806
- const config = loadConfig();
5052
+ const config = loadConfig(getProfileName());
4807
5053
  const tasks = await fetchOverdueTasks(config, { includeClosed: opts.includeClosed });
4808
5054
  await printTasks(tasks, opts.json ?? false, config);
4809
5055
  })
4810
5056
  );
4811
5057
  program.command("assign <taskId>").description("Assign or unassign users from a task").option("--to <userId>", 'Add assignee (user ID or "me")').option("--remove <userId>", 'Remove assignee (user ID or "me")').option("--json", "Force JSON output even in terminal").action(
4812
5058
  wrapAction(async (taskId, opts) => {
4813
- const config = loadConfig();
5059
+ const config = loadConfig(getProfileName());
4814
5060
  const result = await assignTask(config, taskId, opts);
4815
5061
  if (shouldOutputJson(opts.json ?? false)) {
4816
5062
  console.log(JSON.stringify(result, null, 2));
@@ -4821,7 +5067,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4821
5067
  );
4822
5068
  program.command("depend <taskId>").description("Add or remove task dependencies").option("--on <taskId>", "Task that this task depends on (waiting on)").option("--blocks <taskId>", "Task that this task blocks").option("--remove", "Remove the dependency instead of adding it").option("--json", "Force JSON output even in terminal").action(
4823
5069
  wrapAction(async (taskId, opts) => {
4824
- const config = loadConfig();
5070
+ const config = loadConfig(getProfileName());
4825
5071
  const message = await manageDependency(config, taskId, opts);
4826
5072
  if (shouldOutputJson(opts.json ?? false)) {
4827
5073
  console.log(
@@ -4839,7 +5085,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4839
5085
  program.command("link <taskId> <linksTo>").description("Add or remove a link between two tasks").option("--remove", "Remove the link instead of adding it").option("--json", "Force JSON output even in terminal").action(
4840
5086
  wrapAction(
4841
5087
  async (taskId, linksTo, opts) => {
4842
- const config = loadConfig();
5088
+ const config = loadConfig(getProfileName());
4843
5089
  const result = await manageTaskLink(config, taskId, linksTo, opts.remove ?? false);
4844
5090
  if (shouldOutputJson(opts.json ?? false)) {
4845
5091
  console.log(
@@ -4857,7 +5103,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4857
5103
  );
4858
5104
  program.command("attach <taskId> <filePath>").description("Upload a file attachment to a task").option("--json", "Force JSON output even in terminal").action(
4859
5105
  wrapAction(async (taskId, filePath, opts) => {
4860
- const config = loadConfig();
5106
+ const config = loadConfig(getProfileName());
4861
5107
  const result = await attachFile(config, taskId, filePath);
4862
5108
  if (shouldOutputJson(opts.json ?? false)) {
4863
5109
  console.log(JSON.stringify(result, null, 2));
@@ -4869,7 +5115,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4869
5115
  );
4870
5116
  program.command("move <taskId>").description("Add or remove a task from a list").option("--to <listId>", "Add task to this list").option("--remove <listId>", "Remove task from this list").option("--json", "Force JSON output even in terminal").action(
4871
5117
  wrapAction(async (taskId, opts) => {
4872
- const config = loadConfig();
5118
+ const config = loadConfig(getProfileName());
4873
5119
  const message = await moveTask(config, taskId, opts);
4874
5120
  if (shouldOutputJson(opts.json ?? false)) {
4875
5121
  console.log(
@@ -4883,7 +5129,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4883
5129
  program.command("field <taskId>").description("Set or remove a custom field value on a task").option("--set <nameAndValue...>", 'Set field: --set "Field Name" value').option("--remove <fieldName>", "Remove field value by name").option("--json", "Force JSON output even in terminal").action(
4884
5130
  wrapAction(
4885
5131
  async (taskId, opts) => {
4886
- const config = loadConfig();
5132
+ const config = loadConfig(getProfileName());
4887
5133
  const fieldOpts = {};
4888
5134
  if (opts.set) {
4889
5135
  if (opts.set.length !== 2) {
@@ -4911,7 +5157,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4911
5157
  );
4912
5158
  program.command("delete <taskId>").description("Delete a task (requires confirmation)").option("--confirm", "Skip confirmation prompt (required in non-interactive mode)").option("--json", "Force JSON output even in terminal").action(
4913
5159
  wrapAction(async (taskId, opts) => {
4914
- const config = loadConfig();
5160
+ const config = loadConfig(getProfileName());
4915
5161
  const result = await deleteTaskCommand(config, taskId, opts);
4916
5162
  if (shouldOutputJson(opts.json ?? false)) {
4917
5163
  console.log(JSON.stringify(result, null, 2));
@@ -4923,7 +5169,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4923
5169
  program.command("tag <taskId>").description("Add or remove tags from a task").option("--add <tags>", "Comma-separated tag names to add").option("--remove <tags>", "Comma-separated tag names to remove").option("--json", "Force JSON output even in terminal").action(
4924
5170
  wrapAction(
4925
5171
  async (taskId, opts) => {
4926
- const config = loadConfig();
5172
+ const config = loadConfig(getProfileName());
4927
5173
  const result = await manageTags(config, taskId, opts);
4928
5174
  if (shouldOutputJson(opts.json ?? false)) {
4929
5175
  console.log(JSON.stringify(result, null, 2));
@@ -4939,7 +5185,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4939
5185
  const checklistCmd = program.command("checklist").description("Manage checklists on a task");
4940
5186
  checklistCmd.command("view <taskId>").description("View checklists on a task").option("--json", "Force JSON output even in terminal").action(
4941
5187
  wrapAction(async (taskId, opts) => {
4942
- const config = loadConfig();
5188
+ const config = loadConfig(getProfileName());
4943
5189
  const checklists = await viewChecklists(config, taskId);
4944
5190
  if (shouldOutputJson(opts.json ?? false)) {
4945
5191
  console.log(JSON.stringify(checklists, null, 2));
@@ -4952,7 +5198,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4952
5198
  );
4953
5199
  checklistCmd.command("create <taskId> <name>").description("Create a checklist on a task").option("--json", "Force JSON output even in terminal").action(
4954
5200
  wrapAction(async (taskId, name, opts) => {
4955
- const config = loadConfig();
5201
+ const config = loadConfig(getProfileName());
4956
5202
  const result = await createChecklist(config, taskId, name);
4957
5203
  if (shouldOutputJson(opts.json ?? false)) {
4958
5204
  console.log(JSON.stringify(result, null, 2));
@@ -4963,7 +5209,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4963
5209
  );
4964
5210
  checklistCmd.command("delete <checklistId>").description("Delete a checklist").option("--json", "Force JSON output even in terminal").action(
4965
5211
  wrapAction(async (checklistId, opts) => {
4966
- const config = loadConfig();
5212
+ const config = loadConfig(getProfileName());
4967
5213
  const result = await deleteChecklist(config, checklistId);
4968
5214
  if (shouldOutputJson(opts.json ?? false)) {
4969
5215
  console.log(JSON.stringify(result, null, 2));
@@ -4974,7 +5220,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4974
5220
  );
4975
5221
  checklistCmd.command("add-item <checklistId> <name>").description("Add an item to a checklist").option("--json", "Force JSON output even in terminal").action(
4976
5222
  wrapAction(async (checklistId, name, opts) => {
4977
- const config = loadConfig();
5223
+ const config = loadConfig(getProfileName());
4978
5224
  const result = await addChecklistItem(config, checklistId, name);
4979
5225
  if (shouldOutputJson(opts.json ?? false)) {
4980
5226
  console.log(JSON.stringify(result, null, 2));
@@ -4986,7 +5232,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
4986
5232
  checklistCmd.command("edit-item <checklistId> <checklistItemId>").description("Edit a checklist item").option("--name <name>", "New item name").option("--resolved", "Mark item as resolved").option("--unresolved", "Mark item as unresolved").option("--assignee <userId>", 'Assign user by ID (use "null" to unassign)').option("--json", "Force JSON output even in terminal").action(
4987
5233
  wrapAction(
4988
5234
  async (checklistId, checklistItemId, opts) => {
4989
- const config = loadConfig();
5235
+ const config = loadConfig(getProfileName());
4990
5236
  const updates = {};
4991
5237
  if (opts.name) updates.name = opts.name;
4992
5238
  if (opts.resolved) updates.resolved = true;
@@ -5005,7 +5251,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5005
5251
  );
5006
5252
  checklistCmd.command("delete-item <checklistId> <checklistItemId>").description("Delete a checklist item").option("--json", "Force JSON output even in terminal").action(
5007
5253
  wrapAction(async (checklistId, checklistItemId, opts) => {
5008
- const config = loadConfig();
5254
+ const config = loadConfig(getProfileName());
5009
5255
  const result = await deleteChecklistItem(config, checklistId, checklistItemId);
5010
5256
  if (shouldOutputJson(opts.json ?? false)) {
5011
5257
  console.log(JSON.stringify(result, null, 2));
@@ -5017,7 +5263,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5017
5263
  const timeCmd = program.command("time").description("Track time on tasks");
5018
5264
  timeCmd.command("start <taskId>").description("Start tracking time on a task").option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
5019
5265
  wrapAction(async (taskId, opts) => {
5020
- const config = loadConfig();
5266
+ const config = loadConfig(getProfileName());
5021
5267
  const result = await startTimer(config, taskId, opts.description);
5022
5268
  if (shouldOutputJson(opts.json ?? false)) {
5023
5269
  console.log(JSON.stringify(result, null, 2));
@@ -5029,7 +5275,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5029
5275
  );
5030
5276
  timeCmd.command("stop").description("Stop the running timer").option("--json", "Force JSON output even in terminal").action(
5031
5277
  wrapAction(async (opts) => {
5032
- const config = loadConfig();
5278
+ const config = loadConfig(getProfileName());
5033
5279
  const result = await stopTimer(config);
5034
5280
  if (shouldOutputJson(opts.json ?? false)) {
5035
5281
  console.log(JSON.stringify(result, null, 2));
@@ -5042,7 +5288,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5042
5288
  );
5043
5289
  timeCmd.command("status").description("Show the currently running timer").option("--json", "Force JSON output even in terminal").action(
5044
5290
  wrapAction(async (opts) => {
5045
- const config = loadConfig();
5291
+ const config = loadConfig(getProfileName());
5046
5292
  const result = await timerStatus(config);
5047
5293
  if (shouldOutputJson(opts.json ?? false)) {
5048
5294
  console.log(JSON.stringify(result, null, 2));
@@ -5058,7 +5304,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5058
5304
  timeCmd.command("log <taskId> <duration>").description('Log a manual time entry (e.g. "2h", "30m", "1h30m")').option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
5059
5305
  wrapAction(
5060
5306
  async (taskId, duration, opts) => {
5061
- const config = loadConfig();
5307
+ const config = loadConfig(getProfileName());
5062
5308
  const result = await logTime(config, taskId, duration, opts.description);
5063
5309
  if (shouldOutputJson(opts.json ?? false)) {
5064
5310
  console.log(JSON.stringify(result, null, 2));
@@ -5070,7 +5316,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5070
5316
  );
5071
5317
  timeCmd.command("list").description("List recent time entries (default: last 7 days)").option("--days <n>", "Number of days to look back", "7").option("--task <taskId>", "Filter by task ID").option("--json", "Force JSON output even in terminal").action(
5072
5318
  wrapAction(async (opts) => {
5073
- const config = loadConfig();
5319
+ const config = loadConfig(getProfileName());
5074
5320
  const days = opts.days ? Number(opts.days) : 7;
5075
5321
  if (!Number.isFinite(days) || days <= 0) {
5076
5322
  throw new Error("--days must be a positive number");
@@ -5088,7 +5334,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5088
5334
  timeCmd.command("update <timeEntryId>").description("Update a time entry").option("-d, --description <text>", "New description").option("--duration <duration>", 'New duration (e.g. "2h", "30m")').option("--json", "Force JSON output even in terminal").action(
5089
5335
  wrapAction(
5090
5336
  async (timeEntryId, opts) => {
5091
- const config = loadConfig();
5337
+ const config = loadConfig(getProfileName());
5092
5338
  const entry = await updateTimeEntry(config, timeEntryId, {
5093
5339
  description: opts.description,
5094
5340
  duration: opts.duration
@@ -5105,7 +5351,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5105
5351
  );
5106
5352
  timeCmd.command("delete <timeEntryId>").description("Delete a time entry").option("--json", "Force JSON output even in terminal").action(
5107
5353
  wrapAction(async (timeEntryId, opts) => {
5108
- const config = loadConfig();
5354
+ const config = loadConfig(getProfileName());
5109
5355
  await deleteTimeEntry(config, timeEntryId);
5110
5356
  if (shouldOutputJson(opts.json ?? false)) {
5111
5357
  console.log(JSON.stringify({ deleted: timeEntryId }));
@@ -5116,7 +5362,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5116
5362
  );
5117
5363
  program.command("tags <spaceId>").description("List tags in a space").option("--json", "Force JSON output even in terminal").action(
5118
5364
  wrapAction(async (spaceId, opts) => {
5119
- const config = loadConfig();
5365
+ const config = loadConfig(getProfileName());
5120
5366
  const tags = await listSpaceTags(config, spaceId);
5121
5367
  if (shouldOutputJson(opts.json ?? false)) {
5122
5368
  console.log(JSON.stringify(tags, null, 2));
@@ -5130,7 +5376,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5130
5376
  program.command("tag-create <spaceId> <name>").description("Create a tag in a space").option("--fg <color>", "Foreground color (hex)").option("--bg <color>", "Background color (hex)").option("--json", "Force JSON output even in terminal").action(
5131
5377
  wrapAction(
5132
5378
  async (spaceId, name, opts) => {
5133
- const config = loadConfig();
5379
+ const config = loadConfig(getProfileName());
5134
5380
  await createSpaceTag(config, spaceId, name, opts.fg, opts.bg);
5135
5381
  if (shouldOutputJson(opts.json ?? false)) {
5136
5382
  console.log(JSON.stringify({ success: true, spaceId, tag: name }, null, 2));
@@ -5142,7 +5388,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5142
5388
  );
5143
5389
  program.command("tag-delete <spaceId> <name>").description("Delete a tag from a space").option("--json", "Force JSON output even in terminal").action(
5144
5390
  wrapAction(async (spaceId, name, opts) => {
5145
- const config = loadConfig();
5391
+ const config = loadConfig(getProfileName());
5146
5392
  await deleteSpaceTag(config, spaceId, name);
5147
5393
  if (shouldOutputJson(opts.json ?? false)) {
5148
5394
  console.log(JSON.stringify({ success: true, spaceId, tag: name }, null, 2));
@@ -5153,7 +5399,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5153
5399
  );
5154
5400
  program.command("members").description("List workspace members").option("--json", "Force JSON output even in terminal").action(
5155
5401
  wrapAction(async (opts) => {
5156
- const config = loadConfig();
5402
+ const config = loadConfig(getProfileName());
5157
5403
  const members = await listMembers(config);
5158
5404
  if (shouldOutputJson(opts.json ?? false)) {
5159
5405
  console.log(JSON.stringify(members, null, 2));
@@ -5166,7 +5412,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5166
5412
  );
5167
5413
  program.command("fields <listId>").description("List custom fields for a list").option("--json", "Force JSON output even in terminal").action(
5168
5414
  wrapAction(async (listId, opts) => {
5169
- const config = loadConfig();
5415
+ const config = loadConfig(getProfileName());
5170
5416
  const fields = await listFields(config, listId);
5171
5417
  if (shouldOutputJson(opts.json ?? false)) {
5172
5418
  console.log(JSON.stringify(fields, null, 2));
@@ -5179,7 +5425,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5179
5425
  );
5180
5426
  program.command("duplicate <taskId>").description("Duplicate a task").option("--json", "Force JSON output even in terminal").action(
5181
5427
  wrapAction(async (taskId, opts) => {
5182
- const config = loadConfig();
5428
+ const config = loadConfig(getProfileName());
5183
5429
  const result = await duplicateTask(config, taskId);
5184
5430
  if (shouldOutputJson(opts.json ?? false)) {
5185
5431
  console.log(JSON.stringify(result, null, 2));
@@ -5191,7 +5437,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5191
5437
  const bulkCmd = program.command("bulk").description("Bulk task operations");
5192
5438
  bulkCmd.command("status <status> <taskIds...>").description("Update status of multiple tasks").option("--json", "Force JSON output even in terminal").action(
5193
5439
  wrapAction(async (status, taskIds, opts) => {
5194
- const config = loadConfig();
5440
+ const config = loadConfig(getProfileName());
5195
5441
  const result = await bulkUpdateStatus(config, taskIds, status);
5196
5442
  if (shouldOutputJson(opts.json ?? false)) {
5197
5443
  console.log(JSON.stringify(result, null, 2));
@@ -5207,7 +5453,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5207
5453
  );
5208
5454
  program.command("goals").description("List goals in your workspace").option("--json", "Force JSON output even in terminal").action(
5209
5455
  wrapAction(async (opts) => {
5210
- const config = loadConfig();
5456
+ const config = loadConfig(getProfileName());
5211
5457
  const goals = await listGoals(config);
5212
5458
  if (shouldOutputJson(opts.json ?? false)) {
5213
5459
  console.log(JSON.stringify(goals, null, 2));
@@ -5221,7 +5467,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5221
5467
  program.command("goal-create <name>").description("Create a goal").option("-d, --description <text>", "Goal description").option("--color <hex>", "Goal color (hex)").option("--json", "Force JSON output even in terminal").action(
5222
5468
  wrapAction(
5223
5469
  async (name, opts) => {
5224
- const config = loadConfig();
5470
+ const config = loadConfig(getProfileName());
5225
5471
  const goal = await createGoal(config, name, {
5226
5472
  description: opts.description,
5227
5473
  color: opts.color
@@ -5237,7 +5483,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5237
5483
  program.command("goal-update <goalId>").description("Update a goal").option("-n, --name <text>", "New goal name").option("-d, --description <text>", "New description").option("--color <hex>", "New color (hex)").option("--json", "Force JSON output even in terminal").action(
5238
5484
  wrapAction(
5239
5485
  async (goalId, opts) => {
5240
- const config = loadConfig();
5486
+ const config = loadConfig(getProfileName());
5241
5487
  const goal = await updateGoal(config, goalId, {
5242
5488
  name: opts.name,
5243
5489
  description: opts.description,
@@ -5253,7 +5499,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5253
5499
  );
5254
5500
  program.command("goal-delete <goalId>").description("Delete a goal").option("--json", "Force JSON output even in terminal").action(
5255
5501
  wrapAction(async (goalId, opts) => {
5256
- const config = loadConfig();
5502
+ const config = loadConfig(getProfileName());
5257
5503
  await deleteGoal(config, goalId);
5258
5504
  if (shouldOutputJson(opts.json ?? false)) {
5259
5505
  console.log(JSON.stringify({ success: true, goalId }, null, 2));
@@ -5264,7 +5510,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5264
5510
  );
5265
5511
  program.command("key-results <goalId>").description("List key results for a goal").option("--json", "Force JSON output even in terminal").action(
5266
5512
  wrapAction(async (goalId, opts) => {
5267
- const config = loadConfig();
5513
+ const config = loadConfig(getProfileName());
5268
5514
  const krs = await listKeyResults(config, goalId);
5269
5515
  if (shouldOutputJson(opts.json ?? false)) {
5270
5516
  console.log(JSON.stringify(krs, null, 2));
@@ -5278,7 +5524,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5278
5524
  program.command("key-result-create <goalId> <name>").description("Create a key result on a goal").option("--type <type>", "Key result type (number or percentage)", "number").option("--target <n>", "Target value", "100").option("--json", "Force JSON output even in terminal").action(
5279
5525
  wrapAction(
5280
5526
  async (goalId, name, opts) => {
5281
- const config = loadConfig();
5527
+ const config = loadConfig(getProfileName());
5282
5528
  const target = Number(opts.target ?? 100);
5283
5529
  if (!Number.isFinite(target) || target <= 0) {
5284
5530
  throw new Error("--target must be a positive number");
@@ -5295,7 +5541,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5295
5541
  program.command("key-result-update <keyResultId>").description("Update a key result").option("--progress <n>", "Current progress value").option("--note <text>", "Progress note").option("--json", "Force JSON output even in terminal").action(
5296
5542
  wrapAction(
5297
5543
  async (keyResultId, opts) => {
5298
- const config = loadConfig();
5544
+ const config = loadConfig(getProfileName());
5299
5545
  const updates = {};
5300
5546
  if (opts.progress !== void 0) {
5301
5547
  const p = Number(opts.progress);
@@ -5314,7 +5560,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5314
5560
  );
5315
5561
  program.command("key-result-delete <keyResultId>").description("Delete a key result").option("--json", "Force JSON output even in terminal").action(
5316
5562
  wrapAction(async (keyResultId, opts) => {
5317
- const config = loadConfig();
5563
+ const config = loadConfig(getProfileName());
5318
5564
  await deleteKeyResult(config, keyResultId);
5319
5565
  if (shouldOutputJson(opts.json ?? false)) {
5320
5566
  console.log(JSON.stringify({ success: true, keyResultId }, null, 2));
@@ -5325,7 +5571,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5325
5571
  );
5326
5572
  program.command("docs [query]").description("List workspace docs (optionally filter by name)").option("--json", "Force JSON output even in terminal").action(
5327
5573
  wrapAction(async (query, opts) => {
5328
- const config = loadConfig();
5574
+ const config = loadConfig(getProfileName());
5329
5575
  const docs = await listDocs(config, query);
5330
5576
  if (shouldOutputJson(opts.json ?? false)) {
5331
5577
  console.log(JSON.stringify(docs, null, 2));
@@ -5338,7 +5584,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5338
5584
  );
5339
5585
  program.command("doc <docId> [pageId]").description("View a doc (metadata + page tree) or a specific page").option("--json", "Force JSON output even in terminal").action(
5340
5586
  wrapAction(async (docId, pageId, opts) => {
5341
- const config = loadConfig();
5587
+ const config = loadConfig(getProfileName());
5342
5588
  if (pageId) {
5343
5589
  const page = await getDocPage(config, docId, pageId);
5344
5590
  if (shouldOutputJson(opts.json ?? false)) {
@@ -5362,7 +5608,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5362
5608
  );
5363
5609
  program.command("doc-pages <docId>").description("List all pages in a doc with content").option("--json", "Force JSON output even in terminal").action(
5364
5610
  wrapAction(async (docId, opts) => {
5365
- const config = loadConfig();
5611
+ const config = loadConfig(getProfileName());
5366
5612
  const pages = await getAllDocPages(config, docId);
5367
5613
  if (shouldOutputJson(opts.json ?? false)) {
5368
5614
  console.log(JSON.stringify(pages, null, 2));
@@ -5375,7 +5621,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5375
5621
  );
5376
5622
  program.command("folders <spaceId>").description("List folders in a space (with their lists)").option("--name <partial>", "Filter folders by partial name match").option("--json", "Force JSON output even in terminal").action(
5377
5623
  wrapAction(async (spaceId, opts) => {
5378
- const config = loadConfig();
5624
+ const config = loadConfig(getProfileName());
5379
5625
  const folders = await listFolders(config, spaceId, opts.name);
5380
5626
  if (shouldOutputJson(opts.json ?? false)) {
5381
5627
  console.log(JSON.stringify(folders, null, 2));
@@ -5388,7 +5634,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5388
5634
  );
5389
5635
  program.command("doc-create <title>").description("Create a new doc").option("-c, --content <text>", "Initial content (markdown)").option("--json", "Force JSON output even in terminal").action(
5390
5636
  wrapAction(async (title, opts) => {
5391
- const config = loadConfig();
5637
+ const config = loadConfig(getProfileName());
5392
5638
  const result = await createDoc(config, title, opts.content);
5393
5639
  if (shouldOutputJson(opts.json ?? false)) {
5394
5640
  console.log(JSON.stringify(result, null, 2));
@@ -5400,7 +5646,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5400
5646
  program.command("doc-page-create <docId> <name>").description("Create a page in a doc").option("-c, --content <text>", "Page content (markdown)").option("--parent-page <pageId>", "Parent page ID for nesting").option("--json", "Force JSON output even in terminal").action(
5401
5647
  wrapAction(
5402
5648
  async (docId, name, opts) => {
5403
- const config = loadConfig();
5649
+ const config = loadConfig(getProfileName());
5404
5650
  const page = await createDocPage(config, docId, name, opts.content, opts.parentPage);
5405
5651
  if (shouldOutputJson(opts.json ?? false)) {
5406
5652
  console.log(JSON.stringify(page, null, 2));
@@ -5413,7 +5659,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5413
5659
  program.command("doc-page-edit <docId> <pageId>").description("Edit a doc page").option("--name <text>", "New page name").option("-c, --content <text>", "New page content (markdown)").option("--json", "Force JSON output even in terminal").action(
5414
5660
  wrapAction(
5415
5661
  async (docId, pageId, opts) => {
5416
- const config = loadConfig();
5662
+ const config = loadConfig(getProfileName());
5417
5663
  const page = await editDocPage(config, docId, pageId, {
5418
5664
  name: opts.name,
5419
5665
  content: opts.content
@@ -5428,7 +5674,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5428
5674
  );
5429
5675
  program.command("doc-delete <docId>").description("Delete a doc").option("--json", "Force JSON output even in terminal").action(
5430
5676
  wrapAction(async (docId, opts) => {
5431
- const config = loadConfig();
5677
+ const config = loadConfig(getProfileName());
5432
5678
  await deleteDoc(config, docId);
5433
5679
  if (shouldOutputJson(opts.json ?? false)) {
5434
5680
  console.log(JSON.stringify({ success: true, docId }, null, 2));
@@ -5439,7 +5685,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5439
5685
  );
5440
5686
  program.command("doc-page-delete <docId> <pageId>").description("Delete a doc page").option("--json", "Force JSON output even in terminal").action(
5441
5687
  wrapAction(async (docId, pageId, opts) => {
5442
- const config = loadConfig();
5688
+ const config = loadConfig(getProfileName());
5443
5689
  await deleteDocPage(config, docId, pageId);
5444
5690
  if (shouldOutputJson(opts.json ?? false)) {
5445
5691
  console.log(JSON.stringify({ success: true, docId, pageId }, null, 2));
@@ -5451,7 +5697,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5451
5697
  program.command("tag-update <spaceId> <tagName>").description("Update a tag in a space").requiredOption("--name <newName>", "New tag name").option("--fg <color>", "New foreground color (hex)").option("--bg <color>", "New background color (hex)").option("--json", "Force JSON output even in terminal").action(
5452
5698
  wrapAction(
5453
5699
  async (spaceId, tagName, opts) => {
5454
- const config = loadConfig();
5700
+ const config = loadConfig(getProfileName());
5455
5701
  await updateSpaceTag(config, spaceId, tagName, {
5456
5702
  name: opts.name,
5457
5703
  fg: opts.fg,
@@ -5473,7 +5719,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5473
5719
  );
5474
5720
  program.command("task-types").description("List custom task types in your workspace").option("--json", "Force JSON output even in terminal").action(
5475
5721
  wrapAction(async (opts) => {
5476
- const config = loadConfig();
5722
+ const config = loadConfig(getProfileName());
5477
5723
  const types = await listTaskTypes(config);
5478
5724
  if (shouldOutputJson(opts.json ?? false)) {
5479
5725
  console.log(JSON.stringify(types, null, 2));
@@ -5486,7 +5732,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5486
5732
  );
5487
5733
  program.command("templates").description("List task templates in your workspace").option("--json", "Force JSON output even in terminal").action(
5488
5734
  wrapAction(async (opts) => {
5489
- const config = loadConfig();
5735
+ const config = loadConfig(getProfileName());
5490
5736
  const templates = await listTemplates(config);
5491
5737
  if (shouldOutputJson(opts.json ?? false)) {
5492
5738
  console.log(JSON.stringify(templates, null, 2));
@@ -5497,10 +5743,65 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5497
5743
  }
5498
5744
  })
5499
5745
  );
5746
+ const profileCmd = program.command("profile").description("Manage profiles");
5747
+ profileCmd.command("list").description("List all profiles").option("--json", "Force JSON output even in terminal").action(
5748
+ wrapAction(async (opts) => {
5749
+ const profiles = listProfiles();
5750
+ if (shouldOutputJson(opts.json ?? false)) {
5751
+ console.log(JSON.stringify(profiles, null, 2));
5752
+ } else {
5753
+ for (const p of profiles) {
5754
+ const marker = p.isDefault ? " (default)" : "";
5755
+ console.log(`${p.name}${marker}${p.teamId ? ` [team: ${p.teamId}]` : ""}`);
5756
+ }
5757
+ if (profiles.length === 0)
5758
+ console.log("No profiles configured. Run: cup profile add <name>");
5759
+ }
5760
+ })
5761
+ );
5762
+ profileCmd.command("add <name>").description("Add a new profile").action(
5763
+ wrapAction(async (name) => {
5764
+ const { password: password2, select: select3 } = await import("@inquirer/prompts");
5765
+ const apiToken = (await password2({ message: "ClickUp API token (pk_...):" })).trim();
5766
+ if (!apiToken.startsWith("pk_")) throw new Error("Token must start with pk_");
5767
+ const client = new ClickUpClient({ apiToken });
5768
+ const me = await client.getMe();
5769
+ process.stdout.write(`Authenticated as @${me.username}
5770
+ `);
5771
+ const teams = await client.getTeams();
5772
+ if (teams.length === 0) throw new Error("No workspaces found for this token.");
5773
+ let teamId;
5774
+ if (teams.length === 1) {
5775
+ teamId = teams[0].id;
5776
+ process.stdout.write(`Workspace: ${teams[0].name}
5777
+ `);
5778
+ } else {
5779
+ teamId = await select3({
5780
+ message: "Select workspace:",
5781
+ choices: teams.map((t) => ({ name: t.name, value: t.id }))
5782
+ });
5783
+ }
5784
+ addProfile(name, { apiToken, teamId });
5785
+ process.stdout.write(`Profile "${name}" added.
5786
+ `);
5787
+ })
5788
+ );
5789
+ profileCmd.command("remove <name>").description("Remove a profile").action(
5790
+ wrapAction(async (name) => {
5791
+ removeProfile(name);
5792
+ console.log(`Removed profile "${name}"`);
5793
+ })
5794
+ );
5795
+ profileCmd.command("use <name>").description("Set the default profile").action(
5796
+ wrapAction(async (name) => {
5797
+ setDefaultProfile(name);
5798
+ console.log(`Default profile set to "${name}"`);
5799
+ })
5800
+ );
5500
5801
  const configCmd = program.command("config").description("Manage CLI configuration");
5501
5802
  configCmd.command("get <key>").description("Print a config value").action(
5502
5803
  wrapAction(async (key) => {
5503
- const value = getConfigValue(key);
5804
+ const value = getConfigValue(key, getProfileName());
5504
5805
  if (value !== void 0) {
5505
5806
  console.log(value);
5506
5807
  }
@@ -5508,7 +5809,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5508
5809
  );
5509
5810
  configCmd.command("set <key> <value>").description("Set a config value").action(
5510
5811
  wrapAction(async (key, value) => {
5511
- setConfigValue(key, value);
5812
+ setConfigValue(key, value, getProfileName());
5512
5813
  })
5513
5814
  );
5514
5815
  configCmd.command("path").description("Print config file path").action(
@@ -5531,9 +5832,16 @@ async function run(argv = process.argv) {
5531
5832
  }
5532
5833
  process.on("SIGINT", () => {
5533
5834
  process.stderr.write("\nInterrupted\n");
5534
- process.exit(130);
5835
+ process.exitCode = 130;
5535
5836
  });
5536
- var isDirectExecution = process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === realpathSync(resolve(process.argv[1]));
5837
+ function checkDirectExecution() {
5838
+ try {
5839
+ return process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === realpathSync(resolve(process.argv[1]));
5840
+ } catch {
5841
+ return false;
5842
+ }
5843
+ }
5844
+ var isDirectExecution = checkDirectExecution();
5537
5845
  if (isDirectExecution) {
5538
5846
  await run();
5539
5847
  }